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