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 OptionsOptions103 Options() 104 : struct_integers_as_strings(false), 105 ignore_unknown_fields(false), 106 ignore_unknown_enum_values(false), 107 use_lower_camel_for_enums(false), 108 case_insensitive_enum_parsing(false), 109 ignore_null_value_map_entry(false), 110 use_legacy_json_map_format(false) {} 111 112 // Default instance of Options with all options set to defaults. DefaultsOptions113 static const Options& Defaults() { 114 static Options defaults; 115 return defaults; 116 } 117 }; 118 119 // Constructor. Does not take ownership of any parameter passed in. 120 ProtoStreamObjectWriter(TypeResolver* type_resolver, 121 const google::protobuf::Type& type, 122 strings::ByteSink* output, ErrorListener* listener, 123 const ProtoStreamObjectWriter::Options& options = 124 ProtoStreamObjectWriter::Options::Defaults()); 125 ~ProtoStreamObjectWriter() override; 126 127 // ObjectWriter methods. 128 ProtoStreamObjectWriter* StartObject(StringPiece name) override; 129 ProtoStreamObjectWriter* EndObject() override; 130 ProtoStreamObjectWriter* StartList(StringPiece name) override; 131 ProtoStreamObjectWriter* EndList() override; 132 133 // Renders a DataPiece 'value' into a field whose wire type is determined 134 // from the given field 'name'. 135 ProtoStreamObjectWriter* RenderDataPiece(StringPiece name, 136 const DataPiece& data) override; 137 138 protected: 139 // Function that renders a well known type with modified behavior. 140 typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*, 141 const DataPiece&); 142 143 // Handles writing Anys out using nested object writers and the like. 144 class PROTOBUF_EXPORT AnyWriter { 145 public: 146 explicit AnyWriter(ProtoStreamObjectWriter* parent); 147 ~AnyWriter(); 148 149 // Passes a StartObject call through to the Any writer. 150 void StartObject(StringPiece name); 151 152 // Passes an EndObject call through to the Any. Returns true if the any 153 // handled the EndObject call, false if the Any is now all done and is no 154 // longer needed. 155 bool EndObject(); 156 157 // Passes a StartList call through to the Any writer. 158 void StartList(StringPiece name); 159 160 // Passes an EndList call through to the Any writer. 161 void EndList(); 162 163 // Renders a data piece on the any. 164 void RenderDataPiece(StringPiece name, const DataPiece& value); 165 166 private: 167 // Before the "@type" field is encountered, we store all incoming data 168 // into this Event struct and replay them after we get the "@type" field. 169 class PROTOBUF_EXPORT Event { 170 public: 171 enum Type { 172 START_OBJECT = 0, 173 END_OBJECT = 1, 174 START_LIST = 2, 175 END_LIST = 3, 176 RENDER_DATA_PIECE = 4, 177 }; 178 179 // Constructor for END_OBJECT and END_LIST events. Event(Type type)180 explicit Event(Type type) : type_(type), value_(DataPiece::NullData()) {} 181 182 // Constructor for START_OBJECT and START_LIST events. Event(Type type,StringPiece name)183 explicit Event(Type type, StringPiece name) 184 : type_(type), name_(name), value_(DataPiece::NullData()) {} 185 186 // Constructor for RENDER_DATA_PIECE events. Event(StringPiece name,const DataPiece & value)187 explicit Event(StringPiece name, const DataPiece& value) 188 : type_(RENDER_DATA_PIECE), name_(name), value_(value) { 189 DeepCopy(); 190 } 191 Event(const Event & other)192 Event(const Event& other) 193 : type_(other.type_), name_(other.name_), value_(other.value_) { 194 DeepCopy(); 195 } 196 197 Event& operator=(const Event& other) { 198 type_ = other.type_; 199 name_ = other.name_; 200 value_ = other.value_; 201 DeepCopy(); 202 return *this; 203 } 204 205 void Replay(AnyWriter* writer) const; 206 207 private: 208 void DeepCopy(); 209 210 Type type_; 211 std::string name_; 212 DataPiece value_; 213 std::string value_storage_; 214 }; 215 216 // Handles starting up the any once we have a type. 217 void StartAny(const DataPiece& value); 218 219 // Writes the Any out to the parent writer in its serialized form. 220 void WriteAny(); 221 222 // The parent of this writer, needed for various bits such as type info and 223 // the listeners. 224 ProtoStreamObjectWriter* parent_; 225 226 // The nested object writer, used to write events. 227 std::unique_ptr<ProtoStreamObjectWriter> ow_; 228 229 // The type_url_ that this Any represents. 230 std::string type_url_; 231 232 // Whether this any is invalid. This allows us to only report an invalid 233 // Any message a single time rather than every time we get a nested field. 234 bool invalid_; 235 236 // The output data and wrapping ByteSink. 237 std::string data_; 238 strings::StringByteSink output_; 239 240 // The depth within the Any, so we can track when we're done. 241 int depth_; 242 243 // True if the type is a well-known type. Well-known types in Any 244 // has a special formatting: 245 // { 246 // "@type": "type.googleapis.com/google.protobuf.XXX", 247 // "value": <JSON representation of the type>, 248 // } 249 bool is_well_known_type_; 250 TypeRenderer* well_known_type_render_; 251 252 // Store data before the "@type" field. 253 std::vector<Event> uninterpreted_events_; 254 }; 255 256 // Represents an item in a stack of items used to keep state between 257 // ObjectWrier events. 258 class PROTOBUF_EXPORT Item : public BaseElement { 259 public: 260 // Indicates the type of item. 261 enum ItemType { 262 MESSAGE, // Simple message 263 MAP, // Proto3 map type 264 ANY, // Proto3 Any type 265 }; 266 267 // Constructor for the root item. 268 Item(ProtoStreamObjectWriter* enclosing, ItemType item_type, 269 bool is_placeholder, bool is_list); 270 271 // Constructor for a field of a message. 272 Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list); 273 ~Item()274 ~Item() override {} 275 276 // These functions return true if the element type is corresponding to the 277 // type in function name. IsMap()278 bool IsMap() { return item_type_ == MAP; } IsAny()279 bool IsAny() { return item_type_ == ANY; } 280 any()281 AnyWriter* any() const { return any_.get(); } 282 parent()283 Item* parent() const override { 284 return static_cast<Item*>(BaseElement::parent()); 285 } 286 287 // Inserts map key into hash set if and only if the key did NOT already 288 // exist in hash set. 289 // The hash set (map_keys_) is ONLY used to keep track of map keys. 290 // Return true if insert successfully; returns false if the map key was 291 // already present. 292 bool InsertMapKeyIfNotPresent(StringPiece map_key); 293 is_placeholder()294 bool is_placeholder() const { return is_placeholder_; } is_list()295 bool is_list() const { return is_list_; } 296 297 private: 298 // Used for access to variables of the enclosing instance of 299 // ProtoStreamObjectWriter. 300 ProtoStreamObjectWriter* ow_; 301 302 // A writer for Any objects, handles all Any-related nonsense. 303 std::unique_ptr<AnyWriter> any_; 304 305 // The type of this element, see enum for permissible types. 306 ItemType item_type_; 307 308 // Set of map keys already seen for the type_. Used to validate incoming 309 // messages so no map key appears more than once. 310 std::unique_ptr<std::unordered_set<std::string> > map_keys_; 311 312 // Conveys whether this Item is a placeholder or not. Placeholder items are 313 // pushed to stack to account for special types. 314 bool is_placeholder_; 315 316 // Conveys whether this Item is a list or not. This is used to send 317 // StartList or EndList calls to underlying ObjectWriter. 318 bool is_list_; 319 320 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item); 321 }; 322 323 ProtoStreamObjectWriter(const TypeInfo* typeinfo, 324 const google::protobuf::Type& type, 325 strings::ByteSink* output, ErrorListener* listener); 326 327 ProtoStreamObjectWriter(const TypeInfo* typeinfo, 328 const google::protobuf::Type& type, 329 strings::ByteSink* output, ErrorListener* listener, 330 const ProtoStreamObjectWriter::Options& options); 331 332 // Returns true if the field is a map. 333 inline bool IsMap(const google::protobuf::Field& field); 334 335 // Returns true if the field is an any. 336 inline bool IsAny(const google::protobuf::Field& field); 337 338 // Returns true if the field is google.protobuf.Struct. 339 inline bool IsStruct(const google::protobuf::Field& field); 340 341 // Returns true if the field is google.protobuf.Value. 342 inline bool IsStructValue(const google::protobuf::Field& field); 343 344 // Returns true if the field is google.protobuf.ListValue. 345 inline bool IsStructListValue(const google::protobuf::Field& field); 346 347 // Renders google.protobuf.Value in struct.proto. It picks the right oneof 348 // type based on value's type. 349 static util::Status RenderStructValue(ProtoStreamObjectWriter* ow, 350 const DataPiece& data); 351 352 // Renders google.protobuf.Timestamp value. 353 static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow, 354 const DataPiece& data); 355 356 // Renders google.protobuf.FieldMask value. 357 static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow, 358 const DataPiece& data); 359 360 // Renders google.protobuf.Duration value. 361 static util::Status RenderDuration(ProtoStreamObjectWriter* ow, 362 const DataPiece& data); 363 364 // Renders wrapper message types for primitive types in 365 // google/protobuf/wrappers.proto. 366 static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow, 367 const DataPiece& data); 368 369 static void InitRendererMap(); 370 static void DeleteRendererMap(); 371 static TypeRenderer* FindTypeRenderer(const std::string& type_url); 372 373 // Returns true if the map key for type_ is not duplicated key. 374 // If map key is duplicated key, this function returns false. 375 // Note that caller should make sure that the current proto element (current_) 376 // is of element type MAP or STRUCT_MAP. 377 // It also calls the appropriate error callback and unnormalzied_name is used 378 // for error string. 379 bool ValidMapKey(StringPiece unnormalized_name); 380 381 // Pushes an item on to the stack. Also calls either StartObject or StartList 382 // on the underlying ObjectWriter depending on whether is_list is false or 383 // not. 384 // is_placeholder conveys whether the item is a placeholder item or not. 385 // Placeholder items are pushed when adding auxiliary types' StartObject or 386 // StartList calls. 387 void Push(StringPiece name, Item::ItemType item_type, 388 bool is_placeholder, bool is_list); 389 390 391 // Pops items from the stack. All placeholder items are popped until a 392 // non-placeholder item is found. 393 void Pop(); 394 395 // Pops one element from the stack. Calls EndObject() or EndList() on the 396 // underlying ObjectWriter depending on the value of is_list_. 397 void PopOneElement(); 398 399 private: 400 // Helper functions to create the map and find functions responsible for 401 // rendering well known types, keyed by type URL. 402 static std::unordered_map<std::string, TypeRenderer>* renderers_; 403 404 // Variables for describing the structure of the input tree: 405 // master_type_: descriptor for the whole protobuf message. 406 const google::protobuf::Type& master_type_; 407 408 // The current element, variable for internal state processing. 409 std::unique_ptr<Item> current_; 410 411 // Reference to the options that control this class's behavior. 412 const ProtoStreamObjectWriter::Options options_; 413 414 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter); 415 }; 416 417 } // namespace converter 418 } // namespace util 419 } // namespace protobuf 420 } // namespace google 421 422 #include <google/protobuf/port_undef.inc> 423 424 #endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__ 425