diff -r 000000000000 -r 6474c204b198 tools/profiler/JSStreamWriter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/profiler/JSStreamWriter.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "JSStreamWriter.h" + +#include "mozilla/ArrayUtils.h" // for ArrayLength +#include "nsDataHashtable.h" +#include "nsString.h" +#include "nsTArray.h" +#include "nsUTF8Utils.h" + +#if _MSC_VER + #define snprintf _snprintf +#endif + +#define ARRAY (void*)1 +#define OBJECT (void*)2 + +// Escape a UTF8 string to a stream. When an illegal encoding +// is found it will insert "INVALID" and the function will return. +static void EscapeToStream(std::ostream& stream, const char* str) { + stream << "\""; + + size_t len = strlen(str); + const char* end = &str[len]; + while (str < end) { + bool err; + const char* utf8CharStart = str; + uint32_t ucs4Char = UTF8CharEnumerator::NextChar(&str, end, &err); + + if (err) { + // Encoding error + stream << "INVALID\""; + return; + } + + // See http://www.ietf.org/rfc/rfc4627.txt?number=4627 + // characters that must be escaped: quotation mark, + // reverse solidus, and the control characters + // (U+0000 through U+001F). + if (ucs4Char == '\"') { + stream << "\\\""; + } else if (ucs4Char == '\\') { + stream << "\\\\"; + } else if (ucs4Char > 0xFF) { + char16_t chr[2]; + ConvertUTF8toUTF16 encoder(chr); + encoder.write(utf8CharStart, uint32_t(str-utf8CharStart)); + char escChar[13]; + snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X\\u%04X", chr[0], chr[1]); + stream << escChar; + } else if (ucs4Char < 0x1F || ucs4Char > 0xFF) { + char escChar[7]; + snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X", ucs4Char); + stream << escChar; + } else { + stream << char(ucs4Char); + } + } + stream << "\""; +} + +JSStreamWriter::JSStreamWriter(std::ostream& aStream) + : mStream(aStream) + , mNeedsComma(false) + , mNeedsName(false) +{ } + +JSStreamWriter::~JSStreamWriter() +{ + MOZ_ASSERT(mStack.GetSize() == 0); +} + +void +JSStreamWriter::BeginObject() +{ + MOZ_ASSERT(!mNeedsName); + if (mNeedsComma && mStack.Peek() == ARRAY) { + mStream << ","; + } + mStream << "{"; + mNeedsComma = false; + mNeedsName = true; + mStack.Push(OBJECT); +} + +void +JSStreamWriter::EndObject() +{ + MOZ_ASSERT(mStack.Peek() == OBJECT); + mStream << "}"; + mNeedsComma = true; + mNeedsName = false; + mStack.Pop(); + if (mStack.GetSize() > 0 && mStack.Peek() == OBJECT) { + mNeedsName = true; + } +} + +void +JSStreamWriter::BeginArray() +{ + MOZ_ASSERT(!mNeedsName); + if (mNeedsComma && mStack.Peek() == ARRAY) { + mStream << ","; + } + mStream << "["; + mNeedsComma = false; + mStack.Push(ARRAY); +} + +void +JSStreamWriter::EndArray() +{ + MOZ_ASSERT(!mNeedsName); + MOZ_ASSERT(mStack.Peek() == ARRAY); + mStream << "]"; + mNeedsComma = true; + mStack.Pop(); + if (mStack.GetSize() > 0 && mStack.Peek() == OBJECT) { + mNeedsName = true; + } +} + +void +JSStreamWriter::Name(const char *aName) +{ + MOZ_ASSERT(mNeedsName); + if (mNeedsComma && mStack.Peek() == OBJECT) { + mStream << ","; + } + EscapeToStream(mStream, aName); + mStream << ":"; + mNeedsName = false; +} + +void +JSStreamWriter::Value(int aValue) +{ + MOZ_ASSERT(!mNeedsName); + if (mNeedsComma && mStack.Peek() == ARRAY) { + mStream << ","; + } + mStream << aValue; + mNeedsComma = true; + if (mStack.Peek() == OBJECT) { + mNeedsName = true; + } +} + +void +JSStreamWriter::Value(double aValue) +{ + MOZ_ASSERT(!mNeedsName); + if (mNeedsComma && mStack.Peek() == ARRAY) { + mStream << ","; + } + mStream.precision(18); + mStream << aValue; + mNeedsComma = true; + if (mStack.Peek() == OBJECT) { + mNeedsName = true; + } +} + +void +JSStreamWriter::Value(const char *aValue) +{ + MOZ_ASSERT(!mNeedsName); + if (mNeedsComma && mStack.Peek() == ARRAY) { + mStream << ","; + } + EscapeToStream(mStream, aValue); + mNeedsComma = true; + if (mStack.Peek() == OBJECT) { + mNeedsName = true; + } +}