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.

// Utility functions to convert between protobuf binary format and proto3 JSON
// format.
#ifndef GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__
#define GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__

#include <google/protobuf/message.h>
#include <google/protobuf/util/type_resolver.h>
#include <google/protobuf/stubs/bytestream.h>

namespace google {
namespace protobuf {
namespace io {
class ZeroCopyInputStream;
class ZeroCopyOutputStream;
}  // namespace io
namespace util {

struct JsonParseOptions {
  // Whether to ignore unknown JSON fields during parsing
  bool ignore_unknown_fields;

  JsonParseOptions() : ignore_unknown_fields(false) {}
};

struct JsonPrintOptions {
  // Whether to add spaces, line breaks and indentation to make the JSON output
  // easy to read.
  bool add_whitespace;
  // Whether to always print primitive fields. By default primitive fields with
  // default values will be omitted in JSON joutput. For example, an int32 field
  // set to 0 will be omitted. Set this flag to true will override the default
  // behavior and print primitive fields regardless of their values.
  bool always_print_primitive_fields;
  // Whether to always print enums as ints. By default they are rendered as
  // strings.
  bool always_print_enums_as_ints;
  // Whether to preserve proto field names
  bool preserve_proto_field_names;

  JsonPrintOptions()
      : add_whitespace(false),
        always_print_primitive_fields(false),
        always_print_enums_as_ints(false),
        preserve_proto_field_names(false) {}
};

// DEPRECATED. Use JsonPrintOptions instead.
typedef JsonPrintOptions JsonOptions;

// Converts from protobuf message to JSON. This is a simple wrapper of
// BinaryToJsonString(). It will use the DescriptorPool of the passed-in
// message to resolve Any types.
LIBPROTOBUF_EXPORT util::Status MessageToJsonString(const Message& message,
                                   string* output,
                                   const JsonOptions& options);

inline util::Status MessageToJsonString(const Message& message,
                                          string* output) {
  return MessageToJsonString(message, output, JsonOptions());
}

// Converts from JSON to protobuf message. This is a simple wrapper of
// JsonStringToBinary(). It will use the DescriptorPool of the passed-in
// message to resolve Any types.
LIBPROTOBUF_EXPORT util::Status JsonStringToMessage(const string& input,
                                   Message* message,
                                   const JsonParseOptions& options);

inline util::Status JsonStringToMessage(const string& input,
                                          Message* message) {
  return JsonStringToMessage(input, message, JsonParseOptions());
}

// Converts protobuf binary data to JSON.
// The conversion will fail if:
//   1. TypeResolver fails to resolve a type.
//   2. input is not valid protobuf wire format, or conflicts with the type
//      information returned by TypeResolver.
// Note that unknown fields will be discarded silently.
LIBPROTOBUF_EXPORT util::Status BinaryToJsonStream(
    TypeResolver* resolver,
    const string& type_url,
    io::ZeroCopyInputStream* binary_input,
    io::ZeroCopyOutputStream* json_output,
    const JsonPrintOptions& options);

inline util::Status BinaryToJsonStream(
    TypeResolver* resolver, const string& type_url,
    io::ZeroCopyInputStream* binary_input,
    io::ZeroCopyOutputStream* json_output) {
  return BinaryToJsonStream(resolver, type_url, binary_input, json_output,
                            JsonPrintOptions());
}

LIBPROTOBUF_EXPORT util::Status BinaryToJsonString(
    TypeResolver* resolver,
    const string& type_url,
    const string& binary_input,
    string* json_output,
    const JsonPrintOptions& options);

inline util::Status BinaryToJsonString(TypeResolver* resolver,
                                         const string& type_url,
                                         const string& binary_input,
                                         string* json_output) {
  return BinaryToJsonString(resolver, type_url, binary_input, json_output,
                            JsonPrintOptions());
}

// Converts JSON data to protobuf binary format.
// The conversion will fail if:
//   1. TypeResolver fails to resolve a type.
//   2. input is not valid JSON format, or conflicts with the type
//      information returned by TypeResolver.
LIBPROTOBUF_EXPORT util::Status JsonToBinaryStream(
    TypeResolver* resolver,
    const string& type_url,
    io::ZeroCopyInputStream* json_input,
    io::ZeroCopyOutputStream* binary_output,
    const JsonParseOptions& options);

inline util::Status JsonToBinaryStream(
    TypeResolver* resolver,
    const string& type_url,
    io::ZeroCopyInputStream* json_input,
    io::ZeroCopyOutputStream* binary_output) {
  return JsonToBinaryStream(resolver, type_url, json_input, binary_output,
                            JsonParseOptions());
}

LIBPROTOBUF_EXPORT util::Status JsonToBinaryString(
    TypeResolver* resolver,
    const string& type_url,
    const string& json_input,
    string* binary_output,
    const JsonParseOptions& options);

inline util::Status JsonToBinaryString(
    TypeResolver* resolver,
    const string& type_url,
    const string& json_input,
    string* binary_output) {
  return JsonToBinaryString(resolver, type_url, json_input, binary_output,
                            JsonParseOptions());
}

namespace internal {
// Internal helper class. Put in the header so we can write unit-tests for it.
class LIBPROTOBUF_EXPORT ZeroCopyStreamByteSink : public strings::ByteSink {
 public:
  explicit ZeroCopyStreamByteSink(io::ZeroCopyOutputStream* stream)
      : stream_(stream), buffer_(NULL), buffer_size_(0) {}
  ~ZeroCopyStreamByteSink();

