Bug 1079322 - Extract properties using libc functions. r=gwagner
[gecko.git] / tools / profiler / JSStreamWriter.cpp
blob5d4398122608cc9a4357a7dcd2735e2b418446be
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "JSStreamWriter.h"
8 #include "mozilla/ArrayUtils.h" // for ArrayLength
9 #include "nsDataHashtable.h"
10 #include "nsString.h"
11 #include "nsTArray.h"
12 #include "nsUTF8Utils.h"
14 #if _MSC_VER
15 #define snprintf _snprintf
16 #endif
18 #define ARRAY (void*)1
19 #define OBJECT (void*)2
21 // Escape a UTF8 string to a stream. When an illegal encoding
22 // is found it will insert "INVALID" and the function will return.
23 static void EscapeToStream(std::ostream& stream, const char* str) {
24 stream << "\"";
26 size_t len = strlen(str);
27 const char* end = &str[len];
28 while (str < end) {
29 bool err;
30 const char* utf8CharStart = str;
31 uint32_t ucs4Char = UTF8CharEnumerator::NextChar(&str, end, &err);
33 if (err) {
34 // Encoding error
35 stream << "INVALID\"";
36 return;
39 // See http://www.ietf.org/rfc/rfc4627.txt?number=4627
40 // characters that must be escaped: quotation mark,
41 // reverse solidus, and the control characters
42 // (U+0000 through U+001F).
43 if (ucs4Char == '\"') {
44 stream << "\\\"";
45 } else if (ucs4Char == '\\') {
46 stream << "\\\\";
47 } else if (ucs4Char > 0xFF) {
48 char16_t chr[2];
49 ConvertUTF8toUTF16 encoder(chr);
50 encoder.write(utf8CharStart, uint32_t(str-utf8CharStart));
51 char escChar[13];
52 snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X\\u%04X", chr[0], chr[1]);
53 stream << escChar;
54 } else if (ucs4Char < 0x1F || ucs4Char > 0xFF) {
55 char escChar[7];
56 snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X", ucs4Char);
57 stream << escChar;
58 } else {
59 stream << char(ucs4Char);
62 stream << "\"";
65 JSStreamWriter::JSStreamWriter(std::ostream& aStream)
66 : mStream(aStream)
67 , mNeedsComma(false)
68 , mNeedsName(false)
69 { }
71 JSStreamWriter::~JSStreamWriter()
73 MOZ_ASSERT(mStack.GetSize() == 0);
76 void
77 JSStreamWriter::BeginObject()
79 MOZ_ASSERT(!mNeedsName);
80 if (mNeedsComma && mStack.Peek() == ARRAY) {
81 mStream << ",";
83 mStream << "{";
84 mNeedsComma = false;
85 mNeedsName = true;
86 mStack.Push(OBJECT);
89 void
90 JSStreamWriter::EndObject()
92 MOZ_ASSERT(mStack.Peek() == OBJECT);
93 mStream << "}";
94 mNeedsComma = true;
95 mNeedsName = false;
96 mStack.Pop();
97 if (mStack.GetSize() > 0 && mStack.Peek() == OBJECT) {
98 mNeedsName = true;
102 void
103 JSStreamWriter::BeginArray()
105 MOZ_ASSERT(!mNeedsName);
106 if (mNeedsComma && mStack.Peek() == ARRAY) {
107 mStream << ",";
109 mStream << "[";
110 mNeedsComma = false;
111 mStack.Push(ARRAY);
114 void
115 JSStreamWriter::EndArray()
117 MOZ_ASSERT(!mNeedsName);
118 MOZ_ASSERT(mStack.Peek() == ARRAY);
119 mStream << "]";
120 mNeedsComma = true;
121 mStack.Pop();
122 if (mStack.GetSize() > 0 && mStack.Peek() == OBJECT) {
123 mNeedsName = true;
127 void
128 JSStreamWriter::Name(const char *aName)
130 MOZ_ASSERT(mNeedsName);
131 if (mNeedsComma && mStack.Peek() == OBJECT) {
132 mStream << ",";
134 EscapeToStream(mStream, aName);
135 mStream << ":";
136 mNeedsName = false;
139 void
140 JSStreamWriter::Value(int aValue)
142 MOZ_ASSERT(!mNeedsName);
143 if (mNeedsComma && mStack.Peek() == ARRAY) {
144 mStream << ",";
146 mStream << aValue;
147 mNeedsComma = true;
148 if (mStack.Peek() == OBJECT) {
149 mNeedsName = true;
153 void
154 JSStreamWriter::Value(double aValue)
156 MOZ_ASSERT(!mNeedsName);
157 if (mNeedsComma && mStack.Peek() == ARRAY) {
158 mStream << ",";
160 mStream.precision(18);
161 mStream << aValue;
162 mNeedsComma = true;
163 if (mStack.Peek() == OBJECT) {
164 mNeedsName = true;
168 void
169 JSStreamWriter::Value(const char *aValue)
171 MOZ_ASSERT(!mNeedsName);
172 if (mNeedsComma && mStack.Peek() == ARRAY) {
173 mStream << ",";
175 EscapeToStream(mStream, aValue);
176 mNeedsComma = true;
177 if (mStack.Peek() == OBJECT) {
178 mNeedsName = true;