| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "base/json/string_escape.h" | 7 #include "base/json/string_escape.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/stringprintf.h" | 9 #include "base/stringprintf.h" |
| 10 #include "base/string_number_conversions.h" | 10 #include "base/string_number_conversions.h" |
| 11 #include "base/values.h" | 11 #include "base/values.h" |
| 12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
| 13 | 13 |
| 14 namespace base { | 14 namespace base { |
| 15 | 15 |
| 16 #if defined(OS_WIN) | 16 #if defined(OS_WIN) |
| 17 static const char kPrettyPrintLineEnding[] = "\r\n"; | 17 static const char kPrettyPrintLineEnding[] = "\r\n"; |
| 18 #else | 18 #else |
| 19 static const char kPrettyPrintLineEnding[] = "\n"; | 19 static const char kPrettyPrintLineEnding[] = "\n"; |
| 20 #endif | 20 #endif |
| 21 | 21 |
| 22 /* static */ | 22 /* static */ |
| 23 const char* JSONWriter::kEmptyArray = "[]"; | 23 const char* JSONWriter::kEmptyArray = "[]"; |
| 24 | 24 |
| 25 /* static */ | 25 /* static */ |
| 26 void JSONWriter::Write(const Value* const node, | 26 void JSONWriter::Write(const Value* const node, |
| 27 bool pretty_print, | 27 bool pretty_print, |
| 28 std::string* json) { | 28 std::string* json) { |
| 29 WriteWithOptionalEscape(node, pretty_print, true, json); | 29 Write(node, pretty_print, 0, json); |
| 30 } | 30 } |
| 31 | 31 |
| 32 /* static */ | 32 /* static */ |
| 33 void JSONWriter::WriteWithOptionalEscape(const Value* const node, | 33 void JSONWriter::Write(const Value* const node, |
| 34 bool pretty_print, | 34 bool pretty_print, |
| 35 bool escape, | 35 int options, |
| 36 std::string* json) { | 36 std::string* json) { |
| 37 json->clear(); | 37 json->clear(); |
| 38 // Is there a better way to estimate the size of the output? | 38 // Is there a better way to estimate the size of the output? |
| 39 json->reserve(1024); | 39 json->reserve(1024); |
| 40 JSONWriter writer(pretty_print, json); | 40 JSONWriter writer(pretty_print, json); |
| 41 writer.BuildJSONString(node, 0, escape); | 41 bool escape = !(options & OPTIONS_DO_NOT_ESCAPE); |
| 42 bool ignore_binary_values = !!(options & OPTIONS_IGNORE_BINARY_VALUES); |
| 43 writer.BuildJSONString(node, 0, escape, ignore_binary_values); |
| 42 if (pretty_print) | 44 if (pretty_print) |
| 43 json->append(kPrettyPrintLineEnding); | 45 json->append(kPrettyPrintLineEnding); |
| 44 } | 46 } |
| 45 | 47 |
| 46 JSONWriter::JSONWriter(bool pretty_print, std::string* json) | 48 JSONWriter::JSONWriter(bool pretty_print, std::string* json) |
| 47 : json_string_(json), | 49 : json_string_(json), |
| 48 pretty_print_(pretty_print) { | 50 pretty_print_(pretty_print) { |
| 49 DCHECK(json); | 51 DCHECK(json); |
| 50 } | 52 } |
| 51 | 53 |
| 52 void JSONWriter::BuildJSONString(const Value* const node, | 54 void JSONWriter::BuildJSONString(const Value* const node, |
| 53 int depth, | 55 int depth, |
| 54 bool escape) { | 56 bool escape, |
| 57 bool ignore_binary_values) { |
| 55 switch (node->GetType()) { | 58 switch (node->GetType()) { |
| 56 case Value::TYPE_NULL: | 59 case Value::TYPE_NULL: |
| 57 json_string_->append("null"); | 60 json_string_->append("null"); |
| 58 break; | 61 break; |
| 59 | 62 |
| 60 case Value::TYPE_BOOLEAN: | 63 case Value::TYPE_BOOLEAN: |
| 61 { | 64 { |
| 62 bool value; | 65 bool value; |
| 63 bool result = node->GetAsBoolean(&value); | 66 bool result = node->GetAsBoolean(&value); |
| 64 DCHECK(result); | 67 DCHECK(result); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 } | 118 } |
| 116 | 119 |
| 117 case Value::TYPE_LIST: | 120 case Value::TYPE_LIST: |
| 118 { | 121 { |
| 119 json_string_->append("["); | 122 json_string_->append("["); |
| 120 if (pretty_print_) | 123 if (pretty_print_) |
| 121 json_string_->append(" "); | 124 json_string_->append(" "); |
| 122 | 125 |
| 123 const ListValue* list = static_cast<const ListValue*>(node); | 126 const ListValue* list = static_cast<const ListValue*>(node); |
| 124 for (size_t i = 0; i < list->GetSize(); ++i) { | 127 for (size_t i = 0; i < list->GetSize(); ++i) { |
| 128 Value* value = NULL; |
| 129 bool result = list->Get(i, &value); |
| 130 DCHECK(result); |
| 131 |
| 132 if (ignore_binary_values && value->GetType() == Value::TYPE_BINARY) { |
| 133 continue; |
| 134 } |
| 135 |
| 125 if (i != 0) { | 136 if (i != 0) { |
| 126 json_string_->append(","); | 137 json_string_->append(","); |
| 127 if (pretty_print_) | 138 if (pretty_print_) |
| 128 json_string_->append(" "); | 139 json_string_->append(" "); |
| 129 } | 140 } |
| 130 | 141 |
| 131 Value* value = NULL; | 142 BuildJSONString(value, depth, escape, ignore_binary_values); |
| 132 bool result = list->Get(i, &value); | |
| 133 DCHECK(result); | |
| 134 BuildJSONString(value, depth, escape); | |
| 135 } | 143 } |
| 136 | 144 |
| 137 if (pretty_print_) | 145 if (pretty_print_) |
| 138 json_string_->append(" "); | 146 json_string_->append(" "); |
| 139 json_string_->append("]"); | 147 json_string_->append("]"); |
| 140 break; | 148 break; |
| 141 } | 149 } |
| 142 | 150 |
| 143 case Value::TYPE_DICTIONARY: | 151 case Value::TYPE_DICTIONARY: |
| 144 { | 152 { |
| 145 json_string_->append("{"); | 153 json_string_->append("{"); |
| 146 if (pretty_print_) | 154 if (pretty_print_) |
| 147 json_string_->append(kPrettyPrintLineEnding); | 155 json_string_->append(kPrettyPrintLineEnding); |
| 148 | 156 |
| 149 const DictionaryValue* dict = | 157 const DictionaryValue* dict = |
| 150 static_cast<const DictionaryValue*>(node); | 158 static_cast<const DictionaryValue*>(node); |
| 151 for (DictionaryValue::key_iterator key_itr = dict->begin_keys(); | 159 for (DictionaryValue::key_iterator key_itr = dict->begin_keys(); |
| 152 key_itr != dict->end_keys(); | 160 key_itr != dict->end_keys(); |
| 153 ++key_itr) { | 161 ++key_itr) { |
| 162 Value* value = NULL; |
| 163 bool result = dict->GetWithoutPathExpansion(*key_itr, &value); |
| 164 DCHECK(result); |
| 165 |
| 166 if (ignore_binary_values && value->GetType() == Value::TYPE_BINARY) { |
| 167 continue; |
| 168 } |
| 169 |
| 154 if (key_itr != dict->begin_keys()) { | 170 if (key_itr != dict->begin_keys()) { |
| 155 json_string_->append(","); | 171 json_string_->append(","); |
| 156 if (pretty_print_) | 172 if (pretty_print_) |
| 157 json_string_->append(kPrettyPrintLineEnding); | 173 json_string_->append(kPrettyPrintLineEnding); |
| 158 } | 174 } |
| 159 | 175 |
| 160 Value* value = NULL; | |
| 161 bool result = dict->GetWithoutPathExpansion(*key_itr, &value); | |
| 162 DCHECK(result); | |
| 163 | |
| 164 if (pretty_print_) | 176 if (pretty_print_) |
| 165 IndentLine(depth + 1); | 177 IndentLine(depth + 1); |
| 166 AppendQuotedString(*key_itr); | 178 AppendQuotedString(*key_itr); |
| 167 if (pretty_print_) { | 179 if (pretty_print_) { |
| 168 json_string_->append(": "); | 180 json_string_->append(": "); |
| 169 } else { | 181 } else { |
| 170 json_string_->append(":"); | 182 json_string_->append(":"); |
| 171 } | 183 } |
| 172 BuildJSONString(value, depth + 1, escape); | 184 BuildJSONString(value, depth + 1, escape, ignore_binary_values); |
| 173 } | 185 } |
| 174 | 186 |
| 175 if (pretty_print_) { | 187 if (pretty_print_) { |
| 176 json_string_->append(kPrettyPrintLineEnding); | 188 json_string_->append(kPrettyPrintLineEnding); |
| 177 IndentLine(depth); | 189 IndentLine(depth); |
| 178 json_string_->append("}"); | 190 json_string_->append("}"); |
| 179 } else { | 191 } else { |
| 180 json_string_->append("}"); | 192 json_string_->append("}"); |
| 181 } | 193 } |
| 182 break; | 194 break; |
| 183 } | 195 } |
| 184 | 196 |
| 197 case Value::TYPE_BINARY: |
| 198 { |
| 199 if (!ignore_binary_values) { |
| 200 NOTREACHED() << "Cannot serialize binary value."; |
| 201 } |
| 202 break; |
| 203 } |
| 204 |
| 185 default: | 205 default: |
| 186 // TODO(jhughes): handle TYPE_BINARY | |
| 187 NOTREACHED() << "unknown json type"; | 206 NOTREACHED() << "unknown json type"; |
| 188 } | 207 } |
| 189 } | 208 } |
| 190 | 209 |
| 191 void JSONWriter::AppendQuotedString(const std::string& str) { | 210 void JSONWriter::AppendQuotedString(const std::string& str) { |
| 192 // TODO(viettrungluu): |str| is UTF-8, not ASCII, so to properly escape it we | 211 // TODO(viettrungluu): |str| is UTF-8, not ASCII, so to properly escape it we |
| 193 // have to convert it to UTF-16. This round-trip is suboptimal. | 212 // have to convert it to UTF-16. This round-trip is suboptimal. |
| 194 JsonDoubleQuote(UTF8ToUTF16(str), true, json_string_); | 213 JsonDoubleQuote(UTF8ToUTF16(str), true, json_string_); |
| 195 } | 214 } |
| 196 | 215 |
| 197 void JSONWriter::IndentLine(int depth) { | 216 void JSONWriter::IndentLine(int depth) { |
| 198 // It may be faster to keep an indent string so we don't have to keep | 217 // It may be faster to keep an indent string so we don't have to keep |
| 199 // reallocating. | 218 // reallocating. |
| 200 json_string_->append(std::string(depth * 3, ' ')); | 219 json_string_->append(std::string(depth * 3, ' ')); |
| 201 } | 220 } |
| 202 | 221 |
| 203 } // namespace base | 222 } // namespace base |
| OLD | NEW |