  virtual void Append(const char* bytes, size_t len);

 private:
  io::ZeroCopyOutputStream* stream_;
  void* buffer_;
  int buffer_size_;

  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyStreamByteSink);
};
}  // namespace internal

}  // namespace util
}  // namespace protobuf

}  // namespace google
#endif  // GOOGLE_PROTOBUF_UTIL_JSON_UTIL_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_EXPECTING_OBJECTWRITER_H__
#define GOOGLE_PROTOBUF_UTIL_CONVERTER_EXPECTING_OBJECTWRITER_H__

// An implementation of ObjectWriter that automatically sets the
// gmock expectations for the response to a method. Every method
// returns the object itself for chaining.
//
// Usage:
//   // Setup
//   MockObjectWriter mock;
//   ExpectingObjectWriter ow(&mock);
//
//   // Set expectation
//   ow.StartObject("")
//       ->RenderString("key", "value")
//     ->EndObject();
//
//   // Actual testing
//   mock.StartObject(StringPiece())
//         ->RenderString("key", "value")
//       ->EndObject();

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

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

using testing::IsEmpty;
using testing::NanSensitiveDoubleEq;
using testing::NanSensitiveFloatEq;
using testing::Return;
using testing::StrEq;
using testing::TypedEq;

class MockObjectWriter : public ObjectWriter {
 public:
  MockObjectWriter() {}

  MOCK_METHOD1(StartObject, ObjectWriter*(StringPiece));
  MOCK_METHOD0(EndObject, ObjectWriter*());
  MOCK_METHOD1(StartList, ObjectWriter*(StringPiece));
  MOCK_METHOD0(EndList, ObjectWriter*());
  MOCK_METHOD2(RenderBool, ObjectWriter*(StringPiece, bool));
  MOCK_METHOD2(RenderInt32, ObjectWriter*(StringPiece, int32));
  MOCK_METHOD2(RenderUint32, ObjectWriter*(StringPiece, uint32));
  MOCK_METHOD2(RenderInt64, ObjectWriter*(StringPiece, int64));
  MOCK_METHOD2(RenderUint64, ObjectWriter*(StringPiece, uint64));
  MOCK_METHOD2(RenderDouble, ObjectWriter*(StringPiece, double));
  MOCK_METHOD2(RenderFloat, ObjectWriter*(StringPiece, float));
  MOCK_METHOD2(RenderString, ObjectWriter*(StringPiece, StringPiece));
  MOCK_METHOD2(RenderBytes, ObjectWriter*(StringPiece, StringPiece));
  MOCK_METHOD1(RenderNull, ObjectWriter*(StringPiece));
};

class ExpectingObjectWriter : public ObjectWriter {
 public:
  explicit ExpectingObjectWriter(MockObjectWriter* mock) : mock_(mock) {}

