Flutter Engine
The Flutter Engine
text_buffer.cc
Go to the documentation of this file.
1// Copyright (c) 2012, 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
6
7#include "platform/assert.h"
8#include "platform/globals.h"
9#include "platform/unicode.h"
10#include "platform/utils.h"
11
12namespace dart {
13
14intptr_t BaseTextBuffer::Printf(const char* format, ...) {
15 va_list args;
17 intptr_t len = VPrintf(format, args);
18 va_end(args);
19 return len;
20}
21
22intptr_t BaseTextBuffer::VPrintf(const char* format, va_list args) {
23 va_list args1;
24 va_copy(args1, args);
25 intptr_t remaining = capacity_ - length_;
26 ASSERT(remaining >= 0);
27 intptr_t len = Utils::VSNPrint(buffer_ + length_, remaining, format, args1);
28 va_end(args1);
29 if (len >= remaining) {
30 if (!EnsureCapacity(len)) {
31 length_ = capacity_ - 1;
32 buffer_[length_] = '\0';
33 return remaining - 1;
34 }
35 remaining = capacity_ - length_;
36 ASSERT(remaining > len);
37 va_list args2;
38 va_copy(args2, args);
39 intptr_t len2 =
40 Utils::VSNPrint(buffer_ + length_, remaining, format, args2);
41 va_end(args2);
42 ASSERT(len == len2);
43 }
44 length_ += len;
45 buffer_[length_] = '\0';
46 return len;
47}
48
50 if (!EnsureCapacity(sizeof(ch))) return;
51 buffer_[length_] = ch;
52 length_++;
53 buffer_[length_] = '\0';
54}
55
56void BaseTextBuffer::AddRaw(const uint8_t* buffer, intptr_t buffer_length) {
57 ASSERT(buffer != nullptr);
58 if (!EnsureCapacity(buffer_length)) {
59 buffer_length = capacity_ - length_ - 1; // Copy what fits.
60 }
61 memmove(&buffer_[length_], buffer, buffer_length);
62 length_ += buffer_length;
63 buffer_[length_] = '\0';
64}
65
66void BaseTextBuffer::AddEscapedUTF8(const char* const s, intptr_t len) {
67 const uint8_t* cursor = reinterpret_cast<const uint8_t*>(s);
68 const uint8_t* end = cursor + len;
69
70 intptr_t needed = 0;
71 while (cursor < end) {
72 uint8_t codeunit = *cursor++;
73 if (codeunit >= 0x80) {
74 needed += 1;
75 } else {
76 needed += EscapedCodeUnitLength(codeunit);
77 }
78 }
79
80 if (!EnsureCapacity(needed)) return;
81
82 cursor = reinterpret_cast<const uint8_t*>(s);
83 while (cursor < end) {
84 uint8_t codeunit = *cursor++;
85 if (codeunit >= 0x80) {
86 buffer_[length_++] = codeunit;
87 } else {
88 EscapeAndAddCodeUnit(codeunit);
89 }
90 }
91 buffer_[length_] = '\0';
92}
93
94void BaseTextBuffer::AddEscapedLatin1(const uint8_t* const s, intptr_t len) {
95 const uint8_t* cursor = s;
96 const uint8_t* end = cursor + len;
97
98 intptr_t needed = 0;
99 while (cursor < end) {
100 needed += EscapedCodeUnitLength(*cursor++);
101 }
102
103 if (!EnsureCapacity(needed)) return;
104
105 cursor = s;
106 while (cursor < end) {
107 EscapeAndAddCodeUnit(*cursor++);
108 }
109 buffer_[length_] = '\0';
110}
111
112void BaseTextBuffer::AddEscapedUTF16(const uint16_t* s, intptr_t len) {
113 for (const uint16_t* end = s + len; s < end; s++) {
114 if (!EnsureCapacity(6)) return;
115
116 uint16_t code_unit = *s;
117 if (Utf16::IsTrailSurrogate(code_unit)) {
118 EscapeAndAddUTF16CodeUnit(code_unit);
119 } else if (Utf16::IsLeadSurrogate(code_unit)) {
120 if (s + 1 == end) {
121 EscapeAndAddUTF16CodeUnit(code_unit);
122 } else {
123 uint16_t next_code_unit = *(s + 1);
124 if (Utf16::IsTrailSurrogate(next_code_unit)) {
125 uint32_t decoded = Utf16::Decode(code_unit, next_code_unit);
126 EscapeAndAddCodeUnit(decoded);
127 s++;
128 } else {
129 EscapeAndAddUTF16CodeUnit(code_unit);
130 }
131 }
132 } else {
133 EscapeAndAddCodeUnit(code_unit);
134 }
135 }
136 buffer_[length_] = '\0';
137}
138
139DART_FORCE_INLINE
140intptr_t BaseTextBuffer::EscapedCodeUnitLength(uint32_t codeunit) {
141 switch (codeunit) {
142 case '"':
143 case '\\':
144 case '/':
145 case '\b':
146 case '\f':
147 case '\n':
148 case '\r':
149 case '\t':
150 return 2;
151 default:
152 if (codeunit < 0x20) {
153 return 6;
154 } else if (codeunit <= Utf8::kMaxOneByteChar) {
155 return 1;
156 } else if (codeunit <= Utf8::kMaxTwoByteChar) {
157 return 2;
158 } else if (codeunit <= Utf8::kMaxThreeByteChar) {
159 return 3;
160 } else {
161 ASSERT(codeunit <= Utf8::kMaxFourByteChar);
162 return 4;
163 }
164 }
165}
166
167static uint8_t Hex(uint8_t value) {
168 return value < 10 ? '0' + value : 'A' + value - 10;
169}
170
171// Write a UTF-32 code unit so it can be read by a JSON parser in a string
172// literal. Use official encoding from JSON specification. http://json.org/
173DART_FORCE_INLINE
174void BaseTextBuffer::EscapeAndAddCodeUnit(uint32_t codeunit) {
175 intptr_t remaining = capacity_ - length_;
176 switch (codeunit) {
177 case '"':
178 ASSERT(remaining > 2);
179 buffer_[length_++] = '\\';
180 buffer_[length_++] = '\"';
181 break;
182 case '\\':
183 ASSERT(remaining > 2);
184 buffer_[length_++] = '\\';
185 buffer_[length_++] = '\\';
186 break;
187 case '/':
188 ASSERT(remaining > 2);
189 buffer_[length_++] = '\\';
190 buffer_[length_++] = '/';
191 break;
192 case '\b':
193 ASSERT(remaining > 2);
194 buffer_[length_++] = '\\';
195 buffer_[length_++] = 'b';
196 break;
197 case '\f':
198 ASSERT(remaining > 2);
199 buffer_[length_++] = '\\';
200 buffer_[length_++] = 'f';
201 break;
202 case '\n':
203 ASSERT(remaining > 2);
204 buffer_[length_++] = '\\';
205 buffer_[length_++] = 'n';
206 break;
207 case '\r':
208 ASSERT(remaining > 2);
209 buffer_[length_++] = '\\';
210 buffer_[length_++] = 'r';
211 break;
212 case '\t':
213 ASSERT(remaining > 2);
214 buffer_[length_++] = '\\';
215 buffer_[length_++] = 't';
216 break;
217 default:
218 constexpr int kMask = ~(1 << 6);
219 if (codeunit < 0x20) {
220 ASSERT(remaining > 6);
221 buffer_[length_++] = '\\';
222 buffer_[length_++] = 'u';
223 buffer_[length_++] = Hex((codeunit >> 12) & 0xF);
224 buffer_[length_++] = Hex((codeunit >> 8) & 0xF);
225 buffer_[length_++] = Hex((codeunit >> 4) & 0xF);
226 buffer_[length_++] = Hex((codeunit >> 0) & 0xF);
227 } else if (codeunit <= Utf8::kMaxOneByteChar) {
228 ASSERT(remaining > 1);
229 buffer_[length_++] = codeunit;
230 } else if (codeunit <= Utf8::kMaxTwoByteChar) {
231 ASSERT(remaining > 2);
232 buffer_[length_++] = 0xC0 | (codeunit >> 6);
233 buffer_[length_++] = 0x80 | (codeunit & kMask);
234 } else if (codeunit <= Utf8::kMaxThreeByteChar) {
235 ASSERT(remaining > 3);
236 buffer_[length_++] = 0xE0 | (codeunit >> 12);
237 buffer_[length_++] = 0x80 | ((codeunit >> 6) & kMask);
238 buffer_[length_++] = 0x80 | (codeunit & kMask);
239 } else {
240 ASSERT(codeunit <= Utf8::kMaxFourByteChar);
241 ASSERT(remaining > 4);
242 buffer_[length_++] = 0xF0 | (codeunit >> 18);
243 buffer_[length_++] = 0x80 | ((codeunit >> 12) & kMask);
244 buffer_[length_++] = 0x80 | ((codeunit >> 6) & kMask);
245 buffer_[length_++] = 0x80 | (codeunit & kMask);
246 }
247 }
248}
249
250// Write an incomplete UTF-16 code unit so it can be read by a JSON parser in a
251// string literal.
252void BaseTextBuffer::EscapeAndAddUTF16CodeUnit(uint16_t codeunit) {
253 intptr_t remaining = capacity_ - length_;
254 ASSERT(remaining > 6);
255 buffer_[length_++] = '\\';
256 buffer_[length_++] = 'u';
257 buffer_[length_++] = Hex((codeunit >> 12) & 0xF);
258 buffer_[length_++] = Hex((codeunit >> 8) & 0xF);
259 buffer_[length_++] = Hex((codeunit >> 4) & 0xF);
260 buffer_[length_++] = Hex((codeunit >> 0) & 0xF);
261}
262
263void BaseTextBuffer::AddString(const char* s) {
264 AddRaw(reinterpret_cast<const uint8_t*>(s), strlen(s));
265}
266
268 AddEscapedUTF8(s, strlen(s));
269}
270
271TextBuffer::TextBuffer(intptr_t buf_size) {
272 ASSERT(buf_size > 0);
273 buffer_ = reinterpret_cast<char*>(malloc(buf_size));
274 capacity_ = buf_size;
275 Clear();
276}
277
279 free(buffer_);
280 buffer_ = nullptr;
281}
282
284 char* r = buffer_;
285 buffer_ = nullptr;
286 capacity_ = 0;
287 length_ = 0;
288 return r;
289}
290
291bool TextBuffer::EnsureCapacity(intptr_t len) {
292 intptr_t remaining = capacity_ - length_;
293 if (remaining <= len) {
294 intptr_t new_size = capacity_ + Utils::Maximum(capacity_, len + 1);
295 new_size = Utils::Maximum(new_size, static_cast<intptr_t>(256));
296 char* new_buf = reinterpret_cast<char*>(realloc(buffer_, new_size));
297 buffer_ = new_buf;
298 capacity_ = new_size;
299 }
300 return true;
301}
302
303} // namespace dart
void AddString(const char *s)
Definition: text_buffer.cc:263
intptr_t Printf(const char *format,...) PRINTF_ATTRIBUTE(2
Definition: text_buffer.cc:14
char * buffer() const
Definition: text_buffer.h:35
void AddEscapedLatin1(const uint8_t *code_units, intptr_t len)
Definition: text_buffer.cc:94
intptr_t intptr_t VPrintf(const char *format, va_list args)
Definition: text_buffer.cc:22
void AddEscapedString(const char *s)
Definition: text_buffer.cc:267
void AddChar(char ch)
Definition: text_buffer.cc:49
void AddRaw(const uint8_t *buffer, intptr_t buffer_length)
Definition: text_buffer.cc:56
void AddEscapedUTF8(const char *s, intptr_t len)
Definition: text_buffer.cc:66
void AddEscapedUTF16(const uint16_t *code_units, intptr_t len)
Definition: text_buffer.cc:112
virtual bool EnsureCapacity(intptr_t len)=0
TextBuffer(intptr_t buf_size)
Definition: text_buffer.cc:271
static int32_t Decode(uint16_t lead, uint16_t trail)
Definition: unicode.h:151
static bool IsLeadSurrogate(uint32_t ch)
Definition: unicode.h:126
static bool IsTrailSurrogate(uint32_t ch)
Definition: unicode.h:131
static constexpr int32_t kMaxTwoByteChar
Definition: unicode.h:87
static constexpr int32_t kMaxFourByteChar
Definition: unicode.h:89
static constexpr int32_t kMaxThreeByteChar
Definition: unicode.h:88
static constexpr int32_t kMaxOneByteChar
Definition: unicode.h:86
static constexpr T Maximum(T x, T y)
Definition: utils.h:41
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
#define ASSERT(E)
struct MyStruct s
glong glong end
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
uint32_t uint32_t * format
va_start(args, format)
va_end(args)
Definition: dart_vm.cc:33
void * malloc(size_t size)
Definition: allocation.cc:19
static uint8_t Hex(uint8_t value)
Definition: text_buffer.cc:167
void * realloc(void *ptr, size_t size)
Definition: allocation.cc:27
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
@ kMask
Definition: SkGlyph.h:315