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 162 protected: 163 class PROTOBUF_EXPORT ProtoElement : public BaseElement, 164 public LocationTrackerInterface { 165 public: 166 // Constructor for the root element. No parent nor field. 167 ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type, 168 ProtoWriter* enclosing); 169 170 // Constructor for a field of an element. 171 ProtoElement(ProtoElement* parent, const google::protobuf::Field* field, 172 const google::protobuf::Type& type, bool is_list); 173 ~ProtoElement()174 ~ProtoElement() override {} 175 176 // Called just before the destructor for clean up: 177 // - reports any missing required fields 178 // - computes the space needed by the size field, and augment the 179 // length of all parent messages by this additional space. 180 // - releases and returns the parent pointer. 181 ProtoElement* pop(); 182 183 // Accessors 184 // parent_field() may be nullptr if we are at root. parent_field()185 const google::protobuf::Field* parent_field() const { 186 return parent_field_; 187 } type()188 const google::protobuf::Type& type() const { return type_; } 189 190 // Registers field for accounting required fields. 191 void RegisterField(const google::protobuf::Field* field); 192 193 // To report location on error messages. 194 std::string ToString() const override; 195 parent()196 ProtoElement* parent() const override { 197 return static_cast<ProtoElement*>(BaseElement::parent()); 198 } 199 200 // Returns true if the index is already taken by a preceding oneof input. 201 bool IsOneofIndexTaken(int32 index); 202 203 // Marks the oneof 'index' as taken. Future inputs to this oneof will 204 // generate an error. 205 void TakeOneofIndex(int32 index); 206 proto3()207 bool proto3() { return proto3_; } 208 209 private: 210 // Used for access to variables of the enclosing instance of 211 // ProtoWriter. 212 ProtoWriter* ow_; 213 214 // Describes the element as a field in the parent message. 215 // parent_field_ is nullptr if and only if this element is the root element. 216 const google::protobuf::Field* parent_field_; 217 218 // TypeInfo to lookup types. 219 const TypeInfo* typeinfo_; 220 221 // Whether the type_ is proto3 or not. 222 bool proto3_; 223 224 // Additional variables if this element is a message: 225 // (Root element is always a message). 226 // type_ : the type of this element. 227 // required_fields_ : set of required fields. 228 // size_index_ : index into ProtoWriter::size_insert_ 229 // for later insertion of serialized message length. 230 const google::protobuf::Type& type_; 231 std::set<const google::protobuf::Field*> required_fields_; 232 const int size_index_; 233 234 // Tracks position in repeated fields, needed for LocationTrackerInterface. 235 int array_index_; 236 237 // Set of oneof indices already seen for the type_. Used to validate 238 // incoming messages so no more than one oneof is set. 239 std::vector<bool> oneof_indices_; 240 241 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement); 242 }; 243 244 // Container for inserting 'size' information at the 'pos' position. 245 struct SizeInfo { 246 const int pos; 247 int size; 248 }; 249 250 ProtoWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type, 251 strings::ByteSink* output, ErrorListener* listener); 252 element()253 ProtoElement* element() override { return element_.get(); } 254 255 // Helper methods for calling ErrorListener. See error_listener.h. 256 void InvalidName(StringPiece unknown_name, StringPiece message); 257 void InvalidValue(StringPiece type_name, StringPiece value); 258 void MissingField(StringPiece missing_name); 259 260 // Common code for BeginObject() and BeginList() that does invalid_depth_ 261 // bookkeeping associated with name lookup. 262 const google::protobuf::Field* BeginNamed(StringPiece name, 263 bool is_list); 264 265 // Lookup the field in the current element. Looks in the base descriptor 266 // and in any extension. This will report an error if the field cannot be 267 // found when ignore_unknown_names_ is false or if multiple matching 268 // extensions are found. 269 const google::protobuf::Field* Lookup(StringPiece name); 270 271 // Lookup the field type in the type descriptor. Returns nullptr if the type 272 // is not known. 273 const google::protobuf::Type* LookupType( 274 const google::protobuf::Field* field); 275 276 // Write serialized output to the final output ByteSink, inserting all 277 // the size information for nested messages that are missing from the 278 // intermediate Cord buffer. 279 void WriteRootMessage(); 280 281 // Helper method to write proto tags based on the given field. 282 void WriteTag(const google::protobuf::Field& field); 283 284 285 // Returns true if the field for type_ can be set as a oneof. If field is not 286 // a oneof type, this function does nothing and returns true. 287 // If another field for this oneof is already set, this function returns 288 // false. It also calls the appropriate error callback. 289 // unnormalized_name is used for error string. 290 bool ValidOneof(const google::protobuf::Field& field, 291 StringPiece unnormalized_name); 292 293 // Returns true if the field is repeated. 294 bool IsRepeated(const google::protobuf::Field& field); 295 296 // Starts an object given the field and the enclosing type. 297 ProtoWriter* StartObjectField(const google::protobuf::Field& field, 298 const google::protobuf::Type& type); 299 300 // Starts a list given the field and the enclosing type. 301 ProtoWriter* StartListField(const google::protobuf::Field& field, 302 const google::protobuf::Type& type); 303 304 // Renders a primitive field given the field and the enclosing type. 305 ProtoWriter* RenderPrimitiveField(const google::protobuf::Field& field, 306 const google::protobuf::Type& type, 307 const DataPiece& data); 308 309 private: 310 // Writes an ENUM field, including tag, to the stream. 311 static util::Status WriteEnum(int field_number, const DataPiece& data, 312 const google::protobuf::Enum* enum_type, 313 io::CodedOutputStream* stream, 314 bool use_lower_camel_for_enums, 315 bool case_insensitive_enum_parsing, 316 bool ignore_unknown_values); 317 318 // Variables for describing the structure of the input tree: 319 // master_type_: descriptor for the whole protobuf message. 320 // typeinfo_ : the TypeInfo object to lookup types. 321 const google::protobuf::Type& master_type_; 322 const TypeInfo* typeinfo_; 323 // Whether we own the typeinfo_ object. 324 bool own_typeinfo_; 325 326 // Indicates whether we finished writing root message completely. 327 bool done_; 328 329 // If true, don't report unknown field names to the listener. 330 bool ignore_unknown_fields_; 331 332 // If true, don't report unknown enum values to the listener. 333 bool ignore_unknown_enum_values_; 334 335 // If true, check if enum name in camel case or without underscore matches the 336 // field name. 337 bool use_lower_camel_for_enums_; 338 339 // If true, check if enum name in UPPER_CASE matches the field name. 340 bool case_insensitive_enum_parsing_; 341 342 // Variable for internal state processing: 343 // element_ : the current element. 344 // size_insert_: sizes of nested messages. 345 // pos - position to insert the size field. 346 // size - size value to be inserted. 347 std::unique_ptr<ProtoElement> element_; 348 std::deque<SizeInfo> size_insert_; 349 350 // Variables for output generation: 351 // output_ : pointer to an external ByteSink for final user-visible output. 352 // buffer_ : buffer holding partial message before being ready for output_. 353 // adapter_ : internal adapter between CodedOutputStream and buffer_. 354 // stream_ : wrapper for writing tags and other encodings in wire format. 355 strings::ByteSink* output_; 356 std::string buffer_; 357 io::StringOutputStream adapter_; 358 std::unique_ptr<io::CodedOutputStream> stream_; 359 360 // Variables for error tracking and reporting: 361 // listener_ : a place to report any errors found. 362 // invalid_depth_: number of enclosing invalid nested messages. 363 // tracker_ : the root location tracker interface. 364 ErrorListener* listener_; 365 int invalid_depth_; 366 std::unique_ptr<LocationTrackerInterface> tracker_; 367 368 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoWriter); 369 }; 370 371 } // namespace converter 372 } // namespace util 373 } // namespace protobuf 374 } // namespace google 375 376 #include <google/protobuf/port_undef.inc> 377 378 #endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__ 379