  virtual ObjectWriter* StartObject(StringPiece name) {
    (name.empty()
         ? EXPECT_CALL(*mock_, StartObject(IsEmpty()))
         : EXPECT_CALL(*mock_, StartObject(StrEq(name.ToString()))))
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }

  virtual ObjectWriter* EndObject() {
    EXPECT_CALL(*mock_, EndObject())
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }

  virtual ObjectWriter* StartList(StringPiece name) {
    (name.empty()
         ? EXPECT_CALL(*mock_, StartList(IsEmpty()))
         : EXPECT_CALL(*mock_, StartList(StrEq(name.ToString()))))
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }

  virtual ObjectWriter* EndList() {
    EXPECT_CALL(*mock_, EndList())
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }

  virtual ObjectWriter* RenderBool(StringPiece name, bool value) {
    (name.empty()
         ? EXPECT_CALL(*mock_, RenderBool(IsEmpty(), TypedEq<bool>(value)))
         : EXPECT_CALL(*mock_, RenderBool(StrEq(name.ToString()),
                                          TypedEq<bool>(value))))
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }

  virtual ObjectWriter* RenderInt32(StringPiece name, int32 value) {
    (name.empty()
         ? EXPECT_CALL(*mock_, RenderInt32(IsEmpty(), TypedEq<int32>(value)))
         : EXPECT_CALL(*mock_, RenderInt32(StrEq(name.ToString()),
                                           TypedEq<int32>(value))))
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }

  virtual ObjectWriter* RenderUint32(StringPiece name, uint32 value) {
    (name.empty()
         ? EXPECT_CALL(*mock_, RenderUint32(IsEmpty(), TypedEq<uint32>(value)))
         : EXPECT_CALL(*mock_, RenderUint32(StrEq(name.ToString()),
                                            TypedEq<uint32>(value))))
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }

  virtual ObjectWriter* RenderInt64(StringPiece name, int64 value) {
    (name.empty()
         ? EXPECT_CALL(*mock_, RenderInt64(IsEmpty(), TypedEq<int64>(value)))
         : EXPECT_CALL(*mock_, RenderInt64(StrEq(name.ToString()),
                                           TypedEq<int64>(value))))
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }

  virtual ObjectWriter* RenderUint64(StringPiece name, uint64 value) {
    (name.empty()
         ? EXPECT_CALL(*mock_, RenderUint64(IsEmpty(), TypedEq<uint64>(value)))
         : EXPECT_CALL(*mock_, RenderUint64(StrEq(name.ToString()),
                                            TypedEq<uint64>(value))))
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }

  virtual ObjectWriter* RenderDouble(StringPiece name, double value) {
    (name.empty()
         ? EXPECT_CALL(*mock_, RenderDouble(IsEmpty(),
                                            NanSensitiveDoubleEq(value)))
         : EXPECT_CALL(*mock_, RenderDouble(StrEq(name.ToString()),
                                            NanSensitiveDoubleEq(value))))
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }

  virtual ObjectWriter* RenderFloat(StringPiece name, float value) {
    (name.empty()
         ? EXPECT_CALL(*mock_, RenderFloat(IsEmpty(),
                                           NanSensitiveFloatEq(value)))
         : EXPECT_CALL(*mock_, RenderFloat(StrEq(name.ToString()),
                                           NanSensitiveFloatEq(value))))
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }

  virtual ObjectWriter* RenderString(StringPiece name, StringPiece value) {
    (name.empty()
         ? EXPECT_CALL(*mock_, RenderString(IsEmpty(),
               TypedEq<StringPiece>(value.ToString())))
         : EXPECT_CALL(*mock_, RenderString(StrEq(name.ToString()),
               TypedEq<StringPiece>(value.ToString()))))
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }
  virtual ObjectWriter* RenderBytes(StringPiece name, StringPiece value) {
    (name.empty()
         ? EXPECT_CALL(*mock_, RenderBytes(IsEmpty(), TypedEq<StringPiece>(
                                                          value.ToString())))
         : EXPECT_CALL(*mock_,
                       RenderBytes(StrEq(name.ToString()),
                                   TypedEq<StringPiece>(value.ToString()))))
        .WillOnce(Return(mock_))
        .RetiresOnSaturation();
    return this;
  }

