330 lines
14 KiB
C++
330 lines
14 KiB
C++
// 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_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
|
|
#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
|
|
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
|
|
#include <google/protobuf/stubs/status.h>
|
|
|
|
#include <google/protobuf/stubs/common.h>
|
|
#include <google/protobuf/type.pb.h>
|
|
#include <google/protobuf/stubs/statusor.h>
|
|
#include <google/protobuf/stubs/strutil.h>
|
|
#include <google/protobuf/util/internal/object_source.h>
|
|
#include <google/protobuf/util/internal/object_writer.h>
|
|
#include <google/protobuf/util/internal/type_info.h>
|
|
#include <google/protobuf/util/type_resolver.h>
|
|
#include <google/protobuf/stubs/hash.h>
|
|
#include <google/protobuf/stubs/status.h>
|
|
|
|
|
|
// Must be included last.
|
|
#include <google/protobuf/port_def.inc>
|
|
|
|
namespace google {
|
|
namespace protobuf {
|
|
namespace util {
|
|
namespace converter {
|
|
|
|
class TypeInfo;
|
|
|
|
// An ObjectSource that can parse a stream of bytes as a protocol buffer.
|
|
// Its WriteTo() method can be given an ObjectWriter.
|
|
// This implementation uses a google.protobuf.Type for tag and name lookup.
|
|
// The field names are converted into lower camel-case when writing to the
|
|
// ObjectWriter.
|
|
//
|
|
// Sample usage: (suppose input is: string proto)
|
|
// ArrayInputStream arr_stream(proto.data(), proto.size());
|
|
// CodedInputStream in_stream(&arr_stream);
|
|
// ProtoStreamObjectSource os(&in_stream, /*ServiceTypeInfo*/ typeinfo,
|
|
// <your message google::protobuf::Type>);
|
|
//
|
|
// Status status = os.WriteTo(<some ObjectWriter>);
|
|
class PROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
|
|
public:
|
|
|
|
struct RenderOptions {
|
|
RenderOptions() = default;
|
|
RenderOptions(const RenderOptions&) = default;
|
|
|
|
// Sets whether or not to use lowerCamelCase casing for enum values. If set
|
|
// to false, enum values are output without any case conversions.
|
|
//
|
|
// For example, if we have an enum:
|
|
// enum Type {
|
|
// ACTION_AND_ADVENTURE = 1;
|
|
// }
|
|
// Type type = 20;
|
|
//
|
|
// And this option is set to true. Then the rendered "type" field will have
|
|
// the string "actionAndAdventure".
|
|
// {
|
|
// ...
|
|
// "type": "actionAndAdventure",
|
|
// ...
|
|
// }
|
|
//
|
|
// If set to false, the rendered "type" field will have the string
|
|
// "ACTION_AND_ADVENTURE".
|
|
// {
|
|
// ...
|
|
// "type": "ACTION_AND_ADVENTURE",
|
|
// ...
|
|
// }
|
|
bool use_lower_camel_for_enums = false;
|
|
|
|
// Sets whether to always output enums as ints, by default this is off, and
|
|
// enums are rendered as strings.
|
|
bool use_ints_for_enums = false;
|
|
|
|
// Whether to preserve proto field names
|
|
bool preserve_proto_field_names = false;
|
|
|
|
};
|
|
|
|
ProtoStreamObjectSource(io::CodedInputStream* stream,
|
|
TypeResolver* type_resolver,
|
|
const google::protobuf::Type& type)
|
|
: ProtoStreamObjectSource(stream, type_resolver, type, RenderOptions()) {}
|
|
ProtoStreamObjectSource(io::CodedInputStream* stream,
|
|
TypeResolver* type_resolver,
|
|
const google::protobuf::Type& type,
|
|
const RenderOptions& render_options);
|
|
|
|
~ProtoStreamObjectSource() override;
|
|
|
|
util::Status NamedWriteTo(StringPiece name,
|
|
ObjectWriter* ow) const override;
|
|
|
|
// Sets the max recursion depth of proto message to be deserialized. Proto
|
|
// messages over this depth will fail to be deserialized.
|
|
// Default value is 64.
|
|
void set_max_recursion_depth(int max_depth) {
|
|
max_recursion_depth_ = max_depth;
|
|
}
|
|
|
|
protected:
|
|
// Writes a proto2 Message to the ObjectWriter. When the given end_tag is
|
|
// found this method will complete, allowing it to be used for parsing both
|
|
// nested messages (end with 0) and nested groups (end with group end tag).
|
|
// The include_start_and_end parameter allows this method to be called when
|
|
// already inside of an object, and skip calling StartObject and EndObject.
|
|
virtual util::Status WriteMessage(const google::protobuf::Type& type,
|
|
StringPiece name,
|
|
const uint32_t end_tag,
|
|
bool include_start_and_end,
|
|
ObjectWriter* ow) const;
|
|
|
|
// Renders a repeating field (packed or unpacked). Returns the next tag after
|
|
// reading all sequential repeating elements. The caller should use this tag
|
|
// before reading more tags from the stream.
|
|
virtual util::StatusOr<uint32_t> RenderList(
|
|
const google::protobuf::Field* field, StringPiece name,
|
|
uint32_t list_tag, ObjectWriter* ow) const;
|
|
|
|
// Looks up a field and verify its consistency with wire type in tag.
|
|
const google::protobuf::Field* FindAndVerifyField(
|
|
const google::protobuf::Type& type, uint32_t tag) const;
|
|
|
|
// Renders a field value to the ObjectWriter.
|
|
virtual util::Status RenderField(const google::protobuf::Field* field,
|
|
StringPiece field_name,
|
|
ObjectWriter* ow) const;
|
|
|
|
// Reads field value according to Field spec in 'field' and returns the read
|
|
// value as string. This only works for primitive datatypes (no message
|
|
// types).
|
|
const std::string ReadFieldValueAsString(
|
|
const google::protobuf::Field& field) const;
|
|
|
|
|
|
// Returns the input stream.
|
|
io::CodedInputStream* stream() const { return stream_; }
|
|
|
|
private:
|
|
ProtoStreamObjectSource(io::CodedInputStream* stream,
|
|
const TypeInfo* typeinfo,
|
|
const google::protobuf::Type& type,
|
|
const RenderOptions& render_options);
|
|
// Function that renders a well known type with a modified behavior.
|
|
typedef util::Status (*TypeRenderer)(const ProtoStreamObjectSource*,
|
|
const google::protobuf::Type&,
|
|
StringPiece, ObjectWriter*);
|
|
|
|
// TODO(skarvaje): Mark these methods as non-const as they modify internal
|
|
// state (stream_).
|
|
//
|
|
// Renders a NWP map.
|
|
// Returns the next tag after reading all map entries. The caller should use
|
|
// this tag before reading more tags from the stream.
|
|
util::StatusOr<uint32_t> RenderMap(const google::protobuf::Field* field,
|
|
StringPiece name, uint32_t list_tag,
|
|
ObjectWriter* ow) const;
|
|
|
|
// Renders a packed repeating field. A packed field is stored as:
|
|
// {tag length item1 item2 item3} instead of the less efficient
|
|
// {tag item1 tag item2 tag item3}.
|
|
util::Status RenderPacked(const google::protobuf::Field* field,
|
|
ObjectWriter* ow) const;
|
|
|
|
// Renders a google.protobuf.Timestamp value to ObjectWriter
|
|
static util::Status RenderTimestamp(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
|
|
// Renders a google.protobuf.Duration value to ObjectWriter
|
|
static util::Status RenderDuration(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
|
|
// Following RenderTYPE functions render well known types in
|
|
// google/protobuf/wrappers.proto corresponding to TYPE.
|
|
static util::Status RenderDouble(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
static util::Status RenderFloat(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
static util::Status RenderInt64(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
static util::Status RenderUInt64(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
static util::Status RenderInt32(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
static util::Status RenderUInt32(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
static util::Status RenderBool(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
static util::Status RenderString(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
static util::Status RenderBytes(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
|
|
// Renders a google.protobuf.Struct to ObjectWriter.
|
|
static util::Status RenderStruct(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
|
|
// Helper to render google.protobuf.Struct's Value fields to ObjectWriter.
|
|
static util::Status RenderStructValue(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name,
|
|
ObjectWriter* ow);
|
|
|
|
// Helper to render google.protobuf.Struct's ListValue fields to ObjectWriter.
|
|
static util::Status RenderStructListValue(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name,
|
|
ObjectWriter* ow);
|
|
|
|
// Render the "Any" type.
|
|
static util::Status RenderAny(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
|
|
// Render the "FieldMask" type.
|
|
static util::Status RenderFieldMask(const ProtoStreamObjectSource* os,
|
|
const google::protobuf::Type& type,
|
|
StringPiece name, ObjectWriter* ow);
|
|
|
|
static std::unordered_map<std::string, TypeRenderer>* renderers_;
|
|
static void InitRendererMap();
|
|
static void DeleteRendererMap();
|
|
static TypeRenderer* FindTypeRenderer(const std::string& type_url);
|
|
|
|
// Same as above but renders all non-message field types. Callers don't call
|
|
// this function directly. They just use RenderField.
|
|
util::Status RenderNonMessageField(const google::protobuf::Field* field,
|
|
StringPiece field_name,
|
|
ObjectWriter* ow) const;
|
|
|
|
|
|
// Utility function to detect proto maps. The 'field' MUST be repeated.
|
|
bool IsMap(const google::protobuf::Field& field) const;
|
|
|
|
// Utility to read int64 and int32 values from a message type in stream_.
|
|
// Used for reading google.protobuf.Timestamp and Duration messages.
|
|
std::pair<int64_t, int32_t> ReadSecondsAndNanos(
|
|
const google::protobuf::Type& type) const;
|
|
|
|
// Helper function to check recursion depth and increment it. It will return
|
|
// OkStatus() if the current depth is allowed. Otherwise an error is returned.
|
|
// type_name and field_name are used for error reporting.
|
|
util::Status IncrementRecursionDepth(StringPiece type_name,
|
|
StringPiece field_name) const;
|
|
|
|
// Input stream to read from. Ownership rests with the caller.
|
|
mutable io::CodedInputStream* stream_;
|
|
|
|
// Type information for all the types used in the descriptor. Used to find
|
|
// google::protobuf::Type of nested messages/enums.
|
|
const TypeInfo* typeinfo_;
|
|
|
|
// Whether this class owns the typeinfo_ object. If true the typeinfo_ object
|
|
// should be deleted in the destructor.
|
|
bool own_typeinfo_;
|
|
|
|
// google::protobuf::Type of the message source.
|
|
const google::protobuf::Type& type_;
|
|
|
|
|
|
const RenderOptions render_options_;
|
|
|
|
// Tracks current recursion depth.
|
|
mutable int recursion_depth_;
|
|
|
|
// Maximum allowed recursion depth.
|
|
int max_recursion_depth_;
|
|
|
|
GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource);
|
|
};
|
|
|
|
} // namespace converter
|
|
} // namespace util
|
|
} // namespace protobuf
|
|
} // namespace google
|
|
|
|
#include <google/protobuf/port_undef.inc>
|
|
|
|
#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
|