Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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;
16 va_start(args, format);
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
static constexpr uint64_t kMask
Definition DrawPass.cpp:53
void AddString(const char *s)
intptr_t Printf(const char *format,...) PRINTF_ATTRIBUTE(2
char * buffer() const
Definition text_buffer.h:35
void AddEscapedLatin1(const uint8_t *code_units, intptr_t len)
intptr_t intptr_t VPrintf(const char *format, va_list args)
void AddEscapedString(const char *s)
void AddChar(char ch)
void AddRaw(const uint8_t *buffer, intptr_t buffer_length)
void AddEscapedUTF8(const char *s, intptr_t len)
void AddEscapedUTF16(const uint16_t *code_units, intptr_t len)
virtual bool EnsureCapacity(intptr_t len)=0
TextBuffer(intptr_t buf_size)
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:26
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
static const uint8_t buffer[]
uint8_t value
uint32_t uint32_t * format
void * malloc(size_t size)
Definition allocation.cc:19
static uint8_t Hex(uint8_t value)
void * realloc(void *ptr, size_t size)
Definition allocation.cc:27