blob: 10dd39fd61d5bf6d18067d2bb832f8e24ae3906c [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// 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.commit3f4a7322008-07-27 06:49:38 +09004
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)
mmentovai@google.comef3ae5a2008-08-07 00:46:49 +090027 : json_string_(json),
28 pretty_print_(pretty_print) {
initial.commit3f4a7322008-07-27 06:49:38 +090029 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);
61 std::string real = StringPrintf("%g", value);
62 // 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 }
70 json_string_->append(real);
71 break;
72 }
73
74 case Value::TYPE_STRING:
75 {
76 std::wstring value;
77 bool result = node->GetAsString(&value);
78 DCHECK(result);
79 AppendQuotedString(value);
80 break;
81 }
82
83 case Value::TYPE_LIST:
84 {
85 json_string_->append("[");
86 if (pretty_print_)
87 json_string_->append(" ");
88
89 const ListValue* list = static_cast<const ListValue*>(node);
90 for (size_t i = 0; i < list->GetSize(); ++i) {
91 if (i != 0) {
92 json_string_->append(",");
93 if (pretty_print_)
94 json_string_->append(" ");
95 }
96
97 Value* value = NULL;
98 bool result = list->Get(i, &value);
99 DCHECK(result);
100 BuildJSONString(value, depth);
101 }
102
103 if (pretty_print_)
104 json_string_->append(" ");
105 json_string_->append("]");
106 break;
107 }
108
109 case Value::TYPE_DICTIONARY:
110 {
111 json_string_->append("{");
112 if (pretty_print_)
113 json_string_->append(kPrettyPrintLineEnding);
114
115 const DictionaryValue* dict =
116 static_cast<const DictionaryValue*>(node);
117 for (DictionaryValue::key_iterator key_itr = dict->begin_keys();
118 key_itr != dict->end_keys();
119 ++key_itr) {
120
121 if (key_itr != dict->begin_keys()) {
122 json_string_->append(",");
123 if (pretty_print_)
124 json_string_->append(kPrettyPrintLineEnding);
125 }
126
127 Value* value = NULL;
128 bool result = dict->Get(*key_itr, &value);
129 DCHECK(result);
130
131 if (pretty_print_)
132 IndentLine(depth + 1);
133 AppendQuotedString(*key_itr);
134 if (pretty_print_) {
135 json_string_->append(": ");
136 } else {
137 json_string_->append(":");
138 }
139 BuildJSONString(value, depth + 1);
140 }
141
142 if (pretty_print_) {
143 json_string_->append(kPrettyPrintLineEnding);
144 IndentLine(depth);
145 json_string_->append("}");
146 } else {
147 json_string_->append("}");
148 }
149 break;
150 }
151
152 default:
153 // TODO(jhughes): handle TYPE_BINARY
154 NOTREACHED() << "unknown json type";
155 }
156}
157
158void JSONWriter::AppendQuotedString(const std::wstring& str) {
159 string_escape::JavascriptDoubleQuote(str, true, json_string_);
160}
161
162void JSONWriter::IndentLine(int depth) {
163 // It may be faster to keep an indent string so we don't have to keep
164 // reallocating.
165 json_string_->append(std::string(depth * 3, ' '));
166}
license.botf003cfe2008-08-24 09:55:55 +0900167