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
12namespace dart {
13
14intptr_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
41void BaseTextBuffer::AddChar(char ch) {
42 if (!EnsureCapacity(sizeof(ch))) return;
43 buffer_[length_] = ch;
44 length_++;
45 buffer_[length_] = '\0';
46}
47
48void 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/
59void 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.
99void BaseTextBuffer::EscapeAndAddUTF16CodeUnit(uint16_t codeunit) {
100 Printf("\\u%04X", codeunit);
101}
102
103void BaseTextBuffer::AddString(const char* s) {
104 Printf("%s", s);
105}
106
107void 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
114TextBuffer::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
124TextBuffer::~TextBuffer() {
125 free(buffer_);
126 buffer_ = nullptr;
127}
128
129char* TextBuffer::Steal() {
130 char* r = buffer_;
131 buffer_ = nullptr;
132 capacity_ = 0;
133 length_ = 0;
134 return r;
135}
136
137bool 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