• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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