16d528ed9Sopenharmony_ci// Copyright (c) 2012 The Chromium Authors. All rights reserved.
26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
36d528ed9Sopenharmony_ci// found in the LICENSE file.
46d528ed9Sopenharmony_ci
56d528ed9Sopenharmony_ci#include "base/json/json_writer.h"
66d528ed9Sopenharmony_ci
76d528ed9Sopenharmony_ci#include <stdint.h>
86d528ed9Sopenharmony_ci
96d528ed9Sopenharmony_ci#include <cmath>
106d528ed9Sopenharmony_ci#include <limits>
116d528ed9Sopenharmony_ci
126d528ed9Sopenharmony_ci#include "base/json/string_escape.h"
136d528ed9Sopenharmony_ci#include "base/logging.h"
146d528ed9Sopenharmony_ci#include "base/strings/string_number_conversions.h"
156d528ed9Sopenharmony_ci#include "base/strings/utf_string_conversions.h"
166d528ed9Sopenharmony_ci#include "base/values.h"
176d528ed9Sopenharmony_ci#include "util/build_config.h"
186d528ed9Sopenharmony_ci
196d528ed9Sopenharmony_cinamespace base {
206d528ed9Sopenharmony_ci
216d528ed9Sopenharmony_ci#if defined(OS_WIN)
226d528ed9Sopenharmony_ciconst char kPrettyPrintLineEnding[] = "\r\n";
236d528ed9Sopenharmony_ci#else
246d528ed9Sopenharmony_ciconst char kPrettyPrintLineEnding[] = "\n";
256d528ed9Sopenharmony_ci#endif
266d528ed9Sopenharmony_ci
276d528ed9Sopenharmony_ci// static
286d528ed9Sopenharmony_cibool JSONWriter::Write(const Value& node, std::string* json) {
296d528ed9Sopenharmony_ci  return WriteWithOptions(node, 0, json);
306d528ed9Sopenharmony_ci}
316d528ed9Sopenharmony_ci
326d528ed9Sopenharmony_ci// static
336d528ed9Sopenharmony_cibool JSONWriter::WriteWithOptions(const Value& node,
346d528ed9Sopenharmony_ci                                  int options,
356d528ed9Sopenharmony_ci                                  std::string* json) {
366d528ed9Sopenharmony_ci  json->clear();
376d528ed9Sopenharmony_ci  // Is there a better way to estimate the size of the output?
386d528ed9Sopenharmony_ci  json->reserve(1024);
396d528ed9Sopenharmony_ci
406d528ed9Sopenharmony_ci  JSONWriter writer(options, json);
416d528ed9Sopenharmony_ci  bool result = writer.BuildJSONString(node, 0U);
426d528ed9Sopenharmony_ci
436d528ed9Sopenharmony_ci  if (options & OPTIONS_PRETTY_PRINT)
446d528ed9Sopenharmony_ci    json->append(kPrettyPrintLineEnding);
456d528ed9Sopenharmony_ci
466d528ed9Sopenharmony_ci  return result;
476d528ed9Sopenharmony_ci}
486d528ed9Sopenharmony_ci
496d528ed9Sopenharmony_ciJSONWriter::JSONWriter(int options, std::string* json)
506d528ed9Sopenharmony_ci    : omit_binary_values_((options & OPTIONS_OMIT_BINARY_VALUES) != 0),
516d528ed9Sopenharmony_ci      pretty_print_((options & OPTIONS_PRETTY_PRINT) != 0),
526d528ed9Sopenharmony_ci      json_string_(json) {
536d528ed9Sopenharmony_ci  DCHECK(json);
546d528ed9Sopenharmony_ci}
556d528ed9Sopenharmony_ci
566d528ed9Sopenharmony_cibool JSONWriter::BuildJSONString(const Value& node, size_t depth) {
576d528ed9Sopenharmony_ci  switch (node.type()) {
586d528ed9Sopenharmony_ci    case Value::Type::NONE: {
596d528ed9Sopenharmony_ci      json_string_->append("null");
606d528ed9Sopenharmony_ci      return true;
616d528ed9Sopenharmony_ci    }
626d528ed9Sopenharmony_ci
636d528ed9Sopenharmony_ci    case Value::Type::BOOLEAN: {
646d528ed9Sopenharmony_ci      bool value;
656d528ed9Sopenharmony_ci      bool result = node.GetAsBoolean(&value);
666d528ed9Sopenharmony_ci      DCHECK(result);
676d528ed9Sopenharmony_ci      json_string_->append(value ? "true" : "false");
686d528ed9Sopenharmony_ci      return result;
696d528ed9Sopenharmony_ci    }
706d528ed9Sopenharmony_ci
716d528ed9Sopenharmony_ci    case Value::Type::INTEGER: {
726d528ed9Sopenharmony_ci      int value;
736d528ed9Sopenharmony_ci      bool result = node.GetAsInteger(&value);
746d528ed9Sopenharmony_ci      DCHECK(result);
756d528ed9Sopenharmony_ci      json_string_->append(IntToString(value));
766d528ed9Sopenharmony_ci      return result;
776d528ed9Sopenharmony_ci    }
786d528ed9Sopenharmony_ci
796d528ed9Sopenharmony_ci    case Value::Type::STRING: {
806d528ed9Sopenharmony_ci      std::string value;
816d528ed9Sopenharmony_ci      bool result = node.GetAsString(&value);
826d528ed9Sopenharmony_ci      DCHECK(result);
836d528ed9Sopenharmony_ci      EscapeJSONString(value, true, json_string_);
846d528ed9Sopenharmony_ci      return result;
856d528ed9Sopenharmony_ci    }
866d528ed9Sopenharmony_ci
876d528ed9Sopenharmony_ci    case Value::Type::LIST: {
886d528ed9Sopenharmony_ci      json_string_->push_back('[');
896d528ed9Sopenharmony_ci      if (pretty_print_)
906d528ed9Sopenharmony_ci        json_string_->push_back(' ');
916d528ed9Sopenharmony_ci
926d528ed9Sopenharmony_ci      const ListValue* list = nullptr;
936d528ed9Sopenharmony_ci      bool first_value_has_been_output = false;
946d528ed9Sopenharmony_ci      bool result = node.GetAsList(&list);
956d528ed9Sopenharmony_ci      DCHECK(result);
966d528ed9Sopenharmony_ci      for (const auto& value : *list) {
976d528ed9Sopenharmony_ci        if (omit_binary_values_ && value.type() == Value::Type::BINARY)
986d528ed9Sopenharmony_ci          continue;
996d528ed9Sopenharmony_ci
1006d528ed9Sopenharmony_ci        if (first_value_has_been_output) {
1016d528ed9Sopenharmony_ci          json_string_->push_back(',');
1026d528ed9Sopenharmony_ci          if (pretty_print_)
1036d528ed9Sopenharmony_ci            json_string_->push_back(' ');
1046d528ed9Sopenharmony_ci        }
1056d528ed9Sopenharmony_ci
1066d528ed9Sopenharmony_ci        if (!BuildJSONString(value, depth))
1076d528ed9Sopenharmony_ci          result = false;
1086d528ed9Sopenharmony_ci
1096d528ed9Sopenharmony_ci        first_value_has_been_output = true;
1106d528ed9Sopenharmony_ci      }
1116d528ed9Sopenharmony_ci
1126d528ed9Sopenharmony_ci      if (pretty_print_)
1136d528ed9Sopenharmony_ci        json_string_->push_back(' ');
1146d528ed9Sopenharmony_ci      json_string_->push_back(']');
1156d528ed9Sopenharmony_ci      return result;
1166d528ed9Sopenharmony_ci    }
1176d528ed9Sopenharmony_ci
1186d528ed9Sopenharmony_ci    case Value::Type::DICTIONARY: {
1196d528ed9Sopenharmony_ci      json_string_->push_back('{');
1206d528ed9Sopenharmony_ci      if (pretty_print_)
1216d528ed9Sopenharmony_ci        json_string_->append(kPrettyPrintLineEnding);
1226d528ed9Sopenharmony_ci
1236d528ed9Sopenharmony_ci      const DictionaryValue* dict = nullptr;
1246d528ed9Sopenharmony_ci      bool first_value_has_been_output = false;
1256d528ed9Sopenharmony_ci      bool result = node.GetAsDictionary(&dict);
1266d528ed9Sopenharmony_ci      DCHECK(result);
1276d528ed9Sopenharmony_ci      for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
1286d528ed9Sopenharmony_ci           itr.Advance()) {
1296d528ed9Sopenharmony_ci        if (omit_binary_values_ && itr.value().type() == Value::Type::BINARY) {
1306d528ed9Sopenharmony_ci          continue;
1316d528ed9Sopenharmony_ci        }
1326d528ed9Sopenharmony_ci
1336d528ed9Sopenharmony_ci        if (first_value_has_been_output) {
1346d528ed9Sopenharmony_ci          json_string_->push_back(',');
1356d528ed9Sopenharmony_ci          if (pretty_print_)
1366d528ed9Sopenharmony_ci            json_string_->append(kPrettyPrintLineEnding);
1376d528ed9Sopenharmony_ci        }
1386d528ed9Sopenharmony_ci
1396d528ed9Sopenharmony_ci        if (pretty_print_)
1406d528ed9Sopenharmony_ci          IndentLine(depth + 1U);
1416d528ed9Sopenharmony_ci
1426d528ed9Sopenharmony_ci        EscapeJSONString(itr.key(), true, json_string_);
1436d528ed9Sopenharmony_ci        json_string_->push_back(':');
1446d528ed9Sopenharmony_ci        if (pretty_print_)
1456d528ed9Sopenharmony_ci          json_string_->push_back(' ');
1466d528ed9Sopenharmony_ci
1476d528ed9Sopenharmony_ci        if (!BuildJSONString(itr.value(), depth + 1U))
1486d528ed9Sopenharmony_ci          result = false;
1496d528ed9Sopenharmony_ci
1506d528ed9Sopenharmony_ci        first_value_has_been_output = true;
1516d528ed9Sopenharmony_ci      }
1526d528ed9Sopenharmony_ci
1536d528ed9Sopenharmony_ci      if (pretty_print_) {
1546d528ed9Sopenharmony_ci        json_string_->append(kPrettyPrintLineEnding);
1556d528ed9Sopenharmony_ci        IndentLine(depth);
1566d528ed9Sopenharmony_ci      }
1576d528ed9Sopenharmony_ci
1586d528ed9Sopenharmony_ci      json_string_->push_back('}');
1596d528ed9Sopenharmony_ci      return result;
1606d528ed9Sopenharmony_ci    }
1616d528ed9Sopenharmony_ci
1626d528ed9Sopenharmony_ci    case Value::Type::BINARY:
1636d528ed9Sopenharmony_ci      // Successful only if we're allowed to omit it.
1646d528ed9Sopenharmony_ci      DLOG_IF(ERROR, !omit_binary_values_) << "Cannot serialize binary value.";
1656d528ed9Sopenharmony_ci      return omit_binary_values_;
1666d528ed9Sopenharmony_ci  }
1676d528ed9Sopenharmony_ci  NOTREACHED();
1686d528ed9Sopenharmony_ci  return false;
1696d528ed9Sopenharmony_ci}
1706d528ed9Sopenharmony_ci
1716d528ed9Sopenharmony_civoid JSONWriter::IndentLine(size_t depth) {
1726d528ed9Sopenharmony_ci  json_string_->append(depth * 3U, ' ');
1736d528ed9Sopenharmony_ci}
1746d528ed9Sopenharmony_ci
1756d528ed9Sopenharmony_ci}  // namespace base
176