text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <google/protobuf/util/internal/utility.h>

#include <algorithm>

#include <google/protobuf/stubs/callback.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/wrappers.pb.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/util/internal/constants.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/mathlimits.h>

namespace google {
namespace protobuf {
namespace util {
namespace converter {

bool GetBoolOptionOrDefault(
    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
    const string& option_name, bool default_value) {
  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
  if (opt == NULL) {
    return default_value;
  }
  return GetBoolFromAny(opt->value());
}

int64 GetInt64OptionOrDefault(
    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
    const string& option_name, int64 default_value) {
  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
  if (opt == NULL) {
    return default_value;
  }
  return GetInt64FromAny(opt->value());
}

double GetDoubleOptionOrDefault(
    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
    const string& option_name, double default_value) {
  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
  if (opt == NULL) {
    return default_value;
  }
  return GetDoubleFromAny(opt->value());
}

string GetStringOptionOrDefault(
    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
    const string& option_name, const string& default_value) {
  const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
  if (opt == NULL) {
    return default_value;
  }
  return GetStringFromAny(opt->value());
}

template <typename T>
void ParseFromAny(const string& data, T* result) {
  result->ParseFromString(data);
}

// Returns a boolean value contained in Any type.
// TODO(skarvaje): Add type checking & error messages here.
bool GetBoolFromAny(const google::protobuf::Any& any) {
  google::protobuf::BoolValue b;
  ParseFromAny(any.value(), &b);
  return b.value();
}

int64 GetInt64FromAny(const google::protobuf::Any& any) {
  google::protobuf::Int64Value i;
  ParseFromAny(any.value(), &i);
  return i.value();
}

double GetDoubleFromAny(const google::protobuf::Any& any) {
  google::protobuf::DoubleValue i;
  ParseFromAny(any.value(), &i);
  return i.value();
}

string GetStringFromAny(const google::protobuf::Any& any) {
  google::protobuf::StringValue s;
  ParseFromAny(any.value(), &s);
  return s.value();
}

const StringPiece GetTypeWithoutUrl(StringPiece type_url) {
  if (type_url.size() > kTypeUrlSize && type_url[kTypeUrlSize] == '/') {
    return type_url.substr(kTypeUrlSize + 1);
  } else {
    size_t idx = type_url.rfind('/');
    if (idx != type_url.npos) {
      type_url.remove_prefix(idx + 1);
    }
    return type_url;
  }
}

const string GetFullTypeWithUrl(StringPiece simple_type) {
  return StrCat(kTypeServiceBaseUrl, "/", simple_type);
}

const google::protobuf::Option* FindOptionOrNull(
    const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
    const string& option_name) {
  for (int i = 0; i < options.size(); ++i) {
    const google::protobuf::Option& opt = options.Get(i);
    if (opt.name() == option_name) {
      return &opt;
    }
  }
  return NULL;
}

const google::protobuf::Field* FindFieldInTypeOrNull(
    const google::protobuf::Type* type, StringPiece field_name) {
  if (type != NULL) {
    for (int i = 0; i < type->fields_size(); ++i) {
      const google::protobuf::Field& field = type->fields(i);
      if (field.name() == field_name) {
        return &field;
      }
    }
  }
  return NULL;
}

const google::protobuf::Field* FindJsonFieldInTypeOrNull(
    const google::protobuf::Type* type, StringPiece json_name) {
  if (type != NULL) {
    for (int i = 0; i < type->fields_size(); ++i) {
      const google::protobuf::Field& field = type->fields(i);
      if (field.json_name() == json_name) {
        return &field;
      }
    }
  }
  return NULL;
}

const google::protobuf::Field* FindFieldInTypeByNumberOrNull(
    const google::protobuf::Type* type, int32 number) {
  if (type != NULL) {
    for (int i = 0; i < type->fields_size(); ++i) {
      const google::protobuf::Field& field = type->fields(i);
      if (field.number() == number) {
        return &field;
      }
    }
  }
  return NULL;
}

const google::protobuf::EnumValue* FindEnumValueByNameOrNull(
    const google::protobuf::Enum* enum_type, StringPiece enum_name) {
  if (enum_type != NULL) {
    for (int i = 0; i < enum_type->enumvalue_size(); ++i) {
      const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i);
      if (enum_value.name() == enum_name) {
        return &enum_value;
      }
    }
  }
  return NULL;
}

const google::protobuf::EnumValue* FindEnumValueByNumberOrNull(
    const google::protobuf::Enum* enum_type, int32 value) {
  if (enum_type != NULL) {
    for (int i = 0; i < enum_type->enumvalue_size(); ++i) {
      const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i);
      if (enum_value.number() == value) {
        return &enum_value;
      }
    }
  }
  return NULL;
}

const google::protobuf::EnumValue* FindEnumValueByNameWithoutUnderscoreOrNull(
    const google::protobuf::Enum* enum_type, StringPiece enum_name) {
  if (enum_type != NULL) {
    for (int i = 0; i < enum_type->enumvalue_size(); ++i) {
      const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i);
      string enum_name_without_underscore = enum_value.name();

      // Remove underscore from the name.
      enum_name_without_underscore.erase(
          std::remove(enum_name_without_underscore.begin(),
                      enum_name_without_underscore.end(), '_'),
          enum_name_without_underscore.end());
      // Make the name uppercase.
      for (string::iterator it = enum_name_without_underscore.begin();
           it != enum_name_without_underscore.end(); ++it) {
        *it = ascii_toupper(*it);
      }

      if (enum_name_without_underscore == enum_name) {
        return &enum_value;
      }
    }
  }
  return NULL;
}

string ToCamelCase(const StringPiece input) {
  bool capitalize_next = false;
  bool was_cap = true;
  bool is_cap = false;
  bool first_word = true;
  string result;
  result.reserve(input.size());

  for (size_t i = 0; i < input.size(); ++i, was_cap = is_cap) {
    is_cap = ascii_isupper(input[i]);
    if (input[i] == '_') {
      capitalize_next = true;
      if (!result.empty()) first_word = false;
      continue;
    } else if (first_word) {
      // Consider when the current character B is capitalized,
      // first word ends when:
      // 1) following a lowercase:   "...aB..."
      // 2) followed by a lowercase: "...ABc..."
      if (!result.empty() && is_cap &&
          (!was_cap || (i + 1 < input.size() && ascii_islower(input[i + 1])))) {
        first_word = false;
        result.push_back(input[i]);
      } else {
        result.push_back(ascii_tolower(input[i]));
        continue;
      }
    } else if (capitalize_next) {
      capitalize_next = false;
      if (ascii_islower(input[i])) {
        result.push_back(ascii_toupper(input[i]));
        continue;
      } else {
        result.push_back(input[i]);
        continue;
      }
    } else {
      result.push_back(ascii_tolower(input[i]));
    }
  }
  return result;
}

string ToSnakeCase(StringPiece input) {
  bool was_not_underscore = false;  // Initialize to false for case 1 (below)
  bool was_not_cap = false;
  string result;
  result.reserve(input.size() << 1);

  for (size_t i = 0; i < input.size(); ++i) {
    if (ascii_isupper(input[i])) {
      // Consider when the current character B is capitalized:
      // 1) At beginning of input:   "B..." => "b..."
      //    (e.g. "Biscuit" => "biscuit")
      // 2) Following a lowercase:   "...aB..." => "...a_b..."
      //    (e.g. "gBike" => "g_bike")
      // 3) At the end of input:     "...AB" => "...ab"
      //    (e.g. "GoogleLAB" => "google_lab")
      // 4) Followed by a lowercase: "...ABc..." => "...a_bc..."
      //    (e.g. "GBike" => "g_bike")
      if (was_not_underscore &&               //            case 1 out
          (was_not_cap ||                     // case 2 in, case 3 out
           (i + 1 < input.size() &&           //            case 3 out
            ascii_islower(input[i + 1])))) {  // case 4 in
        // We add an underscore for case 2 and case 4.
        result.push_back('_');
      }
      result.push_back(ascii_tolower(input[i]));
      was_not_underscore = true;
      was_not_cap = false;
    } else {
      result.push_back(input[i]);
      was_not_underscore = input[i] != '_';
      was_not_cap = true;
    }
  }
  return result;
}

std::set<string>* well_known_types_ = NULL;
GOOGLE_PROTOBUF_DECLARE_ONCE(well_known_types_init_);
const char* well_known_types_name_array_[] = {
    "google.protobuf.Timestamp",   "google.protobuf.Duration",
    "google.protobuf.DoubleValue", "google.protobuf.FloatValue",
    "google.protobuf.Int64Value",  "google.protobuf.UInt64Value",
    "google.protobuf.Int32Value",  "google.protobuf.UInt32Value",
    "google.protobuf.BoolValue",   "google.protobuf.StringValue",
    "google.protobuf.BytesValue",  "google.protobuf.FieldMask"};

void DeleteWellKnownTypes() { delete well_known_types_; }

void InitWellKnownTypes() {
  well_known_types_ = new std::set<string>;
  for (int i = 0; i < GOOGLE_ARRAYSIZE(well_known_types_name_array_); ++i) {
    well_known_types_->insert(well_known_types_name_array_[i]);
  }
  google::protobuf::internal::OnShutdown(&DeleteWellKnownTypes);
}

bool IsWellKnownType(const string& type_name) {
  InitWellKnownTypes();
  return ContainsKey(*well_known_types_, type_name);
}

bool IsValidBoolString(const string& bool_string) {
  return bool_string == "true" || bool_string == "false" ||
         bool_string == "1" || bool_string == "0";
}

bool IsMap(const google::protobuf::Field& field,
           const google::protobuf::Type& type) {
  return field.cardinality() ==
             google::protobuf::Field_Cardinality_CARDINALITY_REPEATED &&
         (GetBoolOptionOrDefault(type.options(), "map_entry", false) ||
          GetBoolOptionOrDefault(type.options(),
                                 "google.protobuf.MessageOptions.map_entry", false) ||
          GetBoolOptionOrDefault(type.options(),
                                 "google.protobuf.MessageOptions.map_entry",
                                 false));
}

bool IsMessageSetWireFormat(const google::protobuf::Type& type) {
  return GetBoolOptionOrDefault(type.options(), "message_set_wire_format",
                                false) ||
         GetBoolOptionOrDefault(type.options(),
                                "google.protobuf.MessageOptions.message_set_wire_format",
                                false) ||
         GetBoolOptionOrDefault(
             type.options(),
             "google.protobuf.MessageOptions.message_set_wire_format", false);
}

string DoubleAsString(double value) {
  if (MathLimits<double>::IsPosInf(value)) return "Infinity";
  if (MathLimits<double>::IsNegInf(value)) return "-Infinity";
  if (MathLimits<double>::IsNaN(value)) return "NaN";

  return SimpleDtoa(value);
}

string FloatAsString(float value) {
  if (MathLimits<float>::IsFinite(value)) return SimpleFtoa(value);
  return DoubleAsString(value);
}

bool SafeStrToFloat(StringPiece str, float* value) {
  double double_value;
  if (!safe_strtod(str, &double_value)) {
    return false;
  }

  if (MathLimits<double>::IsInf(double_value) ||
      MathLimits<double>::IsNaN(double_value))
    return false;

  // Fail if the value is not representable in float.
  if (double_value > std::numeric_limits<float>::max() ||
      double_value < -std::numeric_limits<float>::max()) {
    return false;
  }

  *value = static_cast<float>(double_value);
  return true;
}

}  // namespace converter
}  // namespace util
}  // namespace protobuf
}  // namespace google

