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_PROTO_WRITER_H__
     32 #define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_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/structured_objectwriter.h>
     46 #include <google/protobuf/util/type_resolver.h>
     47 #include <google/protobuf/stubs/bytestream.h>
     48 
     49 namespace google {
     50 namespace protobuf {
     51 namespace io {
     52 class CodedOutputStream;
     53 }  // namespace io
     54 }  // namespace protobuf
     55 
     56 
     57 namespace protobuf {
     58 class Type;
     59 class Field;
     60 }  // namespace protobuf
     61 
     62 
     63 namespace protobuf {
     64 namespace util {
     65 namespace converter {
     66 
     67 class ObjectLocationTracker;
     68 
     69 // An ObjectWriter that can write protobuf bytes directly from writer events.
     70 // This class does not support special types like Struct or Map. However, since
     71 // this class supports raw protobuf, it can be used to provide support for
     72 // special types by inheriting from it or by wrapping it.
     73 //
     74 // It also supports streaming.
     75 class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter {
     76  public:
     77 // Constructor. Does not take ownership of any parameter passed in.
     78   ProtoWriter(TypeResolver* type_resolver, const google::protobuf::Type& type,
     79               strings::ByteSink* output, ErrorListener* listener);
     80   virtual ~ProtoWriter();
     81 
     82   // ObjectWriter methods.
     83   virtual ProtoWriter* StartObject(StringPiece name);
     84   virtual ProtoWriter* EndObject();
     85   virtual ProtoWriter* StartList(StringPiece name);
     86   virtual ProtoWriter* EndList();
     87   virtual ProtoWriter* RenderBool(StringPiece name, bool value) {
     88     return RenderDataPiece(name, DataPiece(value));
     89   }
     90   virtual ProtoWriter* RenderInt32(StringPiece name, int32 value) {
     91     return RenderDataPiece(name, DataPiece(value));
     92   }
     93   virtual ProtoWriter* RenderUint32(StringPiece name, uint32 value) {
     94     return RenderDataPiece(name, DataPiece(value));
     95   }
     96   virtual ProtoWriter* RenderInt64(StringPiece name, int64 value) {
     97     return RenderDataPiece(name, DataPiece(value));
     98   }
     99   virtual ProtoWriter* RenderUint64(StringPiece name, uint64 value) {
    100     return RenderDataPiece(name, DataPiece(value));
    101   }
    102   virtual ProtoWriter* RenderDouble(StringPiece name, double value) {
    103     return RenderDataPiece(name, DataPiece(value));
    104   }
    105   virtual ProtoWriter* RenderFloat(StringPiece name, float value) {
    106     return RenderDataPiece(name, DataPiece(value));
    107   }
    108   virtual ProtoWriter* RenderString(StringPiece name, StringPiece value) {
    109     return RenderDataPiece(name,
    110                            DataPiece(value, use_strict_base64_decoding()));
    111   }
    112   virtual ProtoWriter* RenderBytes(StringPiece name, StringPiece value) {
    113     return RenderDataPiece(
    114         name, DataPiece(value, false, use_strict_base64_decoding()));
    115   }
    116   virtual ProtoWriter* RenderNull(StringPiece name) {
    117     return RenderDataPiece(name, DataPiece::NullData());
    118   }
    119 
    120   // Renders a DataPiece 'value' into a field whose wire type is determined
    121   // from the given field 'name'.
    122   virtual ProtoWriter* RenderDataPiece(StringPiece name,
    123                                        const DataPiece& value);
    124 
    125   // Returns the location tracker to use for tracking locations for errors.
    126   const LocationTrackerInterface& location() {
    127     return element_ != NULL ? *element_ : *tracker_;
    128   }
    129 
    130   // When true, we finished writing to output a complete message.
    131   bool done() { return done_; }
    132 
    133   // Returns the proto stream object.
    134   google::protobuf::io::CodedOutputStream* stream() { return stream_.get(); }
    135 
    136   // Getters and mutators of invalid_depth_.
    137   void IncrementInvalidDepth() { ++invalid_depth_; }
    138   void DecrementInvalidDepth() { --invalid_depth_; }
    139   int invalid_depth() { return invalid_depth_; }
    140 
    141   ErrorListener* listener() { return listener_; }
    142 
    143   const TypeInfo* typeinfo() { return typeinfo_; }
    144 
    145  protected:
    146   class LIBPROTOBUF_EXPORT ProtoElement : public BaseElement, public LocationTrackerInterface {
    147    public:
    148     // Constructor for the root element. No parent nor field.
    149     ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type,
    150                  ProtoWriter* enclosing);
    151 
    152     // Constructor for a field of an element.
    153     ProtoElement(ProtoElement* parent, const google::protobuf::Field* field,
    154                  const google::protobuf::Type& type, bool is_list);
    155 
    156     virtual ~ProtoElement() {}
    157 
    158     // Called just before the destructor for clean up:
    159     //   - reports any missing required fields
    160     //   - computes the space needed by the size field, and augment the
    161     //     length of all parent messages by this additional space.
    162     //   - releases and returns the parent pointer.
    163     ProtoElement* pop();
    164 
    165     // Accessors
    166     // parent_field() may be NULL if we are at root.
    167     const google::protobuf::Field* parent_field() const {
    168       return parent_field_;
    169     }
    170     const google::protobuf::Type& type() const { return type_; }
    171 
    172     // Registers field for accounting required fields.
    173     void RegisterField(const google::protobuf::Field* field);
    174 
    175     // To report location on error messages.
    176     virtual string ToString() const;
    177 
    178     virtual ProtoElement* parent() const {
    179       return static_cast<ProtoElement*>(BaseElement::parent());
    180     }
    181 
    182     // Returns true if the index is already taken by a preceeding oneof input.
    183     bool IsOneofIndexTaken(int32 index);
    184 
    185     // Marks the oneof 'index' as taken. Future inputs to this oneof will
    186     // generate an error.
    187     void TakeOneofIndex(int32 index);
    188 
    189    private:
    190     // Used for access to variables of the enclosing instance of
    191     // ProtoWriter.
    192     ProtoWriter* ow_;
    193 
    194     // Describes the element as a field in the parent message.
    195     // parent_field_ is NULL if and only if this element is the root element.
    196     const google::protobuf::Field* parent_field_;
    197 
    198     // TypeInfo to lookup types.
    199     const TypeInfo* typeinfo_;
    200 
    201     // Additional variables if this element is a message:
    202     // (Root element is always a message).
    203     // type_             : the type of this element.
    204     // required_fields_  : set of required fields.
    205     // size_index_       : index into ProtoWriter::size_insert_
    206     //                     for later insertion of serialized message length.
    207     const google::protobuf::Type& type_;
    208     std::set<const google::protobuf::Field*> required_fields_;
    209     const int size_index_;
    210 
    211     // Tracks position in repeated fields, needed for LocationTrackerInterface.
    212     int array_index_;
    213 
    214     // Set of oneof indices already seen for the type_. Used to validate
    215     // incoming messages so no more than one oneof is set.
    216     hash_set<int32> oneof_indices_;
    217 
    218     GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement);
    219   };
    220 
    221   // Container for inserting 'size' information at the 'pos' position.
    222   struct SizeInfo {
    223     const int pos;
    224     int size;
    225   };
    226 
    227   ProtoWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type,
    228               strings::ByteSink* output, ErrorListener* listener);
    229 
    230   virtual ProtoElement* element() { return element_.get(); }
    231 
    232   // Helper methods for calling ErrorListener. See error_listener.h.
    233   void InvalidName(StringPiece unknown_name, StringPiece message);
    234   void InvalidValue(StringPiece type_name, StringPiece value);
    235   void MissingField(StringPiece missing_name);
    236 
    237   // Common code for BeginObject() and BeginList() that does invalid_depth_
    238   // bookkeeping associated with name lookup.
    239   const google::protobuf::Field* BeginNamed(StringPiece name, bool is_list);
    240 
    241   // Lookup the field in the current element. Looks in the base descriptor
    242   // and in any extension. This will report an error if the field cannot be
    243   // found or if multiple matching extensions are found.
    244   const google::protobuf::Field* Lookup(StringPiece name);
    245 
    246   // Lookup the field type in the type descriptor. Returns NULL if the type
    247   // is not known.
    248   const google::protobuf::Type* LookupType(
    249       const google::protobuf::Field* field);
    250 
    251   // Write serialized output to the final output ByteSink, inserting all
    252   // the size information for nested messages that are missing from the
    253   // intermediate Cord buffer.
    254   void WriteRootMessage();
    255 
    256   // Helper method to write proto tags based on the given field.
    257   void WriteTag(const google::protobuf::Field& field);
    258 
    259 
    260   // Returns true if the field for type_ can be set as a oneof. If field is not
    261   // a oneof type, this function does nothing and returns true.
    262   // If another field for this oneof is already set, this function returns
    263   // false. It also calls the appropriate error callback.
    264   // unnormalized_name is used for error string.
    265   bool ValidOneof(const google::protobuf::Field& field,
    266                   StringPiece unnormalized_name);
    267 
    268   // Returns true if the field is repeated.
    269   bool IsRepeated(const google::protobuf::Field& field);
    270 
    271   // Starts an object given the field and the enclosing type.
    272   ProtoWriter* StartObjectField(const google::protobuf::Field& field,
    273                                 const google::protobuf::Type& type);
    274 
    275   // Starts a list given the field and the enclosing type.
    276   ProtoWriter* StartListField(const google::protobuf::Field& field,
    277                               const google::protobuf::Type& type);
    278 
    279   // Renders a primitve field given the field and the enclosing type.
    280   ProtoWriter* RenderPrimitiveField(const google::protobuf::Field& field,
    281                                     const google::protobuf::Type& type,
    282                                     const DataPiece& value);
    283 
    284  private:
    285   // Variables for describing the structure of the input tree:
    286   // master_type_: descriptor for the whole protobuf message.
    287   // typeinfo_ : the TypeInfo object to lookup types.
    288   const google::protobuf::Type& master_type_;
    289   const TypeInfo* typeinfo_;
    290   // Whether we own the typeinfo_ object.
    291   bool own_typeinfo_;
    292 
    293   // Indicates whether we finished writing root message completely.
    294   bool done_;
    295 
    296   // Variable for internal state processing:
    297   // element_    : the current element.
    298   // size_insert_: sizes of nested messages.
    299   //               pos  - position to insert the size field.
    300   //               size - size value to be inserted.
    301   google::protobuf::scoped_ptr<ProtoElement> element_;
    302   std::deque<SizeInfo> size_insert_;
    303 
    304   // Variables for output generation:
    305   // output_  : pointer to an external ByteSink for final user-visible output.
    306   // buffer_  : buffer holding partial message before being ready for output_.
    307   // adapter_ : internal adapter between CodedOutputStream and buffer_.
    308   // stream_  : wrapper for writing tags and other encodings in wire format.
    309   strings::ByteSink* output_;
    310   string buffer_;
    311   google::protobuf::io::StringOutputStream adapter_;
    312   google::protobuf::scoped_ptr<google::protobuf::io::CodedOutputStream> stream_;
    313 
    314   // Variables for error tracking and reporting:
    315   // listener_     : a place to report any errors found.
    316   // invalid_depth_: number of enclosing invalid nested messages.
    317   // tracker_      : the root location tracker interface.
    318   ErrorListener* listener_;
    319   int invalid_depth_;
    320   google::protobuf::scoped_ptr<LocationTrackerInterface> tracker_;
    321 
    322   GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoWriter);
    323 };
    324 
    325 }  // namespace converter
    326 }  // namespace util
    327 }  // namespace protobuf
    328 
    329 }  // namespace google
    330 #endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
    331