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(); RenderBool(StringPiece name,bool value)87 virtual ProtoWriter* RenderBool(StringPiece name, bool value) { 88 return RenderDataPiece(name, DataPiece(value)); 89 } RenderInt32(StringPiece name,int32 value)90 virtual ProtoWriter* RenderInt32(StringPiece name, int32 value) { 91 return RenderDataPiece(name, DataPiece(value)); 92 } RenderUint32(StringPiece name,uint32 value)93 virtual ProtoWriter* RenderUint32(StringPiece name, uint32 value) { 94 return RenderDataPiece(name, DataPiece(value)); 95 } RenderInt64(StringPiece name,int64 value)96 virtual ProtoWriter* RenderInt64(StringPiece name, int64 value) { 97 return RenderDataPiece(name, DataPiece(value)); 98 } RenderUint64(StringPiece name,uint64 value)99 virtual ProtoWriter* RenderUint64(StringPiece name, uint64 value) { 100 return RenderDataPiece(name, DataPiece(value)); 101 } RenderDouble(StringPiece name,double value)102 virtual ProtoWriter* RenderDouble(StringPiece name, double value) { 103 return RenderDataPiece(name, DataPiece(value)); 104 } RenderFloat(StringPiece name,float value)105 virtual ProtoWriter* RenderFloat(StringPiece name, float value) { 106 return RenderDataPiece(name, DataPiece(value)); 107 } RenderString(StringPiece name,StringPiece value)108 virtual ProtoWriter* RenderString(StringPiece name, StringPiece value) { 109 return RenderDataPiece(name, 110 DataPiece(value, use_strict_base64_decoding())); 111 } RenderBytes(StringPiece name,StringPiece value)112 virtual ProtoWriter* RenderBytes(StringPiece name, StringPiece value) { 113 return RenderDataPiece( 114 name, DataPiece(value, false, use_strict_base64_decoding())); 115 } RenderNull(StringPiece name)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. location()126 const LocationTrackerInterface& location() { 127 return element_ != NULL ? *element_ : *tracker_; 128 } 129 130 // When true, we finished writing to output a complete message. done()131 bool done() { return done_; } 132 133 // Returns the proto stream object. stream()134 google::protobuf::io::CodedOutputStream* stream() { return stream_.get(); } 135 136 // Getters and mutators of invalid_depth_. IncrementInvalidDepth()137 void IncrementInvalidDepth() { ++invalid_depth_; } DecrementInvalidDepth()138 void DecrementInvalidDepth() { --invalid_depth_; } invalid_depth()139 int invalid_depth() { return invalid_depth_; } 140 listener()141 ErrorListener* listener() { return listener_; } 142 typeinfo()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 ~ProtoElement()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. parent_field()167 const google::protobuf::Field* parent_field() const { 168 return parent_field_; 169 } type()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 parent()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 element()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