mime_type: text/plain


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// FieldMask related utility methods.

#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_FIELD_MASK_UTILITY_H__
#define GOOGLE_PROTOBUF_UTIL_CONVERTER_FIELD_MASK_UTILITY_H__

#include <functional>
#include <stack>

#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stringpiece.h>
#include <google/protobuf/stubs/status.h>

namespace google {
namespace protobuf {
namespace util {
namespace converter {

typedef string (*ConverterCallback)(StringPiece);
typedef ResultCallback1<util::Status, StringPiece>* PathSinkCallback;

// Applies a 'converter' to each segment of a FieldMask path and returns the
// result. Quoted strings in the 'path' are copied to the output as-is without
// converting their content. Escaping is supported within quoted strings.
// For example, "ab\"_c" will be returned as "ab\"_c" without any changes.
string ConvertFieldMaskPath(const StringPiece path,
                            ConverterCallback converter);

// Decodes a compact list of FieldMasks. For example, "a.b,a.c.d,a.c.e" will be
// decoded into a list of field paths - "a.b", "a.c.d", "a.c.e". And the results
// will be sent to 'path_sink', i.e. 'path_sink' will be called once per
// resulting path.
// Note that we also support Apiary style FieldMask form. The above example in
// the Apiary style will look like "a.b,a.c(d,e)".
util::Status DecodeCompactFieldMaskPaths(StringPiece paths,
                                           PathSinkCallback path_sink);

}  // namespace converter
}  // namespace util
}  // namespace protobuf

}  // namespace google
#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_FIELD_MASK_UTILITY_H__


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <google/protobuf/util/internal/field_mask_utility.h>

#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/status_macros.h>

