// 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 { TextBuffer::TextBuffer(intptr_t buf_size) { ASSERT(buf_size > 0); buf_ = reinterpret_cast(malloc(buf_size)); if (buf_ == NULL) { OUT_OF_MEMORY(); } buf_size_ = buf_size; Clear(); } TextBuffer::~TextBuffer() { free(buf_); buf_ = NULL; } void TextBuffer::Clear() { msg_len_ = 0; buf_[0] = '\0'; } char* TextBuffer::Steal() { char* r = buf_; buf_ = NULL; buf_size_ = 0; msg_len_ = 0; return r; } void TextBuffer::AddChar(char ch) { EnsureCapacity(sizeof(ch)); buf_[msg_len_] = ch; msg_len_++; buf_[msg_len_] = '\0'; } void TextBuffer::AddRaw(const uint8_t* buffer, intptr_t buffer_length) { EnsureCapacity(buffer_length); memmove(&buf_[msg_len_], buffer, buffer_length); msg_len_ += buffer_length; buf_[msg_len_] = '\0'; } intptr_t TextBuffer::Printf(const char* format, ...) { va_list args; va_start(args, format); intptr_t remaining = buf_size_ - msg_len_; ASSERT(remaining >= 0); intptr_t len = Utils::VSNPrint(buf_ + msg_len_, remaining, format, args); va_end(args); if (len >= remaining) { EnsureCapacity(len); remaining = buf_size_ - msg_len_; ASSERT(remaining > len); va_list args2; va_start(args2, format); intptr_t len2 = Utils::VSNPrint(buf_ + msg_len_, remaining, format, args2); va_end(args2); ASSERT(len == len2); } msg_len_ += len; buf_[msg_len_] = '\0'; return len; } // 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 TextBuffer::EscapeAndAddCodeUnit(uint32_t codeunit) { switch (codeunit) { case '"': AddRaw(reinterpret_cast("\\\""), 2); break; case '\\': AddRaw(reinterpret_cast("\\\\"), 2); break; case '/': AddRaw(reinterpret_cast("\\/"), 2); break; case '\b': AddRaw(reinterpret_cast("\\b"), 2); break; case '\f': AddRaw(reinterpret_cast("\\f"), 2); break; case '\n': AddRaw(reinterpret_cast("\\n"), 2); break; case '\r': AddRaw(reinterpret_cast("\\r"), 2); break; case '\t': AddRaw(reinterpret_cast("\\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(encoded), length); } } } // Write an incomplete UTF-16 code unit so it can be read by a JSON parser in a // string literal. void TextBuffer::EscapeAndAddUTF16CodeUnit(uint16_t codeunit) { Printf("\\u%04X", codeunit); } void TextBuffer::AddString(const char* s) { Printf("%s", s); } void TextBuffer::AddEscapedString(const char* s) { intptr_t len = strlen(s); for (int i = 0; i < len; i++) { EscapeAndAddCodeUnit(s[i]); } } void TextBuffer::EnsureCapacity(intptr_t len) { intptr_t remaining = buf_size_ - msg_len_; if (remaining <= len) { intptr_t new_size = buf_size_ + Utils::Maximum(buf_size_, len + 1); char* new_buf = reinterpret_cast(realloc(buf_, new_size)); if (new_buf == NULL) { OUT_OF_MEMORY(); } buf_ = new_buf; buf_size_ = new_size; } } void BufferFormatter::Print(const char* format, ...) { va_list args; va_start(args, format); VPrint(format, args); va_end(args); } void BufferFormatter::VPrint(const char* format, va_list args) { intptr_t available = size_ - position_; if (available <= 0) return; intptr_t written = Utils::VSNPrint(buffer_ + position_, available, format, args); if (written >= 0) { position_ += (available <= written) ? available : written; } } } // namespace dart