• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = 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         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 (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 
DoneFallback(const char * ptr,int d)157 std::pair<const char*, bool> EpsCopyInputStream::DoneFallback(const char* ptr,
158                                                               int d) {
159   GOOGLE_DCHECK(ptr >= limit_end_);
160   int overrun = ptr - buffer_end_;
161   GOOGLE_DCHECK(overrun <= kSlopBytes);  // Guaranteed by parse loop.
162   // Did we exceeded the limit (parse error).
163   if (PROTOBUF_PREDICT_FALSE(overrun > limit_)) return {nullptr, true};
164   GOOGLE_DCHECK(overrun != limit_);  // Guaranteed by caller.
165   GOOGLE_DCHECK(overrun < limit_);   // Follows from above
166   // TODO(gerbens) Instead of this dcheck we could just assign, and remove
167   // updating the limit_end from PopLimit, ie.
168   // limit_end_ = buffer_end_ + (std::min)(0, limit_);
169   // if (ptr < limit_end_) return {ptr, false};
170   GOOGLE_DCHECK(limit_end_ == buffer_end_ + (std::min)(0, limit_));
171   // At this point we know the following assertion holds.
172   GOOGLE_DCHECK(limit_ > 0);
173   GOOGLE_DCHECK(limit_end_ == buffer_end_);  // because limit_ > 0
174   do {
175     // We are past the end of buffer_end_, in the slop region.
176     GOOGLE_DCHECK(overrun >= 0);
177     auto p = Next(overrun, d);
178     if (p == nullptr) {
179       // We are at the end of the stream
180       if (PROTOBUF_PREDICT_FALSE(overrun != 0)) return {nullptr, true};
181       GOOGLE_DCHECK(limit_ > 0);
182       limit_end_ = buffer_end_;
183       // Distinquish ending on a pushed limit or ending on end-of-stream.
184       SetEndOfStream();
185       return {ptr, true};
186     }
187     limit_ -= buffer_end_ - p;  // Adjust limit_ relative to new anchor
188     ptr = p + overrun;
189     overrun = ptr - buffer_end_;
190   } while (overrun >= 0);
191   limit_end_ = buffer_end_ + std::min(0, limit_);
192   return {ptr, false};
193 }
194 
SkipFallback(const char * ptr,int size)195 const char* EpsCopyInputStream::SkipFallback(const char* ptr, int size) {
196   return AppendSize(ptr, size, [](const char* p, int s) {});
197 }
198 
ReadStringFallback(const char * ptr,int size,std::string * str)199 const char* EpsCopyInputStream::ReadStringFallback(const char* ptr, int size,
200                                                    std::string* str) {
201   str->clear();
202   if (PROTOBUF_PREDICT_TRUE(size <= buffer_end_ - ptr + limit_)) {
203     // Reserve the string up to a static safe size. If strings are bigger than
204     // this we proceed by growing the string as needed. This protects against
205     // malicious payloads making protobuf hold on to a lot of memory.
206     str->reserve(str->size() + std::min<int>(size, kSafeStringSize));
207   }
208   return AppendSize(ptr, size,
209                     [str](const char* p, int s) { str->append(p, s); });
210 }
211 
AppendStringFallback(const char * ptr,int size,std::string * str)212 const char* EpsCopyInputStream::AppendStringFallback(const char* ptr, int size,
213                                                      std::string* str) {
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 
224 
225 template <typename Tag, typename T>
ReadRepeatedFixed(const char * ptr,Tag expected_tag,RepeatedField<T> * out)226 const char* EpsCopyInputStream::ReadRepeatedFixed(const char* ptr,
227                                                   Tag expected_tag,
228                                                   RepeatedField<T>* out) {
229   do {
230     out->Add(UnalignedLoad<T>(ptr));
231     ptr += sizeof(T);
232     if (PROTOBUF_PREDICT_FALSE(ptr >= limit_end_)) return ptr;
233   } while (UnalignedLoad<Tag>(ptr) == expected_tag&& ptr += sizeof(Tag));
234   return ptr;
235 }
236 
237 template <int>
238 void byteswap(void* p);
239 template <>
byteswap(void * p)240 void byteswap<1>(void* p) {}
241 template <>
byteswap(void * p)242 void byteswap<4>(void* p) {
243   *static_cast<uint32*>(p) = bswap_32(*static_cast<uint32*>(p));
244 }
245 template <>
byteswap(void * p)246 void byteswap<8>(void* p) {
247   *static_cast<uint64*>(p) = bswap_64(*static_cast<uint64*>(p));
248 }
249 
250 template <typename T>
ReadPackedFixed(const char * ptr,int size,RepeatedField<T> * out)251 const char* EpsCopyInputStream::ReadPackedFixed(const char* ptr, int size,
252                                                 RepeatedField<T>* out) {
253   int nbytes = buffer_end_ + kSlopBytes - ptr;
254   while (size > nbytes) {
255     int num = nbytes / sizeof(T);
256     int old_entries = out->size();
257     out->Reserve(old_entries + num);
258     int block_size = num * sizeof(T);
259     auto dst = out->AddNAlreadyReserved(num);
260 #ifdef PROTOBUF_LITTLE_ENDIAN
261     std::memcpy(dst, ptr, block_size);
262 #else
263     for (int i = 0; i < num; i++)
264       dst[i] = UnalignedLoad<T>(ptr + i * sizeof(T));
265 #endif
266     ptr += block_size;
267     size -= block_size;
268     if (DoneWithCheck(&ptr, -1)) return nullptr;
269     nbytes = buffer_end_ + kSlopBytes - ptr;
270   }
271   int num = size / sizeof(T);
272   int old_entries = out->size();
273   out->Reserve(old_entries + num);
274   int block_size = num * sizeof(T);
275   auto dst = out->AddNAlreadyReserved(num);
276 #ifdef PROTOBUF_LITTLE_ENDIAN
277   std::memcpy(dst, ptr, block_size);
278 #else
279   for (int i = 0; i < num; i++) dst[i] = UnalignedLoad<T>(ptr + i * sizeof(T));
280 #endif
281   ptr += block_size;
282   if (size != block_size) return nullptr;
283   return ptr;
284 }
285 
InitFrom(io::ZeroCopyInputStream * zcis)286 const char* EpsCopyInputStream::InitFrom(io::ZeroCopyInputStream* zcis) {
287   zcis_ = zcis;
288   const void* data;
289   int size;
290   limit_ = INT_MAX;
291   if (zcis->Next(&data, &size)) {
292     overall_limit_ -= size;
293     if (size > kSlopBytes) {
294       auto ptr = static_cast<const char*>(data);
295       limit_ -= size - kSlopBytes;
296       limit_end_ = buffer_end_ = ptr + size - kSlopBytes;
297       next_chunk_ = buffer_;
298       if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
299       return ptr;
300     } else {
301       limit_end_ = buffer_end_ = buffer_ + kSlopBytes;
302       next_chunk_ = buffer_;
303       auto ptr = buffer_ + 2 * kSlopBytes - size;
304       std::memcpy(ptr, data, size);
305       return ptr;
306     }
307   }
308   overall_limit_ = 0;
309   next_chunk_ = nullptr;
310   size_ = 0;
311   limit_end_ = buffer_end_ = buffer_;
312   return buffer_;
313 }
314 
ParseMessage(MessageLite * msg,const char * ptr)315 const char* ParseContext::ParseMessage(MessageLite* msg, const char* ptr) {
316   return ParseMessage<MessageLite>(msg, ptr);
317 }
ParseMessage(Message * msg,const char * ptr)318 const char* ParseContext::ParseMessage(Message* msg, const char* ptr) {
319   // Use reinterptret case to prevent inclusion of non lite header
320   return ParseMessage(reinterpret_cast<MessageLite*>(msg), ptr);
321 }
322 
WriteVarint(uint64 val,std::string * s)323 inline void WriteVarint(uint64 val, std::string* s) {
324   while (val >= 128) {
325     uint8 c = val | 0x80;
326     s->push_back(c);
327     val >>= 7;
328   }
329   s->push_back(val);
330 }
331 
WriteVarint(uint32 num,uint64 val,std::string * s)332 void WriteVarint(uint32 num, uint64 val, std::string* s) {
333   WriteVarint(num << 3, s);
334   WriteVarint(val, s);
335 }
336 
WriteLengthDelimited(uint32 num,StringPiece val,std::string * s)337 void WriteLengthDelimited(uint32 num, StringPiece val, std::string* s) {
338   WriteVarint((num << 3) + 2, s);
339   WriteVarint(val.size(), s);
340   s->append(val.data(), val.size());
341 }
342 
VarintParseSlow32(const char * p,uint32 res)343 std::pair<const char*, uint32> VarintParseSlow32(const char* p, uint32 res) {
344   for (std::uint32_t i = 2; i < 5; i++) {
345     uint32 byte = static_cast<uint8>(p[i]);
346     res += (byte - 1) << (7 * i);
347     if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
348       return {p + i + 1, res};
349     }
350   }
351   // Accept >5 bytes
352   for (std::uint32_t i = 5; i < 10; i++) {
353     uint32 byte = static_cast<uint8>(p[i]);
354     if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
355       return {p + i + 1, res};
356     }
357   }
358   return {nullptr, 0};
359 }
360 
VarintParseSlow64(const char * p,uint32 res32)361 std::pair<const char*, uint64> VarintParseSlow64(const char* p, uint32 res32) {
362   uint64 res = res32;
363   for (std::uint32_t i = 2; i < 10; i++) {
364     uint64 byte = static_cast<uint8>(p[i]);
365     res += (byte - 1) << (7 * i);
366     if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
367       return {p + i + 1, res};
368     }
369   }
370   return {nullptr, 0};
371 }
372 
ReadTagFallback(const char * p,uint32 res)373 std::pair<const char*, uint32> ReadTagFallback(const char* p, uint32 res) {
374   for (std::uint32_t i = 2; i < 5; i++) {
375     uint32 byte = static_cast<uint8>(p[i]);
376     res += (byte - 1) << (7 * i);
377     if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
378       return {p + i + 1, res};
379     }
380   }
381   return {nullptr, 0};
382 }
383 
ReadSizeFallback(const char * p,uint32 res)384 std::pair<const char*, int32> ReadSizeFallback(const char* p, uint32 res) {
385   for (std::uint32_t i = 1; i < 4; i++) {
386     uint32 byte = static_cast<uint8>(p[i]);
387     res += (byte - 1) << (7 * i);
388     if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
389       return {p + i + 1, res};
390     }
391   }
392   std::uint32_t byte = static_cast<uint8>(p[4]);
393   if (PROTOBUF_PREDICT_FALSE(byte >= 8)) return {nullptr, 0};  // size >= 2gb
394   res += (byte - 1) << 28;
395   // Protect against sign integer overflow in PushLimit. Limits are relative
396   // to buffer ends and ptr could potential be kSlopBytes beyond a buffer end.
397   // To protect against overflow we reject limits absurdly close to INT_MAX.
398   if (PROTOBUF_PREDICT_FALSE(res > INT_MAX - ParseContext::kSlopBytes)) {
399     return {nullptr, 0};
400   }
401   return {p + 5, res};
402 }
403 
StringParser(const char * begin,const char * end,void * object,ParseContext *)404 const char* StringParser(const char* begin, const char* end, void* object,
405                          ParseContext*) {
406   auto str = static_cast<std::string*>(object);
407   str->append(begin, end - begin);
408   return end;
409 }
410 
411 // Defined in wire_format_lite.cc
412 void PrintUTF8ErrorLog(const char* field_name, const char* operation_str,
413                        bool emit_stacktrace);
414 
VerifyUTF8(StringPiece str,const char * field_name)415 bool VerifyUTF8(StringPiece str, const char* field_name) {
416   if (!IsStructurallyValidUTF8(str)) {
417     PrintUTF8ErrorLog(field_name, "parsing", false);
418     return false;
419   }
420   return true;
421 }
422 
InlineGreedyStringParser(std::string * s,const char * ptr,ParseContext * ctx)423 const char* InlineGreedyStringParser(std::string* s, const char* ptr,
424                                      ParseContext* ctx) {
425   int size = ReadSize(&ptr);
426   if (!ptr) return nullptr;
427   return ctx->ReadString(ptr, size, s);
428 }
429 
430 
431 template <typename T, bool sign>
VarintParser(void * object,const char * ptr,ParseContext * ctx)432 const char* VarintParser(void* object, const char* ptr, ParseContext* ctx) {
433   return ctx->ReadPackedVarint(ptr, [object](uint64 varint) {
434     T val;
435     if (sign) {
436       if (sizeof(T) == 8) {
437         val = WireFormatLite::ZigZagDecode64(varint);
438       } else {
439         val = WireFormatLite::ZigZagDecode32(varint);
440       }
441     } else {
442       val = varint;
443     }
444     static_cast<RepeatedField<T>*>(object)->Add(val);
445   });
446 }
447 
PackedInt32Parser(void * object,const char * ptr,ParseContext * ctx)448 const char* PackedInt32Parser(void* object, const char* ptr,
449                               ParseContext* ctx) {
450   return VarintParser<int32, false>(object, ptr, ctx);
451 }
PackedUInt32Parser(void * object,const char * ptr,ParseContext * ctx)452 const char* PackedUInt32Parser(void* object, const char* ptr,
453                                ParseContext* ctx) {
454   return VarintParser<uint32, false>(object, ptr, ctx);
455 }
PackedInt64Parser(void * object,const char * ptr,ParseContext * ctx)456 const char* PackedInt64Parser(void* object, const char* ptr,
457                               ParseContext* ctx) {
458   return VarintParser<int64, false>(object, ptr, ctx);
459 }
PackedUInt64Parser(void * object,const char * ptr,ParseContext * ctx)460 const char* PackedUInt64Parser(void* object, const char* ptr,
461                                ParseContext* ctx) {
462   return VarintParser<uint64, false>(object, ptr, ctx);
463 }
PackedSInt32Parser(void * object,const char * ptr,ParseContext * ctx)464 const char* PackedSInt32Parser(void* object, const char* ptr,
465                                ParseContext* ctx) {
466   return VarintParser<int32, true>(object, ptr, ctx);
467 }
PackedSInt64Parser(void * object,const char * ptr,ParseContext * ctx)468 const char* PackedSInt64Parser(void* object, const char* ptr,
469                                ParseContext* ctx) {
470   return VarintParser<int64, true>(object, ptr, ctx);
471 }
472 
PackedEnumParser(void * object,const char * ptr,ParseContext * ctx)473 const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx) {
474   return VarintParser<int, false>(object, ptr, ctx);
475 }
476 
PackedBoolParser(void * object,const char * ptr,ParseContext * ctx)477 const char* PackedBoolParser(void* object, const char* ptr, ParseContext* ctx) {
478   return VarintParser<bool, false>(object, ptr, ctx);
479 }
480 
481 template <typename T>
FixedParser(void * object,const char * ptr,ParseContext * ctx)482 const char* FixedParser(void* object, const char* ptr, ParseContext* ctx) {
483   int size = ReadSize(&ptr);
484   GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
485   return ctx->ReadPackedFixed(ptr, size,
486                               static_cast<RepeatedField<T>*>(object));
487 }
488 
PackedFixed32Parser(void * object,const char * ptr,ParseContext * ctx)489 const char* PackedFixed32Parser(void* object, const char* ptr,
490                                 ParseContext* ctx) {
491   return FixedParser<uint32>(object, ptr, ctx);
492 }
PackedSFixed32Parser(void * object,const char * ptr,ParseContext * ctx)493 const char* PackedSFixed32Parser(void* object, const char* ptr,
494                                  ParseContext* ctx) {
495   return FixedParser<int32>(object, ptr, ctx);
496 }
PackedFixed64Parser(void * object,const char * ptr,ParseContext * ctx)497 const char* PackedFixed64Parser(void* object, const char* ptr,
498                                 ParseContext* ctx) {
499   return FixedParser<uint64>(object, ptr, ctx);
500 }
PackedSFixed64Parser(void * object,const char * ptr,ParseContext * ctx)501 const char* PackedSFixed64Parser(void* object, const char* ptr,
502                                  ParseContext* ctx) {
503   return FixedParser<int64>(object, ptr, ctx);
504 }
PackedFloatParser(void * object,const char * ptr,ParseContext * ctx)505 const char* PackedFloatParser(void* object, const char* ptr,
506                               ParseContext* ctx) {
507   return FixedParser<float>(object, ptr, ctx);
508 }
PackedDoubleParser(void * object,const char * ptr,ParseContext * ctx)509 const char* PackedDoubleParser(void* object, const char* ptr,
510                                ParseContext* ctx) {
511   return FixedParser<double>(object, ptr, ctx);
512 }
513 
514 class UnknownFieldLiteParserHelper {
515  public:
UnknownFieldLiteParserHelper(std::string * unknown)516   explicit UnknownFieldLiteParserHelper(std::string* unknown)
517       : unknown_(unknown) {}
518 
AddVarint(uint32 num,uint64 value)519   void AddVarint(uint32 num, uint64 value) {
520     if (unknown_ == nullptr) return;
521     WriteVarint(num * 8, unknown_);
522     WriteVarint(value, unknown_);
523   }
AddFixed64(uint32 num,uint64 value)524   void AddFixed64(uint32 num, uint64 value) {
525     if (unknown_ == nullptr) return;
526     WriteVarint(num * 8 + 1, unknown_);
527     char buffer[8];
528     io::CodedOutputStream::WriteLittleEndian64ToArray(
529         value, reinterpret_cast<uint8*>(buffer));
530     unknown_->append(buffer, 8);
531   }
ParseLengthDelimited(uint32 num,const char * ptr,ParseContext * ctx)532   const char* ParseLengthDelimited(uint32 num, const char* ptr,
533                                    ParseContext* ctx) {
534     int size = ReadSize(&ptr);
535     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
536     if (unknown_ == nullptr) return ctx->Skip(ptr, size);
537     WriteVarint(num * 8 + 2, unknown_);
538     WriteVarint(size, unknown_);
539     return ctx->AppendString(ptr, size, unknown_);
540   }
ParseGroup(uint32 num,const char * ptr,ParseContext * ctx)541   const char* ParseGroup(uint32 num, const char* ptr, ParseContext* ctx) {
542     if (unknown_) WriteVarint(num * 8 + 3, unknown_);
543     ptr = ctx->ParseGroup(this, ptr, num * 8 + 3);
544     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
545     if (unknown_) WriteVarint(num * 8 + 4, unknown_);
546     return ptr;
547   }
AddFixed32(uint32 num,uint32 value)548   void AddFixed32(uint32 num, uint32 value) {
549     if (unknown_ == nullptr) return;
550     WriteVarint(num * 8 + 5, unknown_);
551     char buffer[4];
552     io::CodedOutputStream::WriteLittleEndian32ToArray(
553         value, reinterpret_cast<uint8*>(buffer));
554     unknown_->append(buffer, 4);
555   }
556 
_InternalParse(const char * ptr,ParseContext * ctx)557   const char* _InternalParse(const char* ptr, ParseContext* ctx) {
558     return WireFormatParser(*this, ptr, ctx);
559   }
560 
561  private:
562   std::string* unknown_;
563 };
564 
UnknownGroupLiteParse(std::string * unknown,const char * ptr,ParseContext * ctx)565 const char* UnknownGroupLiteParse(std::string* unknown, const char* ptr,
566                                   ParseContext* ctx) {
567   UnknownFieldLiteParserHelper field_parser(unknown);
568   return WireFormatParser(field_parser, ptr, ctx);
569 }
570 
UnknownFieldParse(uint32 tag,std::string * unknown,const char * ptr,ParseContext * ctx)571 const char* UnknownFieldParse(uint32 tag, std::string* unknown, const char* ptr,
572                               ParseContext* ctx) {
573   UnknownFieldLiteParserHelper field_parser(unknown);
574   return FieldParser(tag, field_parser, ptr, ctx);
575 }
576 
577 }  // namespace internal
578 }  // namespace protobuf
579 }  // namespace google
580