| // 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<char*>(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<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 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<char*>(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 |