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