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