namespace google {
namespace protobuf {
namespace util {
namespace converter {

namespace {
inline util::Status CallPathSink(PathSinkCallback path_sink,
                                   StringPiece arg) {
  return path_sink->Run(arg);
}

// Appends a FieldMask path segment to a prefix.
string AppendPathSegmentToPrefix(StringPiece prefix, StringPiece segment) {
  if (prefix.empty()) {
    return segment.ToString();
  }
  if (segment.empty()) {
    return prefix.ToString();
  }
  // If the segment is a map key, appends it to the prefix without the ".".
  if (segment.starts_with("[\"")) {
    return StrCat(prefix, segment);
  }
  return StrCat(prefix, ".", segment);
}

}  // namespace

string ConvertFieldMaskPath(const StringPiece path,
                            ConverterCallback converter) {
  string result;
  result.reserve(path.size() << 1);

  bool is_quoted = false;
  bool is_escaping = false;
  int current_segment_start = 0;

  // Loops until 1 passed the end of the input to make handling the last
  // segment easier.
  for (size_t i = 0; i <= path.size(); ++i) {
    // Outputs quoted string as-is.
    if (is_quoted) {
      if (i == path.size()) {
        break;
      }
      result.push_back(path[i]);
      if (is_escaping) {
        is_escaping = false;
      } else if (path[i] == '\\') {
        is_escaping = true;
      } else if (path[i] == '\"') {
        current_segment_start = i + 1;
        is_quoted = false;
      }
      continue;
    }
    if (i == path.size() || path[i] == '.' || path[i] == '(' ||
        path[i] == ')' || path[i] == '\"') {
      result += converter(
          path.substr(current_segment_start, i - current_segment_start));
      if (i < path.size()) {
        result.push_back(path[i]);
      }
      current_segment_start = i + 1;
    }
    if (i < path.size() && path[i] == '\"') {
      is_quoted = true;
    }
  }
  return result;
}

util::Status DecodeCompactFieldMaskPaths(StringPiece paths,
                                           PathSinkCallback path_sink) {
  std::stack<string> prefix;
  int length = paths.length();
  int previous_position = 0;
  bool in_map_key = false;
  bool is_escaping = false;
  // Loops until 1 passed the end of the input to make the handle of the last
  // segment easier.
  for (int i = 0; i <= length; ++i) {
    if (i != length) {
      // Skips everything in a map key until we hit the end of it, which is
      // marked by an un-escaped '"' immediately followed by a ']'.
      if (in_map_key) {
        if (is_escaping) {
          is_escaping = false;
          continue;
        }
        if (paths[i] == '\\') {
          is_escaping = true;
          continue;
        }
        if (paths[i] != '\"') {
          continue;
        }
        // Un-escaped '"' must be followed with a ']'.
        if (i >= length - 1 || paths[i + 1] != ']') {
          return util::Status(
              util::error::INVALID_ARGUMENT,
              StrCat("Invalid FieldMask '", paths,
                     "'. Map keys should be represented as [\"some_key\"]."));
        }
        // The end of the map key ("\"]") has been found.
        in_map_key = false;
        // Skips ']'.
        i++;
        // Checks whether the key ends at the end of a path segment.
        if (i < length - 1 && paths[i + 1] != '.' && paths[i + 1] != ',' &&
            paths[i + 1] != ')' && paths[i + 1] != '(') {
          return util::Status(
              util::error::INVALID_ARGUMENT,
              StrCat("Invalid FieldMask '", paths,
                     "'. Map keys should be at the end of a path segment."));
        }
        is_escaping = false;
        continue;
      }

      // We are not in a map key, look for the start of one.
      if (paths[i] == '[') {
        if (i >= length - 1 || paths[i + 1] != '\"') {
          return util::Status(
              util::error::INVALID_ARGUMENT,
              StrCat("Invalid FieldMask '", paths,
                     "'. Map keys should be represented as [\"some_key\"]."));
        }
        // "[\"" starts a map key.
        in_map_key = true;
        i++;  // Skips the '\"'.
        continue;
      }
      // If the current character is not a special character (',', '(' or ')'),
      // continue to the next.
      if (paths[i] != ',' && paths[i] != ')' && paths[i] != '(') {
        continue;
      }
    }
    // Gets the current segment - sub-string between previous position (after
    // '(', ')', ',', or the beginning of the input) and the current position.
    StringPiece segment =
        paths.substr(previous_position, i - previous_position);
    string current_prefix = prefix.empty() ? "" : prefix.top();

    if (i < length && paths[i] == '(') {
      // Builds a prefix and save it into the stack.
      prefix.push(AppendPathSegmentToPrefix(current_prefix, segment));
    } else if (!segment.empty()) {
      // When the current charactor is ')', ',' or the current position has
      // passed the end of the input, builds and outputs a new paths by
      // concatenating the last prefix with the current segment.
      RETURN_IF_ERROR(CallPathSink(
          path_sink, AppendPathSegmentToPrefix(current_prefix, segment)));
    }

    // Removes the last prefix after seeing a ')'.
    if (i < length && paths[i] == ')') {
      if (prefix.empty()) {
        return util::Status(
            util::error::INVALID_ARGUMENT,
            StrCat("Invalid FieldMask '", paths,
                   "'. Cannot find matching '(' for all ')'."));
      }
      prefix.pop();
    }
    previous_position = i + 1;
  }
  if (in_map_key) {
    return util::Status(util::error::INVALID_ARGUMENT,
                          StrCat("Invalid FieldMask '", paths,
                                 "'. Cannot find matching ']' for all '['."));
  }
  if (!prefix.empty()) {
    return util::Status(util::error::INVALID_ARGUMENT,
                          StrCat("Invalid FieldMask '", paths,
                                 "'. Cannot find matching ')' for all '('."));
  }
  return util::Status();
}

}  // namespace converter
}  // namespace util
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <google/protobuf/util/internal/default_value_objectwriter.h>

#include <google/protobuf/stubs/hash.h>

#include <google/protobuf/util/internal/constants.h>
#include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/stubs/map_util.h>

namespace google {
namespace protobuf {
namespace util {
using util::Status;
using util::StatusOr;
namespace converter {

namespace {
// Helper function to convert string value to given data type by calling the
// passed converter function on the DataPiece created from "value" argument.
// If value is empty or if conversion fails, the default_value is returned.
template <typename T>
T ConvertTo(StringPiece value, StatusOr<T> (DataPiece::*converter_fn)() const,
            T default_value) {
  if (value.empty()) return default_value;
  StatusOr<T> result = (DataPiece(value, true).*converter_fn)();
  return result.ok() ? result.ValueOrDie() : default_value;
}
}  // namespace

DefaultValueObjectWriter::DefaultValueObjectWriter(
    TypeResolver* type_resolver, const google::protobuf::Type& type,
    ObjectWriter* ow)
    : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
      own_typeinfo_(true),
      type_(type),
      current_(NULL),
      root_(NULL),
      suppress_empty_list_(false),
      preserve_proto_field_names_(false),
      field_scrub_callback_(NULL),
      ow_(ow) {}

DefaultValueObjectWriter::~DefaultValueObjectWriter() {
  for (int i = 0; i < string_values_.size(); ++i) {
    delete string_values_[i];
  }
  if (own_typeinfo_) {
    delete typeinfo_;
  }
}

DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(StringPiece name,
                                                               bool value) {
  if (current_ == NULL) {
    ow_->RenderBool(name, value);
  } else {
    RenderDataPiece(name, DataPiece(value));
  }
  return this;
}

DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32(
    StringPiece name, int32 value) {
  if (current_ == NULL) {
    ow_->RenderInt32(name, value);
  } else {
    RenderDataPiece(name, DataPiece(value));
  }
  return this;
}

DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32(
    StringPiece name, uint32 value) {
  if (current_ == NULL) {
    ow_->RenderUint32(name, value);
  } else {
    RenderDataPiece(name, DataPiece(value));
  }
  return this;
}

DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64(
    StringPiece name, int64 value) {
  if (current_ == NULL) {
    ow_->RenderInt64(name, value);
  } else {
    RenderDataPiece(name, DataPiece(value));
  }
  return this;
}

DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64(
    StringPiece name, uint64 value) {
  if (current_ == NULL) {
    ow_->RenderUint64(name, value);
  } else {
    RenderDataPiece(name, DataPiece(value));
  }
  return this;
}

DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble(
    StringPiece name, double value) {
  if (current_ == NULL) {
    ow_->RenderDouble(name, value);
  } else {
    RenderDataPiece(name, DataPiece(value));
  }
  return this;
}

DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat(
    StringPiece name, float value) {
  if (current_ == NULL) {
    ow_->RenderBool(name, value);
  } else {
    RenderDataPiece(name, DataPiece(value));
  }
  return this;
}

DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString(
    StringPiece name, StringPiece value) {
  if (current_ == NULL) {
    ow_->RenderString(name, value);
  } else {
    // Since StringPiece is essentially a pointer, takes a copy of "value" to
    // avoid ownership issues.
    string_values_.push_back(new string(value.ToString()));
    RenderDataPiece(name, DataPiece(*string_values_.back(), true));
  }
  return this;
}

DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes(
    StringPiece name, StringPiece value) {
  if (current_ == NULL) {
    ow_->RenderBytes(name, value);
  } else {
    // Since StringPiece is essentially a pointer, takes a copy of "value" to
    // avoid ownership issues.
    string_values_.push_back(new string(value.ToString()));
    RenderDataPiece(name, DataPiece(*string_values_.back(), false, true));
  }
  return this;
}

DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull(
    StringPiece name) {
  if (current_ == NULL) {
    ow_->RenderNull(name);
  } else {
    RenderDataPiece(name, DataPiece::NullData());
  }
  return this;
}

void DefaultValueObjectWriter::RegisterFieldScrubCallBack(
    FieldScrubCallBackPtr field_scrub_callback) {
  field_scrub_callback_.reset(field_scrub_callback.release());
}

DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode(
    const string& name, const google::protobuf::Type* type, NodeKind kind,
    const DataPiece& data, bool is_placeholder, const std::vector<string>& path,
    bool suppress_empty_list, FieldScrubCallBack* field_scrub_callback) {
  return new Node(name, type, kind, data, is_placeholder, path,
                  suppress_empty_list, field_scrub_callback);
}

DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode(
    const string& name, const google::protobuf::Type* type, NodeKind kind,
    const DataPiece& data, bool is_placeholder, const std::vector<string>& path,
    bool suppress_empty_list, bool preserve_proto_field_names,
    FieldScrubCallBack* field_scrub_callback) {
  return new Node(name, type, kind, data, is_placeholder, path,
                  suppress_empty_list, preserve_proto_field_names,
                  field_scrub_callback);
}

DefaultValueObjectWriter::Node::Node(
    const string& name, const google::protobuf::Type* type, NodeKind kind,
    const DataPiece& data, bool is_placeholder, const std::vector<string>& path,
    bool suppress_empty_list, FieldScrubCallBack* field_scrub_callback)
    : name_(name),
      type_(type),
      kind_(kind),
      is_any_(false),
      data_(data),
      is_placeholder_(is_placeholder),
      path_(path),
      suppress_empty_list_(suppress_empty_list),
      preserve_proto_field_names_(false),
      field_scrub_callback_(field_scrub_callback) {}

DefaultValueObjectWriter::Node::Node(
    const string& name, const google::protobuf::Type* type, NodeKind kind,
    const DataPiece& data, bool is_placeholder, const std::vector<string>& path,
    bool suppress_empty_list, bool preserve_proto_field_names,
    FieldScrubCallBack* field_scrub_callback)
    : name_(name),
      type_(type),
      kind_(kind),
      is_any_(false),
      data_(data),
      is_placeholder_(is_placeholder),
      path_(path),
      suppress_empty_list_(suppress_empty_list),
      preserve_proto_field_names_(preserve_proto_field_names),
      field_scrub_callback_(field_scrub_callback) {}

DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild(
    StringPiece name) {
  if (name.empty() || kind_ != OBJECT) {
    return NULL;
  }
  for (int i = 0; i < children_.size(); ++i) {
    Node* child = children_[i];
    if (child->name() == name) {
      return child;
    }
  }
  return NULL;
}

void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) {
  if (kind_ == PRIMITIVE) {
    ObjectWriter::RenderDataPieceTo(data_, name_, ow);
    return;
  }

  // Render maps. Empty maps are rendered as "{}".
  if (kind_ == MAP) {
    ow->StartObject(name_);
    WriteChildren(ow);
    ow->EndObject();
    return;
  }

  // Write out lists. If we didn't have any list in response, write out empty
  // list.
  if (kind_ == LIST) {
    // Suppress empty lists if requested.
    if (suppress_empty_list_ && is_placeholder_) return;

    ow->StartList(name_);
    WriteChildren(ow);
    ow->EndList();
    return;
  }

  // If is_placeholder_ = true, we didn't see this node in the response, so
  // skip output.
  if (is_placeholder_) return;

  ow->StartObject(name_);
  WriteChildren(ow);
  ow->EndObject();
}

void DefaultValueObjectWriter::Node::WriteChildren(ObjectWriter* ow) {
  for (int i = 0; i < children_.size(); ++i) {
    Node* child = children_[i];
    child->WriteTo(ow);
  }
}

const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType(
    const google::protobuf::Type& found_type, const TypeInfo* typeinfo) {
  // If this field is a map, we should use the type of its "Value" as
  // the type of the child node.
  for (int i = 0; i < found_type.fields_size(); ++i) {
    const google::protobuf::Field& sub_field = found_type.fields(i);
    if (sub_field.number() != 2) {
      continue;
    }
    if (sub_field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE) {
      // This map's value type is not a message type. We don't need to
      // get the field_type in this case.
      break;
    }
    util::StatusOr<const google::protobuf::Type*> sub_type =
        typeinfo->ResolveTypeUrl(sub_field.type_url());
    if (!sub_type.ok()) {
      GOOGLE_LOG(WARNING) << "Cannot resolve type '" << sub_field.type_url() << "'.";
    } else {
      return sub_type.ValueOrDie();
    }
    break;
  }
  return NULL;
}

void DefaultValueObjectWriter::Node::PopulateChildren(
    const TypeInfo* typeinfo) {
  // Ignores well known types that don't require automatically populating their
  // primitive children. For type "Any", we only populate its children when the
  // "@type" field is set.
  // TODO(tsun): remove "kStructValueType" from the list. It's being checked
  //     now because of a bug in the tool-chain that causes the "oneof_index"
  //     of kStructValueType to not be set correctly.
  if (type_ == NULL || type_->name() == kAnyType ||
      type_->name() == kStructType || type_->name() == kTimestampType ||
      type_->name() == kDurationType || type_->name() == kStructValueType) {
    return;
  }
  std::vector<Node*> new_children;
  hash_map<string, int> orig_children_map;

  // Creates a map of child nodes to speed up lookup.
  for (int i = 0; i < children_.size(); ++i) {
    InsertIfNotPresent(&orig_children_map, children_[i]->name_, i);
  }

  for (int i = 0; i < type_->fields_size(); ++i) {
    const google::protobuf::Field& field = type_->fields(i);

    // This code is checking if the field to be added to the tree should be
    // scrubbed or not by calling the field_scrub_callback_ callback function.
    std::vector<string> path;
    if (!path_.empty()) {
      path.insert(path.begin(), path_.begin(), path_.end());
    }
    path.push_back(field.name());
    if (field_scrub_callback_ != NULL &&
        field_scrub_callback_->Run(path, &field)) {
      continue;
    }

    hash_map<string, int>::iterator found =
        orig_children_map.find(field.name());
    // If the child field has already been set, we just add it to the new list
    // of children.
    if (found != orig_children_map.end()) {
      new_children.push_back(children_[found->second]);
      children_[found->second] = NULL;
      continue;
    }

    const google::protobuf::Type* field_type = NULL;
    bool is_map = false;
    NodeKind kind = PRIMITIVE;

    if (field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
      kind = OBJECT;
      util::StatusOr<const google::protobuf::Type*> found_result =
          typeinfo->ResolveTypeUrl(field.type_url());
      if (!found_result.ok()) {
        // "field" is of an unknown type.
        GOOGLE_LOG(WARNING) << "Cannot resolve type '" << field.type_url() << "'.";
      } else {
        const google::protobuf::Type* found_type = found_result.ValueOrDie();
        is_map = IsMap(field, *found_type);

        if (!is_map) {
          field_type = found_type;
        } else {
          // If this field is a map, we should use the type of its "Value" as
          // the type of the child node.
          field_type = GetMapValueType(*found_type, typeinfo);
          kind = MAP;
        }
      }
    }

    if (!is_map &&
        field.cardinality() ==
            google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
      kind = LIST;
    }

    // If oneof_index() != 0, the child field is part of a "oneof", which means
    // the child field is optional and we shouldn't populate its default
    // primitive value.
    if (field.oneof_index() != 0 && kind == PRIMITIVE) continue;

    // If the child field is of primitive type, sets its data to the default
    // value of its type.
    google::protobuf::scoped_ptr<Node> child(new Node(
        preserve_proto_field_names_ ? field.name() : field.json_name(),
        field_type, kind,
        kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo)
                          : DataPiece::NullData(),
        true, path, suppress_empty_list_, preserve_proto_field_names_,
        field_scrub_callback_));
    new_children.push_back(child.release());
  }
  // Adds all leftover nodes in children_ to the beginning of new_child.
  for (int i = 0; i < children_.size(); ++i) {
    if (children_[i] == NULL) {
      continue;
    }
    new_children.insert(new_children.begin(), children_[i]);
    children_[i] = NULL;
  }
  children_.swap(new_children);
}

void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) {
  // If this is an "Any" node with "@type" already given and no other children
  // have been added, populates its children.
  if (node != NULL && node->is_any() && node->type() != NULL &&
      node->type()->name() != kAnyType && node->number_of_children() == 1) {
    node->PopulateChildren(typeinfo_);
  }
}

DataPiece DefaultValueObjectWriter::FindEnumDefault(
    const google::protobuf::Field& field, const TypeInfo* typeinfo) {
  if (!field.default_value().empty())
    return DataPiece(field.default_value(), true);

  const google::protobuf::Enum* enum_type =
      typeinfo->GetEnumByTypeUrl(field.type_url());
  if (!enum_type) {
    GOOGLE_LOG(WARNING) << "Could not find enum with type '" << field.type_url()
                 << "'";
    return DataPiece::NullData();
  }
  // We treat the first value as the default if none is specified.
  return enum_type->enumvalue_size() > 0
             ? DataPiece(enum_type->enumvalue(0).name(), true)
             : DataPiece::NullData();
}

DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField(
    const google::protobuf::Field& field, const TypeInfo* typeinfo) {
  switch (field.kind()) {
    case google::protobuf::Field_Kind_TYPE_DOUBLE: {
      return DataPiece(ConvertTo<double>(
          field.default_value(), &DataPiece::ToDouble, static_cast<double>(0)));
    }
    case google::protobuf::Field_Kind_TYPE_FLOAT: {
      return DataPiece(ConvertTo<float>(
          field.default_value(), &DataPiece::ToFloat, static_cast<float>(0)));
    }
    case google::protobuf::Field_Kind_TYPE_INT64:
    case google::protobuf::Field_Kind_TYPE_SINT64:
    case google::protobuf::Field_Kind_TYPE_SFIXED64: {
      return DataPiece(ConvertTo<int64>(
          field.default_value(), &DataPiece::ToInt64, static_cast<int64>(0)));
    }
    case google::protobuf::Field_Kind_TYPE_UINT64:
    case google::protobuf::Field_Kind_TYPE_FIXED64: {
      return DataPiece(ConvertTo<uint64>(
          field.default_value(), &DataPiece::ToUint64, static_cast<uint64>(0)));
    }
    case google::protobuf::Field_Kind_TYPE_INT32:
    case google::protobuf::Field_Kind_TYPE_SINT32:
    case google::protobuf::Field_Kind_TYPE_SFIXED32: {
      return DataPiece(ConvertTo<int32>(
          field.default_value(), &DataPiece::ToInt32, static_cast<int32>(0)));
    }
    case google::protobuf::Field_Kind_TYPE_BOOL: {
      return DataPiece(
          ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false));
    }
    case google::protobuf::Field_Kind_TYPE_STRING: {
      return DataPiece(field.default_value(), true);
    }
    case google::protobuf::Field_Kind_TYPE_BYTES: {
      return DataPiece(field.default_value(), false, true);
    }
    case google::protobuf::Field_Kind_TYPE_UINT32:
    case google::protobuf::Field_Kind_TYPE_FIXED32: {
      return DataPiece(ConvertTo<uint32>(
          field.default_value(), &DataPiece::ToUint32, static_cast<uint32>(0)));
    }
    case google::protobuf::Field_Kind_TYPE_ENUM: {
      return FindEnumDefault(field, typeinfo);
    }
    default: { return DataPiece::NullData(); }
  }
}

DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject(
    StringPiece name) {
  if (current_ == NULL) {
    std::vector<string> path;
    root_.reset(CreateNewNode(string(name), &type_, OBJECT,
                              DataPiece::NullData(), false, path,
                              suppress_empty_list_, preserve_proto_field_names_,
                              field_scrub_callback_.get()));
    root_->PopulateChildren(typeinfo_);
    current_ = root_.get();
    return this;
  }
  MaybePopulateChildrenOfAny(current_);
  Node* child = current_->FindChild(name);
  if (current_->kind() == LIST || current_->kind() == MAP || child == NULL) {
    // If current_ is a list or a map node, we should create a new child and use
    // the type of current_ as the type of the new child.
    google::protobuf::scoped_ptr<Node> node(
        CreateNewNode(string(name),
                      ((current_->kind() == LIST || current_->kind() == MAP)
                           ? current_->type()
                           : NULL),
                      OBJECT, DataPiece::NullData(), false,
                      child == NULL ? current_->path() : child->path(),
                      suppress_empty_list_, preserve_proto_field_names_,
                      field_scrub_callback_.get()));
    child = node.get();
    current_->AddChild(node.release());
  }

  child->set_is_placeholder(false);
  if (child->kind() == OBJECT && child->number_of_children() == 0) {
    child->PopulateChildren(typeinfo_);
  }

  stack_.push(current_);
  current_ = child;
  return this;
}

DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() {
  if (stack_.empty()) {
    // The root object ends here. Writes out the tree.
    WriteRoot();
    return this;
  }
  current_ = stack_.top();
  stack_.pop();
  return this;
}

DefaultValueObjectWriter* DefaultValueObjectWriter::StartList(
    StringPiece name) {
  if (current_ == NULL) {
    std::vector<string> path;
    root_.reset(CreateNewNode(string(name), &type_, LIST, DataPiece::NullData(),
                              false, path, suppress_empty_list_,
                              preserve_proto_field_names_,
                              field_scrub_callback_.get()));
    current_ = root_.get();
    return this;
  }
  MaybePopulateChildrenOfAny(current_);
  Node* child = current_->FindChild(name);
  if (child == NULL || child->kind() != LIST) {
    google::protobuf::scoped_ptr<Node> node(
        CreateNewNode(string(name), NULL, LIST, DataPiece::NullData(), false,
                      child == NULL ? current_->path() : child->path(),
                      suppress_empty_list_, preserve_proto_field_names_,
                      field_scrub_callback_.get()));
    child = node.get();
    current_->AddChild(node.release());
  }
  child->set_is_placeholder(false);

  stack_.push(current_);
  current_ = child;
  return this;
}

void DefaultValueObjectWriter::WriteRoot() {
  root_->WriteTo(ow_);
  root_.reset(NULL);
  current_ = NULL;
}

DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() {
  if (stack_.empty()) {
    WriteRoot();
    return this;
  }
  current_ = stack_.top();
  stack_.pop();
  return this;
}

void DefaultValueObjectWriter::RenderDataPiece(StringPiece name,
                                               const DataPiece& data) {
  MaybePopulateChildrenOfAny(current_);
  if (current_->type() != NULL && current_->type()->name() == kAnyType &&
      name == "@type") {
    util::StatusOr<string> data_string = data.ToString();
    if (data_string.ok()) {
      const string& string_value = data_string.ValueOrDie();
      // If the type of current_ is "Any" and its "@type" field is being set
      // here, sets the type of current_ to be the type specified by the
      // "@type".
      util::StatusOr<const google::protobuf::Type*> found_type =
          typeinfo_->ResolveTypeUrl(string_value);
      if (!found_type.ok()) {
        GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'.";
      } else {
        current_->set_type(found_type.ValueOrDie());
      }
      current_->set_is_any(true);
      // If the "@type" field is placed after other fields, we should populate
      // other children of primitive type now. Otherwise, we should wait until
      // the first value field is rendered before we populate the children,
      // because the "value" field of a Any message could be omitted.
      if (current_->number_of_children() > 1 && current_->type() != NULL) {
        current_->PopulateChildren(typeinfo_);
      }
    }
  }
  Node* child = current_->FindChild(name);
  if (child == NULL || child->kind() != PRIMITIVE) {
    // No children are found, creates a new child.
    google::protobuf::scoped_ptr<Node> node(
        CreateNewNode(string(name), NULL, PRIMITIVE, data, false,
                      child == NULL ? current_->path() : child->path(),
                      suppress_empty_list_, preserve_proto_field_names_,
                      field_scrub_callback_.get()));
    current_->AddChild(node.release());
  } else {
    child->set_data(data);
    child->set_is_placeholder(false);
  }
}

}  // namespace converter
}  // namespace util
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef NET_PROTO2_UTIL_CONVERTER_STRINGS_JSON_ESCAPING_H_
#define NET_PROTO2_UTIL_CONVERTER_STRINGS_JSON_ESCAPING_H_

