blob: c68bfe696dd0c6e25fa8a4f119d6e45e6b56b640 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 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.
initial.commitd7cae122008-07-26 21:49:384
5#include "base/json_writer.h"
6
7#include "base/logging.h"
8#include "base/string_util.h"
9#include "base/values.h"
10#include "base/string_escape.h"
11
12const char kPrettyPrintLineEnding[] = "\r\n";
13
14/* static */
15void JSONWriter::Write(const Value* const node, bool pretty_print,
16 std::string* json) {
17 json->clear();
18 // Is there a better way to estimate the size of the output?
19 json->reserve(1024);
20 JSONWriter writer(pretty_print, json);
21 writer.BuildJSONString(node, 0);
22 if (pretty_print)
23 json->append(kPrettyPrintLineEnding);
24}
25
26JSONWriter::JSONWriter(bool pretty_print, std::string* json)
[email protected]294300a2008-08-06 15:46:4927 : json_string_(json),
28 pretty_print_(pretty_print) {
initial.commitd7cae122008-07-26 21:49:3829 DCHECK(json);
30}
31
32void JSONWriter::BuildJSONString(const Value* const node, int depth) {
33 switch(node->GetType()) {
34 case Value::TYPE_NULL:
35 json_string_->append("null");
36 break;
37
38 case Value::TYPE_BOOLEAN:
39 {
40 bool value;
41 bool result = node->GetAsBoolean(&value);
42 DCHECK(result);
43 json_string_->append(value ? "true" : "false");
44 break;
45 }
46
47 case Value::TYPE_INTEGER:
48 {
49 int value;
50 bool result = node->GetAsInteger(&value);
51 DCHECK(result);
52 StringAppendF(json_string_, "%d", value);
53 break;
54 }
55
56 case Value::TYPE_REAL:
57 {
58 double value;
59 bool result = node->GetAsReal(&value);
60 DCHECK(result);
[email protected]6dce8ade2008-11-18 00:14:2861 std::string real = DoubleToString(value);
initial.commitd7cae122008-07-26 21:49:3862 // Ensure that the number has a .0 if there's no decimal or 'e'. This
63 // makes sure that when we read the JSON back, it's interpreted as a
64 // real rather than an int.
65 if (real.find('.') == std::string::npos &&
66 real.find('e') == std::string::npos &&
67 real.find('E') == std::string::npos) {
68 real.append(".0");
69 }
[email protected]bcf60bb2009-04-20 19:14:4370 // The JSON spec requires that non-integer values in the range (-1,1)
71 // have a zero before the decimal point - ".52" is not valid, "0.52" is.
72 if (real[0] == '.') {
73 real.insert(0, "0");
74 } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
75 // "-.1" bad "-0.1" good
76 real.insert(1, "0");
77 }
initial.commitd7cae122008-07-26 21:49:3878 json_string_->append(real);
79 break;
80 }
81
82 case Value::TYPE_STRING:
83 {
84 std::wstring value;
85 bool result = node->GetAsString(&value);
86 DCHECK(result);
[email protected]8e50b602009-03-03 22:59:4387 AppendQuotedString(value);
initial.commitd7cae122008-07-26 21:49:3888 break;
89 }
90
91 case Value::TYPE_LIST:
92 {
93 json_string_->append("[");
94 if (pretty_print_)
95 json_string_->append(" ");
96
97 const ListValue* list = static_cast<const ListValue*>(node);
98 for (size_t i = 0; i < list->GetSize(); ++i) {
99 if (i != 0) {
100 json_string_->append(",");
101 if (pretty_print_)
102 json_string_->append(" ");
103 }
104
105 Value* value = NULL;
106 bool result = list->Get(i, &value);
107 DCHECK(result);
108 BuildJSONString(value, depth);
109 }
110
111 if (pretty_print_)
112 json_string_->append(" ");
113 json_string_->append("]");
114 break;
115 }
116
117 case Value::TYPE_DICTIONARY:
118 {
119 json_string_->append("{");
120 if (pretty_print_)
121 json_string_->append(kPrettyPrintLineEnding);
122
123 const DictionaryValue* dict =
124 static_cast<const DictionaryValue*>(node);
125 for (DictionaryValue::key_iterator key_itr = dict->begin_keys();
126 key_itr != dict->end_keys();
127 ++key_itr) {
128
129 if (key_itr != dict->begin_keys()) {
130 json_string_->append(",");
131 if (pretty_print_)
132 json_string_->append(kPrettyPrintLineEnding);
133 }
134
135 Value* value = NULL;
136 bool result = dict->Get(*key_itr, &value);
137 DCHECK(result);
138
139 if (pretty_print_)
140 IndentLine(depth + 1);
141 AppendQuotedString(*key_itr);
142 if (pretty_print_) {
143 json_string_->append(": ");
144 } else {
145 json_string_->append(":");
146 }
147 BuildJSONString(value, depth + 1);
148 }
149
150 if (pretty_print_) {
151 json_string_->append(kPrettyPrintLineEnding);
152 IndentLine(depth);
153 json_string_->append("}");
154 } else {
155 json_string_->append("}");
156 }
157 break;
158 }
159
160 default:
161 // TODO(jhughes): handle TYPE_BINARY
162 NOTREACHED() << "unknown json type";
163 }
164}
165
[email protected]8e50b602009-03-03 22:59:43166void JSONWriter::AppendQuotedString(const std::wstring& str) {
167 string_escape::JavascriptDoubleQuote(WideToUTF16Hack(str), true,
[email protected]e22191712009-02-25 19:17:45168 json_string_);
initial.commitd7cae122008-07-26 21:49:38169}
170
171void JSONWriter::IndentLine(int depth) {
172 // It may be faster to keep an indent string so we don't have to keep
173 // reallocating.
174 json_string_->append(std::string(depth * 3, ' '));
175}