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_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
32#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
33
34#include <cstdint>
35#include <functional>
36#include <string>
37#include <unordered_map>
38
39#include <google/protobuf/stubs/status.h>
40
41#include <google/protobuf/stubs/common.h>
42#include <google/protobuf/type.pb.h>
43#include <google/protobuf/stubs/statusor.h>
44#include <google/protobuf/stubs/strutil.h>
45#include <google/protobuf/util/internal/object_source.h>
46#include <google/protobuf/util/internal/object_writer.h>
47#include <google/protobuf/util/internal/type_info.h>
48#include <google/protobuf/util/type_resolver.h>
49#include <google/protobuf/stubs/hash.h>
50#include <google/protobuf/stubs/status.h>
51
52
53// Must be included last.
54#include <google/protobuf/port_def.inc>
55
56namespace google {
57namespace protobuf {
58namespace util {
59namespace converter {
60
61class TypeInfo;
62
63// An ObjectSource that can parse a stream of bytes as a protocol buffer.
64// Its WriteTo() method can be given an ObjectWriter.
65// This implementation uses a google.protobuf.Type for tag and name lookup.
66// The field names are converted into lower camel-case when writing to the
67// ObjectWriter.
68//
69// Sample usage: (suppose input is: string proto)
70// ArrayInputStream arr_stream(proto.data(), proto.size());
71// CodedInputStream in_stream(&arr_stream);
72// ProtoStreamObjectSource os(&in_stream, /*ServiceTypeInfo*/ typeinfo,
73// <your message google::protobuf::Type>);
74//
75// Status status = os.WriteTo(<some ObjectWriter>);
76class PROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
77 public:
78
79 struct RenderOptions {
80 RenderOptions() = default;
81 RenderOptions(const RenderOptions&) = default;
82
83 // Sets whether or not to use lowerCamelCase casing for enum values. If set
84 // to false, enum values are output without any case conversions.
85 //
86 // For example, if we have an enum:
87 // enum Type {
88 // ACTION_AND_ADVENTURE = 1;
89 // }
90 // Type type = 20;
91 //
92 // And this option is set to true. Then the rendered "type" field will have
93 // the string "actionAndAdventure".
94 // {
95 // ...
96 // "type": "actionAndAdventure",
97 // ...
98 // }
99 //
100 // If set to false, the rendered "type" field will have the string
101 // "ACTION_AND_ADVENTURE".
102 // {
103 // ...
104 // "type": "ACTION_AND_ADVENTURE",
105 // ...
106 // }
107 bool use_lower_camel_for_enums = false;
108
109 // Sets whether to always output enums as ints, by default this is off, and
110 // enums are rendered as strings.
111 bool use_ints_for_enums = false;
112
113 // Whether to preserve proto field names
114 bool preserve_proto_field_names = false;
115
116 };
117
118 ProtoStreamObjectSource(io::CodedInputStream* stream,
119 TypeResolver* type_resolver,
120 const google::protobuf::Type& type)
121 : ProtoStreamObjectSource(stream, type_resolver, type, RenderOptions()) {}
122 ProtoStreamObjectSource(io::CodedInputStream* stream,
123 TypeResolver* type_resolver,
124 const google::protobuf::Type& type,
125 const RenderOptions& render_options);
126
127 ~ProtoStreamObjectSource() override;
128
129 util::Status NamedWriteTo(StringPiece name,
130 ObjectWriter* ow) const override;
131
132 // Sets the max recursion depth of proto message to be deserialized. Proto
133 // messages over this depth will fail to be deserialized.
134 // Default value is 64.
135 void set_max_recursion_depth(int max_depth) {
136 max_recursion_depth_ = max_depth;
137 }
138
139 protected:
140 // Writes a proto2 Message to the ObjectWriter. When the given end_tag is
141 // found this method will complete, allowing it to be used for parsing both
142 // nested messages (end with 0) and nested groups (end with group end tag).
143 // The include_start_and_end parameter allows this method to be called when
144 // already inside of an object, and skip calling StartObject and EndObject.
145 virtual util::Status WriteMessage(const google::protobuf::Type& type,
146 StringPiece name,
147 const uint32_t end_tag,
148 bool include_start_and_end,
149 ObjectWriter* ow) const;
150
151 // Renders a repeating field (packed or unpacked). Returns the next tag after
152 // reading all sequential repeating elements. The caller should use this tag
153 // before reading more tags from the stream.
154 virtual util::StatusOr<uint32_t> RenderList(
155 const google::protobuf::Field* field, StringPiece name,
156 uint32_t list_tag, ObjectWriter* ow) const;
157
158 // Looks up a field and verify its consistency with wire type in tag.
159 const google::protobuf::Field* FindAndVerifyField(
160 const google::protobuf::Type& type, uint32_t tag) const;
161
162 // Renders a field value to the ObjectWriter.
163 virtual util::Status RenderField(const google::protobuf::Field* field,
164 StringPiece field_name,
165 ObjectWriter* ow) const;
166
167 // Reads field value according to Field spec in 'field' and returns the read
168 // value as string. This only works for primitive datatypes (no message
169 // types).
170 const std::string ReadFieldValueAsString(
171 const google::protobuf::Field& field) const;
172
173
174 // Returns the input stream.
175 io::CodedInputStream* stream() const { return stream_; }
176
177 private:
178 ProtoStreamObjectSource(io::CodedInputStream* stream,
179 const TypeInfo* typeinfo,
180 const google::protobuf::Type& type,
181 const RenderOptions& render_options);
182 // Function that renders a well known type with a modified behavior.
183 typedef util::Status (*TypeRenderer)(const ProtoStreamObjectSource*,
184 const google::protobuf::Type&,
185 StringPiece, ObjectWriter*);
186
187 // TODO(skarvaje): Mark these methods as non-const as they modify internal
188 // state (stream_).
189 //
190 // Renders a NWP map.
191 // Returns the next tag after reading all map entries. The caller should use
192 // this tag before reading more tags from the stream.
193 util::StatusOr<uint32_t> RenderMap(const google::protobuf::Field* field,
194 StringPiece name, uint32_t list_tag,
195 ObjectWriter* ow) const;
196
197 // Renders a packed repeating field. A packed field is stored as:
198 // {tag length item1 item2 item3} instead of the less efficient
199 // {tag item1 tag item2 tag item3}.
200 util::Status RenderPacked(const google::protobuf::Field* field,
201 ObjectWriter* ow) const;
202
203 // Renders a google.protobuf.Timestamp value to ObjectWriter
204 static util::Status RenderTimestamp(const ProtoStreamObjectSource* os,
205 const google::protobuf::Type& type,
206 StringPiece name, ObjectWriter* ow);
207
208 // Renders a google.protobuf.Duration value to ObjectWriter
209 static util::Status RenderDuration(const ProtoStreamObjectSource* os,
210 const google::protobuf::Type& type,
211 StringPiece name, ObjectWriter* ow);
212
213 // Following RenderTYPE functions render well known types in
214 // google/protobuf/wrappers.proto corresponding to TYPE.
215 static util::Status RenderDouble(const ProtoStreamObjectSource* os,
216 const google::protobuf::Type& type,
217 StringPiece name, ObjectWriter* ow);
218 static util::Status RenderFloat(const ProtoStreamObjectSource* os,
219 const google::protobuf::Type& type,
220 StringPiece name, ObjectWriter* ow);
221 static util::Status RenderInt64(const ProtoStreamObjectSource* os,
222 const google::protobuf::Type& type,
223 StringPiece name, ObjectWriter* ow);
224 static util::Status RenderUInt64(const ProtoStreamObjectSource* os,
225 const google::protobuf::Type& type,
226 StringPiece name, ObjectWriter* ow);
227 static util::Status RenderInt32(const ProtoStreamObjectSource* os,
228 const google::protobuf::Type& type,
229 StringPiece name, ObjectWriter* ow);
230 static util::Status RenderUInt32(const ProtoStreamObjectSource* os,
231 const google::protobuf::Type& type,
232 StringPiece name, ObjectWriter* ow);
233 static util::Status RenderBool(const ProtoStreamObjectSource* os,
234 const google::protobuf::Type& type,
235 StringPiece name, ObjectWriter* ow);
236 static util::Status RenderString(const ProtoStreamObjectSource* os,
237 const google::protobuf::Type& type,
238 StringPiece name, ObjectWriter* ow);
239 static util::Status RenderBytes(const ProtoStreamObjectSource* os,
240 const google::protobuf::Type& type,
241 StringPiece name, ObjectWriter* ow);
242
243 // Renders a google.protobuf.Struct to ObjectWriter.
244 static util::Status RenderStruct(const ProtoStreamObjectSource* os,
245 const google::protobuf::Type& type,
246 StringPiece name, ObjectWriter* ow);
247
248 // Helper to render google.protobuf.Struct's Value fields to ObjectWriter.
249 static util::Status RenderStructValue(const ProtoStreamObjectSource* os,
250 const google::protobuf::Type& type,
251 StringPiece name,
252 ObjectWriter* ow);
253
254 // Helper to render google.protobuf.Struct's ListValue fields to ObjectWriter.
255 static util::Status RenderStructListValue(const ProtoStreamObjectSource* os,
256 const google::protobuf::Type& type,
257 StringPiece name,
258 ObjectWriter* ow);
259
260 // Render the "Any" type.
261 static util::Status RenderAny(const ProtoStreamObjectSource* os,
262 const google::protobuf::Type& type,
263 StringPiece name, ObjectWriter* ow);
264
265 // Render the "FieldMask" type.
266 static util::Status RenderFieldMask(const ProtoStreamObjectSource* os,
267 const google::protobuf::Type& type,
268 StringPiece name, ObjectWriter* ow);
269
270 static std::unordered_map<std::string, TypeRenderer>* renderers_;
271 static void InitRendererMap();
272 static void DeleteRendererMap();
273 static TypeRenderer* FindTypeRenderer(const std::string& type_url);
274
275 // Same as above but renders all non-message field types. Callers don't call
276 // this function directly. They just use RenderField.
277 util::Status RenderNonMessageField(const google::protobuf::Field* field,
278 StringPiece field_name,
279 ObjectWriter* ow) const;
280
281
282 // Utility function to detect proto maps. The 'field' MUST be repeated.
283 bool IsMap(const google::protobuf::Field& field) const;
284
285 // Utility to read int64 and int32 values from a message type in stream_.
286 // Used for reading google.protobuf.Timestamp and Duration messages.
287 std::pair<int64_t, int32_t> ReadSecondsAndNanos(
288 const google::protobuf::Type& type) const;
289
290 // Helper function to check recursion depth and increment it. It will return
291 // OkStatus() if the current depth is allowed. Otherwise an error is returned.
292 // type_name and field_name are used for error reporting.
293 util::Status IncrementRecursionDepth(StringPiece type_name,
294 StringPiece field_name) const;
295
296 // Input stream to read from. Ownership rests with the caller.
297 mutable io::CodedInputStream* stream_;
298
299 // Type information for all the types used in the descriptor. Used to find
300 // google::protobuf::Type of nested messages/enums.
301 const TypeInfo* typeinfo_;
302
303 // Whether this class owns the typeinfo_ object. If true the typeinfo_ object
304 // should be deleted in the destructor.
305 bool own_typeinfo_;
306
307 // google::protobuf::Type of the message source.
308 const google::protobuf::Type& type_;
309
310
311 const RenderOptions render_options_;
312
313 // Tracks current recursion depth.
314 mutable int recursion_depth_;
315
316 // Maximum allowed recursion depth.
317 int max_recursion_depth_;
318
319 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource);
320};
321
322} // namespace converter
323} // namespace util
324} // namespace protobuf
325} // namespace google
326
327#include <google/protobuf/port_undef.inc>
328
329#endif // GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
330