1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #ifndef UPB_WIRE_READER_H_
9 #define UPB_WIRE_READER_H_
10
11 #include "upb/base/internal/endian.h"
12 #include "upb/wire/eps_copy_input_stream.h"
13 #include "upb/wire/internal/reader.h"
14 #include "upb/wire/types.h" // IWYU pragma: export
15
16 // Must be last.
17 #include "upb/port/def.inc"
18
19 // The upb_WireReader interface is suitable for general-purpose parsing of
20 // protobuf binary wire format. It is designed to be used along with
21 // upb_EpsCopyInputStream for buffering, and all parsing routines in this file
22 // assume that at least kUpb_EpsCopyInputStream_SlopBytes worth of data is
23 // available to read without any bounds checks.
24
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28
29 // Parses a tag into `tag`, and returns a pointer past the end of the tag, or
30 // NULL if there was an error in the tag data.
31 //
32 // REQUIRES: there must be at least 10 bytes of data available at `ptr`.
33 // Bounds checks must be performed before calling this function, preferably
34 // by calling upb_EpsCopyInputStream_IsDone().
upb_WireReader_ReadTag(const char * ptr,uint32_t * tag)35 UPB_FORCEINLINE const char* upb_WireReader_ReadTag(const char* ptr,
36 uint32_t* tag) {
37 uint64_t val;
38 ptr = UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, &val, 5, UINT32_MAX);
39 if (!ptr) return NULL;
40 *tag = val;
41 return ptr;
42 }
43
44 // Given a tag, returns the field number.
45 UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag);
46
47 // Given a tag, returns the wire type.
48 UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag);
49
upb_WireReader_ReadVarint(const char * ptr,uint64_t * val)50 UPB_INLINE const char* upb_WireReader_ReadVarint(const char* ptr,
51 uint64_t* val) {
52 return UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, val, 10, UINT64_MAX);
53 }
54
55 // Skips data for a varint, returning a pointer past the end of the varint, or
56 // NULL if there was an error in the varint data.
57 //
58 // REQUIRES: there must be at least 10 bytes of data available at `ptr`.
59 // Bounds checks must be performed before calling this function, preferably
60 // by calling upb_EpsCopyInputStream_IsDone().
upb_WireReader_SkipVarint(const char * ptr)61 UPB_INLINE const char* upb_WireReader_SkipVarint(const char* ptr) {
62 uint64_t val;
63 return upb_WireReader_ReadVarint(ptr, &val);
64 }
65
66 // Reads a varint indicating the size of a delimited field into `size`, or
67 // NULL if there was an error in the varint data.
68 //
69 // REQUIRES: there must be at least 10 bytes of data available at `ptr`.
70 // Bounds checks must be performed before calling this function, preferably
71 // by calling upb_EpsCopyInputStream_IsDone().
upb_WireReader_ReadSize(const char * ptr,int * size)72 UPB_INLINE const char* upb_WireReader_ReadSize(const char* ptr, int* size) {
73 uint64_t size64;
74 ptr = upb_WireReader_ReadVarint(ptr, &size64);
75 if (!ptr || size64 >= INT32_MAX) return NULL;
76 *size = size64;
77 return ptr;
78 }
79
80 // Reads a fixed32 field, performing byte swapping if necessary.
81 //
82 // REQUIRES: there must be at least 4 bytes of data available at `ptr`.
83 // Bounds checks must be performed before calling this function, preferably
84 // by calling upb_EpsCopyInputStream_IsDone().
upb_WireReader_ReadFixed32(const char * ptr,void * val)85 UPB_INLINE const char* upb_WireReader_ReadFixed32(const char* ptr, void* val) {
86 uint32_t uval;
87 memcpy(&uval, ptr, 4);
88 uval = upb_BigEndian32(uval);
89 memcpy(val, &uval, 4);
90 return ptr + 4;
91 }
92
93 // Reads a fixed64 field, performing byte swapping if necessary.
94 //
95 // REQUIRES: there must be at least 4 bytes of data available at `ptr`.
96 // Bounds checks must be performed before calling this function, preferably
97 // by calling upb_EpsCopyInputStream_IsDone().
upb_WireReader_ReadFixed64(const char * ptr,void * val)98 UPB_INLINE const char* upb_WireReader_ReadFixed64(const char* ptr, void* val) {
99 uint64_t uval;
100 memcpy(&uval, ptr, 8);
101 uval = upb_BigEndian64(uval);
102 memcpy(val, &uval, 8);
103 return ptr + 8;
104 }
105
106 const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)(
107 const char* ptr, uint32_t tag, int depth_limit,
108 upb_EpsCopyInputStream* stream);
109
110 // Skips data for a group, returning a pointer past the end of the group, or
111 // NULL if there was an error parsing the group. The `tag` argument should be
112 // the start group tag that begins the group. The `depth_limit` argument
113 // indicates how many levels of recursion the group is allowed to have before
114 // reporting a parse error (this limit exists to protect against stack
115 // overflow).
116 //
117 // TODO: evaluate how the depth_limit should be specified. Do users need
118 // control over this?
upb_WireReader_SkipGroup(const char * ptr,uint32_t tag,upb_EpsCopyInputStream * stream)119 UPB_INLINE const char* upb_WireReader_SkipGroup(
120 const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) {
121 return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, 100, stream);
122 }
123
_upb_WireReader_SkipValue(const char * ptr,uint32_t tag,int depth_limit,upb_EpsCopyInputStream * stream)124 UPB_INLINE const char* _upb_WireReader_SkipValue(
125 const char* ptr, uint32_t tag, int depth_limit,
126 upb_EpsCopyInputStream* stream) {
127 switch (upb_WireReader_GetWireType(tag)) {
128 case kUpb_WireType_Varint:
129 return upb_WireReader_SkipVarint(ptr);
130 case kUpb_WireType_32Bit:
131 return ptr + 4;
132 case kUpb_WireType_64Bit:
133 return ptr + 8;
134 case kUpb_WireType_Delimited: {
135 int size;
136 ptr = upb_WireReader_ReadSize(ptr, &size);
137 if (!ptr) return NULL;
138 ptr += size;
139 return ptr;
140 }
141 case kUpb_WireType_StartGroup:
142 return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, depth_limit,
143 stream);
144 case kUpb_WireType_EndGroup:
145 return NULL; // Should be handled before now.
146 default:
147 return NULL; // Unknown wire type.
148 }
149 }
150
151 // Skips data for a wire value of any type, returning a pointer past the end of
152 // the data, or NULL if there was an error parsing the group. The `tag` argument
153 // should be the tag that was just parsed. The `depth_limit` argument indicates
154 // how many levels of recursion a group is allowed to have before reporting a
155 // parse error (this limit exists to protect against stack overflow).
156 //
157 // REQUIRES: there must be at least 10 bytes of data available at `ptr`.
158 // Bounds checks must be performed before calling this function, preferably
159 // by calling upb_EpsCopyInputStream_IsDone().
160 //
161 // TODO: evaluate how the depth_limit should be specified. Do users need
162 // control over this?
upb_WireReader_SkipValue(const char * ptr,uint32_t tag,upb_EpsCopyInputStream * stream)163 UPB_INLINE const char* upb_WireReader_SkipValue(
164 const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) {
165 return _upb_WireReader_SkipValue(ptr, tag, 100, stream);
166 }
167
168 #ifdef __cplusplus
169 } /* extern "C" */
170 #endif
171
172 #include "upb/port/undef.inc"
173
174 #endif // UPB_WIRE_READER_H_
175