blob: 2a3b80f727f1e0ce8bd948e0d4008aeb0e3690cc [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "platform/text_buffer.h"
#include "platform/assert.h"
#include "platform/globals.h"
#include "platform/unicode.h"
#include "platform/utils.h"
namespace dart {
intptr_t BaseTextBuffer::Printf(const char* format, ...) {
va_list args;
va_start(args, format);
intptr_t len = VPrintf(format, args);
va_end(args);
return len;
}
intptr_t BaseTextBuffer::VPrintf(const char* format, va_list args) {
va_list args1;
va_copy(args1, args);
intptr_t remaining = capacity_ - length_;
ASSERT(remaining >= 0);
intptr_t len = Utils::VSNPrint(buffer_ + length_, remaining, format, args1);
va_end(args1);
if (len >= remaining) {
if (!EnsureCapacity(len)) {
length_ = capacity_ - 1;
buffer_[length_] = '\0';
return remaining - 1;
}
remaining = capacity_ - length_;
ASSERT(remaining > len);
va_list args2;
va_copy(args2, args);
intptr_t len2 =
Utils::VSNPrint(buffer_ + length_, remaining, format, args2);
va_end(args2);
ASSERT(len == len2);
}
length_ += len;
buffer_[length_] = '\0';
return len;
}
void BaseTextBuffer::AddChar(char ch) {
if (!EnsureCapacity(sizeof(ch))) return;
buffer_[length_] = ch;
length_++;
buffer_[length_] = '\0';
}
void BaseTextBuffer::AddRaw(const uint8_t* buffer, intptr_t buffer_length) {
if (!EnsureCapacity(buffer_length)) {
buffer_length = capacity_ - length_ - 1; // Copy what fits.
}
memmove(&buffer_[length_], buffer, buffer_length);
length_ += buffer_length;
buffer_[length_] = '\0';
}
// Write a UTF-32 code unit so it can be read by a JSON parser in a string
// literal. Use official encoding from JSON specification. http://json.org/
void BaseTextBuffer::EscapeAndAddCodeUnit(uint32_t codeunit) {
switch (codeunit) {
case '"':
AddRaw(reinterpret_cast<uint8_t const*>("\\\""), 2);
break;
case '\\':
AddRaw(reinterpret_cast<uint8_t const*>("\\\\"), 2);
break;
case '/':
AddRaw(reinterpret_cast<uint8_t const*>("\\/"), 2);
break;
case '\b':
AddRaw(reinterpret_cast<uint8_t const*>("\\b"), 2);
break;
case '\f':
AddRaw(reinterpret_cast<uint8_t const*>("\\f"), 2);
break;
case '\n':
AddRaw(reinterpret_cast<uint8_t const*>("\\n"), 2);
break;
case '\r':
AddRaw(reinterpret_cast<uint8_t const*>("\\r"), 2);
break;
case '\t':
AddRaw(reinterpret_cast<uint8_t const*>("\\t"), 2);
break;
default:
if (codeunit < 0x20) {
EscapeAndAddUTF16CodeUnit(codeunit);
} else {
char encoded[6];
intptr_t length = Utf8::Length(codeunit);
Utf8::Encode(codeunit, encoded);
AddRaw(reinterpret_cast<uint8_t const*>(encoded), length);
}
}
}
// Write an incomplete UTF-16 code unit so it can be read by a JSON parser in a
// string literal.
void BaseTextBuffer::EscapeAndAddUTF16CodeUnit(uint16_t codeunit) {
Printf("\\u%04X", codeunit);
}
void BaseTextBuffer::AddString(const char* s) {
Printf("%s", s);
}
void BaseTextBuffer::AddEscapedString(const char* s) {
intptr_t len = strlen(s);
for (int i = 0; i < len; i++) {
EscapeAndAddCodeUnit(s[i]);
}
}
TextBuffer::TextBuffer(intptr_t buf_size) {
ASSERT(buf_size > 0);
buffer_ = reinterpret_cast<char*>(malloc(buf_size));
capacity_ = buf_size;
Clear();
}
TextBuffer::~TextBuffer() {
free(buffer_);
buffer_ = nullptr;
}
char* TextBuffer::Steal() {
char* r = buffer_;
buffer_ = nullptr;
capacity_ = 0;
length_ = 0;
return r;
}
bool TextBuffer::EnsureCapacity(intptr_t len) {
intptr_t remaining = capacity_ - length_;
if (remaining <= len) {
intptr_t new_size = capacity_ + Utils::Maximum(capacity_, len + 1);
char* new_buf = reinterpret_cast<char*>(realloc(buffer_, new_size));
buffer_ = new_buf;
capacity_ = new_size;
}
return true;
}
} // namespace dart