| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- // 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_PROTOSTREAM_OBJECTWRITER_H__
- #define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
- #include <deque>
- #include <google/protobuf/stubs/hash.h>
- #include <string>
- #include <google/protobuf/stubs/common.h>
- #include <google/protobuf/io/coded_stream.h>
- #include <google/protobuf/io/zero_copy_stream_impl.h>
- #include <google/protobuf/descriptor.h>
- #include <google/protobuf/util/internal/type_info.h>
- #include <google/protobuf/util/internal/datapiece.h>
- #include <google/protobuf/util/internal/error_listener.h>
- #include <google/protobuf/util/internal/proto_writer.h>
- #include <google/protobuf/util/internal/structured_objectwriter.h>
- #include <google/protobuf/util/type_resolver.h>
- #include <google/protobuf/stubs/bytestream.h>
- namespace google {
- namespace protobuf {
- namespace io {
- class CodedOutputStream;
- } // namespace io
- } // namespace protobuf
- namespace protobuf {
- class Type;
- class Field;
- } // namespace protobuf
- namespace protobuf {
- namespace util {
- namespace converter {
- class ObjectLocationTracker;
- // An ObjectWriter that can write protobuf bytes directly from writer events.
- // This class supports all special types like Struct and Map. It uses
- // the ProtoWriter class to write raw proto bytes.
- //
- // It also supports streaming.
- class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
- public:
- // Options that control ProtoStreamObjectWriter class's behavior.
- struct Options {
- // Treats numeric inputs in google.protobuf.Struct as strings. Normally,
- // numeric values are returned in double field "number_value" of
- // google.protobuf.Struct. However, this can cause precision loss for
- // int64/uint64/double inputs. This option is provided for cases that want
- // to preserve number precision.
- //
- // TODO(skarvaje): Rename to struct_numbers_as_strings as it covers double
- // as well.
- bool struct_integers_as_strings;
- // Not treat unknown fields as an error. If there is an unknown fields,
- // just ignore it and continue to process the rest.
- bool ignore_unknown_fields;
- // If true, check if enum name in camel case or without underscore matches
- // the field name.
- bool use_lower_camel_for_enums;
- Options()
- : struct_integers_as_strings(false),
- ignore_unknown_fields(false),
- use_lower_camel_for_enums(false) {}
- // Default instance of Options with all options set to defaults.
- static const Options& Defaults() {
- static Options defaults;
- return defaults;
- }
- };
- // Constructor. Does not take ownership of any parameter passed in.
- ProtoStreamObjectWriter(TypeResolver* type_resolver,
- const google::protobuf::Type& type,
- strings::ByteSink* output, ErrorListener* listener,
- const ProtoStreamObjectWriter::Options& options =
- ProtoStreamObjectWriter::Options::Defaults());
- virtual ~ProtoStreamObjectWriter();
- // ObjectWriter methods.
- virtual ProtoStreamObjectWriter* StartObject(StringPiece name);
- virtual ProtoStreamObjectWriter* EndObject();
- virtual ProtoStreamObjectWriter* StartList(StringPiece name);
- virtual ProtoStreamObjectWriter* EndList();
- // Renders a DataPiece 'value' into a field whose wire type is determined
- // from the given field 'name'.
- virtual ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
- const DataPiece& value);
- protected:
- // Function that renders a well known type with modified behavior.
- typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*,
- const DataPiece&);
- // Handles writing Anys out using nested object writers and the like.
- class LIBPROTOBUF_EXPORT AnyWriter {
- public:
- explicit AnyWriter(ProtoStreamObjectWriter* parent);
- ~AnyWriter();
- // Passes a StartObject call through to the Any writer.
- void StartObject(StringPiece name);
- // Passes an EndObject call through to the Any. Returns true if the any
- // handled the EndObject call, false if the Any is now all done and is no
- // longer needed.
- bool EndObject();
- // Passes a StartList call through to the Any writer.
- void StartList(StringPiece name);
- // Passes an EndList call through to the Any writer.
- void EndList();
- // Renders a data piece on the any.
- void RenderDataPiece(StringPiece name, const DataPiece& value);
- private:
- // Before the "@type" field is encountered, we store all incoming data
- // into this Event struct and replay them after we get the "@type" field.
- class LIBPROTOBUF_EXPORT Event {
- public:
- enum Type {
- START_OBJECT = 0,
- END_OBJECT = 1,
- START_LIST = 2,
- END_LIST = 3,
- RENDER_DATA_PIECE = 4,
- };
- // Constructor for END_OBJECT and END_LIST events.
- explicit Event(Type type) : type_(type), value_(DataPiece::NullData()) {}
- // Constructor for START_OBJECT and START_LIST events.
- explicit Event(Type type, StringPiece name)
- : type_(type),
- name_(name.ToString()),
- value_(DataPiece::NullData()) {}
- // Constructor for RENDER_DATA_PIECE events.
- explicit Event(StringPiece name, const DataPiece& value)
- : type_(RENDER_DATA_PIECE), name_(name.ToString()), value_(value) {
- DeepCopy();
- }
- Event(const Event& other)
- : type_(other.type_), name_(other.name_), value_(other.value_) {
- DeepCopy();
- }
- Event& operator=(const Event& other) {
- type_ = other.type_;
- name_ = other.name_;
- value_ = other.value_;
- DeepCopy();
- return *this;
- }
- void Replay(AnyWriter* writer) const;
- private:
- void DeepCopy();
- Type type_;
- string name_;
- DataPiece value_;
- string value_storage_;
- };
- // Handles starting up the any once we have a type.
- void StartAny(const DataPiece& value);
- // Writes the Any out to the parent writer in its serialized form.
- void WriteAny();
- // The parent of this writer, needed for various bits such as type info and
- // the listeners.
- ProtoStreamObjectWriter* parent_;
- // The nested object writer, used to write events.
- std::unique_ptr<ProtoStreamObjectWriter> ow_;
- // The type_url_ that this Any represents.
- string type_url_;
- // Whether this any is invalid. This allows us to only report an invalid
- // Any message a single time rather than every time we get a nested field.
- bool invalid_;
- // The output data and wrapping ByteSink.
- string data_;
- strings::StringByteSink output_;
- // The depth within the Any, so we can track when we're done.
- int depth_;
- // True if the type is a well-known type. Well-known types in Any
- // has a special formating:
- // {
- // "@type": "type.googleapis.com/google.protobuf.XXX",
- // "value": <JSON representation of the type>,
- // }
- bool is_well_known_type_;
- TypeRenderer* well_known_type_render_;
- // Store data before the "@type" field.
- std::vector<Event> uninterpreted_events_;
- };
- // Represents an item in a stack of items used to keep state between
- // ObjectWrier events.
- class LIBPROTOBUF_EXPORT Item : public BaseElement {
- public:
- // Indicates the type of item.
- enum ItemType {
- MESSAGE, // Simple message
- MAP, // Proto3 map type
- ANY, // Proto3 Any type
- };
- // Constructor for the root item.
- Item(ProtoStreamObjectWriter* enclosing, ItemType item_type,
- bool is_placeholder, bool is_list);
- // Constructor for a field of a message.
- Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list);
- virtual ~Item() {}
- // These functions return true if the element type is corresponding to the
- // type in function name.
- bool IsMap() { return item_type_ == MAP; }
- bool IsAny() { return item_type_ == ANY; }
- AnyWriter* any() const { return any_.get(); }
- virtual Item* parent() const {
- return static_cast<Item*>(BaseElement::parent());
- }
- // Inserts map key into hash set if and only if the key did NOT already
- // exist in hash set.
- // The hash set (map_keys_) is ONLY used to keep track of map keys.
- // Return true if insert successfully; returns false if the map key was
- // already present.
- bool InsertMapKeyIfNotPresent(StringPiece map_key);
- bool is_placeholder() const { return is_placeholder_; }
- bool is_list() const { return is_list_; }
- private:
- // Used for access to variables of the enclosing instance of
- // ProtoStreamObjectWriter.
- ProtoStreamObjectWriter* ow_;
- // A writer for Any objects, handles all Any-related nonsense.
- std::unique_ptr<AnyWriter> any_;
- // The type of this element, see enum for permissible types.
- ItemType item_type_;
- // Set of map keys already seen for the type_. Used to validate incoming
- // messages so no map key appears more than once.
- std::unique_ptr<hash_set<string> > map_keys_;
- // Conveys whether this Item is a placeholder or not. Placeholder items are
- // pushed to stack to account for special types.
- bool is_placeholder_;
- // Conveys whether this Item is a list or not. This is used to send
- // StartList or EndList calls to underlying ObjectWriter.
- bool is_list_;
- GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item);
- };
- ProtoStreamObjectWriter(const TypeInfo* typeinfo,
- const google::protobuf::Type& type,
- strings::ByteSink* output, ErrorListener* listener);
- // Returns true if the field is a map.
- inline bool IsMap(const google::protobuf::Field& field);
- // Returns true if the field is an any.
- inline bool IsAny(const google::protobuf::Field& field);
- // Returns true if the field is google.protobuf.Struct.
- inline bool IsStruct(const google::protobuf::Field& field);
- // Returns true if the field is google.protobuf.Value.
- inline bool IsStructValue(const google::protobuf::Field& field);
- // Returns true if the field is google.protobuf.ListValue.
- inline bool IsStructListValue(const google::protobuf::Field& field);
- // Renders google.protobuf.Value in struct.proto. It picks the right oneof
- // type based on value's type.
- static util::Status RenderStructValue(ProtoStreamObjectWriter* ow,
- const DataPiece& value);
- // Renders google.protobuf.Timestamp value.
- static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow,
- const DataPiece& value);
- // Renders google.protobuf.FieldMask value.
- static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow,
- const DataPiece& value);
- // Renders google.protobuf.Duration value.
- static util::Status RenderDuration(ProtoStreamObjectWriter* ow,
- const DataPiece& value);
- // Renders wrapper message types for primitive types in
- // google/protobuf/wrappers.proto.
- static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow,
- const DataPiece& value);
- static void InitRendererMap();
- static void DeleteRendererMap();
- static TypeRenderer* FindTypeRenderer(const string& type_url);
- // Returns true if the map key for type_ is not duplicated key.
- // If map key is duplicated key, this function returns false.
- // Note that caller should make sure that the current proto element (current_)
- // is of element type MAP or STRUCT_MAP.
- // It also calls the appropriate error callback and unnormalzied_name is used
- // for error string.
- bool ValidMapKey(StringPiece unnormalized_name);
- // Pushes an item on to the stack. Also calls either StartObject or StartList
- // on the underlying ObjectWriter depending on whether is_list is false or
- // not.
- // is_placeholder conveys whether the item is a placeholder item or not.
- // Placeholder items are pushed when adding auxillary types' StartObject or
- // StartList calls.
- void Push(StringPiece name, Item::ItemType item_type, bool is_placeholder,
- bool is_list);
- // Pops items from the stack. All placeholder items are popped until a
- // non-placeholder item is found.
- void Pop();
- // Pops one element from the stack. Calls EndObject() or EndList() on the
- // underlying ObjectWriter depending on the value of is_list_.
- void PopOneElement();
- private:
- // Helper functions to create the map and find functions responsible for
- // rendering well known types, keyed by type URL.
- static hash_map<string, TypeRenderer>* renderers_;
- // Variables for describing the structure of the input tree:
- // master_type_: descriptor for the whole protobuf message.
- const google::protobuf::Type& master_type_;
- // The current element, variable for internal state processing.
- std::unique_ptr<Item> current_;
- // Reference to the options that control this class's behavior.
- const ProtoStreamObjectWriter::Options options_;
- GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
- };
- } // namespace converter
- } // namespace util
- } // namespace protobuf
- } // namespace google
- #endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
|