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