Home | History | Annotate | Download | only in internal
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 #ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
     32 #define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
     33 
     34 #include <deque>
     35 #include <google/protobuf/stubs/hash.h>
     36 #include <string>
     37 
     38 #include <google/protobuf/stubs/common.h>
     39 #include <google/protobuf/io/coded_stream.h>
     40 #include <google/protobuf/io/zero_copy_stream_impl.h>
     41 #include <google/protobuf/descriptor.h>
     42 #include <google/protobuf/util/internal/type_info.h>
     43 #include <google/protobuf/util/internal/datapiece.h>
     44 #include <google/protobuf/util/internal/error_listener.h>
     45 #include <google/protobuf/util/internal/proto_writer.h>
     46 #include <google/protobuf/util/internal/structured_objectwriter.h>
     47 #include <google/protobuf/util/type_resolver.h>
     48 #include <google/protobuf/stubs/bytestream.h>
     49 
     50 namespace google {
     51 namespace protobuf {
     52 namespace io {
     53 class CodedOutputStream;
     54 }  // namespace io
     55 }  // namespace protobuf
     56 
     57 
     58 namespace protobuf {
     59 class Type;
     60 class Field;
     61 }  // namespace protobuf
     62 
     63 
     64 namespace protobuf {
     65 namespace util {
     66 namespace converter {
     67 
     68 class ObjectLocationTracker;
     69 
     70 // An ObjectWriter that can write protobuf bytes directly from writer events.
     71 // This class supports all special types like Struct and Map. It uses
     72 // the ProtoWriter class to write raw proto bytes.
     73 //
     74 // It also supports streaming.
     75 class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
     76  public:
     77   // Options that control ProtoStreamObjectWriter class's behavior.
     78   struct Options {
     79     // Treats integer inputs in google.protobuf.Struct as strings. Normally,
     80     // integer values are returned in double field "number_value" of
     81     // google.protobuf.Struct. However, this can cause precision loss for
     82     // int64/uint64 inputs. This option is provided for cases that want to
     83     // preserve integer precision.
     84     bool struct_integers_as_strings;
     85 
     86     Options() : struct_integers_as_strings(false) {}
     87 
     88     // Default instance of Options with all options set to defaults.
     89     static const Options& Defaults() {
     90       static Options defaults;
     91       return defaults;
     92     }
     93   };
     94 
     95 // Constructor. Does not take ownership of any parameter passed in.
     96   ProtoStreamObjectWriter(TypeResolver* type_resolver,
     97                           const google::protobuf::Type& type,
     98                           strings::ByteSink* output, ErrorListener* listener,
     99                           const ProtoStreamObjectWriter::Options& options =
    100                               ProtoStreamObjectWriter::Options::Defaults());
    101   virtual ~ProtoStreamObjectWriter();
    102 
    103   // ObjectWriter methods.
    104   virtual ProtoStreamObjectWriter* StartObject(StringPiece name);
    105   virtual ProtoStreamObjectWriter* EndObject();
    106   virtual ProtoStreamObjectWriter* StartList(StringPiece name);
    107   virtual ProtoStreamObjectWriter* EndList();
    108 
    109   // Renders a DataPiece 'value' into a field whose wire type is determined
    110   // from the given field 'name'.
    111   virtual ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
    112                                                    const DataPiece& value);
    113 
    114  protected:
    115   // Function that renders a well known type with modified behavior.
    116   typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*,
    117                                          const DataPiece&);
    118 
    119   // Handles writing Anys out using nested object writers and the like.
    120   class LIBPROTOBUF_EXPORT AnyWriter {
    121    public:
    122     explicit AnyWriter(ProtoStreamObjectWriter* parent);
    123     ~AnyWriter();
    124 
    125     // Passes a StartObject call through to the Any writer.
    126     void StartObject(StringPiece name);
    127 
    128     // Passes an EndObject call through to the Any. Returns true if the any
    129     // handled the EndObject call, false if the Any is now all done and is no
    130     // longer needed.
    131     bool EndObject();
    132 
    133     // Passes a StartList call through to the Any writer.
    134     void StartList(StringPiece name);
    135 
    136     // Passes an EndList call through to the Any writer.
    137     void EndList();
    138 
    139     // Renders a data piece on the any.
    140     void RenderDataPiece(StringPiece name, const DataPiece& value);
    141 
    142    private:
    143     // Handles starting up the any once we have a type.
    144     void StartAny(const DataPiece& value);
    145 
    146     // Writes the Any out to the parent writer in its serialized form.
    147     void WriteAny();
    148 
    149     // The parent of this writer, needed for various bits such as type info and
    150     // the listeners.
    151     ProtoStreamObjectWriter* parent_;
    152 
    153     // The nested object writer, used to write events.
    154     google::protobuf::scoped_ptr<ProtoStreamObjectWriter> ow_;
    155 
    156     // The type_url_ that this Any represents.
    157     string type_url_;
    158 
    159     // Whether this any is invalid. This allows us to only report an invalid
    160     // Any message a single time rather than every time we get a nested field.
    161     bool invalid_;
    162 
    163     // The output data and wrapping ByteSink.
    164     string data_;
    165     strings::StringByteSink output_;
    166 
    167     // The depth within the Any, so we can track when we're done.
    168     int depth_;
    169 
    170     // True if the type is a well-known type. Well-known types in Any
    171     // has a special formating:
    172     // {
    173     //   "@type": "type.googleapis.com/google.protobuf.XXX",
    174     //   "value": <JSON representation of the type>,
    175     // }
    176     bool is_well_known_type_;
    177     TypeRenderer* well_known_type_render_;
    178   };
    179 
    180   // Represents an item in a stack of items used to keep state between
    181   // ObjectWrier events.
    182   class LIBPROTOBUF_EXPORT Item : public BaseElement {
    183    public:
    184     // Indicates the type of item.
    185     enum ItemType {
    186       MESSAGE,  // Simple message
    187       MAP,      // Proto3 map type
    188       ANY,      // Proto3 Any type
    189     };
    190 
    191     // Constructor for the root item.
    192     Item(ProtoStreamObjectWriter* enclosing, ItemType item_type,
    193          bool is_placeholder, bool is_list);
    194 
    195     // Constructor for a field of a message.
    196     Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list);
    197 
    198     virtual ~Item() {}
    199 
    200     // These functions return true if the element type is corresponding to the
    201     // type in function name.
    202     bool IsMap() { return item_type_ == MAP; }
    203     bool IsAny() { return item_type_ == ANY; }
    204 
    205     AnyWriter* any() const { return any_.get(); }
    206 
    207     virtual Item* parent() const {
    208       return static_cast<Item*>(BaseElement::parent());
    209     }
    210 
    211     // Inserts map key into hash set if and only if the key did NOT already
    212     // exist in hash set.
    213     // The hash set (map_keys_) is ONLY used to keep track of map keys.
    214     // Return true if insert successfully; returns false if the map key was
    215     // already present.
    216     bool InsertMapKeyIfNotPresent(StringPiece map_key);
    217 
    218     bool is_placeholder() const { return is_placeholder_; }
    219     bool is_list() const { return is_list_; }
    220 
    221    private:
    222     // Used for access to variables of the enclosing instance of
    223     // ProtoStreamObjectWriter.
    224     ProtoStreamObjectWriter* ow_;
    225 
    226     // A writer for Any objects, handles all Any-related nonsense.
    227     google::protobuf::scoped_ptr<AnyWriter> any_;
    228 
    229     // The type of this element, see enum for permissible types.
    230     ItemType item_type_;
    231 
    232     // Set of map keys already seen for the type_. Used to validate incoming
    233     // messages so no map key appears more than once.
    234     hash_set<string> map_keys_;
    235 
    236     // Conveys whether this Item is a placeholder or not. Placeholder items are
    237     // pushed to stack to account for special types.
    238     bool is_placeholder_;
    239 
    240     // Conveys whether this Item is a list or not. This is used to send
    241     // StartList or EndList calls to underlying ObjectWriter.
    242     bool is_list_;
    243 
    244     GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item);
    245   };
    246 
    247   ProtoStreamObjectWriter(const TypeInfo* typeinfo,
    248                           const google::protobuf::Type& type,
    249                           strings::ByteSink* output, ErrorListener* listener);
    250 
    251   // Returns true if the field is a map.
    252   bool IsMap(const google::protobuf::Field& field);
    253 
    254   // Returns true if the field is an any.
    255   bool IsAny(const google::protobuf::Field& field);
    256 
    257   // Returns true if the field is google.protobuf.Struct.
    258   bool IsStruct(const google::protobuf::Field& field);
    259 
    260   // Returns true if the field is google.protobuf.Value.
    261   bool IsStructValue(const google::protobuf::Field& field);
    262 
    263   // Returns true if the field is google.protobuf.ListValue.
    264   bool IsStructListValue(const google::protobuf::Field& field);
    265 
    266   // Renders google.protobuf.Value in struct.proto. It picks the right oneof
    267   // type based on value's type.
    268   static util::Status RenderStructValue(ProtoStreamObjectWriter* ow,
    269                                           const DataPiece& value);
    270 
    271   // Renders google.protobuf.Timestamp value.
    272   static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow,
    273                                         const DataPiece& value);
    274 
    275   // Renders google.protobuf.FieldMask value.
    276   static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow,
    277                                         const DataPiece& value);
    278 
    279   // Renders google.protobuf.Duration value.
    280   static util::Status RenderDuration(ProtoStreamObjectWriter* ow,
    281                                        const DataPiece& value);
    282 
    283   // Renders wrapper message types for primitive types in
    284   // google/protobuf/wrappers.proto.
    285   static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow,
    286                                           const DataPiece& value);
    287 
    288   static void InitRendererMap();
    289   static void DeleteRendererMap();
    290   static TypeRenderer* FindTypeRenderer(const string& type_url);
    291 
    292   // Returns true if the map key for type_ is not duplicated key.
    293   // If map key is duplicated key, this function returns false.
    294   // Note that caller should make sure that the current proto element (current_)
    295   // is of element type MAP or STRUCT_MAP.
    296   // It also calls the appropriate error callback and unnormalzied_name is used
    297   // for error string.
    298   bool ValidMapKey(StringPiece unnormalized_name);
    299 
    300   // Pushes an item on to the stack. Also calls either StartObject or StartList
    301   // on the underlying ObjectWriter depending on whether is_list is false or
    302   // not.
    303   // is_placeholder conveys whether the item is a placeholder item or not.
    304   // Placeholder items are pushed when adding auxillary types' StartObject or
    305   // StartList calls.
    306   void Push(StringPiece name, Item::ItemType item_type, bool is_placeholder,
    307             bool is_list);
    308 
    309   // Pops items from the stack. All placeholder items are popped until a
    310   // non-placeholder item is found.
    311   void Pop();
    312 
    313   // Pops one element from the stack. Calls EndObject() or EndList() on the
    314   // underlying ObjectWriter depending on the value of is_list_.
    315   void PopOneElement();
    316 
    317  private:
    318   // Helper functions to create the map and find functions responsible for
    319   // rendering well known types, keyed by type URL.
    320   static hash_map<string, TypeRenderer>* renderers_;
    321 
    322   // Variables for describing the structure of the input tree:
    323   // master_type_: descriptor for the whole protobuf message.
    324   const google::protobuf::Type& master_type_;
    325 
    326   // The current element, variable for internal state processing.
    327   google::protobuf::scoped_ptr<Item> current_;
    328 
    329   // Reference to the options that control this class's behavior.
    330   const ProtoStreamObjectWriter::Options options_;
    331 
    332   GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
    333 };
    334 
    335 }  // namespace converter
    336 }  // namespace util
    337 }  // namespace protobuf
    338 
    339 }  // namespace google
    340 #endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
    341