1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/json/json_writer.h"
7 #include "base/json/string_escape.h"
8 #include "base/logging.h"
9 #include "base/string_util.h"
10 #include "base/values.h"
11 #include "base/utf_string_conversions.h"
16 static const char kPrettyPrintLineEnding
[] = "\r\n";
18 static const char kPrettyPrintLineEnding
[] = "\n";
22 const char* JSONWriter::kEmptyArray
= "[]";
25 void JSONWriter::Write(const Value
* const node
,
28 WriteWithOptionalEscape(node
, pretty_print
, true, json
);
32 void JSONWriter::WriteWithOptionalEscape(const Value
* const node
,
37 // Is there a better way to estimate the size of the output?
39 JSONWriter
writer(pretty_print
, json
);
40 writer
.BuildJSONString(node
, 0, escape
);
42 json
->append(kPrettyPrintLineEnding
);
45 JSONWriter::JSONWriter(bool pretty_print
, std::string
* json
)
47 pretty_print_(pretty_print
) {
51 void JSONWriter::BuildJSONString(const Value
* const node
,
54 switch (node
->GetType()) {
55 case Value::TYPE_NULL
:
56 json_string_
->append("null");
59 case Value::TYPE_BOOLEAN
:
62 bool result
= node
->GetAsBoolean(&value
);
64 json_string_
->append(value
? "true" : "false");
68 case Value::TYPE_INTEGER
:
71 bool result
= node
->GetAsInteger(&value
);
73 StringAppendF(json_string_
, "%d", value
);
77 case Value::TYPE_REAL
:
80 bool result
= node
->GetAsReal(&value
);
82 std::string real
= DoubleToString(value
);
83 // Ensure that the number has a .0 if there's no decimal or 'e'. This
84 // makes sure that when we read the JSON back, it's interpreted as a
85 // real rather than an int.
86 if (real
.find('.') == std::string::npos
&&
87 real
.find('e') == std::string::npos
&&
88 real
.find('E') == std::string::npos
) {
91 // The JSON spec requires that non-integer values in the range (-1,1)
92 // have a zero before the decimal point - ".52" is not valid, "0.52" is.
95 } else if (real
.length() > 1 && real
[0] == '-' && real
[1] == '.') {
96 // "-.1" bad "-0.1" good
99 json_string_
->append(real
);
103 case Value::TYPE_STRING
:
106 bool result
= node
->GetAsString(&value
);
109 JsonDoubleQuote(UTF8ToUTF16(value
), true, json_string_
);
111 JsonDoubleQuote(value
, true, json_string_
);
116 case Value::TYPE_LIST
:
118 json_string_
->append("[");
120 json_string_
->append(" ");
122 const ListValue
* list
= static_cast<const ListValue
*>(node
);
123 for (size_t i
= 0; i
< list
->GetSize(); ++i
) {
125 json_string_
->append(",");
127 json_string_
->append(" ");
131 bool result
= list
->Get(i
, &value
);
133 BuildJSONString(value
, depth
, escape
);
137 json_string_
->append(" ");
138 json_string_
->append("]");
142 case Value::TYPE_DICTIONARY
:
144 json_string_
->append("{");
146 json_string_
->append(kPrettyPrintLineEnding
);
148 const DictionaryValue
* dict
=
149 static_cast<const DictionaryValue
*>(node
);
150 for (DictionaryValue::key_iterator key_itr
= dict
->begin_keys();
151 key_itr
!= dict
->end_keys();
153 if (key_itr
!= dict
->begin_keys()) {
154 json_string_
->append(",");
156 json_string_
->append(kPrettyPrintLineEnding
);
160 bool result
= dict
->GetWithoutPathExpansion(*key_itr
, &value
);
164 IndentLine(depth
+ 1);
165 AppendQuotedString(*key_itr
);
167 json_string_
->append(": ");
169 json_string_
->append(":");
171 BuildJSONString(value
, depth
+ 1, escape
);
175 json_string_
->append(kPrettyPrintLineEnding
);
177 json_string_
->append("}");
179 json_string_
->append("}");
185 // TODO(jhughes): handle TYPE_BINARY
186 NOTREACHED() << "unknown json type";
190 void JSONWriter::AppendQuotedString(const std::wstring
& str
) {
191 JsonDoubleQuote(WideToUTF16Hack(str
), true, json_string_
);
194 void JSONWriter::IndentLine(int depth
) {
195 // It may be faster to keep an indent string so we don't have to keep
197 json_string_
->append(std::string(depth
* 3, ' '));