#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/bytestream.h>

namespace google {
namespace protobuf {
namespace util {
namespace converter {

class JsonEscaping {
 public:
  // The minimum value of a unicode high-surrogate code unit in the utf-16
  // encoding. A high-surrogate is also known as a leading-surrogate.
  // See http://www.unicode.org/glossary/#high_surrogate_code_unit
  static const uint16 kMinHighSurrogate = 0xd800;

  // The maximum value of a unicide high-surrogate code unit in the utf-16
  // encoding. A high-surrogate is also known as a leading-surrogate.
  // See http://www.unicode.org/glossary/#high_surrogate_code_unit
  static const uint16 kMaxHighSurrogate = 0xdbff;

  // The minimum value of a unicode low-surrogate code unit in the utf-16
  // encoding. A low-surrogate is also known as a trailing-surrogate.
  // See http://www.unicode.org/glossary/#low_surrogate_code_unit
  static const uint16 kMinLowSurrogate = 0xdc00;

  // The maximum value of a unicode low-surrogate code unit in the utf-16
  // encoding. A low-surrogate is also known as a trailing surrogate.
  // See http://www.unicode.org/glossary/#low_surrogate_code_unit
  static const uint16 kMaxLowSurrogate = 0xdfff;

  // The minimum value of a unicode supplementary code point.
  // See http://www.unicode.org/glossary/#supplementary_code_point
  static const uint32 kMinSupplementaryCodePoint = 0x010000;

