aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/util/internal/protostream_objectwriter.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/util/internal/protostream_objectwriter.h')
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter.h455
1 files changed, 455 insertions, 0 deletions
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h
new file mode 100644
index 00000000..f17278b4
--- /dev/null
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.h
@@ -0,0 +1,455 @@
+// 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/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.
+//
+// It also supports streaming.
+class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter {
+ public:
+ // Constructor. Does not take ownership of any parameter passed in.
+ ProtoStreamObjectWriter(TypeResolver* type_resolver,
+ const google::protobuf::Type& type,
+ strings::ByteSink* output, ErrorListener* listener);
+ virtual ~ProtoStreamObjectWriter();
+
+ // ObjectWriter methods.
+ virtual ProtoStreamObjectWriter* StartObject(StringPiece name);
+ virtual ProtoStreamObjectWriter* EndObject();
+ virtual ProtoStreamObjectWriter* StartList(StringPiece name);
+ virtual ProtoStreamObjectWriter* EndList();
+ virtual ProtoStreamObjectWriter* RenderBool(StringPiece name,
+ const bool value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoStreamObjectWriter* RenderInt32(StringPiece name,
+ const int32 value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoStreamObjectWriter* RenderUint32(StringPiece name,
+ const uint32 value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoStreamObjectWriter* RenderInt64(StringPiece name,
+ const int64 value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoStreamObjectWriter* RenderUint64(StringPiece name,
+ const uint64 value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoStreamObjectWriter* RenderDouble(StringPiece name,
+ const double value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoStreamObjectWriter* RenderFloat(StringPiece name,
+ const float value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoStreamObjectWriter* RenderString(StringPiece name,
+ StringPiece value) {
+ return RenderDataPiece(name, DataPiece(value));
+ }
+ virtual ProtoStreamObjectWriter* RenderBytes(StringPiece name,
+ StringPiece value) {
+ return RenderDataPiece(name, DataPiece(value, false));
+ }
+ virtual ProtoStreamObjectWriter* RenderNull(StringPiece name) {
+ return RenderDataPiece(name, DataPiece::NullData());
+ }
+
+ // Renders a DataPiece 'value' into a field whose wire type is determined
+ // from the given field 'name'.
+ ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
+ const DataPiece& value);
+
+ // Returns the location tracker to use for tracking locations for errors.
+ const LocationTrackerInterface& location() {
+ return element_ != NULL ? *element_ : *tracker_;
+ }
+
+ // When true, we finished writing to output a complete message.
+ bool done() const { return done_; }
+
+ private:
+ // 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:
+ // 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.
+ google::protobuf::scoped_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 message type contained in Any has a special "value" message
+ // injected. This is true for well-known message types like Any or Struct.
+ bool has_injected_value_message_;
+ };
+
+ class LIBPROTOBUF_EXPORT ProtoElement : public BaseElement, public LocationTrackerInterface {
+ public:
+ // Indicates the type of element. Special types like LIST, MAP, MAP_ENTRY,
+ // STRUCT etc. are used to deduce other information based on their position
+ // on the stack of elements.
+ enum ElementType {
+ MESSAGE, // Simple message
+ LIST, // List/repeated element
+ MAP, // Proto3 map type
+ MAP_ENTRY, // Proto3 map message type, with 'key' and 'value' fields
+ ANY, // Proto3 Any type
+ STRUCT, // Proto3 struct type
+ STRUCT_VALUE, // Struct's Value message type
+ STRUCT_LIST, // List type indicator within a struct
+ STRUCT_LIST_VALUE, // Struct Value's ListValue message type
+ STRUCT_MAP, // Struct within a struct type
+ STRUCT_MAP_ENTRY // Struct map's entry type with 'key' and 'value'
+ // fields
+ };
+
+ // Constructor for the root element. No parent nor field.
+ ProtoElement(TypeInfo* typeinfo, const google::protobuf::Type& type,
+ ProtoStreamObjectWriter* enclosing);
+
+ // Constructor for a field of an element.
+ ProtoElement(ProtoElement* parent, const google::protobuf::Field* field,
+ const google::protobuf::Type& type, ElementType element_type);
+
+ virtual ~ProtoElement() {}
+
+ // Called just before the destructor for clean up:
+ // - reports any missing required fields
+ // - computes the space needed by the size field, and augment the
+ // length of all parent messages by this additional space.
+ // - releases and returns the parent pointer.
+ ProtoElement* pop();
+
+ // Accessors
+ const google::protobuf::Field* field() const { return field_; }
+ const google::protobuf::Type& type() const { return type_; }
+
+ // These functions return true if the element type is corresponding to the
+ // type in function name.
+ bool IsMap() { return element_type_ == MAP; }
+ bool IsStructMap() { return element_type_ == STRUCT_MAP; }
+ bool IsStructMapEntry() { return element_type_ == STRUCT_MAP_ENTRY; }
+ bool IsStructList() { return element_type_ == STRUCT_LIST; }
+ bool IsAny() { return element_type_ == ANY; }
+
+ ElementType element_type() { return element_type_; }
+
+ void RegisterField(const google::protobuf::Field* field);
+ virtual string ToString() const;
+
+ AnyWriter* any() const { return any_.get(); }
+
+ virtual ProtoElement* parent() const {
+ return static_cast<ProtoElement*>(BaseElement::parent());
+ }
+
+ private:
+ // Used for access to variables of the enclosing instance of
+ // ProtoStreamObjectWriter.
+ ProtoStreamObjectWriter* ow_;
+
+ // A writer for Any objects, handles all Any-related nonsense.
+ google::protobuf::scoped_ptr<AnyWriter> any_;
+
+ // Describes the element as a field in the parent message.
+ // field_ is NULL if and only if this element is the root element.
+ const google::protobuf::Field* field_;
+
+ // TypeInfo to lookup types.
+ TypeInfo* typeinfo_;
+
+ // Additional variables if this element is a message:
+ // (Root element is always a message).
+ // descriptor_ : describes allowed fields in the message.
+ // required_fields_: set of required fields.
+ // is_repeated_type_ : true if the element is of type list or map.
+ // size_index_ : index into ProtoStreamObjectWriter::size_insert_
+ // for later insertion of serialized message length.
+ const google::protobuf::Type& type_;
+ std::set<const google::protobuf::Field*> required_fields_;
+ const bool is_repeated_type_;
+ const int size_index_;
+
+ // Tracks position in repeated fields, needed for LocationTrackerInterface.
+ int array_index_;
+
+ // The type of this element, see enum for permissible types.
+ ElementType element_type_;
+
+ GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement);
+ };
+
+ // Container for inserting 'size' information at the 'pos' position.
+ struct SizeInfo {
+ const int pos;
+ int size;
+ };
+
+ ProtoStreamObjectWriter(TypeInfo* typeinfo,
+ const google::protobuf::Type& type,
+ strings::ByteSink* output, ErrorListener* listener);
+
+ ProtoElement* element() { return element_.get(); }
+
+ // Helper methods for calling ErrorListener. See error_listener.h.
+ void InvalidName(StringPiece unknown_name, StringPiece message);
+ void InvalidValue(StringPiece type_name, StringPiece value);
+ void MissingField(StringPiece missing_name);
+
+ // Common code for BeginObject() and BeginList() that does invalid_depth_
+ // bookkeeping associated with name lookup.
+ const google::protobuf::Field* BeginNamed(StringPiece name, bool is_list);
+
+ // Lookup the field in the current element. Looks in the base descriptor
+ // and in any extension. This will report an error if the field cannot be
+ // found or if multiple matching extensions are found.
+ const google::protobuf::Field* Lookup(StringPiece name);
+
+ // Lookup the field type in the type descriptor. Returns NULL if the type
+ // is not known.
+ const google::protobuf::Type* LookupType(
+ const google::protobuf::Field* field);
+
+ // Looks up the oneof struct Value field depending on the type.
+ // On failure to find, it returns an appropriate error.
+ util::StatusOr<const google::protobuf::Field*> LookupStructField(
+ DataPiece::Type type);
+
+ // Starts an entry in map. This will be called after placing map element at
+ // the top of the stack. Uses this information to write map entries.
+ const google::protobuf::Field* StartMapEntry(StringPiece name);
+
+ // Starts a google.protobuf.Struct.
+ // 'field' is of type google.protobuf.Struct.
+ // If field is NULL, it indicates that the top-level message is a struct
+ // type.
+ void StartStruct(const google::protobuf::Field* field);
+
+ // Starts another struct within a struct.
+ // 'field' is of type google.protobuf.Value (see struct.proto).
+ const google::protobuf::Field* StartStructValueInStruct(
+ const google::protobuf::Field* field);
+
+ // Starts a list within a struct.
+ // 'field' is of type google.protobuf.ListValue (see struct.proto).
+ const google::protobuf::Field* StartListValueInStruct(
+ const google::protobuf::Field* field);
+
+ // Starts the repeated "values" field in struct.proto's
+ // google.protobuf.ListValue type. 'field' should be of type
+ // google.protobuf.ListValue.
+ const google::protobuf::Field* StartRepeatedValuesInListValue(
+ const google::protobuf::Field* field);
+
+ // Pops sentinel elements off the stack.
+ void SkipElements();
+
+ // Write serialized output to the final output ByteSink, inserting all
+ // the size information for nested messages that are missing from the
+ // intermediate Cord buffer.
+ void WriteRootMessage();
+
+ // Returns true if the field is a map.
+ bool IsMap(const google::protobuf::Field& field);
+
+ // Returns true if the field is an any.
+ bool IsAny(const google::protobuf::Field& field);
+
+ // Helper method to write proto tags based on the given field.
+ void WriteTag(const google::protobuf::Field& field);
+
+ // Helper function to render primitive data types in DataPiece.
+ void RenderSimpleDataPiece(const google::protobuf::Field& field,
+ const google::protobuf::Type& type,
+ const DataPiece& data);
+
+ // 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);
+
+ // Helper functions to create the map and find functions responsible for
+ // rendering well known types, keyed by type URL.
+ static hash_map<string, TypeRenderer>* CreateRendererMap();
+ static TypeRenderer* FindTypeRenderer(const string& type_url);
+
+ // Returns the ProtoElement::ElementType for the given Type.
+ static ProtoElement::ElementType GetElementType(
+ const google::protobuf::Type& type);
+
+ // Variables for describing the structure of the input tree:
+ // master_type_: descriptor for the whole protobuf message.
+ // typeinfo_ : the TypeInfo object to lookup types.
+ const google::protobuf::Type& master_type_;
+ TypeInfo* typeinfo_;
+ // Whether we own the typeinfo_ object.
+ bool own_typeinfo_;
+
+ // Indicates whether we finished writing root message completely.
+ bool done_;
+
+ // Variable for internal state processing:
+ // element_ : the current element.
+ // size_insert_: sizes of nested messages.
+ // pos - position to insert the size field.
+ // size - size value to be inserted.
+ google::protobuf::scoped_ptr<ProtoElement> element_;
+ std::deque<SizeInfo> size_insert_;
+
+ // Variables for output generation:
+ // output_ : pointer to an external ByteSink for final user-visible output.
+ // buffer_ : buffer holding partial message before being ready for output_.
+ // adapter_ : internal adapter between CodedOutputStream and Cord buffer_.
+ // stream_ : wrapper for writing tags and other encodings in wire format.
+ strings::ByteSink* output_;
+ string buffer_;
+ google::protobuf::io::StringOutputStream adapter_;
+ google::protobuf::scoped_ptr<google::protobuf::io::CodedOutputStream> stream_;
+
+ // Variables for error tracking and reporting:
+ // listener_ : a place to report any errors found.
+ // invalid_depth_: number of enclosing invalid nested messages.
+ // tracker_ : the root location tracker interface.
+ ErrorListener* listener_;
+ int invalid_depth_;
+ google::protobuf::scoped_ptr<LocationTrackerInterface> tracker_;
+
+ GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
+};
+
+} // namespace converter
+} // namespace util
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__