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"
12 #include "nsUTF8Utils.h"
15 #define snprintf _snprintf
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
) {
26 size_t len
= strlen(str
);
27 const char* end
= &str
[len
];
30 const char* utf8CharStart
= str
;
31 uint32_t ucs4Char
= UTF8CharEnumerator::NextChar(&str
, end
, &err
);
35 stream
<< "INVALID\"";
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
== '\"') {
45 } else if (ucs4Char
== '\\') {
47 } else if (ucs4Char
> 0xFF) {
49 ConvertUTF8toUTF16
encoder(chr
);
50 encoder
.write(utf8CharStart
, uint32_t(str
-utf8CharStart
));
52 snprintf(escChar
, mozilla::ArrayLength(escChar
), "\\u%04X\\u%04X", chr
[0], chr
[1]);
54 } else if (ucs4Char
< 0x1F || ucs4Char
> 0xFF) {
56 snprintf(escChar
, mozilla::ArrayLength(escChar
), "\\u%04X", ucs4Char
);
59 stream
<< char(ucs4Char
);
65 JSStreamWriter::JSStreamWriter(std::ostream
& aStream
)
71 JSStreamWriter::~JSStreamWriter()
73 MOZ_ASSERT(mStack
.GetSize() == 0);
77 JSStreamWriter::BeginObject()
79 MOZ_ASSERT(!mNeedsName
);
80 if (mNeedsComma
&& mStack
.Peek() == ARRAY
) {
90 JSStreamWriter::EndObject()
92 MOZ_ASSERT(mStack
.Peek() == OBJECT
);
97 if (mStack
.GetSize() > 0 && mStack
.Peek() == OBJECT
) {
103 JSStreamWriter::BeginArray()
105 MOZ_ASSERT(!mNeedsName
);
106 if (mNeedsComma
&& mStack
.Peek() == ARRAY
) {
115 JSStreamWriter::EndArray()
117 MOZ_ASSERT(!mNeedsName
);
118 MOZ_ASSERT(mStack
.Peek() == ARRAY
);
122 if (mStack
.GetSize() > 0 && mStack
.Peek() == OBJECT
) {
128 JSStreamWriter::Name(const char *aName
)
130 MOZ_ASSERT(mNeedsName
);
131 if (mNeedsComma
&& mStack
.Peek() == OBJECT
) {
134 EscapeToStream(mStream
, aName
);
140 JSStreamWriter::Value(int aValue
)
142 MOZ_ASSERT(!mNeedsName
);
143 if (mNeedsComma
&& mStack
.Peek() == ARRAY
) {
148 if (mStack
.Peek() == OBJECT
) {
154 JSStreamWriter::Value(double aValue
)
156 MOZ_ASSERT(!mNeedsName
);
157 if (mNeedsComma
&& mStack
.Peek() == ARRAY
) {
160 mStream
.precision(18);
163 if (mStack
.Peek() == OBJECT
) {
169 JSStreamWriter::Value(const char *aValue
)
171 MOZ_ASSERT(!mNeedsName
);
172 if (mNeedsComma
&& mStack
.Peek() == ARRAY
) {
175 EscapeToStream(mStream
, aValue
);
177 if (mStack
.Peek() == OBJECT
) {