  // The minimum value of a unicode code point.
  // See http://www.unicode.org/glossary/#code_point
  static const uint32 kMinCodePoint = 0x000000;

  // The maximum value of a unicode code point.
  // See http://www.unicode.org/glossary/#code_point
  static const uint32 kMaxCodePoint = 0x10ffff;

  JsonEscaping() {}
  virtual ~JsonEscaping() {}

  // Escape the given ByteSource to the given ByteSink.
  static void Escape(strings::ByteSource* input, strings::ByteSink* output);

 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JsonEscaping);
};

}  // namespace converter
}  // namespace util
}  // namespace protobuf
}  // namespace google

#endif  // NET_PROTO2_UTIL_CONVERTER_STRINGS_JSON_ESCAPING_H_


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_WRITER_H__
#define GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_WRITER_H__

#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stringpiece.h>

namespace google {
namespace protobuf {
namespace util {
namespace converter {

class DataPiece;

// An ObjectWriter is an interface for writing a stream of events
// representing objects and collections. Implementation of this
// interface can be used to write an object stream to an in-memory
// structure, protobufs, JSON, XML, or any other output format
// desired. The ObjectSource interface is typically used as the
// source of an object stream.
//
// See JsonObjectWriter for a sample implementation of ObjectWriter
// and its use.
//
// Derived classes could be thread-unsafe.
//
// TODO(xinb): seems like a prime candidate to apply the RAII paradigm
// and get rid the need to call EndXXX().
class LIBPROTOBUF_EXPORT ObjectWriter {
 public:
  virtual ~ObjectWriter() {}

