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