1// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/assert.h"
6
7#include "platform/unicode.h"
8#include "vm/double_conversion.h"
9#include "vm/json_writer.h"
10#include "vm/object.h"
11
12namespace dart {
13
14class MaybeOnStackBuffer {
15 public:
16 explicit MaybeOnStackBuffer(intptr_t size) {
17 if (size > kOnStackBufferCapacity) {
18 p_ = reinterpret_cast<char*>(malloc(size));
19 } else {
20 p_ = &buffer_[0];
21 }
22 }
23 ~MaybeOnStackBuffer() {
24 if (p_ != &buffer_[0]) free(p_);
25 }
26
27 char* p() { return p_; }
28
29 private:
30 static const intptr_t kOnStackBufferCapacity = 4096;
31 char* p_;
32 char buffer_[kOnStackBufferCapacity];
33};
34
35JSONWriter::JSONWriter(intptr_t buf_size)
36 : open_objects_(0), buffer_(buf_size) {}
37
38void JSONWriter::AppendSerializedObject(const char* serialized_object) {
39 PrintCommaIfNeeded();
40 buffer_.AddString(serialized_object);
41}
42
43void JSONWriter::AppendSerializedObject(const uint8_t* buffer,
44 intptr_t buffer_length) {
45 buffer_.AddRaw(buffer, buffer_length);
46}
47
48void JSONWriter::AppendSerializedObject(const char* property_name,
49 const char* serialized_object) {
50 PrintCommaIfNeeded();
51 PrintPropertyName(property_name);
52 buffer_.AddString(serialized_object);
53}
54
55void JSONWriter::Clear() {
56 buffer_.Clear();
57 open_objects_ = 0;
58}
59
60void JSONWriter::OpenObject(const char* property_name) {
61 PrintCommaIfNeeded();
62 open_objects_++;
63 if (property_name != NULL) {
64 PrintPropertyName(property_name);
65 }
66 buffer_.AddChar('{');
67}
68
69void JSONWriter::UncloseObject() {
70 intptr_t len = buffer_.length();
71 ASSERT(len > 0);
72 ASSERT(buffer_.buffer()[len - 1] == '}');
73 open_objects_++;
74 buffer_.set_length(len - 1);
75}
76
77void JSONWriter::CloseObject() {
78 ASSERT(open_objects_ > 0);
79 open_objects_--;
80 buffer_.AddChar('}');
81}
82
83void JSONWriter::OpenArray(const char* property_name) {
84 PrintCommaIfNeeded();
85 if (property_name != NULL) {
86 PrintPropertyName(property_name);
87 }
88 open_objects_++;
89 buffer_.AddChar('[');
90}
91
92void JSONWriter::CloseArray() {
93 ASSERT(open_objects_ > 0);
94 open_objects_--;
95 buffer_.AddChar(']');
96}
97
98void JSONWriter::PrintValueNull() {
99 PrintCommaIfNeeded();
100 buffer_.Printf("null");
101}
102
103void JSONWriter::PrintValueBool(bool b) {
104 PrintCommaIfNeeded();
105 buffer_.Printf("%s", b ? "true" : "false");
106}
107
108void JSONWriter::PrintValue(intptr_t i) {
109 EnsureIntegerIsRepresentableInJavaScript(static_cast<int64_t>(i));
110 PrintCommaIfNeeded();
111 buffer_.Printf("%" Pd "", i);
112}
113
114void JSONWriter::PrintValue64(int64_t i) {
115 EnsureIntegerIsRepresentableInJavaScript(i);
116 PrintCommaIfNeeded();
117 buffer_.Printf("%" Pd64 "", i);
118}
119
120void JSONWriter::PrintValue(double d) {
121 // Max length of a double in characters (including \0).
122 // See double_conversion.cc.
123 const size_t kBufferLen = 25;
124 char buffer[kBufferLen];
125 DoubleToCString(d, buffer, kBufferLen);
126 PrintCommaIfNeeded();
127 buffer_.Printf("%s", buffer);
128}
129
130static const char base64_digits[65] =
131 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
132static const char base64_pad = '=';
133
134void JSONWriter::PrintValueBase64(const uint8_t* bytes, intptr_t length) {
135 PrintCommaIfNeeded();
136 buffer_.AddChar('"');
137
138 intptr_t odd_bits = length % 3;
139 intptr_t even_bits = length - odd_bits;
140 for (intptr_t i = 0; i < even_bits; i += 3) {
141 intptr_t triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
142 buffer_.AddChar(base64_digits[triplet >> 18]);
143 buffer_.AddChar(base64_digits[(triplet >> 12) & 63]);
144 buffer_.AddChar(base64_digits[(triplet >> 6) & 63]);
145 buffer_.AddChar(base64_digits[triplet & 63]);
146 }
147 if (odd_bits == 1) {
148 intptr_t triplet = bytes[even_bits] << 16;
149 buffer_.AddChar(base64_digits[triplet >> 18]);
150 buffer_.AddChar(base64_digits[(triplet >> 12) & 63]);
151 buffer_.AddChar(base64_pad);
152 buffer_.AddChar(base64_pad);
153 } else if (odd_bits == 2) {
154 intptr_t triplet = (bytes[even_bits] << 16) | (bytes[even_bits + 1] << 8);
155 buffer_.AddChar(base64_digits[triplet >> 18]);
156 buffer_.AddChar(base64_digits[(triplet >> 12) & 63]);
157 buffer_.AddChar(base64_digits[(triplet >> 6) & 63]);
158 buffer_.AddChar(base64_pad);
159 }
160
161 buffer_.AddChar('"');
162}
163
164void JSONWriter::PrintValue(const char* s) {
165 PrintCommaIfNeeded();
166 buffer_.AddChar('"');
167 AddEscapedUTF8String(s);
168 buffer_.AddChar('"');
169}
170
171bool JSONWriter::PrintValueStr(const String& s,
172 intptr_t offset,
173 intptr_t count) {
174 PrintCommaIfNeeded();
175 buffer_.AddChar('"');
176 bool did_truncate = AddDartString(s, offset, count);
177 buffer_.AddChar('"');
178 return did_truncate;
179}
180
181void JSONWriter::PrintValueNoEscape(const char* s) {
182 PrintCommaIfNeeded();
183 buffer_.Printf("%s", s);
184}
185
186void JSONWriter::PrintfValue(const char* format, ...) {
187 va_list args;
188 va_start(args, format);
189 VPrintfValue(format, args);
190 va_end(args);
191}
192
193void JSONWriter::VPrintfValue(const char* format, va_list args) {
194 PrintCommaIfNeeded();
195
196 va_list measure_args;
197 va_copy(measure_args, args);
198 intptr_t len = Utils::VSNPrint(NULL, 0, format, measure_args);
199 va_end(measure_args);
200
201 MaybeOnStackBuffer mosb(len + 1);
202 char* p = mosb.p();
203
204 va_list print_args;
205 va_copy(print_args, args);
206 intptr_t len2 = Utils::VSNPrint(p, len + 1, format, print_args);
207 va_end(print_args);
208 ASSERT(len == len2);
209
210 buffer_.AddChar('"');
211 AddEscapedUTF8String(p, len);
212 buffer_.AddChar('"');
213}
214
215void JSONWriter::PrintPropertyBool(const char* name, bool b) {
216 PrintPropertyName(name);
217 PrintValueBool(b);
218}
219
220void JSONWriter::PrintProperty(const char* name, intptr_t i) {
221 PrintPropertyName(name);
222 PrintValue(i);
223}
224
225void JSONWriter::PrintProperty64(const char* name, int64_t i) {
226 PrintPropertyName(name);
227 PrintValue64(i);
228}
229
230void JSONWriter::PrintProperty(const char* name, double d) {
231 PrintPropertyName(name);
232 PrintValue(d);
233}
234
235void JSONWriter::PrintProperty(const char* name, const char* s) {
236 PrintPropertyName(name);
237 PrintValue(s);
238}
239
240void JSONWriter::PrintPropertyBase64(const char* name,
241 const uint8_t* b,
242 intptr_t len) {
243 PrintPropertyName(name);
244 PrintValueBase64(b, len);
245}
246
247bool JSONWriter::PrintPropertyStr(const char* name,
248 const String& s,
249 intptr_t offset,
250 intptr_t count) {
251 PrintPropertyName(name);
252 return PrintValueStr(s, offset, count);
253}
254
255void JSONWriter::PrintPropertyNoEscape(const char* name, const char* s) {
256 PrintPropertyName(name);
257 PrintValueNoEscape(s);
258}
259
260void JSONWriter::PrintfProperty(const char* name, const char* format, ...) {
261 va_list args;
262 va_start(args, format);
263 VPrintfProperty(name, format, args);
264 va_end(args);
265}
266
267void JSONWriter::VPrintfProperty(const char* name,
268 const char* format,
269 va_list args) {
270 PrintPropertyName(name);
271
272 va_list measure_args;
273 va_copy(measure_args, args);
274 intptr_t len = Utils::VSNPrint(NULL, 0, format, measure_args);
275 va_end(measure_args);
276
277 MaybeOnStackBuffer mosb(len + 1);
278 char* p = mosb.p();
279
280 va_list print_args;
281 va_copy(print_args, args);
282 intptr_t len2 = Utils::VSNPrint(p, len + 1, format, print_args);
283 va_end(print_args);
284 ASSERT(len == len2);
285
286 buffer_.AddChar('"');
287 AddEscapedUTF8String(p, len);
288 buffer_.AddChar('"');
289}
290
291void JSONWriter::Steal(char** buffer, intptr_t* buffer_length) {
292 ASSERT(buffer != NULL);
293 ASSERT(buffer_length != NULL);
294 *buffer_length = buffer_.length();
295 *buffer = buffer_.Steal();
296}
297
298void JSONWriter::PrintPropertyName(const char* name) {
299 ASSERT(name != NULL);
300 PrintCommaIfNeeded();
301 buffer_.AddChar('"');
302 AddEscapedUTF8String(name);
303 buffer_.AddChar('"');
304 buffer_.AddChar(':');
305}
306
307void JSONWriter::PrintNewline() {
308 buffer_.AddChar('\n');
309}
310
311void JSONWriter::PrintCommaIfNeeded() {
312 if (NeedComma()) {
313 buffer_.AddChar(',');
314 }
315}
316
317bool JSONWriter::NeedComma() {
318 const char* buffer = buffer_.buffer();
319 intptr_t length = buffer_.length();
320 if (length == 0) {
321 return false;
322 }
323 char ch = buffer[length - 1];
324 return (ch != '[') && (ch != '{') && (ch != ':') && (ch != ',');
325}
326
327void JSONWriter::EnsureIntegerIsRepresentableInJavaScript(int64_t i) {
328#ifdef DEBUG
329 if (!Utils::IsJavascriptInt(i)) {
330 OS::PrintErr(
331 "JSONWriter::EnsureIntegerIsRepresentableInJavaScript failed on "
332 "%" Pd64 "\n",
333 i);
334 UNREACHABLE();
335 }
336#endif
337}
338
339void JSONWriter::AddEscapedUTF8String(const char* s) {
340 if (s == NULL) {
341 return;
342 }
343 intptr_t len = strlen(s);
344 AddEscapedUTF8String(s, len);
345}
346
347void JSONWriter::AddEscapedUTF8String(const char* s, intptr_t len) {
348 if (s == NULL) {
349 return;
350 }
351 const uint8_t* s8 = reinterpret_cast<const uint8_t*>(s);
352 intptr_t i = 0;
353 for (; i < len;) {
354 // Extract next UTF8 character.
355 int32_t ch = 0;
356 int32_t ch_len = Utf8::Decode(&s8[i], len - i, &ch);
357 ASSERT(ch_len != 0);
358 buffer_.EscapeAndAddCodeUnit(ch);
359 // Move i forward.
360 i += ch_len;
361 }
362 ASSERT(i == len);
363}
364
365bool JSONWriter::AddDartString(const String& s,
366 intptr_t offset,
367 intptr_t count) {
368 intptr_t length = s.Length();
369 ASSERT(offset >= 0);
370 if (offset > length) {
371 offset = length;
372 }
373 if (!Utils::RangeCheck(offset, count, length)) {
374 count = length - offset;
375 }
376 intptr_t limit = offset + count;
377 for (intptr_t i = offset; i < limit; i++) {
378 uint16_t code_unit = s.CharAt(i);
379 if (Utf16::IsTrailSurrogate(code_unit)) {
380 buffer_.EscapeAndAddUTF16CodeUnit(code_unit);
381 } else if (Utf16::IsLeadSurrogate(code_unit)) {
382 if (i + 1 == limit) {
383 buffer_.EscapeAndAddUTF16CodeUnit(code_unit);
384 } else {
385 uint16_t next_code_unit = s.CharAt(i + 1);
386 if (Utf16::IsTrailSurrogate(next_code_unit)) {
387 uint32_t decoded = Utf16::Decode(code_unit, next_code_unit);
388 buffer_.EscapeAndAddCodeUnit(decoded);
389 i++;
390 } else {
391 buffer_.EscapeAndAddUTF16CodeUnit(code_unit);
392 }
393 }
394 } else {
395 buffer_.EscapeAndAddCodeUnit(code_unit);
396 }
397 }
398 // Return value indicates whether the string is truncated.
399 return (offset > 0) || (limit < length);
400}
401
402} // namespace dart
403