  // Starts an object. If the name is empty, the object will not be named.
  virtual ObjectWriter* StartObject(StringPiece name) = 0;

  // Ends an object.
  virtual ObjectWriter* EndObject() = 0;

  // Starts a list. If the name is empty, the list will not be named.
  virtual ObjectWriter* StartList(StringPiece name) = 0;

  // Ends a list.
  virtual ObjectWriter* EndList() = 0;

  // Renders a boolean value.
  virtual ObjectWriter* RenderBool(StringPiece name, bool value) = 0;

  // Renders an 32-bit integer value.
  virtual ObjectWriter* RenderInt32(StringPiece name, int32 value) = 0;

  // Renders an 32-bit unsigned integer value.
  virtual ObjectWriter* RenderUint32(StringPiece name, uint32 value) = 0;

  // Renders a 64-bit integer value.
  virtual ObjectWriter* RenderInt64(StringPiece name, int64 value) = 0;

  // Renders an 64-bit unsigned integer value.
  virtual ObjectWriter* RenderUint64(StringPiece name, uint64 value) = 0;

  // Renders a double value.
  virtual ObjectWriter* RenderDouble(StringPiece name, double value) = 0;

  // Renders a float value.
  virtual ObjectWriter* RenderFloat(StringPiece name, float value) = 0;

