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 <google/protobuf/stubs/hash.h> 36 #include <string> 37 38 #include <google/protobuf/stubs/common.h> 39 #include <google/protobuf/io/coded_stream.h> 40 #include <google/protobuf/io/zero_copy_stream_impl.h> 41 #include <google/protobuf/descriptor.h> 42 #include <google/protobuf/util/internal/type_info.h> 43 #include <google/protobuf/util/internal/datapiece.h> 44 #include <google/protobuf/util/internal/error_listener.h> 45 #include <google/protobuf/util/internal/proto_writer.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 50 namespace google { 51 namespace protobuf { 52 namespace io { 53 class CodedOutputStream; 54 } // namespace io 55 } // namespace protobuf 56 57 58 namespace protobuf { 59 class Type; 60 class Field; 61 } // namespace protobuf 62 63 64 namespace protobuf { 65 namespace util { 66 namespace converter { 67 68 class ObjectLocationTracker; 69 70 // An ObjectWriter that can write protobuf bytes directly from writer events. 71 // This class supports all special types like Struct and Map. It uses 72 // the ProtoWriter class to write raw proto bytes. 73 // 74 // It also supports streaming. 75 class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { 76 public: 77 // Options that control ProtoStreamObjectWriter class's behavior. 78 struct Options { 79 // Treats integer inputs in google.protobuf.Struct as strings. Normally, 80 // integer values are returned in double field "number_value" of 81 // google.protobuf.Struct. However, this can cause precision loss for 82 // int64/uint64 inputs. This option is provided for cases that want to 83 // preserve integer precision. 84 bool struct_integers_as_strings; 85 86 // Not treat unknown fields as an error. If there is an unknown fields, 87 // just ignore it and continue to process the rest. 88 bool ignore_unknown_fields; 89 OptionsOptions90 Options() 91 : struct_integers_as_strings(false), ignore_unknown_fields(false) {} 92 93 // Default instance of Options with all options set to defaults. DefaultsOptions94 static const Options& Defaults() { 95 static Options defaults; 96 return defaults; 97 } 98 }; 99 100 // Constructor. Does not take ownership of any parameter passed in. 101 ProtoStreamObjectWriter(TypeResolver* type_resolver, 102 const google::protobuf::Type& type, 103 strings::ByteSink* output, ErrorListener* listener, 104 const ProtoStreamObjectWriter::Options& options = 105 ProtoStreamObjectWriter::Options::Defaults()); 106 virtual ~ProtoStreamObjectWriter(); 107 108 // ObjectWriter methods. 109 virtual ProtoStreamObjectWriter* StartObject(StringPiece name); 110 virtual ProtoStreamObjectWriter* EndObject(); 111 virtual ProtoStreamObjectWriter* StartList(StringPiece name); 112 virtual ProtoStreamObjectWriter* EndList(); 113 114 // Renders a DataPiece 'value' into a field whose wire type is determined 115 // from the given field 'name'. 116 virtual ProtoStreamObjectWriter* RenderDataPiece(StringPiece name, 117 const DataPiece& value); 118 119 protected: 120 // Function that renders a well known type with modified behavior. 121 typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*, 122 const DataPiece&); 123 124 // Handles writing Anys out using nested object writers and the like. 125 class LIBPROTOBUF_EXPORT AnyWriter { 126 public: 127 explicit AnyWriter(ProtoStreamObjectWriter* parent); 128 ~AnyWriter(); 129 130 // Passes a StartObject call through to the Any writer. 131 void StartObject(StringPiece name); 132 133 // Passes an EndObject call through to the Any. Returns true if the any 134 // handled the EndObject call, false if the Any is now all done and is no 135 // longer needed. 136 bool EndObject(); 137 138 // Passes a StartList call through to the Any writer. 139 void StartList(StringPiece name); 140 141 // Passes an EndList call through to the Any writer. 142 void EndList(); 143 144 // Renders a data piece on the any. 145 void RenderDataPiece(StringPiece name, const DataPiece& value); 146 147 private: 148 // Handles starting up the any once we have a type. 149 void StartAny(const DataPiece& value); 150 151 // Writes the Any out to the parent writer in its serialized form. 152 void WriteAny(); 153 154 // The parent of this writer, needed for various bits such as type info and 155 // the listeners. 156 ProtoStreamObjectWriter* parent_; 157 158 // The nested object writer, used to write events. 159 google::protobuf::scoped_ptr<ProtoStreamObjectWriter> ow_; 160 161 // The type_url_ that this Any represents. 162 string type_url_; 163 164 // Whether this any is invalid. This allows us to only report an invalid 165 // Any message a single time rather than every time we get a nested field. 166 bool invalid_; 167 168 // The output data and wrapping ByteSink. 169 string data_; 170 strings::StringByteSink output_; 171 172 // The depth within the Any, so we can track when we're done. 173 int depth_; 174 175 // True if the type is a well-known type. Well-known types in Any 176 // has a special formating: 177 // { 178 // "@type": "type.googleapis.com/google.protobuf.XXX", 179 // "value": <JSON representation of the type>, 180 // } 181 bool is_well_known_type_; 182 TypeRenderer* well_known_type_render_; 183 }; 184 185 // Represents an item in a stack of items used to keep state between 186 // ObjectWrier events. 187 class LIBPROTOBUF_EXPORT Item : public BaseElement { 188 public: 189 // Indicates the type of item. 190 enum ItemType { 191 MESSAGE, // Simple message 192 MAP, // Proto3 map type 193 ANY, // Proto3 Any type 194 }; 195 196 // Constructor for the root item. 197 Item(ProtoStreamObjectWriter* enclosing, ItemType item_type, 198 bool is_placeholder, bool is_list); 199 200 // Constructor for a field of a message. 201 Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list); 202 ~Item()203 virtual ~Item() {} 204 205 // These functions return true if the element type is corresponding to the 206 // type in function name. IsMap()207 bool IsMap() { return item_type_ == MAP; } IsAny()208 bool IsAny() { return item_type_ == ANY; } 209 any()210 AnyWriter* any() const { return any_.get(); } 211 parent()212 virtual Item* parent() const { 213 return static_cast<Item*>(BaseElement::parent()); 214 } 215 216 // Inserts map key into hash set if and only if the key did NOT already 217 // exist in hash set. 218 // The hash set (map_keys_) is ONLY used to keep track of map keys. 219 // Return true if insert successfully; returns false if the map key was 220 // already present. 221 bool InsertMapKeyIfNotPresent(StringPiece map_key); 222 is_placeholder()223 bool is_placeholder() const { return is_placeholder_; } is_list()224 bool is_list() const { return is_list_; } 225 226 private: 227 // Used for access to variables of the enclosing instance of 228 // ProtoStreamObjectWriter. 229 ProtoStreamObjectWriter* ow_; 230 231 // A writer for Any objects, handles all Any-related nonsense. 232 google::protobuf::scoped_ptr<AnyWriter> any_; 233 234 // The type of this element, see enum for permissible types. 235 ItemType item_type_; 236 237 // Set of map keys already seen for the type_. Used to validate incoming 238 // messages so no map key appears more than once. 239 google::protobuf::scoped_ptr<hash_set<string> > map_keys_; 240 241 // Conveys whether this Item is a placeholder or not. Placeholder items are 242 // pushed to stack to account for special types. 243 bool is_placeholder_; 244 245 // Conveys whether this Item is a list or not. This is used to send 246 // StartList or EndList calls to underlying ObjectWriter. 247 bool is_list_; 248 249 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item); 250 }; 251 252 ProtoStreamObjectWriter(const TypeInfo* typeinfo, 253 const google::protobuf::Type& type, 254 strings::ByteSink* output, ErrorListener* listener); 255 256 // Returns true if the field is a map. 257 inline bool IsMap(const google::protobuf::Field& field); 258 259 // Returns true if the field is an any. 260 inline bool IsAny(const google::protobuf::Field& field); 261 262 // Returns true if the field is google.protobuf.Struct. 263 inline bool IsStruct(const google::protobuf::Field& field); 264 265 // Returns true if the field is google.protobuf.Value. 266 inline bool IsStructValue(const google::protobuf::Field& field); 267 268 // Returns true if the field is google.protobuf.ListValue. 269 inline bool IsStructListValue(const google::protobuf::Field& field); 270 271 // Renders google.protobuf.Value in struct.proto. It picks the right oneof 272 // type based on value's type. 273 static util::Status RenderStructValue(ProtoStreamObjectWriter* ow, 274 const DataPiece& value); 275 276 // Renders google.protobuf.Timestamp value. 277 static util::Status RenderTimestamp(ProtoStreamObjectWriter* ow, 278 const DataPiece& value); 279 280 // Renders google.protobuf.FieldMask value. 281 static util::Status RenderFieldMask(ProtoStreamObjectWriter* ow, 282 const DataPiece& value); 283 284 // Renders google.protobuf.Duration value. 285 static util::Status RenderDuration(ProtoStreamObjectWriter* ow, 286 const DataPiece& value); 287 288 // Renders wrapper message types for primitive types in 289 // google/protobuf/wrappers.proto. 290 static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow, 291 const DataPiece& value); 292 293 static void InitRendererMap(); 294 static void DeleteRendererMap(); 295 static TypeRenderer* FindTypeRenderer(const string& type_url); 296 297 // Returns true if the map key for type_ is not duplicated key. 298 // If map key is duplicated key, this function returns false. 299 // Note that caller should make sure that the current proto element (current_) 300 // is of element type MAP or STRUCT_MAP. 301 // It also calls the appropriate error callback and unnormalzied_name is used 302 // for error string. 303 bool ValidMapKey(StringPiece unnormalized_name); 304 305 // Pushes an item on to the stack. Also calls either StartObject or StartList 306 // on the underlying ObjectWriter depending on whether is_list is false or 307 // not. 308 // is_placeholder conveys whether the item is a placeholder item or not. 309 // Placeholder items are pushed when adding auxillary types' StartObject or 310 // StartList calls. 311 void Push(StringPiece name, Item::ItemType item_type, bool is_placeholder, 312 bool is_list); 313 314 // Pops items from the stack. All placeholder items are popped until a 315 // non-placeholder item is found. 316 void Pop(); 317 318 // Pops one element from the stack. Calls EndObject() or EndList() on the 319 // underlying ObjectWriter depending on the value of is_list_. 320 void PopOneElement(); 321 322 private: 323 // Helper functions to create the map and find functions responsible for 324 // rendering well known types, keyed by type URL. 325 static hash_map<string, TypeRenderer>* renderers_; 326 327 // Variables for describing the structure of the input tree: 328 // master_type_: descriptor for the whole protobuf message. 329 const google::protobuf::Type& master_type_; 330 331 // The current element, variable for internal state processing. 332 google::protobuf::scoped_ptr<Item> current_; 333 334 // Reference to the options that control this class's behavior. 335 const ProtoStreamObjectWriter::Options options_; 336 337 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter); 338 }; 339 340 } // namespace converter 341 } // namespace util 342 } // namespace protobuf 343 344 } // namespace google 345 #endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__ 346