15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_writer.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cmath> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/string_escape.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kPrettyPrintLineEnding[] = "\r\n"; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kPrettyPrintLineEnding[] = "\n"; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)// static 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JSONWriter::Write(const Value* const node, std::string* json) { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteWithOptions(node, 0, json); 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)// static 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JSONWriter::WriteWithOptions(const Value* const node, int options, 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* json) { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json->clear(); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Is there a better way to estimate the size of the output? 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json->reserve(1024); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool omit_binary_values = !!(options & OPTIONS_OMIT_BINARY_VALUES); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool omit_double_type_preservation = 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !!(options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool pretty_print = !!(options & OPTIONS_PRETTY_PRINT); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) JSONWriter writer(omit_binary_values, omit_double_type_preservation, 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pretty_print, json); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer.BuildJSONString(node, 0); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pretty_print) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json->append(kPrettyPrintLineEnding); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 49d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)JSONWriter::JSONWriter(bool omit_binary_values, 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool omit_double_type_preservation, bool pretty_print, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* json) 52d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) : omit_binary_values_(omit_binary_values), 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) omit_double_type_preservation_(omit_double_type_preservation), 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pretty_print_(pretty_print), 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_(json) { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(json); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JSONWriter::BuildJSONString(const Value* const node, int depth) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (node->GetType()) { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Value::TYPE_NULL: 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append("null"); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Value::TYPE_BOOLEAN: 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool value; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool result = node->GetAsBoolean(&value); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(result); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(value ? "true" : "false"); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Value::TYPE_INTEGER: 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int value; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool result = node->GetAsInteger(&value); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(result); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringAppendF(json_string_, "%d", value); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Value::TYPE_DOUBLE: 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double value; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool result = node->GetAsDouble(&value); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(result); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (omit_double_type_preservation_ && 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value <= kint64max && 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value >= kint64min && 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::floor(value) == value) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(Int64ToString(static_cast<int64>(value))); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string real = DoubleToString(value); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure that the number has a .0 if there's no decimal or 'e'. This 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // makes sure that when we read the JSON back, it's interpreted as a 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // real rather than an int. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (real.find('.') == std::string::npos && 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) real.find('e') == std::string::npos && 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) real.find('E') == std::string::npos) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) real.append(".0"); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The JSON spec requires that non-integer values in the range (-1,1) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have a zero before the decimal point - ".52" is not valid, "0.52" is. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (real[0] == '.') { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) real.insert(0, "0"); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "-.1" bad "-0.1" good 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) real.insert(1, "0"); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(real); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Value::TYPE_STRING: 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string value; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool result = node->GetAsString(&value); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(result); 121d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeJSONString(value, true, json_string_); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Value::TYPE_LIST: 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append("["); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pretty_print_) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(" "); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ListValue* list = static_cast<const ListValue*>(node); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < list->GetSize(); ++i) { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Value* value = NULL; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool result = list->Get(i, &value); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(result); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i != 0) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(","); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pretty_print_) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(" "); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BuildJSONString(value, depth); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pretty_print_) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(" "); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append("]"); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Value::TYPE_DICTIONARY: 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append("{"); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pretty_print_) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(kPrettyPrintLineEnding); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DictionaryValue* dict = 163d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) static_cast<const DictionaryValue*>(node); 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool first_entry = true; 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd(); 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) itr.Advance(), first_entry = false) { 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (omit_binary_values_ && 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) itr.value().GetType() == Value::TYPE_BINARY) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!first_entry) { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(","); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pretty_print_) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(kPrettyPrintLineEnding); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pretty_print_) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IndentLine(depth + 1); 180d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 181d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeJSONString(itr.key(), true, json_string_); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pretty_print_) { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(": "); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(":"); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BuildJSONString(&itr.value(), depth + 1); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pretty_print_) { 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(kPrettyPrintLineEnding); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IndentLine(depth); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append("}"); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append("}"); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case Value::TYPE_BINARY: 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!omit_binary_values_) { 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Cannot serialize binary value."; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "unknown json type"; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JSONWriter::IndentLine(int depth) { 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It may be faster to keep an indent string so we don't have to keep 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reallocating. 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) json_string_->append(std::string(depth * 3, ' ')); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 220