| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 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 #include "base/utf_string_conversions.h" | |
| 12 | |
| 13 #if defined(OS_WIN) | |
| 14 static const char kPrettyPrintLineEnding[] = "\r\n"; | |
| 15 #else | |
| 16 static const char kPrettyPrintLineEnding[] = "\n"; | |
| 17 #endif | |
| 18 | |
| 19 /* static */ | |
| 20 void JSONWriter::Write(const Value* const node, | |
| 21 bool pretty_print, | |
| 22 std::string* json) { | |
| 23 WriteWithOptionalEscape(node, pretty_print, true, json); | |
| 24 } | |
| 25 | |
| 26 /* static */ | |
| 27 void JSONWriter::WriteWithOptionalEscape(const Value* const node, | |
| 28 bool pretty_print, | |
| 29 bool escape, | |
| 30 std::string* json) { | |
| 31 json->clear(); | |
| 32 // Is there a better way to estimate the size of the output? | |
| 33 json->reserve(1024); | |
| 34 JSONWriter writer(pretty_print, json); | |
| 35 writer.BuildJSONString(node, 0, escape); | |
| 36 if (pretty_print) | |
| 37 json->append(kPrettyPrintLineEnding); | |
| 38 } | |
| 39 | |
| 40 JSONWriter::JSONWriter(bool pretty_print, std::string* json) | |
| 41 : json_string_(json), | |
| 42 pretty_print_(pretty_print) { | |
| 43 DCHECK(json); | |
| 44 } | |
| 45 | |
| 46 void JSONWriter::BuildJSONString(const Value* const node, | |
| 47 int depth, | |
| 48 bool escape) { | |
| 49 switch(node->GetType()) { | |
| 50 case Value::TYPE_NULL: | |
| 51 json_string_->append("null"); | |
| 52 break; | |
| 53 | |
| 54 case Value::TYPE_BOOLEAN: | |
| 55 { | |
| 56 bool value; | |
| 57 bool result = node->GetAsBoolean(&value); | |
| 58 DCHECK(result); | |
| 59 json_string_->append(value ? "true" : "false"); | |
| 60 break; | |
| 61 } | |
| 62 | |
| 63 case Value::TYPE_INTEGER: | |
| 64 { | |
| 65 int value; | |
| 66 bool result = node->GetAsInteger(&value); | |
| 67 DCHECK(result); | |
| 68 StringAppendF(json_string_, "%d", value); | |
| 69 break; | |
| 70 } | |
| 71 | |
| 72 case Value::TYPE_REAL: | |
| 73 { | |
| 74 double value; | |
| 75 bool result = node->GetAsReal(&value); | |
| 76 DCHECK(result); | |
| 77 std::string real = DoubleToString(value); | |
| 78 // Ensure that the number has a .0 if there's no decimal or 'e'. This | |
| 79 // makes sure that when we read the JSON back, it's interpreted as a | |
| 80 // real rather than an int. | |
| 81 if (real.find('.') == std::string::npos && | |
| 82 real.find('e') == std::string::npos && | |
| 83 real.find('E') == std::string::npos) { | |
| 84 real.append(".0"); | |
| 85 } | |
| 86 // The JSON spec requires that non-integer values in the range (-1,1) | |
| 87 // have a zero before the decimal point - ".52" is not valid, "0.52" is. | |
| 88 if (real[0] == '.') { | |
| 89 real.insert(0, "0"); | |
| 90 } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') { | |
| 91 // "-.1" bad "-0.1" good | |
| 92 real.insert(1, "0"); | |
| 93 } | |
| 94 json_string_->append(real); | |
| 95 break; | |
| 96 } | |
| 97 | |
| 98 case Value::TYPE_STRING: | |
| 99 { | |
| 100 std::string value; | |
| 101 bool result = node->GetAsString(&value); | |
| 102 DCHECK(result); | |
| 103 if (escape) { | |
| 104 string_escape::JsonDoubleQuote(UTF8ToUTF16(value), | |
| 105 true, | |
| 106 json_string_); | |
| 107 } else { | |
| 108 string_escape::JsonDoubleQuote(value, true, json_string_); | |
| 109 } | |
| 110 break; | |
| 111 } | |
| 112 | |
| 113 case Value::TYPE_LIST: | |
| 114 { | |
| 115 json_string_->append("["); | |
| 116 if (pretty_print_) | |
| 117 json_string_->append(" "); | |
| 118 | |
| 119 const ListValue* list = static_cast<const ListValue*>(node); | |
| 120 for (size_t i = 0; i < list->GetSize(); ++i) { | |
| 121 if (i != 0) { | |
| 122 json_string_->append(","); | |
| 123 if (pretty_print_) | |
| 124 json_string_->append(" "); | |
| 125 } | |
| 126 | |
| 127 Value* value = NULL; | |
| 128 bool result = list->Get(i, &value); | |
| 129 DCHECK(result); | |
| 130 BuildJSONString(value, depth, escape); | |
| 131 } | |
| 132 | |
| 133 if (pretty_print_) | |
| 134 json_string_->append(" "); | |
| 135 json_string_->append("]"); | |
| 136 break; | |
| 137 } | |
| 138 | |
| 139 case Value::TYPE_DICTIONARY: | |
| 140 { | |
| 141 json_string_->append("{"); | |
| 142 if (pretty_print_) | |
| 143 json_string_->append(kPrettyPrintLineEnding); | |
| 144 | |
| 145 const DictionaryValue* dict = | |
| 146 static_cast<const DictionaryValue*>(node); | |
| 147 for (DictionaryValue::key_iterator key_itr = dict->begin_keys(); | |
| 148 key_itr != dict->end_keys(); | |
| 149 ++key_itr) { | |
| 150 | |
| 151 if (key_itr != dict->begin_keys()) { | |
| 152 json_string_->append(","); | |
| 153 if (pretty_print_) | |
| 154 json_string_->append(kPrettyPrintLineEnding); | |
| 155 } | |
| 156 | |
| 157 Value* value = NULL; | |
| 158 bool result = dict->Get(*key_itr, &value); | |
| 159 DCHECK(result); | |
| 160 | |
| 161 if (pretty_print_) | |
| 162 IndentLine(depth + 1); | |
| 163 AppendQuotedString(*key_itr); | |
| 164 if (pretty_print_) { | |
| 165 json_string_->append(": "); | |
| 166 } else { | |
| 167 json_string_->append(":"); | |
| 168 } | |
| 169 BuildJSONString(value, depth + 1, escape); | |
| 170 } | |
| 171 | |
| 172 if (pretty_print_) { | |
| 173 json_string_->append(kPrettyPrintLineEnding); | |
| 174 IndentLine(depth); | |
| 175 json_string_->append("}"); | |
| 176 } else { | |
| 177 json_string_->append("}"); | |
| 178 } | |
| 179 break; | |
| 180 } | |
| 181 | |
| 182 default: | |
| 183 // TODO(jhughes): handle TYPE_BINARY | |
| 184 NOTREACHED() << "unknown json type"; | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 void JSONWriter::AppendQuotedString(const std::wstring& str) { | |
| 189 string_escape::JsonDoubleQuote(WideToUTF16Hack(str), | |
| 190 true, | |
| 191 json_string_); | |
| 192 } | |
| 193 | |
| 194 void JSONWriter::IndentLine(int depth) { | |
| 195 // It may be faster to keep an indent string so we don't have to keep | |
| 196 // reallocating. | |
| 197 json_string_->append(std::string(depth * 3, ' ')); | |
| 198 } | |
| OLD | NEW |