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)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* static */
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* JSONWriter::kEmptyArray = "[]";
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* static */
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JSONWriter::Write(const Value* const node, std::string* json) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WriteWithOptions(node, 0, json);
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* static */
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JSONWriter::WriteWithOptions(const Value* const node, int options,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  std::string* json) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  json->clear();
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Is there a better way to estimate the size of the output?
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  json->reserve(1024);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool escape = !(options & OPTIONS_DO_NOT_ESCAPE);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool omit_binary_values = !!(options & OPTIONS_OMIT_BINARY_VALUES);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool omit_double_type_preservation =
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !!(options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool pretty_print = !!(options & OPTIONS_PRETTY_PRINT);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JSONWriter writer(escape, omit_binary_values, omit_double_type_preservation,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    pretty_print, json);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  writer.BuildJSONString(node, 0);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pretty_print)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    json->append(kPrettyPrintLineEnding);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JSONWriter::JSONWriter(bool escape, bool omit_binary_values,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       bool omit_double_type_preservation, bool pretty_print,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       std::string* json)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : escape_(escape),
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      omit_binary_values_(omit_binary_values),
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      omit_double_type_preservation_(omit_double_type_preservation),
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pretty_print_(pretty_print),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      json_string_(json) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(json);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JSONWriter::BuildJSONString(const Value* const node, int depth) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (node->GetType()) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case Value::TYPE_NULL:
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      json_string_->append("null");
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case Value::TYPE_BOOLEAN:
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bool value;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bool result = node->GetAsBoolean(&value);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(result);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        json_string_->append(value ? "true" : "false");
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case Value::TYPE_INTEGER:
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int value;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bool result = node->GetAsInteger(&value);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(result);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::StringAppendF(json_string_, "%d", value);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case Value::TYPE_DOUBLE:
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        double value;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bool result = node->GetAsDouble(&value);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(result);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (omit_double_type_preservation_ &&
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            value <= kint64max &&
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            value >= kint64min &&
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            std::floor(value) == value) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          json_string_->append(Int64ToString(static_cast<int64>(value)));
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::string real = DoubleToString(value);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Ensure that the number has a .0 if there's no decimal or 'e'.  This
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // makes sure that when we read the JSON back, it's interpreted as a
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // real rather than an int.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (real.find('.') == std::string::npos &&
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            real.find('e') == std::string::npos &&
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            real.find('E') == std::string::npos) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          real.append(".0");
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The JSON spec requires that non-integer values in the range (-1,1)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // have a zero before the decimal point - ".52" is not valid, "0.52" is.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (real[0] == '.') {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          real.insert(0, "0");
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // "-.1" bad "-0.1" good
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          real.insert(1, "0");
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        json_string_->append(real);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case Value::TYPE_STRING:
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::string value;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bool result = node->GetAsString(&value);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(result);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (escape_) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          JsonDoubleQuote(UTF8ToUTF16(value), true, json_string_);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          JsonDoubleQuote(value, true, json_string_);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case Value::TYPE_LIST:
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        json_string_->append("[");
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (pretty_print_)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          json_string_->append(" ");
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const ListValue* list = static_cast<const ListValue*>(node);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t i = 0; i < list->GetSize(); ++i) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          const Value* value = NULL;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bool result = list->Get(i, &value);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          DCHECK(result);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            continue;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (i != 0) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            json_string_->append(",");
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (pretty_print_)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              json_string_->append(" ");
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          BuildJSONString(value, depth);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (pretty_print_)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          json_string_->append(" ");
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        json_string_->append("]");
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case Value::TYPE_DICTIONARY:
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        json_string_->append("{");
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (pretty_print_)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          json_string_->append(kPrettyPrintLineEnding);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const DictionaryValue* dict =
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static_cast<const DictionaryValue*>(node);
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        bool first_entry = true;
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             itr.Advance(), first_entry = false) {
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if (omit_binary_values_ &&
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              itr.value().GetType() == Value::TYPE_BINARY) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            continue;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if (!first_entry) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            json_string_->append(",");
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (pretty_print_)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              json_string_->append(kPrettyPrintLineEnding);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (pretty_print_)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            IndentLine(depth + 1);
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          AppendQuotedString(itr.key());
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (pretty_print_) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            json_string_->append(": ");
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          } else {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            json_string_->append(":");
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          BuildJSONString(&itr.value(), depth + 1);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (pretty_print_) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          json_string_->append(kPrettyPrintLineEnding);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          IndentLine(depth);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          json_string_->append("}");
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          json_string_->append("}");
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case Value::TYPE_BINARY:
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!omit_binary_values_) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          NOTREACHED() << "Cannot serialize binary value.";
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "unknown json type";
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JSONWriter::AppendQuotedString(const std::string& str) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(viettrungluu): |str| is UTF-8, not ASCII, so to properly escape it we
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // have to convert it to UTF-16. This round-trip is suboptimal.
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JsonDoubleQuote(UTF8ToUTF16(str), true, json_string_);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JSONWriter::IndentLine(int depth) {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It may be faster to keep an indent string so we don't have to keep
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reallocating.
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  json_string_->append(std::string(depth * 3, ' '));
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
234