1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/profiler/JSStreamWriter.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,180 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "JSStreamWriter.h" 1.10 + 1.11 +#include "mozilla/ArrayUtils.h" // for ArrayLength 1.12 +#include "nsDataHashtable.h" 1.13 +#include "nsString.h" 1.14 +#include "nsTArray.h" 1.15 +#include "nsUTF8Utils.h" 1.16 + 1.17 +#if _MSC_VER 1.18 + #define snprintf _snprintf 1.19 +#endif 1.20 + 1.21 +#define ARRAY (void*)1 1.22 +#define OBJECT (void*)2 1.23 + 1.24 +// Escape a UTF8 string to a stream. When an illegal encoding 1.25 +// is found it will insert "INVALID" and the function will return. 1.26 +static void EscapeToStream(std::ostream& stream, const char* str) { 1.27 + stream << "\""; 1.28 + 1.29 + size_t len = strlen(str); 1.30 + const char* end = &str[len]; 1.31 + while (str < end) { 1.32 + bool err; 1.33 + const char* utf8CharStart = str; 1.34 + uint32_t ucs4Char = UTF8CharEnumerator::NextChar(&str, end, &err); 1.35 + 1.36 + if (err) { 1.37 + // Encoding error 1.38 + stream << "INVALID\""; 1.39 + return; 1.40 + } 1.41 + 1.42 + // See http://www.ietf.org/rfc/rfc4627.txt?number=4627 1.43 + // characters that must be escaped: quotation mark, 1.44 + // reverse solidus, and the control characters 1.45 + // (U+0000 through U+001F). 1.46 + if (ucs4Char == '\"') { 1.47 + stream << "\\\""; 1.48 + } else if (ucs4Char == '\\') { 1.49 + stream << "\\\\"; 1.50 + } else if (ucs4Char > 0xFF) { 1.51 + char16_t chr[2]; 1.52 + ConvertUTF8toUTF16 encoder(chr); 1.53 + encoder.write(utf8CharStart, uint32_t(str-utf8CharStart)); 1.54 + char escChar[13]; 1.55 + snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X\\u%04X", chr[0], chr[1]); 1.56 + stream << escChar; 1.57 + } else if (ucs4Char < 0x1F || ucs4Char > 0xFF) { 1.58 + char escChar[7]; 1.59 + snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X", ucs4Char); 1.60 + stream << escChar; 1.61 + } else { 1.62 + stream << char(ucs4Char); 1.63 + } 1.64 + } 1.65 + stream << "\""; 1.66 +} 1.67 + 1.68 +JSStreamWriter::JSStreamWriter(std::ostream& aStream) 1.69 + : mStream(aStream) 1.70 + , mNeedsComma(false) 1.71 + , mNeedsName(false) 1.72 +{ } 1.73 + 1.74 +JSStreamWriter::~JSStreamWriter() 1.75 +{ 1.76 + MOZ_ASSERT(mStack.GetSize() == 0); 1.77 +} 1.78 + 1.79 +void 1.80 +JSStreamWriter::BeginObject() 1.81 +{ 1.82 + MOZ_ASSERT(!mNeedsName); 1.83 + if (mNeedsComma && mStack.Peek() == ARRAY) { 1.84 + mStream << ","; 1.85 + } 1.86 + mStream << "{"; 1.87 + mNeedsComma = false; 1.88 + mNeedsName = true; 1.89 + mStack.Push(OBJECT); 1.90 +} 1.91 + 1.92 +void 1.93 +JSStreamWriter::EndObject() 1.94 +{ 1.95 + MOZ_ASSERT(mStack.Peek() == OBJECT); 1.96 + mStream << "}"; 1.97 + mNeedsComma = true; 1.98 + mNeedsName = false; 1.99 + mStack.Pop(); 1.100 + if (mStack.GetSize() > 0 && mStack.Peek() == OBJECT) { 1.101 + mNeedsName = true; 1.102 + } 1.103 +} 1.104 + 1.105 +void 1.106 +JSStreamWriter::BeginArray() 1.107 +{ 1.108 + MOZ_ASSERT(!mNeedsName); 1.109 + if (mNeedsComma && mStack.Peek() == ARRAY) { 1.110 + mStream << ","; 1.111 + } 1.112 + mStream << "["; 1.113 + mNeedsComma = false; 1.114 + mStack.Push(ARRAY); 1.115 +} 1.116 + 1.117 +void 1.118 +JSStreamWriter::EndArray() 1.119 +{ 1.120 + MOZ_ASSERT(!mNeedsName); 1.121 + MOZ_ASSERT(mStack.Peek() == ARRAY); 1.122 + mStream << "]"; 1.123 + mNeedsComma = true; 1.124 + mStack.Pop(); 1.125 + if (mStack.GetSize() > 0 && mStack.Peek() == OBJECT) { 1.126 + mNeedsName = true; 1.127 + } 1.128 +} 1.129 + 1.130 +void 1.131 +JSStreamWriter::Name(const char *aName) 1.132 +{ 1.133 + MOZ_ASSERT(mNeedsName); 1.134 + if (mNeedsComma && mStack.Peek() == OBJECT) { 1.135 + mStream << ","; 1.136 + } 1.137 + EscapeToStream(mStream, aName); 1.138 + mStream << ":"; 1.139 + mNeedsName = false; 1.140 +} 1.141 + 1.142 +void 1.143 +JSStreamWriter::Value(int aValue) 1.144 +{ 1.145 + MOZ_ASSERT(!mNeedsName); 1.146 + if (mNeedsComma && mStack.Peek() == ARRAY) { 1.147 + mStream << ","; 1.148 + } 1.149 + mStream << aValue; 1.150 + mNeedsComma = true; 1.151 + if (mStack.Peek() == OBJECT) { 1.152 + mNeedsName = true; 1.153 + } 1.154 +} 1.155 + 1.156 +void 1.157 +JSStreamWriter::Value(double aValue) 1.158 +{ 1.159 + MOZ_ASSERT(!mNeedsName); 1.160 + if (mNeedsComma && mStack.Peek() == ARRAY) { 1.161 + mStream << ","; 1.162 + } 1.163 + mStream.precision(18); 1.164 + mStream << aValue; 1.165 + mNeedsComma = true; 1.166 + if (mStack.Peek() == OBJECT) { 1.167 + mNeedsName = true; 1.168 + } 1.169 +} 1.170 + 1.171 +void 1.172 +JSStreamWriter::Value(const char *aValue) 1.173 +{ 1.174 + MOZ_ASSERT(!mNeedsName); 1.175 + if (mNeedsComma && mStack.Peek() == ARRAY) { 1.176 + mStream << ","; 1.177 + } 1.178 + EscapeToStream(mStream, aValue); 1.179 + mNeedsComma = true; 1.180 + if (mStack.Peek() == OBJECT) { 1.181 + mNeedsName = true; 1.182 + } 1.183 +}