  virtual ObjectWriter* RenderNull(StringPiece name) {
    (name.empty() ? EXPECT_CALL(*mock_, RenderNull(IsEmpty()))
                  : EXPECT_CALL(*mock_, RenderNull(StrEq(name.ToString())))
                        .WillOnce(Return(mock_))
                        .RetiresOnSaturation());
    return this;
  }

 private:
  MockObjectWriter* mock_;

  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ExpectingObjectWriter);
};

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

}  // namespace google
#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_EXPECTING_OBJECTWRITER_H__

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.

#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_STREAM_PARSER_H__
#define GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_STREAM_PARSER_H__

#include <stack>
#include <string>

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

namespace google {
namespace util {
class Status;
}  // namespace util

namespace protobuf {
namespace util {
namespace converter {

class ObjectWriter;

// A JSON parser that can parse a stream of JSON chunks rather than needing the
// entire JSON string up front. It is a modified version of the parser in
// //net/proto/json/json-parser.h that has been changed in the following ways:
// - Changed from recursion to an explicit stack to allow resumption
// - Added support for int64 and uint64 numbers
// - Removed support for octal and decimal escapes
// - Removed support for numeric keys
// - Removed support for functions (javascript)
// - Removed some lax-comma support (but kept trailing comma support)
// - Writes directly to an ObjectWriter rather than using subclassing
//
// Here is an example usage:
// JsonStreamParser parser(ow_.get());
// util::Status result = parser.Parse(chunk1);
// result.Update(parser.Parse(chunk2));
// result.Update(parser.FinishParse());
// GOOGLE_DCHECK(result.ok()) << "Failed to parse JSON";
//
// This parser is thread-compatible as long as only one thread is calling a
// Parse() method at a time.
class LIBPROTOBUF_EXPORT JsonStreamParser {
 public:
  // Creates a JsonStreamParser that will write to the given ObjectWriter.
  explicit JsonStreamParser(ObjectWriter* ow);
  virtual ~JsonStreamParser();

  // Parses a UTF-8 encoded JSON string from a StringPiece.
  util::Status Parse(StringPiece json);

  // Finish parsing the JSON string.
  util::Status FinishParse();

 private:
  enum TokenType {
    BEGIN_STRING,     // " or '
    BEGIN_NUMBER,     // - or digit
    BEGIN_TRUE,       // true
    BEGIN_FALSE,      // false
    BEGIN_NULL,       // null
    BEGIN_OBJECT,     // {
    END_OBJECT,       // }
    BEGIN_ARRAY,      // [
    END_ARRAY,        // ]
    ENTRY_SEPARATOR,  // :
    VALUE_SEPARATOR,  // ,
    BEGIN_KEY,        // letter, _, $ or digit.  Must begin with non-digit
    UNKNOWN           // Unknown token or we ran out of the stream.
  };

  enum ParseType {
    VALUE,        // Expects a {, [, true, false, null, string or number
    OBJ_MID,      // Expects a ',' or }
    ENTRY,        // Expects a key or }
    ENTRY_MID,    // Expects a :
    ARRAY_VALUE,  // Expects a value or ]
    ARRAY_MID     // Expects a ',' or ]
  };

  // Holds the result of parsing a number
  struct NumberResult {
    enum Type { DOUBLE, INT, UINT };
    Type type;
    union {
      double double_val;
      int64 int_val;
      uint64 uint_val;
    };
  };

  // Parses a single chunk of JSON, returning an error if the JSON was invalid.
  util::Status ParseChunk(StringPiece json);

  // Runs the parser based on stack_ and p_, until the stack is empty or p_ runs
  // out of data. If we unexpectedly run out of p_ we push the latest back onto
  // the stack and return.
  util::Status RunParser();

  // Parses a value from p_ and writes it to ow_.
  // A value may be an object, array, true, false, null, string or number.
  util::Status ParseValue(TokenType type);

  // Parses a string and writes it out to the ow_.
  util::Status ParseString();

  // Parses a string, storing the result in parsed_.
  util::Status ParseStringHelper();

  // This function parses unicode escape sequences in strings. It returns an
  // error when there's a parsing error, either the size is not the expected
  // size or a character is not a hex digit.  When it returns str will contain
  // what has been successfully parsed so far.
  util::Status ParseUnicodeEscape();

