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 | |
5 | #include "platform/text_buffer.h" |
6 | |
7 | #include "platform/assert.h" |
8 | #include "platform/globals.h" |
9 | #include "platform/unicode.h" |
10 | #include "platform/utils.h" |
11 | |
12 | namespace dart { |
13 | |
14 | intptr_t BaseTextBuffer::Printf(const char* format, ...) { |
15 | va_list args; |
16 | va_start(args, format); |
17 | intptr_t remaining = capacity_ - length_; |
18 | ASSERT(remaining >= 0); |
19 | intptr_t len = Utils::VSNPrint(buffer_ + length_, remaining, format, args); |
20 | va_end(args); |
21 | if (len >= remaining) { |
22 | if (!EnsureCapacity(len)) { |
23 | length_ = capacity_ - 1; |
24 | buffer_[length_] = '\0'; |
25 | return remaining - 1; |
26 | } |
27 | remaining = capacity_ - length_; |
28 | ASSERT(remaining > len); |
29 | va_list args2; |
30 | va_start(args2, format); |
31 | intptr_t len2 = |
32 | Utils::VSNPrint(buffer_ + length_, remaining, format, args2); |
33 | va_end(args2); |
34 | ASSERT(len == len2); |
35 | } |
36 | length_ += len; |
37 | buffer_[length_] = '\0'; |
38 | return len; |
39 | } |
40 | |
41 | void BaseTextBuffer::AddChar(char ch) { |
42 | if (!EnsureCapacity(sizeof(ch))) return; |
43 | buffer_[length_] = ch; |
44 | length_++; |
45 | buffer_[length_] = '\0'; |
46 | } |
47 | |
48 | void BaseTextBuffer::AddRaw(const uint8_t* buffer, intptr_t buffer_length) { |
49 | if (!EnsureCapacity(buffer_length)) { |
50 | buffer_length = capacity_ - length_ - 1; // Copy what fits. |
51 | } |
52 | memmove(&buffer_[length_], buffer, buffer_length); |
53 | length_ += buffer_length; |
54 | buffer_[length_] = '\0'; |
55 | } |
56 | |
57 | // Write a UTF-32 code unit so it can be read by a JSON parser in a string |
58 | // literal. Use official encoding from JSON specification. http://json.org/ |
59 | void BaseTextBuffer::EscapeAndAddCodeUnit(uint32_t codeunit) { |
60 | switch (codeunit) { |
61 | case '"': |
62 | AddRaw(reinterpret_cast<uint8_t const*>("\\\"" ), 2); |
63 | break; |
64 | case '\\': |
65 | AddRaw(reinterpret_cast<uint8_t const*>("\\\\" ), 2); |
66 | break; |
67 | case '/': |
68 | AddRaw(reinterpret_cast<uint8_t const*>("\\/" ), 2); |
69 | break; |
70 | case '\b': |
71 | AddRaw(reinterpret_cast<uint8_t const*>("\\b" ), 2); |
72 | break; |
73 | case '\f': |
74 | AddRaw(reinterpret_cast<uint8_t const*>("\\f" ), 2); |
75 | break; |
76 | case '\n': |
77 | AddRaw(reinterpret_cast<uint8_t const*>("\\n" ), 2); |
78 | break; |
79 | case '\r': |
80 | AddRaw(reinterpret_cast<uint8_t const*>("\\r" ), 2); |
81 | break; |
82 | case '\t': |
83 | AddRaw(reinterpret_cast<uint8_t const*>("\\t" ), 2); |
84 | break; |
85 | default: |
86 | if (codeunit < 0x20) { |
87 | EscapeAndAddUTF16CodeUnit(codeunit); |
88 | } else { |
89 | char encoded[6]; |
90 | intptr_t length = Utf8::Length(codeunit); |
91 | Utf8::Encode(codeunit, encoded); |
92 | AddRaw(reinterpret_cast<uint8_t const*>(encoded), length); |
93 | } |
94 | } |
95 | } |
96 | |
97 | // Write an incomplete UTF-16 code unit so it can be read by a JSON parser in a |
98 | // string literal. |
99 | void BaseTextBuffer::EscapeAndAddUTF16CodeUnit(uint16_t codeunit) { |
100 | Printf("\\u%04X" , codeunit); |
101 | } |
102 | |
103 | void BaseTextBuffer::AddString(const char* s) { |
104 | Printf("%s" , s); |
105 | } |
106 | |
107 | void BaseTextBuffer::AddEscapedString(const char* s) { |
108 | intptr_t len = strlen(s); |
109 | for (int i = 0; i < len; i++) { |
110 | EscapeAndAddCodeUnit(s[i]); |
111 | } |
112 | } |
113 | |
114 | TextBuffer::TextBuffer(intptr_t buf_size) { |
115 | ASSERT(buf_size > 0); |
116 | buffer_ = reinterpret_cast<char*>(malloc(buf_size)); |
117 | if (buffer_ == nullptr) { |
118 | OUT_OF_MEMORY(); |
119 | } |
120 | capacity_ = buf_size; |
121 | Clear(); |
122 | } |
123 | |
124 | TextBuffer::~TextBuffer() { |
125 | free(buffer_); |
126 | buffer_ = nullptr; |
127 | } |
128 | |
129 | char* TextBuffer::Steal() { |
130 | char* r = buffer_; |
131 | buffer_ = nullptr; |
132 | capacity_ = 0; |
133 | length_ = 0; |
134 | return r; |
135 | } |
136 | |
137 | bool TextBuffer::EnsureCapacity(intptr_t len) { |
138 | intptr_t remaining = capacity_ - length_; |
139 | if (remaining <= len) { |
140 | intptr_t new_size = capacity_ + Utils::Maximum(capacity_, len + 1); |
141 | char* new_buf = reinterpret_cast<char*>(realloc(buffer_, new_size)); |
142 | if (new_buf == nullptr) { |
143 | OUT_OF_MEMORY(); |
144 | } |
145 | buffer_ = new_buf; |
146 | capacity_ = new_size; |
147 | } |
148 | return true; |
149 | } |
150 | |
151 | } // namespace dart |
152 | |