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