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