| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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/json_writer.h" | |
| 6 | |
| 7 #include <cmath> | |
| 8 | |
| 9 #include "base/json/string_escape.h" | |
| 10 #include "base/logging.h" | |
| 11 #include "base/strings/string_number_conversions.h" | |
| 12 #include "base/strings/utf_string_conversions.h" | |
| 13 #include "base/values.h" | |
| 14 | |
| 15 namespace base { | |
| 16 | |
| 17 #if defined(OS_WIN) | |
| 18 const char kPrettyPrintLineEnding[] = "\r\n"; | |
| 19 #else | |
| 20 const char kPrettyPrintLineEnding[] = "\n"; | |
| 21 #endif | |
| 22 | |
| 23 // static | |
| 24 bool JSONWriter::Write(const Value& node, std::string* json) { | |
| 25 return WriteWithOptions(node, 0, json); | |
| 26 } | |
| 27 | |
| 28 // static | |
| 29 bool JSONWriter::WriteWithOptions(const Value& node, | |
| 30 int options, | |
| 31 std::string* json) { | |
| 32 json->clear(); | |
| 33 // Is there a better way to estimate the size of the output? | |
| 34 json->reserve(1024); | |
| 35 | |
| 36 JSONWriter writer(options, json); | |
| 37 bool result = writer.BuildJSONString(node, 0U); | |
| 38 | |
| 39 if (options & OPTIONS_PRETTY_PRINT) | |
| 40 json->append(kPrettyPrintLineEnding); | |
| 41 | |
| 42 return result; | |
| 43 } | |
| 44 | |
| 45 JSONWriter::JSONWriter(int options, std::string* json) | |
| 46 : omit_binary_values_((options & OPTIONS_OMIT_BINARY_VALUES) != 0), | |
| 47 omit_double_type_preservation_( | |
| 48 (options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION) != 0), | |
| 49 pretty_print_((options & OPTIONS_PRETTY_PRINT) != 0), | |
| 50 json_string_(json) { | |
| 51 DCHECK(json); | |
| 52 } | |
| 53 | |
| 54 bool JSONWriter::BuildJSONString(const Value& node, size_t depth) { | |
| 55 switch (node.GetType()) { | |
| 56 case Value::TYPE_NULL: { | |
| 57 json_string_->append("null"); | |
| 58 return true; | |
| 59 } | |
| 60 | |
| 61 case Value::TYPE_BOOLEAN: { | |
| 62 bool value; | |
| 63 bool result = node.GetAsBoolean(&value); | |
| 64 DCHECK(result); | |
| 65 json_string_->append(value ? "true" : "false"); | |
| 66 return result; | |
| 67 } | |
| 68 | |
| 69 case Value::TYPE_INTEGER: { | |
| 70 int value; | |
| 71 bool result = node.GetAsInteger(&value); | |
| 72 DCHECK(result); | |
| 73 json_string_->append(IntToString(value)); | |
| 74 return result; | |
| 75 } | |
| 76 | |
| 77 case Value::TYPE_DOUBLE: { | |
| 78 double value; | |
| 79 bool result = node.GetAsDouble(&value); | |
| 80 DCHECK(result); | |
| 81 if (omit_double_type_preservation_ && | |
| 82 value <= kint64max && | |
| 83 value >= kint64min && | |
| 84 std::floor(value) == value) { | |
| 85 json_string_->append(Int64ToString(static_cast<int64>(value))); | |
| 86 return result; | |
| 87 } | |
| 88 std::string real = DoubleToString(value); | |
| 89 // Ensure that the number has a .0 if there's no decimal or 'e'. This | |
| 90 // makes sure that when we read the JSON back, it's interpreted as a | |
| 91 // real rather than an int. | |
| 92 if (real.find('.') == std::string::npos && | |
| 93 real.find('e') == std::string::npos && | |
| 94 real.find('E') == std::string::npos) { | |
| 95 real.append(".0"); | |
| 96 } | |
| 97 // The JSON spec requires that non-integer values in the range (-1,1) | |
| 98 // have a zero before the decimal point - ".52" is not valid, "0.52" is. | |
| 99 if (real[0] == '.') { | |
| 100 real.insert(static_cast<size_t>(0), static_cast<size_t>(1), '0'); | |
| 101 } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') { | |
| 102 // "-.1" bad "-0.1" good | |
| 103 real.insert(static_cast<size_t>(1), static_cast<size_t>(1), '0'); | |
| 104 } | |
| 105 json_string_->append(real); | |
| 106 return result; | |
| 107 } | |
| 108 | |
| 109 case Value::TYPE_STRING: { | |
| 110 std::string value; | |
| 111 bool result = node.GetAsString(&value); | |
| 112 DCHECK(result); | |
| 113 EscapeJSONString(value, true, json_string_); | |
| 114 return result; | |
| 115 } | |
| 116 | |
| 117 case Value::TYPE_LIST: { | |
| 118 json_string_->push_back('['); | |
| 119 if (pretty_print_) | |
| 120 json_string_->push_back(' '); | |
| 121 | |
| 122 const ListValue* list = NULL; | |
| 123 bool first_value_has_been_output = false; | |
| 124 bool result = node.GetAsList(&list); | |
| 125 DCHECK(result); | |
| 126 for (ListValue::const_iterator it = list->begin(); it != list->end(); | |
| 127 ++it) { | |
| 128 const Value* value = *it; | |
| 129 if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) | |
| 130 continue; | |
| 131 | |
| 132 if (first_value_has_been_output) { | |
| 133 json_string_->push_back(','); | |
| 134 if (pretty_print_) | |
| 135 json_string_->push_back(' '); | |
| 136 } | |
| 137 | |
| 138 if (!BuildJSONString(*value, depth)) | |
| 139 result = false; | |
| 140 | |
| 141 first_value_has_been_output = true; | |
| 142 } | |
| 143 | |
| 144 if (pretty_print_) | |
| 145 json_string_->push_back(' '); | |
| 146 json_string_->push_back(']'); | |
| 147 return result; | |
| 148 } | |
| 149 | |
| 150 case Value::TYPE_DICTIONARY: { | |
| 151 json_string_->push_back('{'); | |
| 152 if (pretty_print_) | |
| 153 json_string_->append(kPrettyPrintLineEnding); | |
| 154 | |
| 155 const DictionaryValue* dict = NULL; | |
| 156 bool first_value_has_been_output = false; | |
| 157 bool result = node.GetAsDictionary(&dict); | |
| 158 DCHECK(result); | |
| 159 for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd(); | |
| 160 itr.Advance()) { | |
| 161 if (omit_binary_values_ && | |
| 162 itr.value().GetType() == Value::TYPE_BINARY) { | |
| 163 continue; | |
| 164 } | |
| 165 | |
| 166 if (first_value_has_been_output) { | |
| 167 json_string_->push_back(','); | |
| 168 if (pretty_print_) | |
| 169 json_string_->append(kPrettyPrintLineEnding); | |
| 170 } | |
| 171 | |
| 172 if (pretty_print_) | |
| 173 IndentLine(depth + 1U); | |
| 174 | |
| 175 EscapeJSONString(itr.key(), true, json_string_); | |
| 176 json_string_->push_back(':'); | |
| 177 if (pretty_print_) | |
| 178 json_string_->push_back(' '); | |
| 179 | |
| 180 if (!BuildJSONString(itr.value(), depth + 1U)) | |
| 181 result = false; | |
| 182 | |
| 183 first_value_has_been_output = true; | |
| 184 } | |
| 185 | |
| 186 if (pretty_print_) { | |
| 187 json_string_->append(kPrettyPrintLineEnding); | |
| 188 IndentLine(depth); | |
| 189 } | |
| 190 | |
| 191 json_string_->push_back('}'); | |
| 192 return result; | |
| 193 } | |
| 194 | |
| 195 case Value::TYPE_BINARY: | |
| 196 // Successful only if we're allowed to omit it. | |
| 197 DLOG_IF(ERROR, !omit_binary_values_) << "Cannot serialize binary value."; | |
| 198 return omit_binary_values_; | |
| 199 } | |
| 200 NOTREACHED(); | |
| 201 return false; | |
| 202 } | |
| 203 | |
| 204 void JSONWriter::IndentLine(size_t depth) { | |
| 205 json_string_->append(depth * 3U, ' '); | |
| 206 } | |
| 207 | |
| 208 } // namespace base | |
| OLD | NEW |