mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 15:42:20 +00:00
[VM/Service] Create JSONBase64String class
TEST=CI Change-Id: Ia14fcb1788a2685bef4fd61babfdd7089dd85a06 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287801 Reviewed-by: Ben Konyi <bkonyi@google.com> Commit-Queue: Derek Xu <derekx@google.com>
This commit is contained in:
parent
b4aa83b0b7
commit
8df1b88877
|
@ -595,6 +595,40 @@ void JSONArray::AddValueF(const char* format, ...) const {
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
void JSONBase64String::AppendBytes(const uint8_t* bytes, intptr_t length) {
|
||||
ASSERT(bytes != nullptr);
|
||||
|
||||
if (num_queued_bytes_ > 0) {
|
||||
while (length > 0) {
|
||||
queued_bytes_[num_queued_bytes_++] = bytes[0];
|
||||
bytes++;
|
||||
length--;
|
||||
if (num_queued_bytes_ == 3) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (num_queued_bytes_ < 3) {
|
||||
return;
|
||||
}
|
||||
stream_->AppendBytesInBase64(queued_bytes_, 3);
|
||||
num_queued_bytes_ = 0;
|
||||
}
|
||||
|
||||
intptr_t length_mod_3 = length % 3;
|
||||
intptr_t largest_multiple_of_3_less_than_or_equal_to_length =
|
||||
length - length_mod_3;
|
||||
if (largest_multiple_of_3_less_than_or_equal_to_length > 0) {
|
||||
stream_->AppendBytesInBase64(
|
||||
bytes, largest_multiple_of_3_less_than_or_equal_to_length);
|
||||
}
|
||||
|
||||
for (intptr_t i = 0; i < length_mod_3; ++i) {
|
||||
queued_bytes_[i] =
|
||||
bytes[largest_multiple_of_3_less_than_or_equal_to_length + i];
|
||||
}
|
||||
num_queued_bytes_ = length_mod_3;
|
||||
}
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
||||
} // namespace dart
|
||||
|
|
|
@ -217,6 +217,16 @@ class JSONStream : ValueObject {
|
|||
writer_.CloseArray();
|
||||
}
|
||||
|
||||
// Append the Base64 encoding of |bytes| to the stream.
|
||||
//
|
||||
// Beware that padding characters are added when |length| is not a multiple of
|
||||
// three. Padding is only valid at the end of Base64 strings, so you must be
|
||||
// careful when trying to populate a single Base64 string with multiple calls
|
||||
// to this method. |JSONBase64String| should be used for that use-case,
|
||||
// because it handles padding management.
|
||||
void AppendBytesInBase64(const uint8_t* bytes, intptr_t length) {
|
||||
writer_.AppendBytesInBase64(bytes, length);
|
||||
}
|
||||
void PrintValueNull() { writer_.PrintValueNull(); }
|
||||
void PrintValueBool(bool b) { writer_.PrintValueBool(b); }
|
||||
void PrintValue(intptr_t i) { writer_.PrintValue(i); }
|
||||
|
@ -350,6 +360,7 @@ class JSONStream : ValueObject {
|
|||
intptr_t ignore_object_depth_;
|
||||
friend class JSONObject;
|
||||
friend class JSONArray;
|
||||
friend class JSONBase64String;
|
||||
friend class TimelineEvent;
|
||||
};
|
||||
|
||||
|
@ -519,6 +530,28 @@ class JSONArray : public ValueObject {
|
|||
DISALLOW_COPY_AND_ASSIGN(JSONArray);
|
||||
};
|
||||
|
||||
class JSONBase64String : public ValueObject {
|
||||
public:
|
||||
explicit JSONBase64String(JSONStream* stream)
|
||||
: stream_(stream), queued_bytes_(), num_queued_bytes_(0) {
|
||||
stream_->AppendBytes(reinterpret_cast<const uint8_t*>("\""), 1);
|
||||
}
|
||||
~JSONBase64String() {
|
||||
stream_->AppendBytesInBase64(queued_bytes_, num_queued_bytes_);
|
||||
stream_->AppendBytes(reinterpret_cast<const uint8_t*>("\""), 1);
|
||||
}
|
||||
|
||||
void AppendBytes(const uint8_t* bytes, intptr_t length);
|
||||
|
||||
private:
|
||||
JSONStream* stream_;
|
||||
uint8_t queued_bytes_[3];
|
||||
intptr_t num_queued_bytes_;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(JSONBase64String);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_JSON_STREAM_H_
|
||||
|
|
|
@ -91,6 +91,17 @@ TEST_CASE(JSON_JSONStream_Array) {
|
|||
EXPECT_STREQ("[true,false]", js.ToCString());
|
||||
}
|
||||
|
||||
TEST_CASE(JSON_JSONStream_Base64String) {
|
||||
JSONStream js;
|
||||
{
|
||||
JSONBase64String jsonBase64String(&js);
|
||||
jsonBase64String.AppendBytes(reinterpret_cast<const uint8_t*>("Hello"), 5);
|
||||
jsonBase64String.AppendBytes(reinterpret_cast<const uint8_t*>(", "), 2);
|
||||
jsonBase64String.AppendBytes(reinterpret_cast<const uint8_t*>("world!"), 6);
|
||||
}
|
||||
EXPECT_STREQ("\"SGVsbG8sIHdvcmxkIQ==\"", js.ToCString());
|
||||
}
|
||||
|
||||
TEST_CASE(JSON_JSONStream_Object) {
|
||||
JSONStream js;
|
||||
{
|
||||
|
|
|
@ -39,6 +39,36 @@ void JSONWriter::AppendBytes(const uint8_t* buffer, intptr_t buffer_length) {
|
|||
buffer_.AddRaw(buffer, buffer_length);
|
||||
}
|
||||
|
||||
static const char base64_digits[65] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char base64_pad = '=';
|
||||
|
||||
void JSONWriter::AppendBytesInBase64(const uint8_t* bytes, intptr_t length) {
|
||||
ASSERT(bytes != nullptr);
|
||||
intptr_t odd_bits = length % 3;
|
||||
intptr_t even_bits = length - odd_bits;
|
||||
for (intptr_t i = 0; i < even_bits; i += 3) {
|
||||
intptr_t triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
|
||||
buffer_.AddChar(base64_digits[triplet >> 18]);
|
||||
buffer_.AddChar(base64_digits[(triplet >> 12) & 63]);
|
||||
buffer_.AddChar(base64_digits[(triplet >> 6) & 63]);
|
||||
buffer_.AddChar(base64_digits[triplet & 63]);
|
||||
}
|
||||
if (odd_bits == 1) {
|
||||
intptr_t triplet = bytes[even_bits] << 16;
|
||||
buffer_.AddChar(base64_digits[triplet >> 18]);
|
||||
buffer_.AddChar(base64_digits[(triplet >> 12) & 63]);
|
||||
buffer_.AddChar(base64_pad);
|
||||
buffer_.AddChar(base64_pad);
|
||||
} else if (odd_bits == 2) {
|
||||
intptr_t triplet = (bytes[even_bits] << 16) | (bytes[even_bits + 1] << 8);
|
||||
buffer_.AddChar(base64_digits[triplet >> 18]);
|
||||
buffer_.AddChar(base64_digits[(triplet >> 12) & 63]);
|
||||
buffer_.AddChar(base64_digits[(triplet >> 6) & 63]);
|
||||
buffer_.AddChar(base64_pad);
|
||||
}
|
||||
}
|
||||
|
||||
void JSONWriter::AppendSerializedObject(const char* serialized_object) {
|
||||
PrintCommaIfNeeded();
|
||||
buffer_.AddString(serialized_object);
|
||||
|
@ -126,37 +156,10 @@ void JSONWriter::PrintValue(double d) {
|
|||
buffer_.Printf("%s", buffer);
|
||||
}
|
||||
|
||||
static const char base64_digits[65] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char base64_pad = '=';
|
||||
|
||||
void JSONWriter::PrintValueBase64(const uint8_t* bytes, intptr_t length) {
|
||||
PrintCommaIfNeeded();
|
||||
buffer_.AddChar('"');
|
||||
|
||||
intptr_t odd_bits = length % 3;
|
||||
intptr_t even_bits = length - odd_bits;
|
||||
for (intptr_t i = 0; i < even_bits; i += 3) {
|
||||
intptr_t triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
|
||||
buffer_.AddChar(base64_digits[triplet >> 18]);
|
||||
buffer_.AddChar(base64_digits[(triplet >> 12) & 63]);
|
||||
buffer_.AddChar(base64_digits[(triplet >> 6) & 63]);
|
||||
buffer_.AddChar(base64_digits[triplet & 63]);
|
||||
}
|
||||
if (odd_bits == 1) {
|
||||
intptr_t triplet = bytes[even_bits] << 16;
|
||||
buffer_.AddChar(base64_digits[triplet >> 18]);
|
||||
buffer_.AddChar(base64_digits[(triplet >> 12) & 63]);
|
||||
buffer_.AddChar(base64_pad);
|
||||
buffer_.AddChar(base64_pad);
|
||||
} else if (odd_bits == 2) {
|
||||
intptr_t triplet = (bytes[even_bits] << 16) | (bytes[even_bits + 1] << 8);
|
||||
buffer_.AddChar(base64_digits[triplet >> 18]);
|
||||
buffer_.AddChar(base64_digits[(triplet >> 12) & 63]);
|
||||
buffer_.AddChar(base64_digits[(triplet >> 6) & 63]);
|
||||
buffer_.AddChar(base64_pad);
|
||||
}
|
||||
|
||||
AppendBytesInBase64(bytes, length);
|
||||
buffer_.AddChar('"');
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,15 @@ class JSONWriter : ValueObject {
|
|||
// Append |buffer| to the stream.
|
||||
void AppendBytes(const uint8_t* buffer, intptr_t buffer_length);
|
||||
|
||||
// Append the Base64 encoding of |bytes| to the stream.
|
||||
//
|
||||
// Beware that padding characters are added when |length| is not a multiple of
|
||||
// three. Padding is only valid at the end of Base64 strings, so you must be
|
||||
// careful when trying to populate a single Base64 string with multiple calls
|
||||
// to this method. |JSONBase64String| should be used for that use-case,
|
||||
// because it handles padding management.
|
||||
void AppendBytesInBase64(const uint8_t* bytes, intptr_t length);
|
||||
|
||||
// Append |serialized_object| to the stream.
|
||||
void AppendSerializedObject(const char* serialized_object);
|
||||
|
||||
|
|
Loading…
Reference in a new issue