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