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 #include <google/protobuf/parse_context.h>
32
33 #include <google/protobuf/stubs/stringprintf.h>
34 #include <google/protobuf/io/coded_stream.h>
35 #include <google/protobuf/io/zero_copy_stream.h>
36 #include <google/protobuf/arenastring.h>
37 #include <google/protobuf/message_lite.h>
38 #include <google/protobuf/repeated_field.h>
39 #include <google/protobuf/wire_format_lite.h>
40 #include <google/protobuf/stubs/strutil.h>
41
42 #include <google/protobuf/port_def.inc>
43
44 namespace google {
45 namespace protobuf {
46 namespace internal {
47
48 namespace {
49
50 // Only call if at start of tag.
ParseEndsInSlopRegion(const char * begin,int overrun,int depth)51 bool ParseEndsInSlopRegion(const char* begin, int overrun, int depth) {
52 constexpr int kSlopBytes = EpsCopyInputStream::kSlopBytes;
53 GOOGLE_DCHECK(overrun >= 0);
54 GOOGLE_DCHECK(overrun <= kSlopBytes);
55 auto ptr = begin + overrun;
56 auto end = begin + kSlopBytes;
57 while (ptr < end) {
58 uint32 tag;
59 ptr = ReadTag(ptr, &tag);
60 if (ptr == nullptr || ptr > end) return false;
61 // ending on 0 tag is allowed and is the major reason for the necessity of
62 // this function.
63 if (tag == 0) return true;
64 switch (tag & 7) {
65 case 0: { // Varint
66 uint64 val;
67 ptr = VarintParse(ptr, &val);
68 if (ptr == nullptr) return false;
69 break;
70 }
71 case 1: { // fixed64
72 ptr += 8;
73 break;
74 }
75 case 2: { // len delim
76 int32 size = ReadSize(&ptr);
77 if (ptr == nullptr || size > end - ptr) return false;
78 ptr += size;
79 break;
80 }
81 case 3: { // start group
82 depth++;
83 break;
84 }
85 case 4: { // end group
86 if (--depth < 0) return true; // We exit early
87 break;
88 }
89 case 5: { // fixed32
90 ptr += 4;
91 break;
92 }
93 default:
94 return false; // Unknown wireformat
95 }
96 }
97 return false;
98 }
99
100 } // namespace
101
NextBuffer(int overrun,int depth)102 const char* EpsCopyInputStream::NextBuffer(int overrun, int depth) {
103 if (next_chunk_ == nullptr) return nullptr; // We've reached end of stream.
104 if (next_chunk_ != buffer_) {
105 GOOGLE_DCHECK(size_ > kSlopBytes);
106 // The chunk is large enough to be used directly
107 buffer_end_ = next_chunk_ + size_ - kSlopBytes;
108 auto res = next_chunk_;
109 next_chunk_ = buffer_;
110 if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
111 return res;
112 }
113 // Move the slop bytes of previous buffer to start of the patch buffer.
114 // Note we must use memmove because the previous buffer could be part of
115 // buffer_.
116 std::memmove(buffer_, buffer_end_, kSlopBytes);
117 if (overall_limit_ > 0 &&
118 (depth < 0 || !ParseEndsInSlopRegion(buffer_, overrun, depth))) {
119 const void* data;
120 // ZeroCopyInputStream indicates Next may return 0 size buffers. Hence
121 // we loop.
122 while (StreamNext(&data)) {
123 if (size_ > kSlopBytes) {
124 // We got a large chunk
125 std::memcpy(buffer_ + kSlopBytes, data, kSlopBytes);
126 next_chunk_ = static_cast<const char*>(data);
127 buffer_end_ = buffer_ + kSlopBytes;
128 if (aliasing_ >= kNoDelta) aliasing_ = kOnPatch;
129 return buffer_;
130 } else if (size_ > 0) {
131 std::memcpy(buffer_ + kSlopBytes, data, size_);
132 next_chunk_ = buffer_;
133 buffer_end_ = buffer_ + size_;
134 if (aliasing_ >= kNoDelta) aliasing_ = kOnPatch;
135 return buffer_;
136 }
137 GOOGLE_DCHECK(size_ == 0) << size_;
138 }
139 overall_limit_ = 0; // Next failed, no more needs for next
140 }
141 // End of stream or array
142 if (aliasing_ == kNoDelta) {
143 // If there is no more block and aliasing is true, the previous block
144 // is still valid and we can alias. We have users relying on string_view's
145 // obtained from protos to outlive the proto, when the parse was from an
146 // array. This guarantees string_view's are always aliased if parsed from
147 // an array.
148 aliasing_ = reinterpret_cast<std::uintptr_t>(buffer_end_) -
149 reinterpret_cast<std::uintptr_t>(buffer_);
150 }
151 next_chunk_ = nullptr;
152 buffer_end_ = buffer_ + kSlopBytes;
153 size_ = 0;
154 return buffer_;
155 }
156
Next()157 const char* EpsCopyInputStream::Next() {
158 GOOGLE_DCHECK(limit_ > kSlopBytes);
159 auto p = NextBuffer(0 /* immaterial */, -1);
160 if (p == nullptr) {
161 limit_end_ = buffer_end_;
162 // Distinguish ending on a pushed limit or ending on end-of-stream.
163 SetEndOfStream();
164 return nullptr;
165 }
166 limit_ -= buffer_end_ - p; // Adjust limit_ relative to new anchor
167 limit_end_ = buffer_end_ + std::min(0, limit_);
168 return p;
169 }
170
DoneFallback(int overrun,int depth)171 std::pair<const char*, bool> EpsCopyInputStream::DoneFallback(int overrun,
172 int depth) {
173 // Did we exceeded the limit (parse error).
174 if (PROTOBUF_PREDICT_FALSE(overrun > limit_)) return {nullptr, true};
175 GOOGLE_DCHECK(overrun != limit_); // Guaranteed by caller.
176 GOOGLE_DCHECK(overrun < limit_); // Follows from above
177 // TODO(gerbens) Instead of this dcheck we could just assign, and remove
178 // updating the limit_end from PopLimit, ie.
179 // limit_end_ = buffer_end_ + (std::min)(0, limit_);
180 // if (ptr < limit_end_) return {ptr, false};
181 GOOGLE_DCHECK(limit_end_ == buffer_end_ + (std::min)(0, limit_));
182 // At this point we know the following assertion holds.
183 GOOGLE_DCHECK(limit_ > 0);
184 GOOGLE_DCHECK(limit_end_ == buffer_end_); // because limit_ > 0
185 const char* p;
186 do {
187 // We are past the end of buffer_end_, in the slop region.
188 GOOGLE_DCHECK(overrun >= 0);
189 p = NextBuffer(overrun, depth);
190 if (p == nullptr) {
191 // We are at the end of the stream
192 if (PROTOBUF_PREDICT_FALSE(overrun != 0)) return {nullptr, true};
193 GOOGLE_DCHECK(limit_ > 0);
194 limit_end_ = buffer_end_;
195 // Distinguish ending on a pushed limit or ending on end-of-stream.
196 SetEndOfStream();
197 return {buffer_end_, true};
198 }
199 limit_ -= buffer_end_ - p; // Adjust limit_ relative to new anchor
200 p += overrun;
201 overrun = p - buffer_end_;
202 } while (overrun >= 0);
203 limit_end_ = buffer_end_ + std::min(0, limit_);
204 return {p, false};
205 }
206
SkipFallback(const char * ptr,int size)207 const char* EpsCopyInputStream::SkipFallback(const char* ptr, int size) {
208 return AppendSize(ptr, size, [](const char* p, int s) {});
209 }
210
ReadStringFallback(const char * ptr,int size,std::string * str)211 const char* EpsCopyInputStream::ReadStringFallback(const char* ptr, int size,
212 std::string* str) {
213 str->clear();
214 if (PROTOBUF_PREDICT_TRUE(size <= buffer_end_ - ptr + limit_)) {
215 // Reserve the string up to a static safe size. If strings are bigger than
216 // this we proceed by growing the string as needed. This protects against
217 // malicious payloads making protobuf hold on to a lot of memory.
218 str->reserve(str->size() + std::min<int>(size, kSafeStringSize));
219 }
220 return AppendSize(ptr, size,
221 [str](const char* p, int s) { str->append(p, s); });
222 }
223
AppendStringFallback(const char * ptr,int size,std::string * str)224 const char* EpsCopyInputStream::AppendStringFallback(const char* ptr, int size,
225 std::string* str) {
226 if (PROTOBUF_PREDICT_TRUE(size <= buffer_end_ - ptr + limit_)) {
227 // Reserve the string up to a static safe size. If strings are bigger than
228 // this we proceed by growing the string as needed. This protects against
229 // malicious payloads making protobuf hold on to a lot of memory.
230 str->reserve(str->size() + std::min<int>(size, kSafeStringSize));
231 }
232 return AppendSize(ptr, size,
233 [str](const char* p, int s) { str->append(p, s); });
234 }
235
236
237 template <typename Tag, typename T>
ReadRepeatedFixed(const char * ptr,Tag expected_tag,RepeatedField<T> * out)238 const char* EpsCopyInputStream::ReadRepeatedFixed(const char* ptr,
239 Tag expected_tag,
240 RepeatedField<T>* out) {
241 do {
242 out->Add(UnalignedLoad<T>(ptr));
243 ptr += sizeof(T);
244 if (PROTOBUF_PREDICT_FALSE(ptr >= limit_end_)) return ptr;
245 } while (UnalignedLoad<Tag>(ptr) == expected_tag&& ptr += sizeof(Tag));
246 return ptr;
247 }
248
249 template <int>
250 void byteswap(void* p);
251 template <>
byteswap(void * p)252 void byteswap<1>(void* p) {}
253 template <>
byteswap(void * p)254 void byteswap<4>(void* p) {
255 *static_cast<uint32*>(p) = bswap_32(*static_cast<uint32*>(p));
256 }
257 template <>
byteswap(void * p)258 void byteswap<8>(void* p) {
259 *static_cast<uint64*>(p) = bswap_64(*static_cast<uint64*>(p));
260 }
261
262 template <typename T>
ReadPackedFixed(const char * ptr,int size,RepeatedField<T> * out)263 const char* EpsCopyInputStream::ReadPackedFixed(const char* ptr, int size,
264 RepeatedField<T>* out) {
265 int nbytes = buffer_end_ + kSlopBytes - ptr;
266 while (size > nbytes) {
267 int num = nbytes / sizeof(T);
268 int old_entries = out->size();
269 out->Reserve(old_entries + num);
270 int block_size = num * sizeof(T);
271 auto dst = out->AddNAlreadyReserved(num);
272 #ifdef PROTOBUF_LITTLE_ENDIAN
273 std::memcpy(dst, ptr, block_size);
274 #else
275 for (int i = 0; i < num; i++)
276 dst[i] = UnalignedLoad<T>(ptr + i * sizeof(T));
277 #endif
278 size -= block_size;
279 if (limit_ <= kSlopBytes) return nullptr;
280 ptr = Next();
281 if (ptr == nullptr) return nullptr;
282 ptr += kSlopBytes - (nbytes - block_size);
283 nbytes = buffer_end_ + kSlopBytes - ptr;
284 }
285 int num = size / sizeof(T);
286 int old_entries = out->size();
287 out->Reserve(old_entries + num);
288 int block_size = num * sizeof(T);
289 auto dst = out->AddNAlreadyReserved(num);
290 #ifdef PROTOBUF_LITTLE_ENDIAN
291 std::memcpy(dst, ptr, block_size);
292 #else
293 for (int i = 0; i < num; i++) dst[i] = UnalignedLoad<T>(ptr + i * sizeof(T));
294 #endif
295 ptr += block_size;
296 if (size != block_size) return nullptr;
297 return ptr;
298 }
299
InitFrom(io::ZeroCopyInputStream * zcis)300 const char* EpsCopyInputStream::InitFrom(io::ZeroCopyInputStream* zcis) {
301 zcis_ = zcis;
302 const void* data;
303 int size;
304 limit_ = INT_MAX;
305 if (zcis->Next(&data, &size)) {
306 overall_limit_ -= size;
307 if (size > kSlopBytes) {
308 auto ptr = static_cast<const char*>(data);
309 limit_ -= size - kSlopBytes;
310 limit_end_ = buffer_end_ = ptr + size - kSlopBytes;
311 next_chunk_ = buffer_;
312 if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
313 return ptr;
314 } else {
315 limit_end_ = buffer_end_ = buffer_ + kSlopBytes;
316 next_chunk_ = buffer_;
317 auto ptr = buffer_ + 2 * kSlopBytes - size;
318 std::memcpy(ptr, data, size);
319 return ptr;
320 }
321 }
322 overall_limit_ = 0;
323 next_chunk_ = nullptr;
324 size_ = 0;
325 limit_end_ = buffer_end_ = buffer_;
326 return buffer_;
327 }
328
ParseMessage(MessageLite * msg,const char * ptr)329 const char* ParseContext::ParseMessage(MessageLite* msg, const char* ptr) {
330 return ParseMessage<MessageLite>(msg, ptr);
331 }
ParseMessage(Message * msg,const char * ptr)332 const char* ParseContext::ParseMessage(Message* msg, const char* ptr) {
333 // Use reinterptret case to prevent inclusion of non lite header
334 return ParseMessage(reinterpret_cast<MessageLite*>(msg), ptr);
335 }
336
WriteVarint(uint64 val,std::string * s)337 inline void WriteVarint(uint64 val, std::string* s) {
338 while (val >= 128) {
339 uint8 c = val | 0x80;
340 s->push_back(c);
341 val >>= 7;
342 }
343 s->push_back(val);
344 }
345
WriteVarint(uint32 num,uint64 val,std::string * s)346 void WriteVarint(uint32 num, uint64 val, std::string* s) {
347 WriteVarint(num << 3, s);
348 WriteVarint(val, s);
349 }
350
WriteLengthDelimited(uint32 num,StringPiece val,std::string * s)351 void WriteLengthDelimited(uint32 num, StringPiece val, std::string* s) {
352 WriteVarint((num << 3) + 2, s);
353 WriteVarint(val.size(), s);
354 s->append(val.data(), val.size());
355 }
356
VarintParseSlow32(const char * p,uint32 res)357 std::pair<const char*, uint32> VarintParseSlow32(const char* p, uint32 res) {
358 for (std::uint32_t i = 2; i < 5; i++) {
359 uint32 byte = static_cast<uint8>(p[i]);
360 res += (byte - 1) << (7 * i);
361 if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
362 return {p + i + 1, res};
363 }
364 }
365 // Accept >5 bytes
366 for (std::uint32_t i = 5; i < 10; i++) {
367 uint32 byte = static_cast<uint8>(p[i]);
368 if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
369 return {p + i + 1, res};
370 }
371 }
372 return {nullptr, 0};
373 }
374
VarintParseSlow64(const char * p,uint32 res32)375 std::pair<const char*, uint64> VarintParseSlow64(const char* p, uint32 res32) {
376 uint64 res = res32;
377 for (std::uint32_t i = 2; i < 10; i++) {
378 uint64 byte = static_cast<uint8>(p[i]);
379 res += (byte - 1) << (7 * i);
380 if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
381 return {p + i + 1, res};
382 }
383 }
384 return {nullptr, 0};
385 }
386
ReadTagFallback(const char * p,uint32 res)387 std::pair<const char*, uint32> ReadTagFallback(const char* p, uint32 res) {
388 for (std::uint32_t i = 2; i < 5; i++) {
389 uint32 byte = static_cast<uint8>(p[i]);
390 res += (byte - 1) << (7 * i);
391 if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
392 return {p + i + 1, res};
393 }
394 }
395 return {nullptr, 0};
396 }
397
ReadSizeFallback(const char * p,uint32 res)398 std::pair<const char*, int32> ReadSizeFallback(const char* p, uint32 res) {
399 for (std::uint32_t i = 1; i < 4; i++) {
400 uint32 byte = static_cast<uint8>(p[i]);
401 res += (byte - 1) << (7 * i);
402 if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
403 return {p + i + 1, res};
404 }
405 }
406 std::uint32_t byte = static_cast<uint8>(p[4]);
407 if (PROTOBUF_PREDICT_FALSE(byte >= 8)) return {nullptr, 0}; // size >= 2gb
408 res += (byte - 1) << 28;
409 // Protect against sign integer overflow in PushLimit. Limits are relative
410 // to buffer ends and ptr could potential be kSlopBytes beyond a buffer end.
411 // To protect against overflow we reject limits absurdly close to INT_MAX.
412 if (PROTOBUF_PREDICT_FALSE(res > INT_MAX - ParseContext::kSlopBytes)) {
413 return {nullptr, 0};
414 }
415 return {p + 5, res};
416 }
417
StringParser(const char * begin,const char * end,void * object,ParseContext *)418 const char* StringParser(const char* begin, const char* end, void* object,
419 ParseContext*) {
420 auto str = static_cast<std::string*>(object);
421 str->append(begin, end - begin);
422 return end;
423 }
424
425 // Defined in wire_format_lite.cc
426 void PrintUTF8ErrorLog(const char* field_name, const char* operation_str,
427 bool emit_stacktrace);
428
VerifyUTF8(StringPiece str,const char * field_name)429 bool VerifyUTF8(StringPiece str, const char* field_name) {
430 if (!IsStructurallyValidUTF8(str)) {
431 PrintUTF8ErrorLog(field_name, "parsing", false);
432 return false;
433 }
434 return true;
435 }
436
InlineGreedyStringParser(std::string * s,const char * ptr,ParseContext * ctx)437 const char* InlineGreedyStringParser(std::string* s, const char* ptr,
438 ParseContext* ctx) {
439 int size = ReadSize(&ptr);
440 if (!ptr) return nullptr;
441 return ctx->ReadString(ptr, size, s);
442 }
443
444
445 template <typename T, bool sign>
VarintParser(void * object,const char * ptr,ParseContext * ctx)446 const char* VarintParser(void* object, const char* ptr, ParseContext* ctx) {
447 return ctx->ReadPackedVarint(ptr, [object](uint64 varint) {
448 T val;
449 if (sign) {
450 if (sizeof(T) == 8) {
451 val = WireFormatLite::ZigZagDecode64(varint);
452 } else {
453 val = WireFormatLite::ZigZagDecode32(varint);
454 }
455 } else {
456 val = varint;
457 }
458 static_cast<RepeatedField<T>*>(object)->Add(val);
459 });
460 }
461
PackedInt32Parser(void * object,const char * ptr,ParseContext * ctx)462 const char* PackedInt32Parser(void* object, const char* ptr,
463 ParseContext* ctx) {
464 return VarintParser<int32, false>(object, ptr, ctx);
465 }
PackedUInt32Parser(void * object,const char * ptr,ParseContext * ctx)466 const char* PackedUInt32Parser(void* object, const char* ptr,
467 ParseContext* ctx) {
468 return VarintParser<uint32, false>(object, ptr, ctx);
469 }
PackedInt64Parser(void * object,const char * ptr,ParseContext * ctx)470 const char* PackedInt64Parser(void* object, const char* ptr,
471 ParseContext* ctx) {
472 return VarintParser<int64, false>(object, ptr, ctx);
473 }
PackedUInt64Parser(void * object,const char * ptr,ParseContext * ctx)474 const char* PackedUInt64Parser(void* object, const char* ptr,
475 ParseContext* ctx) {
476 return VarintParser<uint64, false>(object, ptr, ctx);
477 }
PackedSInt32Parser(void * object,const char * ptr,ParseContext * ctx)478 const char* PackedSInt32Parser(void* object, const char* ptr,
479 ParseContext* ctx) {
480 return VarintParser<int32, true>(object, ptr, ctx);
481 }
PackedSInt64Parser(void * object,const char * ptr,ParseContext * ctx)482 const char* PackedSInt64Parser(void* object, const char* ptr,
483 ParseContext* ctx) {
484 return VarintParser<int64, true>(object, ptr, ctx);
485 }
486
PackedEnumParser(void * object,const char * ptr,ParseContext * ctx)487 const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx) {
488 return VarintParser<int, false>(object, ptr, ctx);
489 }
490
PackedBoolParser(void * object,const char * ptr,ParseContext * ctx)491 const char* PackedBoolParser(void* object, const char* ptr, ParseContext* ctx) {
492 return VarintParser<bool, false>(object, ptr, ctx);
493 }
494
495 template <typename T>
FixedParser(void * object,const char * ptr,ParseContext * ctx)496 const char* FixedParser(void* object, const char* ptr, ParseContext* ctx) {
497 int size = ReadSize(&ptr);
498 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
499 return ctx->ReadPackedFixed(ptr, size,
500 static_cast<RepeatedField<T>*>(object));
501 }
502
PackedFixed32Parser(void * object,const char * ptr,ParseContext * ctx)503 const char* PackedFixed32Parser(void* object, const char* ptr,
504 ParseContext* ctx) {
505 return FixedParser<uint32>(object, ptr, ctx);
506 }
PackedSFixed32Parser(void * object,const char * ptr,ParseContext * ctx)507 const char* PackedSFixed32Parser(void* object, const char* ptr,
508 ParseContext* ctx) {
509 return FixedParser<int32>(object, ptr, ctx);
510 }
PackedFixed64Parser(void * object,const char * ptr,ParseContext * ctx)511 const char* PackedFixed64Parser(void* object, const char* ptr,
512 ParseContext* ctx) {
513 return FixedParser<uint64>(object, ptr, ctx);
514 }
PackedSFixed64Parser(void * object,const char * ptr,ParseContext * ctx)515 const char* PackedSFixed64Parser(void* object, const char* ptr,
516 ParseContext* ctx) {
517 return FixedParser<int64>(object, ptr, ctx);
518 }
PackedFloatParser(void * object,const char * ptr,ParseContext * ctx)519 const char* PackedFloatParser(void* object, const char* ptr,
520 ParseContext* ctx) {
521 return FixedParser<float>(object, ptr, ctx);
522 }
PackedDoubleParser(void * object,const char * ptr,ParseContext * ctx)523 const char* PackedDoubleParser(void* object, const char* ptr,
524 ParseContext* ctx) {
525 return FixedParser<double>(object, ptr, ctx);
526 }
527
528 class UnknownFieldLiteParserHelper {
529 public:
UnknownFieldLiteParserHelper(std::string * unknown)530 explicit UnknownFieldLiteParserHelper(std::string* unknown)
531 : unknown_(unknown) {}
532
AddVarint(uint32 num,uint64 value)533 void AddVarint(uint32 num, uint64 value) {
534 if (unknown_ == nullptr) return;
535 WriteVarint(num * 8, unknown_);
536 WriteVarint(value, unknown_);
537 }
AddFixed64(uint32 num,uint64 value)538 void AddFixed64(uint32 num, uint64 value) {
539 if (unknown_ == nullptr) return;
540 WriteVarint(num * 8 + 1, unknown_);
541 char buffer[8];
542 io::CodedOutputStream::WriteLittleEndian64ToArray(
543 value, reinterpret_cast<uint8*>(buffer));
544 unknown_->append(buffer, 8);
545 }
ParseLengthDelimited(uint32 num,const char * ptr,ParseContext * ctx)546 const char* ParseLengthDelimited(uint32 num, const char* ptr,
547 ParseContext* ctx) {
548 int size = ReadSize(&ptr);
549 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
550 if (unknown_ == nullptr) return ctx->Skip(ptr, size);
551 WriteVarint(num * 8 + 2, unknown_);
552 WriteVarint(size, unknown_);
553 return ctx->AppendString(ptr, size, unknown_);
554 }
ParseGroup(uint32 num,const char * ptr,ParseContext * ctx)555 const char* ParseGroup(uint32 num, const char* ptr, ParseContext* ctx) {
556 if (unknown_) WriteVarint(num * 8 + 3, unknown_);
557 ptr = ctx->ParseGroup(this, ptr, num * 8 + 3);
558 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
559 if (unknown_) WriteVarint(num * 8 + 4, unknown_);
560 return ptr;
561 }
AddFixed32(uint32 num,uint32 value)562 void AddFixed32(uint32 num, uint32 value) {
563 if (unknown_ == nullptr) return;
564 WriteVarint(num * 8 + 5, unknown_);
565 char buffer[4];
566 io::CodedOutputStream::WriteLittleEndian32ToArray(
567 value, reinterpret_cast<uint8*>(buffer));
568 unknown_->append(buffer, 4);
569 }
570
_InternalParse(const char * ptr,ParseContext * ctx)571 const char* _InternalParse(const char* ptr, ParseContext* ctx) {
572 return WireFormatParser(*this, ptr, ctx);
573 }
574
575 private:
576 std::string* unknown_;
577 };
578
UnknownGroupLiteParse(std::string * unknown,const char * ptr,ParseContext * ctx)579 const char* UnknownGroupLiteParse(std::string* unknown, const char* ptr,
580 ParseContext* ctx) {
581 UnknownFieldLiteParserHelper field_parser(unknown);
582 return WireFormatParser(field_parser, ptr, ctx);
583 }
584
UnknownFieldParse(uint32 tag,std::string * unknown,const char * ptr,ParseContext * ctx)585 const char* UnknownFieldParse(uint32 tag, std::string* unknown, const char* ptr,
586 ParseContext* ctx) {
587 UnknownFieldLiteParserHelper field_parser(unknown);
588 return FieldParser(tag, field_parser, ptr, ctx);
589 }
590
591 } // namespace internal
592 } // namespace protobuf
593 } // namespace google
594