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_PROTOSTREAM_OBJECTWRITER_H__ 32 #define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__ 33 34 #include <deque> 35 #include <string> 36 #include <unordered_map> 37 #include <unordered_set> 38 39 #include <google/protobuf/stubs/common.h> 40 #include <google/protobuf/type.pb.h> 41 #include <google/protobuf/io/coded_stream.h> 42 #include <google/protobuf/io/zero_copy_stream_impl.h> 43 #include <google/protobuf/descriptor.h> 44 #include <google/protobuf/util/internal/type_info.h> 45 #include <google/protobuf/util/internal/datapiece.h> 46 #include <google/protobuf/util/internal/error_listener.h> 47 #include <google/protobuf/util/internal/proto_writer.h> 48 #include <google/protobuf/util/internal/structured_objectwriter.h> 49 #include <google/protobuf/util/type_resolver.h> 50 #include <google/protobuf/stubs/bytestream.h> 51 #include <google/protobuf/stubs/hash.h> 52 53 #include <google/protobuf/port_def.inc> 54 55 namespace google { 56 namespace protobuf { 57 namespace util { 58 namespace converter { 59 60 class ObjectLocationTracker; 61 62 // An ObjectWriter that can write protobuf bytes directly from writer events. 63 // This class supports all special types like Struct and Map. It uses 64 // the ProtoWriter class to write raw proto bytes. 65 // 66 // It also supports streaming. 67 class PROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { 68 public: 69 // Options that control ProtoStreamObjectWriter class's behavior. 70 struct Options { 71 // Treats numeric inputs in google.protobuf.Struct as strings. Normally, 72 // numeric values are returned in double field "number_value" of 73 // google.protobuf.Struct. However, this can cause precision loss for 74 // int64/uint64/double inputs. This option is provided for cases that want 75 // to preserve number precision. 76 // 77 // TODO(skarvaje): Rename to struct_numbers_as_strings as it covers double 78 // as well. 79 bool struct_integers_as_strings; 80 81 // Not treat unknown fields as an error. If there is an unknown fields, 82 // just ignore it and continue to process the rest. Note that this doesn't 83 // apply to unknown enum values. 84 bool ignore_unknown_fields; 85 86 // Ignore unknown enum values. 87 bool ignore_unknown_enum_values; 88 89 // If true, check if enum name in camel case or without underscore matches 90 // the field name. 91 bool use_lower_camel_for_enums; 92 93 // If true, check if enum name in UPPER_CASE matches the field name. 94 bool case_insensitive_enum_parsing; 95 96 // If true, skips rendering the map entry if map value is null unless the 97 // value type is google.protobuf.NullType. 98 bool ignore_null_value_map_entry; 99 100 // If true, accepts repeated key/value pair for a map proto field. 101 bool use_legacy_json_map_format; 102 103 // If true, disable implicitly creating message list. 104 bool disable_implicit_message_list; 105 106 // If true, suppress the error of implicitly creating message list when it 107 // is disabled. 108 bool suppress_implicit_message_list_error; 109 110 // If true, suppress the error of rendering scalar field if the source is an 111 // object. 112 bool suppress_object_to_scalar_error; 113 114 // If true, use the json name in missing fields errors. 115 bool use_json_name_in_missing_fields; 116 OptionsOptions117 Options() 118 : struct_integers_as_strings(false), 119 ignore_unknown_fields(false), 120 ignore_unknown_enum_values(false), 121 use_lower_camel_for_enums(false), 122 case_insensitive_enum_parsing(false), 123 ignore_null_value_map_entry(false), 124 use_legacy_json_map_format(false), 125 disable_implicit_message_list(false), 126 suppress_implicit_message_list_error(false), 127 suppress_object_to_scalar_error(false), 128 use_json_name_in_missing_fields(false) {} 129 130 // Default instance of Options with all options set to defaults. DefaultsOptions131 static const Options& Defaults() { 132 static Options defaults; 133 return defaults; 134 } 135 }; 136 137 // Constructor. Does not take ownership of any parameter passed in. 138 ProtoStreamObjectWriter(TypeResolver* type_resolver, 139 const google::protobuf::Type& type, 140 strings::ByteSink* output, ErrorListener* listener, 141 const ProtoStreamObjectWriter::Options& options = 142 ProtoStreamObjectWriter::Options::Defaults()); 143 ~ProtoStreamObjectWriter() override; 144 145 // ObjectWriter methods. 146 ProtoStreamObjectWriter* StartObject(StringPiece name) override; 147 ProtoStreamObjectWriter* EndObject() override; 148 ProtoStreamObjectWriter* StartList(StringPiece name) override; 149 ProtoStreamObjectWriter* EndList() override; 150 151 // Renders a DataPiece 'value' into a field whose wire type is determined 152 // from the given field 'name'. 153 ProtoStreamObjectWriter* RenderDataPiece(StringPiece name, 154 const DataPiece& data) override; 155 156 protected: 157 // Function that renders a well known type with modified behavior. 158 typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*, 159 const DataPiece&); 160 161 // Handles writing Anys out using nested object writers and the like. 162 class PROTOBUF_EXPORT AnyWriter { 163 public: 164 explicit AnyWriter(ProtoStreamObjectWriter* parent); 165 ~AnyWriter(); 166 167 // Passes a StartObject call through to the Any writer. 168 void StartObject(StringPiece name); 169 170 // Passes an EndObject call through to the Any. Returns true if the any 171 // handled the EndObject call, false if the Any is now all done and is no 172 // longer needed. 173 bool EndObject(); 174 175 // Passes a StartList call through to the Any writer. 176 void StartList(StringPiece name); 177 178 // Passes an EndList call through to the Any writer. 179 void EndList(); 180 181 // Renders a data piece on the any. 182 void RenderDataPiece(StringPiece name, const DataPiece& value); 183 184 private: 185 // Before the "@type" field is encountered, we store all incoming data 186 // into this Event struct and replay them after we get the "@type" field. 187 class PROTOBUF_EXPORT Event { 188 public: 189 enum Type { 190 START_OBJECT = 0, 191 END_OBJECT = 1, 192 START_LIST = 2, 193 END_LIST = 3, 194 RENDER_DATA_PIECE = 4, 195 }; 196 197 // Constructor for END_OBJECT and END_LIST events. Event(Type type)198 explicit Event(Type type) : type_(type), value_(DataPiece::NullData()) {} 199 200 // Constructor for START_OBJECT and START_LIST events. Event(Type type,StringPiece name)201 explicit Event(Type type, StringPiece name) 202 : type_(type), name_(name), value_(DataPiece::NullData()) {} 203 204 // Constructor for RENDER_DATA_PIECE events. Event(StringPiece name,const DataPiece & value)205 explicit Event(StringPiece name, const DataPiece& value) 206 : type_(RENDER_DATA_PIECE), name_(name), value_(value) { 207 DeepCopy(); 208 } 209 Event(const Event & other)210 Event(const Event& other) 211 : type_(other.type_), name_(other.name_), value_(other.value_) { 212 DeepCopy(); 213 } 214 215 Event& operator=(const Event& other) { 216 type_ = other.type_; 217 name_ = other.name_; 218 value_ = other.value_; 219 DeepCopy(); 220 return *this; 221 } 222 223 void Replay(AnyWriter* writer) const; 224 225 private: 226 void DeepCopy(); 227 228 Type type_; 229 std::string name_; 230 DataPiece value_; 231 std::string value_storage_; 232 }; 233 234 // Handles starting up the any once we have a type. 235 void StartAny(const DataPiece& value); 236 237 // Writes the Any out to the parent writer in its serialized form. 238 void WriteAny(); 239 240 // The parent of this writer, needed for various bits such as type info and 241 // the listeners. 242 ProtoStreamObjectWriter* parent_; 243 244 // The nested object writer, used to write events. 245 std::unique_ptr<ProtoStreamObjectWriter> ow_; 246 247 // The type_url_ that this Any represents. 248 std::string type_url_; 249 250 // Whether this any is invalid. This allows us to only report an invalid 251 // Any message a single time rather than every time we get a nested field. 252 bool invalid_; 253 254 // The output data and wrapping ByteSink. 255 std::string data_; 256 strings::StringByteSink output_; 257 258 // The depth within the Any, so we can track when we're done. 259 int depth_; 260 261 // True if the type is a well-known type. Well-known types in Any 262 // has a special formatting: 263 // { 264 // "@type": "type.googleapis.com/google.protobuf.XXX", 265 // "value": <JSON representation of the type>, 266 // } 267 bool is_well_known_type_; 268 TypeRenderer* well_known_type_render_; 269 270 // Store data before the "@type" field. 271 std::vector<Event> uninterpreted_events_; 272 }; 273 274 // Represents an item in a stack of items used to keep state between 275 // ObjectWrier events. 276 class PROTOBUF_EXPORT Item : public BaseElement { 277 public: 278 // Indicates the type of item. 279 enum ItemType { 280 MESSAGE, // Simple message 281 MAP, // Proto3 map type 282 ANY, // Proto3 Any type 283 }; 284 285 // Constructor for the root item. 286 Item(ProtoStreamObjectWriter* enclosing, ItemType item_type, 287 bool is_placeholder, bool is_list); 288 289 // Constructor for a field of a message. 290 Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list); 291 ~Item()292 ~Item() override {} 293 294 // These functions return true if the element type is corresponding to the 295 // type in function name. IsMap()296 bool IsMap() { return item_type_ == MAP; } IsAny()297 bool IsAny() { return item_type_ == ANY; } 298 any()299 AnyWriter* any() const { return any_.get(); } 300 parent()301 Item* parent() const override { 302 return static_cast<Item*>(BaseElement::parent()); 303 } 304 305 // Inserts map key into hash set if and only if the key did NOT already 306 // exist in hash set. 307 // The hash set (map_keys_) is ONLY used to keep track of map keys. 308 // Return true if insert successfully; returns false if the map key was 309 // already present. 310 bool InsertMapKeyIfNotPresent(StringPiece map_key); 311 is_placeholder()312 bool is_placeholder() const { return is_placeholder_; } is_list()313 bool is_list() const { return is_list_; } 314 315 private: 316 // Used for access to variables of the enclosing instance of 317 // ProtoStreamObjectWriter. 318 ProtoStreamObjectWriter* ow_; 319 320 // A writer for Any objects, handles all Any-related nonsense. 321 std::unique_ptr<AnyWriter> any_; 322 323 // The type of this element, see enum for permissible types. 324 ItemType item_type_; 325 326 // Set of map keys already seen for the type_. Used to validate incoming 327 // messages so no map key appears more than once. 328 std::unique_ptr<std::unordered_set<std::string> > map_keys_; 329 330 // Conveys whether this Item is a placeholder or not. Placeholder items are 331 // pushed to stack to account for special types. 332 bool is_placeholder_; 333 334 // Conveys whether this Item is a list or not. This is used to send 335 // StartList or EndList calls to underlying ObjectWriter. 336 bool is_list_; 337 338 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item); 339 }; 340 341 ProtoStreamObjectWriter(const TypeInfo* typeinfo, 342 const google::protobuf::Type& type, 343 strings::ByteSink* output, ErrorListener* listener); 344 345 ProtoStreamObjectWriter(const TypeInfo* typeinfo, 346 const google::protobuf::Type& type, 347 strings::ByteSink* output, ErrorListener* listener, 348 const ProtoStreamObjectWriter::Options& options); 349 350 // Returns true if the field is a map. 351 inline bool IsMap(const google::protobuf::Field& field); 352 353 // Returns true if the field is an any. 354 inline bool IsAny(const google::protobuf::Field& field); 355 356 // Returns true if the field is google.protobuf.Struct. 357 inline bool IsStruct(const google::protobuf::Field& field); 358 359 // Returns true if the field is google.protobuf.Value. 360 inline bool IsStructValue(const google::protobuf::Field& field); 361 362 // Returns true if the field is google.protobuf.ListValue. 363 inline bool IsStructListValue(const google::protobuf::Field& field); 364 365 // Renders google.protobuf.Value in struct.proto. It picks the right oneof 366 // type based on value's type. 367 static util::Status RenderStructValue(ProtoStreamObjectWriter* ow, 368 const DataPiece& data); 369 370 // Renders google.protobuf.Timestamp value. 371 static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow, 372 const DataPiece& data); 373 374 // Renders google.protobuf.FieldMask value. 375 static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow, 376 const DataPiece& data); 377 378 // Renders google.protobuf.Duration value. 379 static util::Status RenderDuration(ProtoStreamObjectWriter* ow, 380 const DataPiece& data); 381 382 // Renders wrapper message types for primitive types in 383 // google/protobuf/wrappers.proto. 384 static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow, 385 const DataPiece& data); 386 387 static void InitRendererMap(); 388 static void DeleteRendererMap(); 389 static TypeRenderer* FindTypeRenderer(const std::string& type_url); 390 391 // Returns true if the map key for type_ is not duplicated key. 392 // If map key is duplicated key, this function returns false. 393 // Note that caller should make sure that the current proto element (current_) 394 // is of element type MAP or STRUCT_MAP. 395 // It also calls the appropriate error callback and unnormalzied_name is used 396 // for error string. 397 bool ValidMapKey(StringPiece unnormalized_name); 398 399 // Pushes an item on to the stack. Also calls either StartObject or StartList 400 // on the underlying ObjectWriter depending on whether is_list is false or 401 // not. 402 // is_placeholder conveys whether the item is a placeholder item or not. 403 // Placeholder items are pushed when adding auxiliary types' StartObject or 404 // StartList calls. 405 void Push(StringPiece name, Item::ItemType item_type, 406 bool is_placeholder, bool is_list); 407 408 409 // Pops items from the stack. All placeholder items are popped until a 410 // non-placeholder item is found. 411 void Pop(); 412 413 // Pops one element from the stack. Calls EndObject() or EndList() on the 414 // underlying ObjectWriter depending on the value of is_list_. 415 void PopOneElement(); 416 417 private: 418 // Helper functions to create the map and find functions responsible for 419 // rendering well known types, keyed by type URL. 420 static std::unordered_map<std::string, TypeRenderer>* renderers_; 421 422 // Variables for describing the structure of the input tree: 423 // master_type_: descriptor for the whole protobuf message. 424 const google::protobuf::Type& master_type_; 425 426 // The current element, variable for internal state processing. 427 std::unique_ptr<Item> current_; 428 429 // Reference to the options that control this class's behavior. 430 const ProtoStreamObjectWriter::Options options_; 431 432 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter); 433 }; 434 435 } // namespace converter 436 } // namespace util 437 } // namespace protobuf 438 } // namespace google 439 440 #include <google/protobuf/port_undef.inc> 441 442 #endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__ 443