  // Expects p_ to point to a JSON number, writes the number to the writer using
  // the appropriate Render method based on the type of number.
  util::Status ParseNumber();

  // Parse a number into a NumberResult, reporting an error if no number could
  // be parsed. This method will try to parse into a uint64, int64, or double
  // based on whether the number was positive or negative or had a decimal
  // component.
  util::Status ParseNumberHelper(NumberResult* result);

  // Parse a number as double into a NumberResult.
  util::Status ParseDoubleHelper(const string& number, NumberResult* result);

  // Handles a { during parsing of a value.
  util::Status HandleBeginObject();

  // Parses from the ENTRY state.
  util::Status ParseEntry(TokenType type);

  // Parses from the ENTRY_MID state.
  util::Status ParseEntryMid(TokenType type);

  // Parses from the OBJ_MID state.
  util::Status ParseObjectMid(TokenType type);

  // Handles a [ during parsing of a value.
  util::Status HandleBeginArray();

  // Parses from the ARRAY_VALUE state.
  util::Status ParseArrayValue(TokenType type);

  // Parses from the ARRAY_MID state.
  util::Status ParseArrayMid(TokenType type);

  // Expects p_ to point to an unquoted literal
  util::Status ParseTrue();
  util::Status ParseFalse();
  util::Status ParseNull();
  util::Status ParseEmptyNull();

  // Whether an empty-null is allowed in the current state.
  bool IsEmptyNullAllowed(TokenType type);

  // Report a failure as a util::Status.
  util::Status ReportFailure(StringPiece message);

  // Report a failure due to an UNKNOWN token type. We check if we hit the
  // end of the stream and if we're finishing or not to detect what type of
  // status to return in this case.
  util::Status ReportUnknown(StringPiece message);

  // Advance p_ past all whitespace or until the end of the string.
  void SkipWhitespace();

  // Advance p_ one UTF-8 character
  void Advance();

  // Expects p_ to point to the beginning of a key.
  util::Status ParseKey();

  // Return the type of the next token at p_.
  TokenType GetNextTokenType();

  // The object writer to write parse events to.
  ObjectWriter* ow_;

  // The stack of parsing we still need to do. When the stack runs empty we will
  // have parsed a single value from the root (e.g. an object or list).
  std::stack<ParseType> stack_;

  // Contains any leftover text from a previous chunk that we weren't able to
  // fully parse, for example the start of a key or number.
  string leftover_;

  // The current chunk of JSON being parsed. Primarily used for providing
  // context during error reporting.
  StringPiece json_;

  // A pointer within the current JSON being parsed, used to track location.
  StringPiece p_;

  // Stores the last key read, as we separate parsing of keys and values.
  StringPiece key_;

  // Storage for key_ if we need to keep ownership, for example between chunks
  // or if the key was unescaped from a JSON string.
  string key_storage_;

  // True during the FinishParse() call, so we know that any errors are fatal.
  // For example an unterminated string will normally result in cancelling and
  // trying during the next chunk, but during FinishParse() it is an error.
  bool finishing_;

  // String we parsed during a call to ParseStringHelper().
  StringPiece parsed_;

  // Storage for the string we parsed. This may be empty if the string was able
  // to be parsed directly from the input.
  string parsed_storage_;

  // The character that opened the string, either ' or ".
  // A value of 0 indicates that string parsing is not in process.
  char string_open_;

  // Storage for the chunk that are being parsed in ParseChunk().
  string chunk_storage_;

  // Whether to allow non UTF-8 encoded input and replace invalid code points.
  bool coerce_to_utf8_;

  // Whether allows empty string represented null array value or object entry
  // value.
  bool allow_empty_null_;

