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 d)51 bool ParseEndsInSlopRegion(const char* begin, int overrun, int d) {
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 = ParseVarint64(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         d++;
83         break;
84       }
85       case 4: {                    // end group
86         if (--d < 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 
Next(int overrun,int d)102 const char* EpsCopyInputStream::Next(int overrun, int d) {
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       (d < 0 || !ParseEndsInSlopRegion(buffer_, overrun, d))) {
119     const void* data;
120     // ZeroCopyInputStream indicates Next may return 0 size buffers. Hence
121     // we loop.
122     while (zcis_->Next(&data, &size_)) {
123       overall_limit_ -= size_;
124       if (size_ > kSlopBytes) {
125         // We got a large chunk
126         std::memcpy(buffer_ + kSlopBytes, data, kSlopBytes);
127         next_chunk_ = static_cast<const char*>(data);
128         buffer_end_ = buffer_ + kSlopBytes;
129         if (aliasing_ >= kNoDelta) aliasing_ = kOnPatch;
130         return buffer_;
131       } else if (size_ > 0) {
132         std::memcpy(buffer_ + kSlopBytes, data, size_);
133         next_chunk_ = buffer_;
134         buffer_end_ = buffer_ + size_;
135         if (aliasing_ >= kNoDelta) aliasing_ = kOnPatch;
136         return buffer_;
137       }
138       GOOGLE_DCHECK(size_ == 0) << size_;
139     }
140     overall_limit_ = 0;  // Next failed, no more needs for next
141   }
142   // End of stream or array
143   if (aliasing_ == kNoDelta) {
144     // If there is no more block and aliasing is true, the previous block
145     // is still valid and we can alias. We have users relying on string_view's
146     // obtained from protos to outlive the proto, when the parse was from an
147     // array. This guarantees string_view's are always aliased if parsed from
148     // an array.
149     aliasing_ = reinterpret_cast<std::uintptr_t>(buffer_end_) -
150                 reinterpret_cast<std::uintptr_t>(buffer_);
151   }
152   next_chunk_ = nullptr;
153   buffer_end_ = buffer_ + kSlopBytes;
154   size_ = 0;
155   return buffer_;
156 }
157 
DoneFallback(const char * ptr,int d)158 std::pair<const char*, bool> EpsCopyInputStream::DoneFallback(const char* ptr,
159                                                               int d) {
160   GOOGLE_DCHECK(ptr >= limit_end_);
161   int overrun = ptr - buffer_end_;
162   GOOGLE_DCHECK(overrun <= kSlopBytes);  // Guaranteed by parse loop.
163   // Did we exceeded the limit (parse error).
164   if (PROTOBUF_PREDICT_FALSE(overrun > limit_)) return {nullptr, true};
165   GOOGLE_DCHECK(overrun != limit_);  // Guaranteed by caller.
166   GOOGLE_DCHECK(overrun < limit_);   // Follows from above
167   // TODO(gerbens) Instead of this dcheck we could just assign, and remove
168   // updating the limit_end from PopLimit, ie.
169   // limit_end_ = buffer_end_ + (std::min)(0, limit_);
170   // if (ptr < limit_end_) return {ptr, false};
171   GOOGLE_DCHECK(limit_end_ == buffer_end_ + (std::min)(0, limit_));
172   // At this point we know the following assertion holds.
173   GOOGLE_DCHECK(limit_ > 0);
174   GOOGLE_DCHECK(limit_end_ == buffer_end_);  // because limit_ > 0
175   do {
176     // We are past the end of buffer_end_, in the slop region.
177     GOOGLE_DCHECK(overrun >= 0);
178     auto p = Next(overrun, d);
179     if (p == nullptr) {
180       // We are at the end of the stream
181       if (PROTOBUF_PREDICT_FALSE(overrun != 0)) return {nullptr, true};
182       GOOGLE_DCHECK(limit_ > 0);
183       limit_end_ = buffer_end_;
184       // Distinquish ending on a pushed limit or ending on end-of-stream.
185       SetEndOfStream();
186       return {ptr, true};
187     }
188     limit_ -= buffer_end_ - p;  // Adjust limit_ relative to new anchor
189     ptr = p + overrun;
190     overrun = ptr - buffer_end_;
191   } while (overrun >= 0);
192   limit_end_ = buffer_end_ + std::min(0, limit_);
193   return {ptr, false};
194 }
195 
SkipFallback(const char * ptr,int size)196 const char* EpsCopyInputStream::SkipFallback(const char* ptr, int size) {
197   return AppendSize(ptr, size, [](const char* p, int s) {});
198 }
199 
ReadStringFallback(const char * ptr,int size,std::string * s)200 const char* EpsCopyInputStream::ReadStringFallback(const char* ptr, int size,
201                                                    std::string* s) {
202   s->clear();
203   // TODO(gerbens) assess security. At the moment its parity with
204   // CodedInputStream but it allows a payload to reserve large memory.
205   if (PROTOBUF_PREDICT_TRUE(size <= buffer_end_ - ptr + limit_)) {
206     s->reserve(size);
207   }
208   return AppendStringFallback(ptr, size, s);
209 }
210 
AppendStringFallback(const char * ptr,int size,std::string * str)211 const char* EpsCopyInputStream::AppendStringFallback(const char* ptr, int size,
212                                                      std::string* str) {
213   // TODO(gerbens) assess security. At the moment its parity with
214   // CodedInputStream but it allows a payload to reserve large memory.
215   if (PROTOBUF_PREDICT_TRUE(size <= buffer_end_ - ptr + limit_)) {
216     str->reserve(size);
217   }
218   return AppendSize(ptr, size,
219                     [str](const char* p, int s) { str->append(p, s); });
220 }
221 
222 
223 template <typename Tag, typename T>
ReadRepeatedFixed(const char * ptr,Tag expected_tag,RepeatedField<T> * out)224 const char* EpsCopyInputStream::ReadRepeatedFixed(const char* ptr,
225                                                   Tag expected_tag,
226                                                   RepeatedField<T>* out) {
227   do {
228     out->Add(UnalignedLoad<T>(ptr));
229     ptr += sizeof(T);
230     if (PROTOBUF_PREDICT_FALSE(ptr >= limit_end_)) return ptr;
231   } while (UnalignedLoad<Tag>(ptr) == expected_tag&& ptr += sizeof(Tag));
232   return ptr;
233 }
234 
235 template <typename T>
ReadPackedFixed(const char * ptr,int size,RepeatedField<T> * out)236 const char* EpsCopyInputStream::ReadPackedFixed(const char* ptr, int size,
237                                                 RepeatedField<T>* out) {
238   int nbytes = buffer_end_ + kSlopBytes - ptr;
239   while (size > nbytes) {
240     int num = nbytes / sizeof(T);
241     int old_entries = out->size();
242     out->Reserve(old_entries + num);
243     int block_size = num * sizeof(T);
244     std::memcpy(out->AddNAlreadyReserved(num), ptr, block_size);
245     ptr += block_size;
246     size -= block_size;
247     if (DoneWithCheck(&ptr, -1)) return nullptr;
248     nbytes = buffer_end_ + kSlopBytes - ptr;
249   }
250   int num = size / sizeof(T);
251   int old_entries = out->size();
252   out->Reserve(old_entries + num);
253   int block_size = num * sizeof(T);
254   std::memcpy(out->AddNAlreadyReserved(num), ptr, block_size);
255   ptr += block_size;
256   if (size != block_size) return nullptr;
257   return ptr;
258 }
259 
InitFrom(io::ZeroCopyInputStream * zcis)260 const char* EpsCopyInputStream::InitFrom(io::ZeroCopyInputStream* zcis) {
261   zcis_ = zcis;
262   const void* data;
263   int size;
264   limit_ = INT_MAX;
265   if (zcis->Next(&data, &size)) {
266     overall_limit_ -= size;
267     if (size > kSlopBytes) {
268       auto ptr = static_cast<const char*>(data);
269       limit_ -= size - kSlopBytes;
270       limit_end_ = buffer_end_ = ptr + size - kSlopBytes;
271       next_chunk_ = buffer_;
272       if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
273       return ptr;
274     } else {
275       limit_end_ = buffer_end_ = buffer_ + kSlopBytes;
276       next_chunk_ = buffer_;
277       auto ptr = buffer_ + 2 * kSlopBytes - size;
278       std::memcpy(ptr, data, size);
279       return ptr;
280     }
281   }
282   overall_limit_ = 0;
283   next_chunk_ = nullptr;
284   size_ = 0;
285   limit_end_ = buffer_end_ = buffer_;
286   return buffer_;
287 }
288 
289 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
ParseMessage(MessageLite * msg,const char * ptr)290 const char* ParseContext::ParseMessage(MessageLite* msg, const char* ptr) {
291   return ParseMessage<MessageLite>(msg, ptr);
292 }
ParseMessage(Message * msg,const char * ptr)293 const char* ParseContext::ParseMessage(Message* msg, const char* ptr) {
294   // Use reinterptret case to prevent inclusion of non lite header
295   return ParseMessage(reinterpret_cast<MessageLite*>(msg), ptr);
296 }
297 #endif
298 
WriteVarint(uint64 val,std::string * s)299 inline void WriteVarint(uint64 val, std::string* s) {
300   while (val >= 128) {
301     uint8 c = val | 0x80;
302     s->push_back(c);
303     val >>= 7;
304   }
305   s->push_back(val);
306 }
307 
WriteVarint(uint32 num,uint64 val,std::string * s)308 void WriteVarint(uint32 num, uint64 val, std::string* s) {
309   WriteVarint(num << 3, s);
310   WriteVarint(val, s);
311 }
312 
WriteLengthDelimited(uint32 num,StringPiece val,std::string * s)313 void WriteLengthDelimited(uint32 num, StringPiece val, std::string* s) {
314   WriteVarint((num << 3) + 2, s);
315   WriteVarint(val.size(), s);
316   s->append(val.data(), val.size());
317 }
318 
ReadTagFallback(const char * p,uint32 res)319 std::pair<const char*, uint32> ReadTagFallback(const char* p, uint32 res) {
320   for (std::uint32_t i = 0; i < 3; i++) {
321     std::uint32_t byte = static_cast<uint8>(p[i]);
322     res += (byte - 1) << (7 * (i + 2));
323     if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
324       return {p + i + 1, res};
325     }
326   }
327   return {nullptr, 0};
328 }
329 
ParseVarint64Fallback(const char * p,uint64 res)330 std::pair<const char*, uint64> ParseVarint64Fallback(const char* p,
331                                                      uint64 res) {
332   return ParseVarint64FallbackInline(p, res);
333 }
334 
ReadSizeFallback(const char * p,uint32 first)335 std::pair<const char*, int32> ReadSizeFallback(const char* p, uint32 first) {
336   uint32 tmp;
337   auto res = VarintParse<4>(p + 1, &tmp);
338   if (tmp >= (1 << 24) - ParseContext::kSlopBytes) return {nullptr, 0};
339   return {res, (tmp << 7) + first - 0x80};
340 }
341 
StringParser(const char * begin,const char * end,void * object,ParseContext *)342 const char* StringParser(const char* begin, const char* end, void* object,
343                          ParseContext*) {
344   auto str = static_cast<std::string*>(object);
345   str->append(begin, end - begin);
346   return end;
347 }
348 
349 // Defined in wire_format_lite.cc
350 void PrintUTF8ErrorLog(const char* field_name, const char* operation_str,
351                        bool emit_stacktrace);
352 
VerifyUTF8(StringPiece str,const char * field_name)353 bool VerifyUTF8(StringPiece str, const char* field_name) {
354   if (!IsStructurallyValidUTF8(str)) {
355     PrintUTF8ErrorLog(field_name, "parsing", false);
356     return false;
357   }
358   return true;
359 }
360 
InlineGreedyStringParser(std::string * s,const char * ptr,ParseContext * ctx)361 const char* InlineGreedyStringParser(std::string* s, const char* ptr,
362                                      ParseContext* ctx) {
363   int size = ReadSize(&ptr);
364   if (!ptr) return nullptr;
365   return ctx->ReadString(ptr, size, s);
366 }
367 
InlineGreedyStringParserUTF8(std::string * s,const char * ptr,ParseContext * ctx,const char * field_name)368 const char* InlineGreedyStringParserUTF8(std::string* s, const char* ptr,
369                                          ParseContext* ctx,
370                                          const char* field_name) {
371   auto p = InlineGreedyStringParser(s, ptr, ctx);
372   GOOGLE_PROTOBUF_PARSER_ASSERT(VerifyUTF8(*s, field_name));
373   return p;
374 }
375 
376 
377 template <typename T, bool sign>
VarintParser(void * object,const char * ptr,ParseContext * ctx)378 const char* VarintParser(void* object, const char* ptr, ParseContext* ctx) {
379   return ctx->ReadPackedVarint(ptr, [object](uint64 varint) {
380     T val;
381     if (sign) {
382       if (sizeof(T) == 8) {
383         val = WireFormatLite::ZigZagDecode64(varint);
384       } else {
385         val = WireFormatLite::ZigZagDecode32(varint);
386       }
387     } else {
388       val = varint;
389     }
390     static_cast<RepeatedField<T>*>(object)->Add(val);
391   });
392 }
393 
PackedInt32Parser(void * object,const char * ptr,ParseContext * ctx)394 const char* PackedInt32Parser(void* object, const char* ptr,
395                               ParseContext* ctx) {
396   return VarintParser<int32, false>(object, ptr, ctx);
397 }
PackedUInt32Parser(void * object,const char * ptr,ParseContext * ctx)398 const char* PackedUInt32Parser(void* object, const char* ptr,
399                                ParseContext* ctx) {
400   return VarintParser<uint32, false>(object, ptr, ctx);
401 }
PackedInt64Parser(void * object,const char * ptr,ParseContext * ctx)402 const char* PackedInt64Parser(void* object, const char* ptr,
403                               ParseContext* ctx) {
404   return VarintParser<int64, false>(object, ptr, ctx);
405 }
PackedUInt64Parser(void * object,const char * ptr,ParseContext * ctx)406 const char* PackedUInt64Parser(void* object, const char* ptr,
407                                ParseContext* ctx) {
408   return VarintParser<uint64, false>(object, ptr, ctx);
409 }
PackedSInt32Parser(void * object,const char * ptr,ParseContext * ctx)410 const char* PackedSInt32Parser(void* object, const char* ptr,
411                                ParseContext* ctx) {
412   return VarintParser<int32, true>(object, ptr, ctx);
413 }
PackedSInt64Parser(void * object,const char * ptr,ParseContext * ctx)414 const char* PackedSInt64Parser(void* object, const char* ptr,
415                                ParseContext* ctx) {
416   return VarintParser<int64, true>(object, ptr, ctx);
417 }
418 
PackedEnumParser(void * object,const char * ptr,ParseContext * ctx)419 const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx) {
420   return VarintParser<int, false>(object, ptr, ctx);
421 }
422 
PackedEnumParser(void * object,const char * ptr,ParseContext * ctx,bool (* is_valid)(int),InternalMetadataWithArenaLite * metadata,int field_num)423 const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx,
424                              bool (*is_valid)(int),
425                              InternalMetadataWithArenaLite* metadata,
426                              int field_num) {
427   return ctx->ReadPackedVarint(
428       ptr, [object, is_valid, metadata, field_num](uint64 val) {
429         if (is_valid(val)) {
430           static_cast<RepeatedField<int>*>(object)->Add(val);
431         } else {
432           WriteVarint(field_num, val, metadata->mutable_unknown_fields());
433         }
434       });
435 }
436 
PackedEnumParserArg(void * object,const char * ptr,ParseContext * ctx,bool (* is_valid)(const void *,int),const void * data,InternalMetadataWithArenaLite * metadata,int field_num)437 const char* PackedEnumParserArg(void* object, const char* ptr,
438                                 ParseContext* ctx,
439                                 bool (*is_valid)(const void*, int),
440                                 const void* data,
441                                 InternalMetadataWithArenaLite* metadata,
442                                 int field_num) {
443   return ctx->ReadPackedVarint(
444       ptr, [object, is_valid, data, metadata, field_num](uint64 val) {
445         if (is_valid(data, val)) {
446           static_cast<RepeatedField<int>*>(object)->Add(val);
447         } else {
448           WriteVarint(field_num, val, metadata->mutable_unknown_fields());
449         }
450       });
451 }
452 
PackedBoolParser(void * object,const char * ptr,ParseContext * ctx)453 const char* PackedBoolParser(void* object, const char* ptr, ParseContext* ctx) {
454   return VarintParser<bool, false>(object, ptr, ctx);
455 }
456 
457 template <typename T>
FixedParser(void * object,const char * ptr,ParseContext * ctx)458 const char* FixedParser(void* object, const char* ptr, ParseContext* ctx) {
459   int size = ReadSize(&ptr);
460   GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
461   return ctx->ReadPackedFixed(ptr, size,
462                               static_cast<RepeatedField<T>*>(object));
463 }
464 
PackedFixed32Parser(void * object,const char * ptr,ParseContext * ctx)465 const char* PackedFixed32Parser(void* object, const char* ptr,
466                                 ParseContext* ctx) {
467   return FixedParser<uint32>(object, ptr, ctx);
468 }
PackedSFixed32Parser(void * object,const char * ptr,ParseContext * ctx)469 const char* PackedSFixed32Parser(void* object, const char* ptr,
470                                  ParseContext* ctx) {
471   return FixedParser<int32>(object, ptr, ctx);
472 }
PackedFixed64Parser(void * object,const char * ptr,ParseContext * ctx)473 const char* PackedFixed64Parser(void* object, const char* ptr,
474                                 ParseContext* ctx) {
475   return FixedParser<uint64>(object, ptr, ctx);
476 }
PackedSFixed64Parser(void * object,const char * ptr,ParseContext * ctx)477 const char* PackedSFixed64Parser(void* object, const char* ptr,
478                                  ParseContext* ctx) {
479   return FixedParser<int64>(object, ptr, ctx);
480 }
PackedFloatParser(void * object,const char * ptr,ParseContext * ctx)481 const char* PackedFloatParser(void* object, const char* ptr,
482                               ParseContext* ctx) {
483   return FixedParser<float>(object, ptr, ctx);
484 }
PackedDoubleParser(void * object,const char * ptr,ParseContext * ctx)485 const char* PackedDoubleParser(void* object, const char* ptr,
486                                ParseContext* ctx) {
487   return FixedParser<double>(object, ptr, ctx);
488 }
489 
490 class UnknownFieldLiteParserHelper {
491  public:
UnknownFieldLiteParserHelper(std::string * unknown)492   explicit UnknownFieldLiteParserHelper(std::string* unknown)
493       : unknown_(unknown) {}
494 
AddVarint(uint32 num,uint64 value)495   void AddVarint(uint32 num, uint64 value) {
496     if (unknown_ == nullptr) return;
497     WriteVarint(num * 8, unknown_);
498     WriteVarint(value, unknown_);
499   }
AddFixed64(uint32 num,uint64 value)500   void AddFixed64(uint32 num, uint64 value) {
501     if (unknown_ == nullptr) return;
502     WriteVarint(num * 8 + 1, unknown_);
503     char buffer[8];
504     std::memcpy(buffer, &value, 8);
505     unknown_->append(buffer, 8);
506   }
ParseLengthDelimited(uint32 num,const char * ptr,ParseContext * ctx)507   const char* ParseLengthDelimited(uint32 num, const char* ptr,
508                                    ParseContext* ctx) {
509     int size = ReadSize(&ptr);
510     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
511     if (unknown_ == nullptr) return ctx->Skip(ptr, size);
512     WriteVarint(num * 8 + 2, unknown_);
513     WriteVarint(size, unknown_);
514     return ctx->AppendString(ptr, size, unknown_);
515   }
ParseGroup(uint32 num,const char * ptr,ParseContext * ctx)516   const char* ParseGroup(uint32 num, const char* ptr, ParseContext* ctx) {
517     if (unknown_) WriteVarint(num * 8 + 3, unknown_);
518     ptr = ctx->ParseGroup(this, ptr, num * 8 + 3);
519     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
520     if (unknown_) WriteVarint(num * 8 + 4, unknown_);
521     return ptr;
522   }
AddFixed32(uint32 num,uint32 value)523   void AddFixed32(uint32 num, uint32 value) {
524     if (unknown_ == nullptr) return;
525     WriteVarint(num * 8 + 5, unknown_);
526     char buffer[4];
527     std::memcpy(buffer, &value, 4);
528     unknown_->append(buffer, 4);
529   }
530 
_InternalParse(const char * ptr,ParseContext * ctx)531   const char* _InternalParse(const char* ptr, ParseContext* ctx) {
532     return WireFormatParser(*this, ptr, ctx);
533   }
534 
535  private:
536   std::string* unknown_;
537 };
538 
UnknownGroupLiteParse(std::string * unknown,const char * ptr,ParseContext * ctx)539 const char* UnknownGroupLiteParse(std::string* unknown, const char* ptr,
540                                   ParseContext* ctx) {
541   UnknownFieldLiteParserHelper field_parser(unknown);
542   return WireFormatParser(field_parser, ptr, ctx);
543 }
544 
UnknownFieldParse(uint32 tag,std::string * unknown,const char * ptr,ParseContext * ctx)545 const char* UnknownFieldParse(uint32 tag, std::string* unknown, const char* ptr,
546                               ParseContext* ctx) {
547   UnknownFieldLiteParserHelper field_parser(unknown);
548   return FieldParser(tag, field_parser, ptr, ctx);
549 }
550 
UnknownFieldParse(uint32 tag,InternalMetadataWithArenaLite * metadata,const char * ptr,ParseContext * ctx)551 const char* UnknownFieldParse(uint32 tag,
552                               InternalMetadataWithArenaLite* metadata,
553                               const char* ptr, ParseContext* ctx) {
554   return UnknownFieldParse(tag, metadata->mutable_unknown_fields(), ptr, ctx);
555 }
556 
557 }  // namespace internal
558 }  // namespace protobuf
559 }  // namespace google
560