| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/json/json_writer.h" | 5 #include "base/json/json_writer.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 | 8 |
| 9 #include "base/json/string_escape.h" | 9 #include "base/json/string_escape.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/stringprintf.h" | 11 #include "base/stringprintf.h" |
| 12 #include "base/string_number_conversions.h" | 12 #include "base/string_number_conversions.h" |
| 13 #include "base/values.h" | 13 #include "base/values.h" |
| 14 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
| 15 | 15 |
| 16 namespace base { | 16 namespace base { |
| 17 | 17 |
| 18 #if defined(OS_WIN) | 18 #if defined(OS_WIN) |
| 19 static const char kPrettyPrintLineEnding[] = "\r\n"; | 19 static const char kPrettyPrintLineEnding[] = "\r\n"; |
| 20 #else | 20 #else |
| 21 static const char kPrettyPrintLineEnding[] = "\n"; | 21 static const char kPrettyPrintLineEnding[] = "\n"; |
| 22 #endif | 22 #endif |
| 23 | 23 |
| 24 /* static */ | 24 /* static */ |
| 25 const char* JSONWriter::kEmptyArray = "[]"; | 25 const char* JSONWriter::kEmptyArray = "[]"; |
| 26 | 26 |
| 27 /* static */ | 27 /* static */ |
| 28 void JSONWriter::Write(const Value* const node, | 28 void JSONWriter::Write(const Value* const node, std::string* json) { |
| 29 bool pretty_print, | 29 WriteWithOptions(node, 0, json); |
| 30 std::string* json) { | |
| 31 WriteWithOptions(node, pretty_print, 0, json); | |
| 32 } | 30 } |
| 33 | 31 |
| 34 /* static */ | 32 /* static */ |
| 35 void JSONWriter::WriteWithOptions(const Value* const node, | 33 void JSONWriter::WriteWithOptions(const Value* const node, int options, |
| 36 bool pretty_print, | |
| 37 int options, | |
| 38 std::string* json) { | 34 std::string* json) { |
| 39 json->clear(); | 35 json->clear(); |
| 40 // Is there a better way to estimate the size of the output? | 36 // Is there a better way to estimate the size of the output? |
| 41 json->reserve(1024); | 37 json->reserve(1024); |
| 42 JSONWriter writer(pretty_print, json); | 38 |
| 43 bool escape = !(options & OPTIONS_DO_NOT_ESCAPE); | 39 bool escape = !(options & OPTIONS_DO_NOT_ESCAPE); |
| 44 bool omit_binary_values = !!(options & OPTIONS_OMIT_BINARY_VALUES); | 40 bool omit_binary_values = !!(options & OPTIONS_OMIT_BINARY_VALUES); |
| 45 bool omit_double_type_preservation = | 41 bool omit_double_type_preservation = |
| 46 !!(options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION); | 42 !!(options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION); |
| 47 writer.BuildJSONString(node, 0, escape, omit_binary_values, | 43 bool pretty_print = !!(options & OPTIONS_PRETTY_PRINT); |
| 48 omit_double_type_preservation); | 44 |
| 45 JSONWriter writer(escape, omit_binary_values, omit_double_type_preservation, |
| 46 pretty_print, json); |
| 47 writer.BuildJSONString(node, 0); |
| 48 |
| 49 if (pretty_print) | 49 if (pretty_print) |
| 50 json->append(kPrettyPrintLineEnding); | 50 json->append(kPrettyPrintLineEnding); |
| 51 } | 51 } |
| 52 | 52 |
| 53 JSONWriter::JSONWriter(bool pretty_print, std::string* json) | 53 JSONWriter::JSONWriter(bool escape, bool omit_binary_values, |
| 54 : json_string_(json), | 54 bool omit_double_type_preservation, bool pretty_print, |
| 55 pretty_print_(pretty_print) { | 55 std::string* json) |
| 56 : escape_(escape), |
| 57 omit_binary_values_(omit_binary_values), |
| 58 omit_double_type_preservation_(omit_double_type_preservation), |
| 59 pretty_print_(pretty_print), |
| 60 json_string_(json) { |
| 56 DCHECK(json); | 61 DCHECK(json); |
| 57 } | 62 } |
| 58 | 63 |
| 59 void JSONWriter::BuildJSONString(const Value* const node, | 64 void JSONWriter::BuildJSONString(const Value* const node, int depth) { |
| 60 int depth, | |
| 61 bool escape, | |
| 62 bool omit_binary_values, | |
| 63 bool omit_double_type_preservation) { | |
| 64 switch (node->GetType()) { | 65 switch (node->GetType()) { |
| 65 case Value::TYPE_NULL: | 66 case Value::TYPE_NULL: |
| 66 json_string_->append("null"); | 67 json_string_->append("null"); |
| 67 break; | 68 break; |
| 68 | 69 |
| 69 case Value::TYPE_BOOLEAN: | 70 case Value::TYPE_BOOLEAN: |
| 70 { | 71 { |
| 71 bool value; | 72 bool value; |
| 72 bool result = node->GetAsBoolean(&value); | 73 bool result = node->GetAsBoolean(&value); |
| 73 DCHECK(result); | 74 DCHECK(result); |
| 74 json_string_->append(value ? "true" : "false"); | 75 json_string_->append(value ? "true" : "false"); |
| 75 break; | 76 break; |
| 76 } | 77 } |
| 77 | 78 |
| 78 case Value::TYPE_INTEGER: | 79 case Value::TYPE_INTEGER: |
| 79 { | 80 { |
| 80 int value; | 81 int value; |
| 81 bool result = node->GetAsInteger(&value); | 82 bool result = node->GetAsInteger(&value); |
| 82 DCHECK(result); | 83 DCHECK(result); |
| 83 base::StringAppendF(json_string_, "%d", value); | 84 base::StringAppendF(json_string_, "%d", value); |
| 84 break; | 85 break; |
| 85 } | 86 } |
| 86 | 87 |
| 87 case Value::TYPE_DOUBLE: | 88 case Value::TYPE_DOUBLE: |
| 88 { | 89 { |
| 89 double value; | 90 double value; |
| 90 bool result = node->GetAsDouble(&value); | 91 bool result = node->GetAsDouble(&value); |
| 91 DCHECK(result); | 92 DCHECK(result); |
| 92 if (omit_double_type_preservation && | 93 if (omit_double_type_preservation_ && |
| 93 value <= kint64max && | 94 value <= kint64max && |
| 94 value >= kint64min && | 95 value >= kint64min && |
| 95 std::floor(value) == value) { | 96 std::floor(value) == value) { |
| 96 json_string_->append(Int64ToString(static_cast<int64>(value))); | 97 json_string_->append(Int64ToString(static_cast<int64>(value))); |
| 97 break; | 98 break; |
| 98 } | 99 } |
| 99 std::string real = DoubleToString(value); | 100 std::string real = DoubleToString(value); |
| 100 // Ensure that the number has a .0 if there's no decimal or 'e'. This | 101 // Ensure that the number has a .0 if there's no decimal or 'e'. This |
| 101 // makes sure that when we read the JSON back, it's interpreted as a | 102 // makes sure that when we read the JSON back, it's interpreted as a |
| 102 // real rather than an int. | 103 // real rather than an int. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 115 } | 116 } |
| 116 json_string_->append(real); | 117 json_string_->append(real); |
| 117 break; | 118 break; |
| 118 } | 119 } |
| 119 | 120 |
| 120 case Value::TYPE_STRING: | 121 case Value::TYPE_STRING: |
| 121 { | 122 { |
| 122 std::string value; | 123 std::string value; |
| 123 bool result = node->GetAsString(&value); | 124 bool result = node->GetAsString(&value); |
| 124 DCHECK(result); | 125 DCHECK(result); |
| 125 if (escape) { | 126 if (escape_) { |
| 126 JsonDoubleQuote(UTF8ToUTF16(value), true, json_string_); | 127 JsonDoubleQuote(UTF8ToUTF16(value), true, json_string_); |
| 127 } else { | 128 } else { |
| 128 JsonDoubleQuote(value, true, json_string_); | 129 JsonDoubleQuote(value, true, json_string_); |
| 129 } | 130 } |
| 130 break; | 131 break; |
| 131 } | 132 } |
| 132 | 133 |
| 133 case Value::TYPE_LIST: | 134 case Value::TYPE_LIST: |
| 134 { | 135 { |
| 135 json_string_->append("["); | 136 json_string_->append("["); |
| 136 if (pretty_print_) | 137 if (pretty_print_) |
| 137 json_string_->append(" "); | 138 json_string_->append(" "); |
| 138 | 139 |
| 139 const ListValue* list = static_cast<const ListValue*>(node); | 140 const ListValue* list = static_cast<const ListValue*>(node); |
| 140 for (size_t i = 0; i < list->GetSize(); ++i) { | 141 for (size_t i = 0; i < list->GetSize(); ++i) { |
| 141 Value* value = NULL; | 142 Value* value = NULL; |
| 142 bool result = list->Get(i, &value); | 143 bool result = list->Get(i, &value); |
| 143 DCHECK(result); | 144 DCHECK(result); |
| 144 | 145 |
| 145 if (omit_binary_values && value->GetType() == Value::TYPE_BINARY) { | 146 if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) { |
| 146 continue; | 147 continue; |
| 147 } | 148 } |
| 148 | 149 |
| 149 if (i != 0) { | 150 if (i != 0) { |
| 150 json_string_->append(","); | 151 json_string_->append(","); |
| 151 if (pretty_print_) | 152 if (pretty_print_) |
| 152 json_string_->append(" "); | 153 json_string_->append(" "); |
| 153 } | 154 } |
| 154 | 155 |
| 155 BuildJSONString(value, depth, escape, omit_binary_values, | 156 BuildJSONString(value, depth); |
| 156 omit_double_type_preservation); | |
| 157 } | 157 } |
| 158 | 158 |
| 159 if (pretty_print_) | 159 if (pretty_print_) |
| 160 json_string_->append(" "); | 160 json_string_->append(" "); |
| 161 json_string_->append("]"); | 161 json_string_->append("]"); |
| 162 break; | 162 break; |
| 163 } | 163 } |
| 164 | 164 |
| 165 case Value::TYPE_DICTIONARY: | 165 case Value::TYPE_DICTIONARY: |
| 166 { | 166 { |
| 167 json_string_->append("{"); | 167 json_string_->append("{"); |
| 168 if (pretty_print_) | 168 if (pretty_print_) |
| 169 json_string_->append(kPrettyPrintLineEnding); | 169 json_string_->append(kPrettyPrintLineEnding); |
| 170 | 170 |
| 171 const DictionaryValue* dict = | 171 const DictionaryValue* dict = |
| 172 static_cast<const DictionaryValue*>(node); | 172 static_cast<const DictionaryValue*>(node); |
| 173 for (DictionaryValue::key_iterator key_itr = dict->begin_keys(); | 173 for (DictionaryValue::key_iterator key_itr = dict->begin_keys(); |
| 174 key_itr != dict->end_keys(); | 174 key_itr != dict->end_keys(); |
| 175 ++key_itr) { | 175 ++key_itr) { |
| 176 Value* value = NULL; | 176 Value* value = NULL; |
| 177 bool result = dict->GetWithoutPathExpansion(*key_itr, &value); | 177 bool result = dict->GetWithoutPathExpansion(*key_itr, &value); |
| 178 DCHECK(result); | 178 DCHECK(result); |
| 179 | 179 |
| 180 if (omit_binary_values && value->GetType() == Value::TYPE_BINARY) { | 180 if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) { |
| 181 continue; | 181 continue; |
| 182 } | 182 } |
| 183 | 183 |
| 184 if (key_itr != dict->begin_keys()) { | 184 if (key_itr != dict->begin_keys()) { |
| 185 json_string_->append(","); | 185 json_string_->append(","); |
| 186 if (pretty_print_) | 186 if (pretty_print_) |
| 187 json_string_->append(kPrettyPrintLineEnding); | 187 json_string_->append(kPrettyPrintLineEnding); |
| 188 } | 188 } |
| 189 | 189 |
| 190 if (pretty_print_) | 190 if (pretty_print_) |
| 191 IndentLine(depth + 1); | 191 IndentLine(depth + 1); |
| 192 AppendQuotedString(*key_itr); | 192 AppendQuotedString(*key_itr); |
| 193 if (pretty_print_) { | 193 if (pretty_print_) { |
| 194 json_string_->append(": "); | 194 json_string_->append(": "); |
| 195 } else { | 195 } else { |
| 196 json_string_->append(":"); | 196 json_string_->append(":"); |
| 197 } | 197 } |
| 198 BuildJSONString(value, depth + 1, escape, omit_binary_values, | 198 BuildJSONString(value, depth + 1); |
| 199 omit_double_type_preservation); | |
| 200 } | 199 } |
| 201 | 200 |
| 202 if (pretty_print_) { | 201 if (pretty_print_) { |
| 203 json_string_->append(kPrettyPrintLineEnding); | 202 json_string_->append(kPrettyPrintLineEnding); |
| 204 IndentLine(depth); | 203 IndentLine(depth); |
| 205 json_string_->append("}"); | 204 json_string_->append("}"); |
| 206 } else { | 205 } else { |
| 207 json_string_->append("}"); | 206 json_string_->append("}"); |
| 208 } | 207 } |
| 209 break; | 208 break; |
| 210 } | 209 } |
| 211 | 210 |
| 212 case Value::TYPE_BINARY: | 211 case Value::TYPE_BINARY: |
| 213 { | 212 { |
| 214 if (!omit_binary_values) { | 213 if (!omit_binary_values_) { |
| 215 NOTREACHED() << "Cannot serialize binary value."; | 214 NOTREACHED() << "Cannot serialize binary value."; |
| 216 } | 215 } |
| 217 break; | 216 break; |
| 218 } | 217 } |
| 219 | 218 |
| 220 default: | 219 default: |
| 221 NOTREACHED() << "unknown json type"; | 220 NOTREACHED() << "unknown json type"; |
| 222 } | 221 } |
| 223 } | 222 } |
| 224 | 223 |
| 225 void JSONWriter::AppendQuotedString(const std::string& str) { | 224 void JSONWriter::AppendQuotedString(const std::string& str) { |
| 226 // TODO(viettrungluu): |str| is UTF-8, not ASCII, so to properly escape it we | 225 // TODO(viettrungluu): |str| is UTF-8, not ASCII, so to properly escape it we |
| 227 // have to convert it to UTF-16. This round-trip is suboptimal. | 226 // have to convert it to UTF-16. This round-trip is suboptimal. |
| 228 JsonDoubleQuote(UTF8ToUTF16(str), true, json_string_); | 227 JsonDoubleQuote(UTF8ToUTF16(str), true, json_string_); |
| 229 } | 228 } |
| 230 | 229 |
| 231 void JSONWriter::IndentLine(int depth) { | 230 void JSONWriter::IndentLine(int depth) { |
| 232 // It may be faster to keep an indent string so we don't have to keep | 231 // It may be faster to keep an indent string so we don't have to keep |
| 233 // reallocating. | 232 // reallocating. |
| 234 json_string_->append(std::string(depth * 3, ' ')); | 233 json_string_->append(std::string(depth * 3, ' ')); |
| 235 } | 234 } |
| 236 | 235 |
| 237 } // namespace base | 236 } // namespace base |
| OLD | NEW |