  // Renders a StringPiece value. This is for rendering strings.
  virtual ObjectWriter* RenderString(StringPiece name, StringPiece value) = 0;

  // Renders a bytes value.
  virtual ObjectWriter* RenderBytes(StringPiece name, StringPiece value) = 0;

  // Renders a Null value.
  virtual ObjectWriter* RenderNull(StringPiece name) = 0;

  // Renders a DataPiece object to a ObjectWriter.
  static void RenderDataPieceTo(const DataPiece& data, StringPiece name,
                                ObjectWriter* ow);

  // Indicates whether this ObjectWriter has completed writing the root message,
  // usually this means writing of one complete object. Subclasses must override
  // this behavior appropriately.
  virtual bool done() { return false; }

  void set_use_strict_base64_decoding(bool value) {
    use_strict_base64_decoding_ = value;
  }

  bool use_strict_base64_decoding() const {
    return use_strict_base64_decoding_;
  }

  // Whether empty strings should be rendered for the next name for Start/Render
  // calls. This setting is only valid until the next key is rendered, after
  // which it gets reset.
  // It is up to the derived classes to interpret this and render accordingly.
  // Default implementation ignores this setting.
  virtual void empty_name_ok_for_next_key() {}

 protected:
  ObjectWriter() : use_strict_base64_decoding_(true) {}

 private:
  // If set to true, we use the stricter version of base64 decoding for byte
  // fields by making sure decoded version encodes back to the original string.
  bool use_strict_base64_decoding_;

  // Do not add any data members to this class.
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectWriter);
};

}  // namespace converter
}  // namespace util
}  // namespace protobuf

}  // namespace google
#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_WRITER_H__


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_LOCATION_TRACKER_H__
#define GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_LOCATION_TRACKER_H__

#include <string>

#include <google/protobuf/stubs/common.h>
#include <google/protobuf/util/internal/location_tracker.h>

namespace google {
namespace protobuf {
namespace util {
namespace converter {

// An empty concrete implementation of LocationTrackerInterface.
class ObjectLocationTracker : public LocationTrackerInterface {
 public:
  // Creates an empty location tracker.
  ObjectLocationTracker() {}

  virtual ~ObjectLocationTracker() {}

  // Returns empty because nothing is tracked.
  virtual string ToString() const { return ""; }

 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectLocationTracker);
};

}  // namespace converter
}  // namespace util
}  // namespace protobuf

}  // namespace google
#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_LOCATION_TRACKER_H__


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <google/protobuf/util/internal/json_objectwriter.h>

#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/util/internal/utility.h>
#include <gtest/gtest.h>

namespace google {
namespace protobuf {
namespace util {
namespace converter {

using google::protobuf::io::CodedOutputStream;
using google::protobuf::io::StringOutputStream;

class JsonObjectWriterTest : public ::testing::Test {
 protected:
  JsonObjectWriterTest()
      : str_stream_(new StringOutputStream(&output_)),
        out_stream_(new CodedOutputStream(str_stream_)),
        ow_(NULL) {}

  virtual ~JsonObjectWriterTest() {
    delete ow_;
    delete out_stream_;
    delete str_stream_;
  }

