File indexing completed on 2026-09-08 09:12:13
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
0009 #define GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
0010
0011 #include <algorithm>
0012 #include <climits>
0013 #include <cstddef>
0014 #include <cstdint>
0015 #include <cstring>
0016 #include <limits>
0017 #include <string>
0018 #include <type_traits>
0019 #include <utility>
0020
0021 #include "absl/base/config.h"
0022 #include "absl/base/prefetch.h"
0023 #include "absl/log/absl_check.h"
0024 #include "absl/log/absl_log.h"
0025 #include "absl/strings/cord.h"
0026 #include "absl/strings/internal/resize_uninitialized.h"
0027 #include "absl/strings/string_view.h"
0028 #include "absl/types/span.h"
0029 #include "google/protobuf/arena.h"
0030 #include "google/protobuf/arenastring.h"
0031 #include "google/protobuf/endian.h"
0032 #include "google/protobuf/inlined_string_field.h"
0033 #include "google/protobuf/io/coded_stream.h"
0034 #include "google/protobuf/io/zero_copy_stream.h"
0035 #include "google/protobuf/message_lite.h"
0036 #include "google/protobuf/metadata_lite.h"
0037 #include "google/protobuf/micro_string.h"
0038 #include "google/protobuf/port.h"
0039 #include "google/protobuf/repeated_field.h"
0040 #include "google/protobuf/repeated_ptr_field.h"
0041 #include "google/protobuf/wire_format_lite.h"
0042
0043
0044
0045 #include "google/protobuf/port_def.inc"
0046
0047
0048 namespace google {
0049 namespace protobuf {
0050
0051 class UnknownFieldSet;
0052 class DescriptorPool;
0053 class MessageFactory;
0054
0055 namespace internal {
0056
0057
0058 PROTOBUF_EXPORT void WriteVarint(uint32_t num, uint64_t val, std::string* s);
0059 PROTOBUF_EXPORT void WriteLengthDelimited(uint32_t num, absl::string_view val,
0060 std::string* s);
0061
0062 inline void WriteVarint(uint32_t num, uint64_t val, UnknownFieldSet* unknown);
0063 inline void WriteLengthDelimited(uint32_t num, absl::string_view val,
0064 UnknownFieldSet* unknown);
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 class PROTOBUF_EXPORT EpsCopyInputStream {
0105 public:
0106 enum { kMaxCordBytesToCopy = 512 };
0107 explicit EpsCopyInputStream(bool enable_aliasing)
0108 : aliasing_(enable_aliasing ? kOnPatch : kNoAliasing) {}
0109
0110 void BackUp(const char* ptr) {
0111 ABSL_DCHECK(ptr <= buffer_end_ + kSlopBytes);
0112 int count;
0113 if (next_chunk_ == patch_buffer_) {
0114 count = BytesAvailable(ptr);
0115 } else {
0116 count = size_ + static_cast<int>(buffer_end_ - ptr);
0117 }
0118 if (count > 0) StreamBackUp(count);
0119 }
0120
0121
0122
0123
0124
0125 class LimitToken {
0126 public:
0127 LimitToken() { internal::PoisonMemoryRegion(&token_, sizeof(token_)); }
0128
0129 explicit LimitToken(int token) : token_(token) {
0130 internal::UnpoisonMemoryRegion(&token_, sizeof(token_));
0131 }
0132
0133 LimitToken(const LimitToken&) = delete;
0134 LimitToken& operator=(const LimitToken&) = delete;
0135
0136 LimitToken(LimitToken&& other) { *this = std::move(other); }
0137
0138 LimitToken& operator=(LimitToken&& other) {
0139 internal::UnpoisonMemoryRegion(&token_, sizeof(token_));
0140 token_ = other.token_;
0141 internal::PoisonMemoryRegion(&other.token_, sizeof(token_));
0142 return *this;
0143 }
0144
0145 ~LimitToken() { internal::UnpoisonMemoryRegion(&token_, sizeof(token_)); }
0146
0147 int token() && {
0148 int t = token_;
0149 internal::PoisonMemoryRegion(&token_, sizeof(token_));
0150 return t;
0151 }
0152
0153 private:
0154 int token_;
0155 };
0156
0157
0158 [[nodiscard]] LimitToken PushLimit(const char* ptr, int limit) {
0159 ABSL_DCHECK(limit >= 0 && limit <= INT_MAX - kSlopBytes);
0160
0161
0162 limit += static_cast<int>(ptr - buffer_end_);
0163 limit_end_ = buffer_end_ + (std::min)(0, limit);
0164 auto old_limit = limit_;
0165 limit_ = limit;
0166 return LimitToken(old_limit - limit);
0167 }
0168
0169 [[nodiscard]] bool PopLimit(LimitToken delta) {
0170
0171
0172 limit_ = limit_ + std::move(delta).token();
0173 if (ABSL_PREDICT_FALSE(!EndedAtLimit())) return false;
0174
0175
0176 limit_end_ = buffer_end_ + (std::min)(0, limit_);
0177 return true;
0178 }
0179
0180 [[nodiscard]] const char* Skip(const char* ptr, int size) {
0181 if (CanReadFromPtr(size, ptr)) {
0182 return ptr + size;
0183 }
0184 return SkipFallback(ptr, size);
0185 }
0186 [[nodiscard]] const char* ReadString(const char* ptr, int size,
0187 std::string* s) {
0188 if (CanReadFromPtr(size, ptr)) {
0189
0190
0191
0192
0193 absl::strings_internal::STLStringResizeUninitialized(s, size);
0194 char* z = &(*s)[0];
0195 memcpy(z, ptr, size);
0196 return ptr + size;
0197 }
0198 return ReadStringFallback(ptr, size, s);
0199 }
0200 [[nodiscard]] const char* AppendString(const char* ptr, int size,
0201 std::string* s) {
0202 if (CanReadFromPtr(size, ptr)) {
0203 s->append(ptr, size);
0204 return ptr + size;
0205 }
0206 return AppendStringFallback(ptr, size, s);
0207 }
0208
0209 [[nodiscard]] const char* ReadArray(const char* ptr, absl::Span<char> out);
0210 [[nodiscard]] const char* VerifyUTF8(const char* ptr, size_t size);
0211
0212 [[nodiscard]] const char* ReadMicroString(const char* ptr, MicroString& str,
0213 Arena* arena);
0214 [[nodiscard]] const char* ReadMicroStringFallback(const char* ptr, int size,
0215 MicroString& str,
0216 Arena* arena);
0217
0218
0219 [[nodiscard]] const char* ReadArenaString(const char* ptr, ArenaStringPtr* s,
0220 Arena* arena);
0221
0222 [[nodiscard]] const char* ReadCord(const char* ptr, int size,
0223 ::absl::Cord* cord) {
0224 if (IsRequestedLessThanOrEqualTo(
0225 size, std::min<int>(BytesAvailable(ptr), kMaxCordBytesToCopy))) {
0226 *cord = absl::string_view(ptr, size);
0227 return ptr + size;
0228 }
0229 return ReadCordFallback(ptr, size, cord);
0230 }
0231
0232
0233 template <typename FuncT>
0234 [[nodiscard]] const char* ReadChunkAndCallback(const char* ptr, int size,
0235 FuncT&& callback) {
0236 if (CanReadFromPtr(size, ptr)) {
0237 callback(ptr, size);
0238 return ptr + size;
0239 }
0240 return AppendSize(ptr, size, callback);
0241 }
0242
0243 template <typename Tag, typename T>
0244 [[nodiscard]] const char* ReadRepeatedFixed(const char* ptr, Tag expected_tag,
0245 RepeatedField<T>* out);
0246
0247 template <typename T>
0248 [[nodiscard]] const char* ReadPackedFixed(const char* ptr, int size,
0249 RepeatedField<T>* out);
0250 template <typename Add>
0251 [[nodiscard]] const char* ReadPackedVarint(const char* ptr, Add add) {
0252 return ReadPackedVarint(ptr, add, [](int) {});
0253 }
0254 template <typename Add, typename SizeCb>
0255 [[nodiscard]] const char* ReadPackedVarint(const char* ptr, Add add,
0256 SizeCb size_callback);
0257
0258 uint32_t LastTag() const { return last_tag_minus_1_ + 1; }
0259 bool ConsumeEndGroup(uint32_t start_tag) {
0260 bool res = last_tag_minus_1_ == start_tag;
0261 last_tag_minus_1_ = 0;
0262 return res;
0263 }
0264 bool EndedAtLimit() const { return last_tag_minus_1_ == 0; }
0265 bool EndedAtEndOfStream() const { return last_tag_minus_1_ == 1; }
0266 void SetLastTag(uint32_t tag) { last_tag_minus_1_ = tag - 1; }
0267 void SetEndOfStream() { last_tag_minus_1_ = 1; }
0268 bool IsExceedingLimit(const char* ptr) {
0269 return ptr > limit_end_ &&
0270 (next_chunk_ == nullptr || ptr - buffer_end_ > limit_);
0271 }
0272 bool AliasingEnabled() const { return aliasing_ != kNoAliasing; }
0273 int BytesUntilLimit(const char* ptr) const {
0274 return limit_ + static_cast<int>(buffer_end_ - ptr);
0275 }
0276
0277 int MaximumReadSize(const char* ptr) const {
0278 return static_cast<int>(limit_end_ - ptr) + kSlopBytes;
0279 }
0280
0281
0282 bool DataAvailable(const char* ptr) { return ptr < limit_end_; }
0283
0284 int BytesAvailable(const char* ptr) const {
0285 ABSL_DCHECK_NE(ptr, nullptr);
0286 ptrdiff_t available = buffer_end_ + kSlopBytes - ptr;
0287 ABSL_DCHECK_GE(available, 0);
0288 ABSL_DCHECK_LE(available, INT_MAX);
0289 return static_cast<int>(available);
0290 }
0291
0292
0293 protected:
0294
0295
0296
0297 template <bool kExperimentalV2>
0298 bool DoneWithCheck(const char** ptr, int d) {
0299 ABSL_DCHECK(*ptr);
0300 if (ABSL_PREDICT_TRUE(*ptr < limit_end_)) return false;
0301 int overrun = static_cast<int>(*ptr - buffer_end_);
0302 ABSL_DCHECK_LE(overrun, kSlopBytes);
0303 if (overrun ==
0304 limit_) {
0305
0306
0307 if (overrun > 0 && next_chunk_ == nullptr) *ptr = nullptr;
0308 return true;
0309 }
0310 auto res = DoneFallback<kExperimentalV2>(overrun, d);
0311 *ptr = res.first;
0312 return res.second;
0313 }
0314
0315
0316 const char* InitFrom(absl::string_view flat) {
0317 overall_limit_ = 0;
0318 if (flat.size() > kSlopBytes) {
0319 limit_ = kSlopBytes;
0320 limit_end_ = buffer_end_ = flat.data() + flat.size() - kSlopBytes;
0321 next_chunk_ = patch_buffer_;
0322 if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
0323 return flat.data();
0324 } else {
0325 if (!flat.empty()) {
0326 std::memcpy(patch_buffer_, flat.data(), flat.size());
0327 }
0328 limit_ = 0;
0329 limit_end_ = buffer_end_ = patch_buffer_ + flat.size();
0330 next_chunk_ = nullptr;
0331 if (aliasing_ == kOnPatch) {
0332 aliasing_ = reinterpret_cast<std::uintptr_t>(flat.data()) -
0333 reinterpret_cast<std::uintptr_t>(patch_buffer_);
0334 }
0335 return patch_buffer_;
0336 }
0337 }
0338
0339 const char* InitFrom(io::ZeroCopyInputStream* zcis);
0340
0341 const char* InitFrom(io::ZeroCopyInputStream* zcis, int limit) {
0342 if (limit == -1) return InitFrom(zcis);
0343 overall_limit_ = limit;
0344 auto res = InitFrom(zcis);
0345 limit_ = limit - static_cast<int>(buffer_end_ - res);
0346 limit_end_ = buffer_end_ + (std::min)(0, limit_);
0347 return res;
0348 }
0349
0350
0351 const char* InitFrom(const BoundedZCIS& bounded_zcis) {
0352 return InitFrom(bounded_zcis.zcis, bounded_zcis.limit);
0353 }
0354
0355 protected:
0356 enum { kSlopBytes = 16, kPatchBufferSize = 32 };
0357 static_assert(kPatchBufferSize >= kSlopBytes * 2,
0358 "Patch buffer needs to be at least large enough to hold all "
0359 "the slop bytes from the previous buffer, plus the first "
0360 "kSlopBytes from the next buffer.");
0361
0362 private:
0363 const char* limit_end_;
0364 const char* buffer_end_;
0365 const char* next_chunk_;
0366 int size_;
0367 int limit_;
0368 io::ZeroCopyInputStream* zcis_ = nullptr;
0369 char patch_buffer_[kPatchBufferSize] = {};
0370 enum { kNoAliasing = 0, kOnPatch = 1, kNoDelta = 2 };
0371 std::uintptr_t aliasing_ = kNoAliasing;
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385 uint32_t last_tag_minus_1_ = 0;
0386 int overall_limit_ = INT_MAX;
0387
0388
0389 enum { kSafeStringSize = 50000000 };
0390
0391
0392
0393
0394 bool IsRequestedLessThanOrEqualTo(int requested, int available);
0395
0396
0397
0398
0399 bool CanReadFromPtr(int requested, const char* ptr);
0400
0401
0402
0403 bool HasEnoughTillLimit(int requested, const char* ptr);
0404
0405
0406
0407
0408
0409
0410
0411
0412 template <bool kExperimentalV2>
0413 std::pair<const char*, bool> DoneFallback(int overrun, int depth);
0414
0415
0416
0417
0418
0419 const char* Next();
0420
0421
0422
0423
0424
0425 template <bool kExperimentalV2>
0426 inline const char* NextBuffer(int overrun, int depth);
0427 const char* SkipFallback(const char* ptr, int size);
0428 const char* AppendStringFallback(const char* ptr, int size, std::string* str);
0429 const char* VerifyUTF8Fallback(const char* ptr, size_t size);
0430 const char* ReadStringFallback(const char* ptr, int size, std::string* str);
0431 const char* ReadArrayFallback(const char* ptr, absl::Span<char> out);
0432 const char* ReadCordFallback(const char* ptr, int size, absl::Cord* cord);
0433 template <bool kExperimentalV2>
0434 static bool ParseEndsInSlopRegion(const char* begin, int overrun, int depth);
0435 bool StreamNext(const void** data) {
0436 bool res = zcis_->Next(data, &size_);
0437 if (res) overall_limit_ -= size_;
0438 return res;
0439 }
0440 void StreamBackUp(int count) {
0441 zcis_->BackUp(count);
0442 overall_limit_ += count;
0443 }
0444
0445 template <typename A>
0446 const char* AppendSize(const char* ptr, uint32_t size, const A& append) {
0447
0448 constexpr bool kCheckReturn =
0449 std::is_invocable_r_v<bool, decltype(append), const char*, int>;
0450
0451 ABSL_DCHECK_GE(BytesAvailable(ptr), 0);
0452 uint32_t chunk_size = static_cast<uint32_t>(BytesAvailable(ptr));
0453 do {
0454 ABSL_DCHECK_GT(size, chunk_size);
0455 if (next_chunk_ == nullptr) return nullptr;
0456 if constexpr (kCheckReturn) {
0457 if (!append(ptr, chunk_size)) return nullptr;
0458 } else {
0459 append(ptr, chunk_size);
0460 }
0461 ptr += chunk_size;
0462 size -= chunk_size;
0463
0464
0465
0466 if (limit_ <= kSlopBytes) return nullptr;
0467 ptr = Next();
0468 if (ptr == nullptr) return nullptr;
0469 ptr += kSlopBytes;
0470 chunk_size = BytesAvailable(ptr);
0471 } while (size > chunk_size);
0472
0473 if constexpr (kCheckReturn) {
0474 if (!append(ptr, size)) return nullptr;
0475 } else {
0476 append(ptr, size);
0477 }
0478 return ptr + size;
0479 }
0480
0481
0482
0483
0484
0485
0486 template <typename A>
0487 const char* AppendUntilEnd(const char* ptr, const A& append) {
0488 if (ptr - buffer_end_ > limit_) return nullptr;
0489 while (limit_ > kSlopBytes) {
0490 size_t chunk_size = BytesAvailable(ptr);
0491 append(ptr, chunk_size);
0492 ptr = Next();
0493 if (ptr == nullptr) return limit_end_;
0494 ptr += kSlopBytes;
0495 }
0496 auto end = buffer_end_ + limit_;
0497 ABSL_DCHECK(end >= ptr);
0498 append(ptr, end - ptr);
0499 return end;
0500 }
0501
0502 [[nodiscard]] const char* AppendString(const char* ptr, std::string* str) {
0503 return AppendUntilEnd(
0504 ptr, [str](const char* p, ptrdiff_t s) { str->append(p, s); });
0505 }
0506 friend class ImplicitWeakMessage;
0507
0508
0509 friend PROTOBUF_EXPORT std::pair<const char*, int32_t> ReadSizeFallback(
0510 const char* p, uint32_t res);
0511 };
0512
0513 using LazyEagerVerifyFnType = const char* (*)(const char* ptr,
0514 ParseContext* ctx);
0515 using LazyEagerVerifyFnRef = std::remove_pointer<LazyEagerVerifyFnType>::type&;
0516
0517
0518
0519
0520
0521 class PROTOBUF_EXPORT ParseContext : public EpsCopyInputStream {
0522 public:
0523 struct Data {
0524 const DescriptorPool* pool = nullptr;
0525 MessageFactory* factory = nullptr;
0526 };
0527
0528 template <typename... T>
0529 ParseContext(int depth, bool aliasing, const char** start, T&&... args)
0530 : EpsCopyInputStream(aliasing), depth_(depth) {
0531 *start = InitFrom(std::forward<T>(args)...);
0532 }
0533
0534 struct Spawn {};
0535 static constexpr Spawn kSpawn = {};
0536
0537
0538
0539
0540
0541
0542 template <typename... T>
0543 ParseContext(Spawn, const ParseContext& ctx, const char** start, T&&... args)
0544 : EpsCopyInputStream(false),
0545 depth_(ctx.depth_),
0546 data_(ctx.data_)
0547 {
0548 *start = InitFrom(std::forward<T>(args)...);
0549 }
0550
0551
0552
0553
0554 ParseContext(ParseContext&&) = delete;
0555 ParseContext& operator=(ParseContext&&) = delete;
0556 ParseContext& operator=(const ParseContext&) = delete;
0557
0558 void TrackCorrectEnding() {
0559 group_depth_ = 0;
0560 }
0561
0562
0563
0564 bool Done(const char** ptr) {
0565 return DoneWithCheck<false>(ptr, group_depth_);
0566 }
0567
0568
0569 int depth() const { return depth_; }
0570
0571 Data& data() { return data_; }
0572 const Data& data() const { return data_; }
0573
0574 const char* ParseMessage(MessageLite* msg, const char* ptr);
0575
0576
0577
0578 template <typename Func>
0579 [[nodiscard]] const char* ParseLengthDelimitedInlined(const char*,
0580 const Func& func);
0581
0582
0583
0584 template <typename Func>
0585 [[nodiscard]] const char* ParseGroupInlined(const char* ptr,
0586 uint32_t start_tag,
0587 const Func& func);
0588
0589
0590
0591 template <typename Parser = TcParser>
0592 PROTOBUF_ALWAYS_INLINE const char* ParseMessage(
0593 MessageLite* msg, const TcParseTableBase* tc_table, const char* ptr) {
0594 return ParseLengthDelimitedInlined(ptr, [&](const char* ptr) {
0595 return Parser::ParseLoop(msg, ptr, this, tc_table);
0596 });
0597 }
0598 template <typename Parser = TcParser>
0599 PROTOBUF_ALWAYS_INLINE const char* ParseGroup(
0600 MessageLite* msg, const TcParseTableBase* tc_table, const char* ptr,
0601 uint32_t start_tag) {
0602 return ParseGroupInlined(ptr, start_tag, [&](const char* ptr) {
0603 return Parser::ParseLoop(msg, ptr, this, tc_table);
0604 });
0605 }
0606
0607
0608 [[nodiscard]] PROTOBUF_NDEBUG_INLINE const char* ParseGroup(MessageLite* msg,
0609 const char* ptr,
0610 uint32_t tag) {
0611 if (--depth_ < 0) return nullptr;
0612 group_depth_++;
0613 auto old_depth = depth_;
0614 auto old_group_depth = group_depth_;
0615 ptr = msg->_InternalParse(ptr, this);
0616 if (ptr != nullptr) {
0617 ABSL_DCHECK_EQ(old_depth, depth_);
0618 ABSL_DCHECK_EQ(old_group_depth, group_depth_);
0619 }
0620 group_depth_--;
0621 depth_++;
0622 if (ABSL_PREDICT_FALSE(!ConsumeEndGroup(tag))) return nullptr;
0623 return ptr;
0624 }
0625
0626 private:
0627
0628
0629
0630
0631
0632
0633
0634
0635 [[nodiscard]] const char* ReadSizeAndPushLimitAndDepth(const char* ptr,
0636 LimitToken* old_limit);
0637
0638
0639
0640 [[nodiscard]] PROTOBUF_ALWAYS_INLINE const char*
0641 ReadSizeAndPushLimitAndDepthInlined(const char* ptr, LimitToken* old_limit);
0642
0643
0644
0645
0646
0647
0648 int depth_;
0649
0650
0651
0652 int group_depth_ = std::numeric_limits<int16_t>::min();
0653 Data data_;
0654 };
0655
0656 template <int>
0657 struct EndianHelper;
0658
0659 template <>
0660 struct EndianHelper<1> {
0661 static uint8_t Load(const void* p) { return *static_cast<const uint8_t*>(p); }
0662 };
0663
0664 template <>
0665 struct EndianHelper<2> {
0666 static uint16_t Load(const void* p) {
0667 uint16_t tmp;
0668 std::memcpy(&tmp, p, 2);
0669 return little_endian::ToHost(tmp);
0670 }
0671 };
0672
0673 template <>
0674 struct EndianHelper<4> {
0675 static uint32_t Load(const void* p) {
0676 uint32_t tmp;
0677 std::memcpy(&tmp, p, 4);
0678 return little_endian::ToHost(tmp);
0679 }
0680 };
0681
0682 template <>
0683 struct EndianHelper<8> {
0684 static uint64_t Load(const void* p) {
0685 uint64_t tmp;
0686 std::memcpy(&tmp, p, 8);
0687 return little_endian::ToHost(tmp);
0688 }
0689 };
0690
0691 template <typename T>
0692 T UnalignedLoad(const char* p) {
0693 auto tmp = EndianHelper<sizeof(T)>::Load(p);
0694 T res;
0695 memcpy(&res, &tmp, sizeof(T));
0696 return res;
0697 }
0698 template <typename T, typename Void,
0699 typename = std::enable_if_t<std::is_same<Void, void>::value>>
0700 T UnalignedLoad(const Void* p) {
0701 return UnalignedLoad<T>(reinterpret_cast<const char*>(p));
0702 }
0703
0704 PROTOBUF_EXPORT
0705 std::pair<const char*, uint32_t> VarintParseSlow32(const char* p, uint32_t res);
0706 PROTOBUF_EXPORT
0707 std::pair<const char*, uint64_t> VarintParseSlow64(const char* p, uint32_t res);
0708
0709 inline const char* VarintParseSlow(const char* p, uint32_t res, uint32_t* out) {
0710 auto tmp = VarintParseSlow32(p, res);
0711 *out = tmp.second;
0712 return tmp.first;
0713 }
0714
0715 inline const char* VarintParseSlow(const char* p, uint32_t res, uint64_t* out) {
0716 auto tmp = VarintParseSlow64(p, res);
0717 *out = tmp.second;
0718 return tmp.first;
0719 }
0720
0721 #if defined(__aarch64__) && !defined(_MSC_VER)
0722
0723
0724
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754
0755
0756
0757
0758
0759
0760
0761
0762
0763
0764
0765
0766
0767
0768
0769
0770
0771
0772
0773
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784
0785
0786
0787
0788
0789
0790
0791
0792
0793
0794
0795
0796
0797
0798
0799
0800
0801
0802 template <typename V1Type>
0803 PROTOBUF_ALWAYS_INLINE V1Type ValueBarrier(V1Type value1) {
0804 asm("" : "+r"(value1));
0805 return value1;
0806 }
0807
0808 template <typename V1Type, typename V2Type>
0809 PROTOBUF_ALWAYS_INLINE V1Type ValueBarrier(V1Type value1, V2Type value2) {
0810 asm("" : "+r"(value1) : "r"(value2));
0811 return value1;
0812 }
0813
0814
0815 static PROTOBUF_ALWAYS_INLINE uint64_t Ubfx7(uint64_t data, uint64_t start) {
0816 return ValueBarrier((data >> start) & 0x7f);
0817 }
0818
0819 PROTOBUF_ALWAYS_INLINE uint64_t ExtractAndMergeTwoChunks(uint64_t data,
0820 uint64_t first_byte) {
0821 ABSL_DCHECK_LE(first_byte, 6U);
0822 uint64_t first = Ubfx7(data, first_byte * 8);
0823 uint64_t second = Ubfx7(data, (first_byte + 1) * 8);
0824 return ValueBarrier(first | (second << 7));
0825 }
0826
0827 struct SlowPathEncodedInfo {
0828 const char* p;
0829 uint64_t last8;
0830 uint64_t valid_bits;
0831 uint64_t valid_chunk_bits;
0832 uint64_t masked_cont_bits;
0833 };
0834
0835
0836
0837
0838 PROTOBUF_ALWAYS_INLINE SlowPathEncodedInfo
0839 ComputeLengthAndUpdateP(const char* p) {
0840 SlowPathEncodedInfo result;
0841
0842 std::memcpy(&result.last8, p + 2, sizeof(result.last8));
0843 uint64_t mask = ValueBarrier(0x8080808080808080);
0844
0845 result.masked_cont_bits = ValueBarrier(mask & ~result.last8);
0846
0847
0848
0849 result.valid_bits = absl::countr_zero(result.masked_cont_bits);
0850
0851
0852
0853 uint64_t set_continuation_bits = result.valid_bits >> 3;
0854
0855 result.p = p + set_continuation_bits + 3;
0856
0857
0858
0859 result.valid_chunk_bits = result.valid_bits - set_continuation_bits;
0860 return result;
0861 }
0862
0863 PROTOBUF_ALWAYS_INLINE std::pair<const char*, uint64_t> VarintParseSlowArm64(
0864 const char* p, uint64_t first8) {
0865 constexpr uint64_t kResultMaskUnshifted = 0xffffffffffffc000ULL;
0866 constexpr uint64_t kFirstResultBitChunk2 = 2 * 7;
0867 constexpr uint64_t kFirstResultBitChunk4 = 4 * 7;
0868 constexpr uint64_t kFirstResultBitChunk6 = 6 * 7;
0869 constexpr uint64_t kFirstResultBitChunk8 = 8 * 7;
0870
0871 SlowPathEncodedInfo info = ComputeLengthAndUpdateP(p);
0872
0873
0874 uint64_t merged_01 = ExtractAndMergeTwoChunks(first8, 0);
0875 uint64_t merged_23 = ExtractAndMergeTwoChunks(first8, 2);
0876 uint64_t merged_45 = ExtractAndMergeTwoChunks(first8, 4);
0877
0878 uint64_t result = merged_01 | (merged_23 << kFirstResultBitChunk2) |
0879 (merged_45 << kFirstResultBitChunk4);
0880
0881 uint64_t result_mask = kResultMaskUnshifted << info.valid_chunk_bits;
0882
0883 if (ABSL_PREDICT_FALSE(info.masked_cont_bits == 0)) {
0884 return {nullptr, 0};
0885 }
0886
0887
0888 if (ABSL_PREDICT_FALSE((info.valid_bits & 0x20) != 0)) {
0889
0890 uint64_t merged_67 = ExtractAndMergeTwoChunks(first8, 6);
0891
0892 uint64_t merged_89 =
0893 ExtractAndMergeTwoChunks(info.last8, 6);
0894 result |= merged_67 << kFirstResultBitChunk6;
0895 result |= merged_89 << kFirstResultBitChunk8;
0896
0897 }
0898
0899 result &= ~result_mask;
0900 return {info.p, result};
0901 }
0902
0903
0904
0905 PROTOBUF_ALWAYS_INLINE std::pair<const char*, uint32_t> VarintParseSlowArm32(
0906 const char* p, uint64_t first8) {
0907 constexpr uint64_t kResultMaskUnshifted = 0xffffffffffffc000ULL;
0908 constexpr uint64_t kFirstResultBitChunk1 = 1 * 7;
0909 constexpr uint64_t kFirstResultBitChunk3 = 3 * 7;
0910
0911
0912 SlowPathEncodedInfo info = ComputeLengthAndUpdateP(p);
0913
0914 uint64_t merged_12 = ExtractAndMergeTwoChunks(first8, 1);
0915 uint64_t merged_34 = ExtractAndMergeTwoChunks(first8, 3);
0916 first8 = ValueBarrier(first8, p);
0917 uint64_t result = Ubfx7(first8, 0);
0918 result = ValueBarrier(result | merged_12 << kFirstResultBitChunk1);
0919 result = ValueBarrier(result | merged_34 << kFirstResultBitChunk3);
0920 uint64_t result_mask = kResultMaskUnshifted << info.valid_chunk_bits;
0921 result &= ~result_mask;
0922
0923
0924
0925 info.masked_cont_bits = ValueBarrier(info.masked_cont_bits, result);
0926 if (ABSL_PREDICT_FALSE(info.masked_cont_bits == 0)) {
0927 return {nullptr, 0};
0928 }
0929 return {info.p, result};
0930 }
0931
0932 static const char* VarintParseSlowArm(const char* p, uint32_t* out,
0933 uint64_t first8) {
0934 auto tmp = VarintParseSlowArm32(p, first8);
0935 *out = tmp.second;
0936 return tmp.first;
0937 }
0938
0939 static const char* VarintParseSlowArm(const char* p, uint64_t* out,
0940 uint64_t first8) {
0941 auto tmp = VarintParseSlowArm64(p, first8);
0942 *out = tmp.second;
0943 return tmp.first;
0944 }
0945 #endif
0946
0947
0948 template <typename T>
0949 [[nodiscard]] const char* VarintParse(const char* p, T* out) {
0950 AssertBytesAreReadable(p, 10);
0951 #if defined(__aarch64__) && defined(ABSL_IS_LITTLE_ENDIAN) && !defined(_MSC_VER)
0952
0953 uint64_t first8;
0954 std::memcpy(&first8, p, sizeof(first8));
0955 if (ABSL_PREDICT_TRUE((first8 & 0x80) == 0)) {
0956 *out = static_cast<uint8_t>(first8);
0957 return p + 1;
0958 }
0959 if (ABSL_PREDICT_TRUE((first8 & 0x8000) == 0)) {
0960 uint64_t chunk1;
0961 uint64_t chunk2;
0962
0963 chunk1 = Ubfx7(first8, 0);
0964 chunk2 = Ubfx7(first8, 8);
0965 *out = chunk1 | (chunk2 << 7);
0966 return p + 2;
0967 }
0968 return VarintParseSlowArm(p, out, first8);
0969 #else
0970 auto ptr = reinterpret_cast<const uint8_t*>(p);
0971 uint32_t res = ptr[0];
0972 if ((res & 0x80) == 0) {
0973 *out = res;
0974 return p + 1;
0975 }
0976 return VarintParseSlow(p, res, out);
0977 #endif
0978 }
0979
0980
0981
0982
0983 PROTOBUF_EXPORT
0984 std::pair<const char*, uint32_t> ReadTagFallback(const char* p, uint32_t res);
0985
0986
0987 inline const char* ReadTag(const char* p, uint32_t* out,
0988 uint32_t = 0) {
0989 uint32_t res = static_cast<uint8_t>(p[0]);
0990 if (res < 128) {
0991 *out = res;
0992 return p + 1;
0993 }
0994 uint32_t second = static_cast<uint8_t>(p[1]);
0995 res += (second - 1) << 7;
0996 if (second < 128) {
0997 *out = res;
0998 return p + 2;
0999 }
1000 auto tmp = ReadTagFallback(p, res);
1001 *out = tmp.second;
1002 return tmp.first;
1003 }
1004
1005
1006
1007
1008
1009
1010 template <class T>
1011 [[nodiscard]] PROTOBUF_ALWAYS_INLINE constexpr T RotateLeft(T x,
1012 int s) noexcept {
1013 return static_cast<T>(x << (s & (std::numeric_limits<T>::digits - 1))) |
1014 static_cast<T>(x >> ((-s) & (std::numeric_limits<T>::digits - 1)));
1015 }
1016
1017 [[nodiscard]] PROTOBUF_ALWAYS_INLINE uint64_t
1018 RotRight7AndReplaceLowByte(uint64_t res, const char byte) {
1019
1020 #if defined(__x86_64__) && defined(__GNUC__)
1021
1022
1023
1024
1025
1026
1027
1028 asm("ror $7,%0\n\t"
1029 "movb %1,%b0"
1030 : "+r"(res)
1031 : "m"(byte));
1032 #else
1033 res = RotateLeft(res, -7);
1034 res = res & ~0xFF;
1035 res |= 0xFF & byte;
1036 #endif
1037 return res;
1038 }
1039
1040 PROTOBUF_ALWAYS_INLINE const char* ReadTagInlined(const char* ptr,
1041 uint32_t* out) {
1042 uint64_t res = 0xFF & ptr[0];
1043 if (ABSL_PREDICT_FALSE(res >= 128)) {
1044 res = RotRight7AndReplaceLowByte(res, ptr[1]);
1045 if (ABSL_PREDICT_FALSE(res & 0x80)) {
1046 res = RotRight7AndReplaceLowByte(res, ptr[2]);
1047 if (ABSL_PREDICT_FALSE(res & 0x80)) {
1048 res = RotRight7AndReplaceLowByte(res, ptr[3]);
1049 if (ABSL_PREDICT_FALSE(res & 0x80)) {
1050
1051
1052
1053 res = RotRight7AndReplaceLowByte(res, ptr[4]);
1054 if (ABSL_PREDICT_FALSE(res & 0x80)) {
1055
1056
1057 *out = 0;
1058 return nullptr;
1059 }
1060 *out = static_cast<uint32_t>(RotateLeft(res, 28));
1061 #if defined(__GNUC__)
1062
1063
1064
1065 asm("" : "+r"(ptr));
1066 #endif
1067 return ptr + 5;
1068 }
1069 *out = static_cast<uint32_t>(RotateLeft(res, 21));
1070 return ptr + 4;
1071 }
1072 *out = static_cast<uint32_t>(RotateLeft(res, 14));
1073 return ptr + 3;
1074 }
1075 *out = static_cast<uint32_t>(RotateLeft(res, 7));
1076 return ptr + 2;
1077 }
1078 *out = static_cast<uint32_t>(res);
1079 return ptr + 1;
1080 }
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091 inline uint32_t DecodeTwoBytes(const char** ptr) {
1092 uint32_t value = UnalignedLoad<uint16_t>(*ptr);
1093
1094 uint32_t x = static_cast<int8_t>(value);
1095 value &= x;
1096
1097
1098
1099
1100 value += x;
1101
1102 *ptr += value < x ? 2 : 1;
1103 return value;
1104 }
1105
1106
1107 inline const char* ParseBigVarint(const char* p, uint64_t* out) {
1108 auto pnew = p;
1109 auto tmp = DecodeTwoBytes(&pnew);
1110 uint64_t res = tmp >> 1;
1111 if (ABSL_PREDICT_TRUE(static_cast<std::int16_t>(tmp) >= 0)) {
1112 *out = res;
1113 return pnew;
1114 }
1115 for (std::uint32_t i = 1; i < 5; i++) {
1116 pnew = p + 2 * i;
1117 tmp = DecodeTwoBytes(&pnew);
1118 res += (static_cast<std::uint64_t>(tmp) - 2) << (14 * i - 1);
1119 if (ABSL_PREDICT_TRUE(static_cast<std::int16_t>(tmp) >= 0)) {
1120 *out = res;
1121 return pnew;
1122 }
1123 }
1124 return nullptr;
1125 }
1126
1127 PROTOBUF_EXPORT
1128 std::pair<const char*, int32_t> ReadSizeFallback(const char* p, uint32_t res);
1129
1130
1131
1132
1133
1134 inline uint32_t ReadSize(const char** pp) {
1135 auto p = *pp;
1136 uint32_t res = static_cast<uint8_t>(p[0]);
1137 if (res < 128) {
1138 *pp = p + 1;
1139 return res;
1140 }
1141 auto x = ReadSizeFallback(p, res);
1142 *pp = x.first;
1143 return x.second;
1144 }
1145
1146
1147
1148
1149
1150
1151 inline uint64_t ReadVarint64(const char** p) {
1152 uint64_t tmp;
1153 *p = VarintParse(*p, &tmp);
1154 return tmp;
1155 }
1156
1157 inline uint32_t ReadVarint32(const char** p) {
1158 uint32_t tmp;
1159 *p = VarintParse(*p, &tmp);
1160 return tmp;
1161 }
1162
1163 inline int64_t ReadVarintZigZag64(const char** p) {
1164 uint64_t tmp;
1165 *p = VarintParse(*p, &tmp);
1166 return WireFormatLite::ZigZagDecode64(tmp);
1167 }
1168
1169 inline int32_t ReadVarintZigZag32(const char** p) {
1170 uint64_t tmp;
1171 *p = VarintParse(*p, &tmp);
1172 return WireFormatLite::ZigZagDecode32(static_cast<uint32_t>(tmp));
1173 }
1174
1175 template <typename Func>
1176 [[nodiscard]] PROTOBUF_ALWAYS_INLINE const char*
1177 ParseContext::ParseLengthDelimitedInlined(const char* ptr, const Func& func) {
1178 LimitToken old;
1179 ptr = ReadSizeAndPushLimitAndDepthInlined(ptr, &old);
1180 if (ptr == nullptr) return ptr;
1181 auto old_depth = depth_;
1182 PROTOBUF_ALWAYS_INLINE_CALL ptr = func(ptr);
1183 if (ptr != nullptr) ABSL_DCHECK_EQ(old_depth, depth_);
1184 depth_++;
1185 if (!PopLimit(std::move(old))) return nullptr;
1186 return ptr;
1187 }
1188
1189 template <typename Func>
1190 [[nodiscard]] PROTOBUF_ALWAYS_INLINE const char*
1191 ParseContext::ParseGroupInlined(const char* ptr, uint32_t start_tag,
1192 const Func& func) {
1193 if (--depth_ < 0) return nullptr;
1194 group_depth_++;
1195 auto old_depth = depth_;
1196 auto old_group_depth = group_depth_;
1197 PROTOBUF_ALWAYS_INLINE_CALL ptr = func(ptr);
1198 if (ptr != nullptr) {
1199 ABSL_DCHECK_EQ(old_depth, depth_);
1200 ABSL_DCHECK_EQ(old_group_depth, group_depth_);
1201 }
1202 group_depth_--;
1203 depth_++;
1204 if (ABSL_PREDICT_FALSE(!ConsumeEndGroup(start_tag))) return nullptr;
1205 return ptr;
1206 }
1207
1208 inline const char* ParseContext::ReadSizeAndPushLimitAndDepthInlined(
1209 const char* ptr, LimitToken* old_limit) {
1210 int size = ReadSize(&ptr);
1211 if (ABSL_PREDICT_FALSE(!ptr) || depth_ <= 0) {
1212 return nullptr;
1213 }
1214 *old_limit = PushLimit(ptr, size);
1215 --depth_;
1216 return ptr;
1217 }
1218
1219 inline const char* EpsCopyInputStream::ReadMicroString(const char* ptr,
1220 MicroString& str,
1221 Arena* arena) {
1222 int size = ReadSize(&ptr);
1223 if (!ptr) return nullptr;
1224
1225 if (size <= BytesAvailable(ptr)) {
1226 str.Set(absl::string_view(ptr, size), arena);
1227 return ptr + size;
1228 }
1229 return ReadMicroStringFallback(ptr, size, str, arena);
1230 }
1231
1232
1233 template <typename Tag, typename T>
1234 const char* EpsCopyInputStream::ReadRepeatedFixed(const char* ptr,
1235 Tag expected_tag,
1236 RepeatedField<T>* out) {
1237 do {
1238 out->Add(UnalignedLoad<T>(ptr));
1239 ptr += sizeof(T);
1240 if (ABSL_PREDICT_FALSE(ptr >= limit_end_)) return ptr;
1241 } while (UnalignedLoad<Tag>(ptr) == expected_tag && (ptr += sizeof(Tag)));
1242 return ptr;
1243 }
1244
1245
1246
1247 #define GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, ret) \
1248 if (!(predicate)) { \
1249 \
1250 \
1251 return ret; \
1252 }
1253
1254 #define GOOGLE_PROTOBUF_PARSER_ASSERT(predicate) \
1255 GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, nullptr)
1256
1257 template <typename T>
1258 const char* EpsCopyInputStream::ReadPackedFixed(const char* ptr, int size,
1259 RepeatedField<T>* out) {
1260 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
1261 int nbytes = BytesAvailable(ptr);
1262 while (size > nbytes) {
1263 int num = nbytes / sizeof(T);
1264 int old_entries = out->size();
1265 out->Reserve(old_entries + num);
1266 int block_size = num * sizeof(T);
1267 auto dst = out->AddNAlreadyReserved(num);
1268 #ifdef ABSL_IS_LITTLE_ENDIAN
1269 std::memcpy(dst, ptr, block_size);
1270 #else
1271 for (int i = 0; i < num; i++)
1272 dst[i] = UnalignedLoad<T>(ptr + i * sizeof(T));
1273 #endif
1274 size -= block_size;
1275 if (limit_ <= kSlopBytes) return nullptr;
1276 ptr = Next();
1277 if (ptr == nullptr) return nullptr;
1278 ptr += kSlopBytes - (nbytes - block_size);
1279 nbytes = BytesAvailable(ptr);
1280 }
1281 int num = size / sizeof(T);
1282 int block_size = num * sizeof(T);
1283 if (num == 0) return size == block_size ? ptr : nullptr;
1284 int old_entries = out->size();
1285 out->Reserve(old_entries + num);
1286 auto dst = out->AddNAlreadyReserved(num);
1287 #ifdef ABSL_IS_LITTLE_ENDIAN
1288 ABSL_CHECK(dst != nullptr) << out << "," << num;
1289 std::memcpy(dst, ptr, block_size);
1290 #else
1291 for (int i = 0; i < num; i++) dst[i] = UnalignedLoad<T>(ptr + i * sizeof(T));
1292 #endif
1293 ptr += block_size;
1294 if (size != block_size) return nullptr;
1295 return ptr;
1296 }
1297
1298 template <typename Add>
1299 const char* ReadPackedVarintArray(const char* ptr, const char* end, Add add) {
1300 while (ptr < end) {
1301 uint64_t varint;
1302 ptr = VarintParse(ptr, &varint);
1303 if (ptr == nullptr) return nullptr;
1304 add(varint);
1305 }
1306 return ptr;
1307 }
1308
1309 template <typename Add, typename SizeCb>
1310 const char* EpsCopyInputStream::ReadPackedVarint(const char* ptr, Add add,
1311 SizeCb size_callback) {
1312 int size = ReadSize(&ptr);
1313 size_callback(size);
1314
1315 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
1316 int chunk_size = static_cast<int>(buffer_end_ - ptr);
1317 while (size > chunk_size) {
1318 ptr = ReadPackedVarintArray(ptr, buffer_end_, add);
1319 if (ptr == nullptr) return nullptr;
1320 int overrun = static_cast<int>(ptr - buffer_end_);
1321 ABSL_DCHECK(overrun >= 0 && overrun <= kSlopBytes);
1322 if (size - chunk_size <= kSlopBytes) {
1323
1324
1325
1326 char buf[kSlopBytes + 10] = {};
1327 std::memcpy(buf, buffer_end_, kSlopBytes);
1328 ABSL_CHECK_LE(size - chunk_size, kSlopBytes);
1329 auto end = buf + (size - chunk_size);
1330 auto res = ReadPackedVarintArray(buf + overrun, end, add);
1331 if (res == nullptr || res != end) return nullptr;
1332 return buffer_end_ + (res - buf);
1333 }
1334 size -= overrun + chunk_size;
1335 ABSL_DCHECK_GT(size, 0);
1336
1337 if (limit_ <= kSlopBytes) return nullptr;
1338 ptr = Next();
1339 if (ptr == nullptr) return nullptr;
1340 ptr += overrun;
1341 chunk_size = static_cast<int>(buffer_end_ - ptr);
1342 }
1343 auto end = ptr + size;
1344 ptr = ReadPackedVarintArray(ptr, end, add);
1345 return end == ptr ? ptr : nullptr;
1346 }
1347
1348
1349 PROTOBUF_EXPORT
1350 bool VerifyUTF8(absl::string_view s, const char* field_name);
1351
1352 inline bool VerifyUTF8(const std::string* s, const char* field_name) {
1353 return VerifyUTF8(*s, field_name);
1354 }
1355
1356
1357 [[nodiscard]] PROTOBUF_EXPORT const char* InlineGreedyStringParser(
1358 std::string* s, const char* ptr, ParseContext* ctx);
1359
1360 [[nodiscard]] inline const char* InlineCordParser(::absl::Cord* cord,
1361 const char* ptr,
1362 ParseContext* ctx) {
1363 int size = ReadSize(&ptr);
1364 if (!ptr) return nullptr;
1365 return ctx->ReadCord(ptr, size, cord);
1366 }
1367
1368
1369 template <typename T>
1370 [[nodiscard]] const char* FieldParser(uint64_t tag, T& field_parser,
1371 const char* ptr, ParseContext* ctx) {
1372 uint32_t number = tag >> 3;
1373 GOOGLE_PROTOBUF_PARSER_ASSERT(number != 0);
1374 using WireType = internal::WireFormatLite::WireType;
1375 switch (tag & 7) {
1376 case WireType::WIRETYPE_VARINT: {
1377 uint64_t value;
1378 ptr = VarintParse(ptr, &value);
1379 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
1380 field_parser.AddVarint(number, value);
1381 break;
1382 }
1383 case WireType::WIRETYPE_FIXED64: {
1384 uint64_t value = UnalignedLoad<uint64_t>(ptr);
1385 ptr += 8;
1386 field_parser.AddFixed64(number, value);
1387 break;
1388 }
1389 case WireType::WIRETYPE_LENGTH_DELIMITED: {
1390 ptr = field_parser.ParseLengthDelimited(number, ptr, ctx);
1391 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
1392 break;
1393 }
1394 case WireType::WIRETYPE_START_GROUP: {
1395 ptr = field_parser.ParseGroup(number, ptr, ctx);
1396 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
1397 break;
1398 }
1399 case WireType::WIRETYPE_END_GROUP: {
1400 ABSL_LOG(FATAL) << "Can't happen";
1401 break;
1402 }
1403 case WireType::WIRETYPE_FIXED32: {
1404 uint32_t value = UnalignedLoad<uint32_t>(ptr);
1405 ptr += 4;
1406 field_parser.AddFixed32(number, value);
1407 break;
1408 }
1409 default:
1410 return nullptr;
1411 }
1412 return ptr;
1413 }
1414
1415 template <typename T>
1416 [[nodiscard]] const char* WireFormatParser(T& field_parser, const char* ptr,
1417 ParseContext* ctx) {
1418 while (!ctx->Done(&ptr)) {
1419 uint32_t tag;
1420 ptr = ReadTag(ptr, &tag);
1421 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
1422 if (tag == 0 || (tag & 7) == 4) {
1423 ctx->SetLastTag(tag);
1424 return ptr;
1425 }
1426 ptr = FieldParser(tag, field_parser, ptr, ctx);
1427 GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
1428 }
1429 return ptr;
1430 }
1431
1432
1433
1434
1435
1436 [[nodiscard]] PROTOBUF_EXPORT const char* PackedInt32Parser(void* object,
1437 const char* ptr,
1438 ParseContext* ctx);
1439 [[nodiscard]] PROTOBUF_EXPORT const char* PackedUInt32Parser(void* object,
1440 const char* ptr,
1441 ParseContext* ctx);
1442 [[nodiscard]] PROTOBUF_EXPORT const char* PackedInt64Parser(void* object,
1443 const char* ptr,
1444 ParseContext* ctx);
1445 [[nodiscard]] PROTOBUF_EXPORT const char* PackedUInt64Parser(void* object,
1446 const char* ptr,
1447 ParseContext* ctx);
1448 [[nodiscard]] PROTOBUF_EXPORT const char* PackedSInt32Parser(void* object,
1449 const char* ptr,
1450 ParseContext* ctx);
1451 [[nodiscard]] PROTOBUF_EXPORT const char* PackedSInt64Parser(void* object,
1452 const char* ptr,
1453 ParseContext* ctx);
1454 [[nodiscard]] PROTOBUF_EXPORT const char* PackedEnumParser(void* object,
1455 const char* ptr,
1456 ParseContext* ctx);
1457
1458 template <typename T, typename Validator>
1459 [[nodiscard]] const char* PackedEnumParserArg(void* object, const char* ptr,
1460 ParseContext* ctx,
1461 Validator validator,
1462 InternalMetadata* metadata,
1463 int field_num) {
1464 return ctx->ReadPackedVarint(
1465 ptr, [object, validator, metadata, field_num](int32_t val) {
1466 if (validator.IsValid(val)) {
1467 static_cast<RepeatedField<int>*>(object)->Add(val);
1468 } else {
1469 WriteVarint(field_num, val, metadata->mutable_unknown_fields<T>());
1470 }
1471 });
1472 }
1473
1474 [[nodiscard]] PROTOBUF_EXPORT const char* PackedBoolParser(void* object,
1475 const char* ptr,
1476 ParseContext* ctx);
1477 [[nodiscard]] PROTOBUF_EXPORT const char* PackedFixed32Parser(
1478 void* object, const char* ptr, ParseContext* ctx);
1479 [[nodiscard]] PROTOBUF_EXPORT const char* PackedSFixed32Parser(
1480 void* object, const char* ptr, ParseContext* ctx);
1481 [[nodiscard]] PROTOBUF_EXPORT const char* PackedFixed64Parser(
1482 void* object, const char* ptr, ParseContext* ctx);
1483 [[nodiscard]] PROTOBUF_EXPORT const char* PackedSFixed64Parser(
1484 void* object, const char* ptr, ParseContext* ctx);
1485 [[nodiscard]] PROTOBUF_EXPORT const char* PackedFloatParser(void* object,
1486 const char* ptr,
1487 ParseContext* ctx);
1488 [[nodiscard]] PROTOBUF_EXPORT const char* PackedDoubleParser(void* object,
1489 const char* ptr,
1490 ParseContext* ctx);
1491
1492
1493 [[nodiscard]] PROTOBUF_EXPORT const char* UnknownGroupLiteParse(
1494 std::string* unknown, const char* ptr, ParseContext* ctx);
1495
1496
1497
1498 [[nodiscard]] PROTOBUF_EXPORT const char* UnknownFieldParse(
1499 uint32_t tag, std::string* unknown, const char* ptr, ParseContext* ctx);
1500
1501 extern template std::pair<const char*, bool>
1502 EpsCopyInputStream::DoneFallback<false>(int, int);
1503 extern template std::pair<const char*, bool>
1504 EpsCopyInputStream::DoneFallback<true>(int, int);
1505
1506 }
1507 }
1508 }
1509
1510 #include "google/protobuf/port_undef.inc"
1511
1512 #endif