blob: 512e0a10fdcbcf468c9f2381307f83a1fde85571 [file] [log] [blame]
initial.commitd7cae122008-07-26 21:49:381// Copyright 2008, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include "base/json_writer.h"
31
32#include "base/logging.h"
33#include "base/string_util.h"
34#include "base/values.h"
35#include "base/string_escape.h"
36
37const char kPrettyPrintLineEnding[] = "\r\n";
38
39/* static */
40void JSONWriter::Write(const Value* const node, bool pretty_print,
41 std::string* json) {
42 json->clear();
43 // Is there a better way to estimate the size of the output?
44 json->reserve(1024);
45 JSONWriter writer(pretty_print, json);
46 writer.BuildJSONString(node, 0);
47 if (pretty_print)
48 json->append(kPrettyPrintLineEnding);
49}
50
51JSONWriter::JSONWriter(bool pretty_print, std::string* json)
52 : pretty_print_(pretty_print),
53 json_string_(json) {
54 DCHECK(json);
55}
56
57void JSONWriter::BuildJSONString(const Value* const node, int depth) {
58 switch(node->GetType()) {
59 case Value::TYPE_NULL:
60 json_string_->append("null");
61 break;
62
63 case Value::TYPE_BOOLEAN:
64 {
65 bool value;
66 bool result = node->GetAsBoolean(&value);
67 DCHECK(result);
68 json_string_->append(value ? "true" : "false");
69 break;
70 }
71
72 case Value::TYPE_INTEGER:
73 {
74 int value;
75 bool result = node->GetAsInteger(&value);
76 DCHECK(result);
77 StringAppendF(json_string_, "%d", value);
78 break;
79 }
80
81 case Value::TYPE_REAL:
82 {
83 double value;
84 bool result = node->GetAsReal(&value);
85 DCHECK(result);
86 std::string real = StringPrintf("%g", value);
87 // Ensure that the number has a .0 if there's no decimal or 'e'. This
88 // makes sure that when we read the JSON back, it's interpreted as a
89 // real rather than an int.
90 if (real.find('.') == std::string::npos &&
91 real.find('e') == std::string::npos &&
92 real.find('E') == std::string::npos) {
93 real.append(".0");
94 }
95 json_string_->append(real);
96 break;
97 }
98
99 case Value::TYPE_STRING:
100 {
101 std::wstring value;
102 bool result = node->GetAsString(&value);
103 DCHECK(result);
104 AppendQuotedString(value);
105 break;
106 }
107
108 case Value::TYPE_LIST:
109 {
110 json_string_->append("[");
111 if (pretty_print_)
112 json_string_->append(" ");
113
114 const ListValue* list = static_cast<const ListValue*>(node);
115 for (size_t i = 0; i < list->GetSize(); ++i) {
116 if (i != 0) {
117 json_string_->append(",");
118 if (pretty_print_)
119 json_string_->append(" ");
120 }
121
122 Value* value = NULL;
123 bool result = list->Get(i, &value);
124 DCHECK(result);
125 BuildJSONString(value, depth);
126 }
127
128 if (pretty_print_)
129 json_string_->append(" ");
130 json_string_->append("]");
131 break;
132 }
133
134 case Value::TYPE_DICTIONARY:
135 {
136 json_string_->append("{");
137 if (pretty_print_)
138 json_string_->append(kPrettyPrintLineEnding);
139
140 const DictionaryValue* dict =
141 static_cast<const DictionaryValue*>(node);
142 for (DictionaryValue::key_iterator key_itr = dict->begin_keys();
143 key_itr != dict->end_keys();
144 ++key_itr) {
145
146 if (key_itr != dict->begin_keys()) {
147 json_string_->append(",");
148 if (pretty_print_)
149 json_string_->append(kPrettyPrintLineEnding);
150 }
151
152 Value* value = NULL;
153 bool result = dict->Get(*key_itr, &value);
154 DCHECK(result);
155
156 if (pretty_print_)
157 IndentLine(depth + 1);
158 AppendQuotedString(*key_itr);
159 if (pretty_print_) {
160 json_string_->append(": ");
161 } else {
162 json_string_->append(":");
163 }
164 BuildJSONString(value, depth + 1);
165 }
166
167 if (pretty_print_) {
168 json_string_->append(kPrettyPrintLineEnding);
169 IndentLine(depth);
170 json_string_->append("}");
171 } else {
172 json_string_->append("}");
173 }
174 break;
175 }
176
177 default:
178 // TODO(jhughes): handle TYPE_BINARY
179 NOTREACHED() << "unknown json type";
180 }
181}
182
183void JSONWriter::AppendQuotedString(const std::wstring& str) {
184 string_escape::JavascriptDoubleQuote(str, true, json_string_);
185}
186
187void JSONWriter::IndentLine(int depth) {
188 // It may be faster to keep an indent string so we don't have to keep
189 // reallocating.
190 json_string_->append(std::string(depth * 3, ' '));
191}