  string output_;
  StringOutputStream* const str_stream_;
  CodedOutputStream* const out_stream_;
  JsonObjectWriter* ow_;
};

TEST_F(JsonObjectWriterTest, EmptyRootObject) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartObject("")->EndObject();
  EXPECT_EQ("{}", output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, EmptyObject) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartObject("")
      ->RenderString("test", "value")
      ->StartObject("empty")
      ->EndObject()
      ->EndObject();
  EXPECT_EQ("{\"test\":\"value\",\"empty\":{}}",
            output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, EmptyRootList) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartList("")->EndList();
  EXPECT_EQ("[]", output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, EmptyList) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartObject("")
      ->RenderString("test", "value")
      ->StartList("empty")
      ->EndList()
      ->EndObject();
  EXPECT_EQ("{\"test\":\"value\",\"empty\":[]}",
            output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, ObjectInObject) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartObject("")
      ->StartObject("nested")
      ->RenderString("field", "value")
      ->EndObject()
      ->EndObject();
  EXPECT_EQ("{\"nested\":{\"field\":\"value\"}}",
            output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, ListInObject) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartObject("")
      ->StartList("nested")
      ->RenderString("", "value")
      ->EndList()
      ->EndObject();
  EXPECT_EQ("{\"nested\":[\"value\"]}",
            output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, ObjectInList) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartList("")
      ->StartObject("")
      ->RenderString("field", "value")
      ->EndObject()
      ->EndList();
  EXPECT_EQ("[{\"field\":\"value\"}]",
            output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, ListInList) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartList("")
      ->StartList("")
      ->RenderString("", "value")
      ->EndList()
      ->EndList();
  EXPECT_EQ("[[\"value\"]]", output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, RenderPrimitives) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartObject("")
      ->RenderBool("bool", true)
      ->RenderDouble("double", std::numeric_limits<double>::max())
      ->RenderFloat("float", std::numeric_limits<float>::max())
      ->RenderInt32("int", std::numeric_limits<int32>::min())
      ->RenderInt64("long", std::numeric_limits<int64>::min())
      ->RenderBytes("bytes", "abracadabra")
      ->RenderString("string", "string")
      ->RenderBytes("emptybytes", "")
      ->RenderString("emptystring", string())
      ->EndObject();
  EXPECT_EQ(
      "{\"bool\":true,"
      "\"double\":" +
          ValueAsString<double>(std::numeric_limits<double>::max()) +
          ","
          "\"float\":" +
          ValueAsString<float>(std::numeric_limits<float>::max()) +
          ","
          "\"int\":-2147483648,"
          "\"long\":\"-9223372036854775808\","
          "\"bytes\":\"YWJyYWNhZGFicmE=\","
          "\"string\":\"string\","
          "\"emptybytes\":\"\","
          "\"emptystring\":\"\"}",
      output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, BytesEncodesAsNonWebSafeBase64) {
  string s;
  s.push_back('\377');
  s.push_back('\357');
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartObject("")->RenderBytes("bytes", s)->EndObject();
  // Non-web-safe would encode this as "/+8="
  EXPECT_EQ("{\"bytes\":\"/+8=\"}",
            output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, PrettyPrintList) {
  ow_ = new JsonObjectWriter(" ", out_stream_);
  ow_->StartObject("")
      ->StartList("items")
      ->RenderString("", "item1")
      ->RenderString("", "item2")
      ->RenderString("", "item3")
      ->EndList()
      ->StartList("empty")
      ->EndList()
      ->EndObject();
  EXPECT_EQ(
      "{\n"
      " \"items\": [\n"
      "  \"item1\",\n"
      "  \"item2\",\n"
      "  \"item3\"\n"
      " ],\n"
      " \"empty\": []\n"
      "}\n",
      output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, PrettyPrintObject) {
  ow_ = new JsonObjectWriter(" ", out_stream_);
  ow_->StartObject("")
      ->StartObject("items")
      ->RenderString("key1", "item1")
      ->RenderString("key2", "item2")
      ->RenderString("key3", "item3")
      ->EndObject()
      ->StartObject("empty")
      ->EndObject()
      ->EndObject();
  EXPECT_EQ(
      "{\n"
      " \"items\": {\n"
      "  \"key1\": \"item1\",\n"
      "  \"key2\": \"item2\",\n"
      "  \"key3\": \"item3\"\n"
      " },\n"
      " \"empty\": {}\n"
      "}\n",
      output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, PrettyPrintEmptyObjectInEmptyList) {
  ow_ = new JsonObjectWriter(" ", out_stream_);
  ow_->StartObject("")
      ->StartList("list")
      ->StartObject("")
      ->EndObject()
      ->EndList()
      ->EndObject();
  EXPECT_EQ(
      "{\n"
      " \"list\": [\n"
      "  {}\n"
      " ]\n"
      "}\n",
      output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, PrettyPrintDoubleIndent) {
  ow_ = new JsonObjectWriter("  ", out_stream_);
  ow_->StartObject("")
      ->RenderBool("bool", true)
      ->RenderInt32("int", 42)
      ->EndObject();
  EXPECT_EQ(
      "{\n"
      "  \"bool\": true,\n"
      "  \"int\": 42\n"
      "}\n",
      output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartObject("")->RenderString("string", "'<>&\\\"\r\n")->EndObject();
  EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&\\\\\\\"\\r\\n\"}",
            output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, Stringification) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartObject("")
      ->RenderDouble("double_nan", std::numeric_limits<double>::quiet_NaN())
      ->RenderFloat("float_nan", std::numeric_limits<float>::quiet_NaN())
      ->RenderDouble("double_pos", std::numeric_limits<double>::infinity())
      ->RenderFloat("float_pos", std::numeric_limits<float>::infinity())
      ->RenderDouble("double_neg", -std::numeric_limits<double>::infinity())
      ->RenderFloat("float_neg", -std::numeric_limits<float>::infinity())
      ->EndObject();
  EXPECT_EQ(
      "{\"double_nan\":\"NaN\","
      "\"float_nan\":\"NaN\","
      "\"double_pos\":\"Infinity\","
      "\"float_pos\":\"Infinity\","
      "\"double_neg\":\"-Infinity\","
      "\"float_neg\":\"-Infinity\"}",
      output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, TestRegularByteEncoding) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->StartObject("")
      ->RenderBytes("bytes", "\x03\xef\xc0")
      ->EndObject();

  // Test that we get regular (non websafe) base64 encoding on byte fields by
  // default.
  EXPECT_EQ("{\"bytes\":\"A+/A\"}",
            output_.substr(0, out_stream_->ByteCount()));
}

TEST_F(JsonObjectWriterTest, TestWebsafeByteEncoding) {
  ow_ = new JsonObjectWriter("", out_stream_);
  ow_->set_use_websafe_base64_for_bytes(true);
  ow_->StartObject("")
      ->RenderBytes("bytes", "\x03\xef\xc0\x10")
      ->EndObject();

  // Test that we get websafe base64 encoding when explicitly asked.
  EXPECT_EQ("{\"bytes\":\"A-_AEA==\"}",
            output_.substr(0, out_stream_->ByteCount()));
}

}  // namespace converter
}  // namespace util
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_H__
#define GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_H__

#include <google/protobuf/stubs/common.h>
#include <google/protobuf/type.pb.h>
#include <google/protobuf/util/type_resolver.h>
#include <google/protobuf/stubs/stringpiece.h>
#include <google/protobuf/stubs/status.h>
#include <google/protobuf/stubs/statusor.h>

namespace google {
namespace protobuf {
namespace util {
namespace converter {
// Internal helper class for type resolving. Note that this class is not
// thread-safe and should only be accessed in one thread.
class LIBPROTOBUF_EXPORT TypeInfo {
 public:
  TypeInfo() {}
  virtual ~TypeInfo() {}

  // Resolves a type url into a Type. If the type url is invalid, returns
  // INVALID_ARGUMENT error status. If the type url is valid but the
  // corresponding type cannot be found, returns a NOT_FOUND error status.
  //
  // This TypeInfo class retains the ownership of the returned pointer.
  virtual util::StatusOr<const google::protobuf::Type*> ResolveTypeUrl(
      StringPiece type_url) const = 0;

  // Resolves a type url into a Type. Like ResolveTypeUrl() but returns
  // NULL if the type url is invalid or the type cannot be found.
  //
  // This TypeInfo class retains the ownership of the returned pointer.
  virtual const google::protobuf::Type* GetTypeByTypeUrl(
      StringPiece type_url) const = 0;

  // Resolves a type url for an enum. Returns NULL if the type url is
  // invalid or the type cannot be found.
  //
  // This TypeInfo class retains the ownership of the returned pointer.
  virtual const google::protobuf::Enum* GetEnumByTypeUrl(
      StringPiece type_url) const = 0;

  // Looks up a field in the specified type given a CamelCase name.
  virtual const google::protobuf::Field* FindField(
      const google::protobuf::Type* type,
      StringPiece camel_case_name) const = 0;

  // Creates a TypeInfo object that looks up type information from a
  // TypeResolver. Caller takes ownership of the returned pointer.
  static TypeInfo* NewTypeInfo(TypeResolver* type_resolver);

 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeInfo);
};

}  // namespace converter
}  // namespace util
}  // namespace protobuf

}  // namespace google
#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_H__