  // Whether allows out-of-range floating point numbers or reject them.
  bool loose_float_number_conversion_;

  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonStreamParser);
};

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

}  // namespace google
#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_STREAM_PARSER_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 <math.h>

#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/util/internal/json_escaping.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/mathlimits.h>

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

using strings::ArrayByteSource;
;

JsonObjectWriter::~JsonObjectWriter() {
  if (!element_->is_root()) {
    GOOGLE_LOG(WARNING) << "JsonObjectWriter was not fully closed.";
  }
}

JsonObjectWriter* JsonObjectWriter::StartObject(StringPiece name) {
  WritePrefix(name);
  WriteChar('{');
  Push();
  return this;
}

JsonObjectWriter* JsonObjectWriter::EndObject() {
  Pop();
  WriteChar('}');
  if (element()->is_root()) NewLine();
  return this;
}

JsonObjectWriter* JsonObjectWriter::StartList(StringPiece name) {
  WritePrefix(name);
  WriteChar('[');
  Push();
  return this;
}

JsonObjectWriter* JsonObjectWriter::EndList() {
  Pop();
  WriteChar(']');
  if (element()->is_root()) NewLine();
  return this;
}

JsonObjectWriter* JsonObjectWriter::RenderBool(StringPiece name, bool value) {
  return RenderSimple(name, value ? "true" : "false");
}

JsonObjectWriter* JsonObjectWriter::RenderInt32(StringPiece name, int32 value) {
  return RenderSimple(name, SimpleItoa(value));
}

JsonObjectWriter* JsonObjectWriter::RenderUint32(StringPiece name,
                                                 uint32 value) {
  return RenderSimple(name, SimpleItoa(value));
}

JsonObjectWriter* JsonObjectWriter::RenderInt64(StringPiece name, int64 value) {
  WritePrefix(name);
  WriteChar('"');
  stream_->WriteString(SimpleItoa(value));
  WriteChar('"');
  return this;
}

JsonObjectWriter* JsonObjectWriter::RenderUint64(StringPiece name,
                                                 uint64 value) {
  WritePrefix(name);
  WriteChar('"');
  stream_->WriteString(SimpleItoa(value));
  WriteChar('"');
  return this;
}

JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name,
                                                 double value) {
  if (MathLimits<double>::IsFinite(value)) {
    return RenderSimple(name, SimpleDtoa(value));
  }

  // Render quoted with NaN/Infinity-aware DoubleAsString.
  return RenderString(name, DoubleAsString(value));
}

JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name, float value) {
  if (MathLimits<float>::IsFinite(value)) {
    return RenderSimple(name, SimpleFtoa(value));
  }

  // Render quoted with NaN/Infinity-aware FloatAsString.
  return RenderString(name, FloatAsString(value));
}

JsonObjectWriter* JsonObjectWriter::RenderString(StringPiece name,
                                                 StringPiece value) {
  WritePrefix(name);
  WriteChar('"');
  ArrayByteSource source(value);
  JsonEscaping::Escape(&source, &sink_);
  WriteChar('"');
  return this;
}

JsonObjectWriter* JsonObjectWriter::RenderBytes(StringPiece name,
                                                StringPiece value) {
  WritePrefix(name);
  string base64;

  if (use_websafe_base64_for_bytes_)
    WebSafeBase64EscapeWithPadding(value.ToString(), &base64);
  else
    Base64Escape(value, &base64);

  WriteChar('"');
  // TODO(wpoon): Consider a ByteSink solution that writes the base64 bytes
  //              directly to the stream, rather than first putting them
  //              into a string and then writing them to the stream.
  stream_->WriteRaw(base64.data(), base64.size());
  WriteChar('"');
  return this;
}

JsonObjectWriter* JsonObjectWriter::RenderNull(StringPiece name) {
  return RenderSimple(name, "null");
}

JsonObjectWriter* JsonObjectWriter::RenderNullAsEmpty(StringPiece name) {
  return RenderSimple(name, "");
}

void JsonObjectWriter::WritePrefix(StringPiece name) {
  bool not_first = !element()->is_first();
  if (not_first) WriteChar(',');
  if (not_first || !element()->is_root()) NewLine();
  bool empty_key_ok = GetAndResetEmptyKeyOk();
  if (!name.empty() || empty_key_ok) {
    WriteChar('"');
    if (!name.empty()) {
      ArrayByteSource source(name);
      JsonEscaping::Escape(&source, &sink_);
    }
    stream_->WriteString("\":");
    if (!indent_string_.empty()) WriteChar(' ');
  }
}

bool JsonObjectWriter::GetAndResetEmptyKeyOk() {
  bool retval = empty_name_ok_for_next_key_;
  empty_name_ok_for_next_key_ = false;
  return retval;
}

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