BinaryTokenizer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 24 SBuf */
10 
11 #include "squid.h"
12 #include "base/Raw.h"
13 #include "ip/Address.h"
14 #include "parser/BinaryTokenizer.h"
15 
17 {
18 }
19 
20 Parser::BinaryTokenizer::BinaryTokenizer(const SBuf &data, const bool expectMore):
21  context(nullptr),
22  data_(data),
23  parsed_(0),
24  syncPoint_(0),
25  expectMore_(expectMore)
26 {
27 }
28 
29 static inline
30 std::ostream &
31 operator <<(std::ostream &os, const Parser::BinaryTokenizerContext *context)
32 {
33  if (context)
34  os << context->parent << context->name;
35  return os;
36 }
37 
39 #define BinaryTokenizer_tail(size, start) \
40  " occupying " << (size) << " bytes @" << (start) << " in " << this << \
41  (expectMore_ ? ';' : '.');
42 
44 void
45 Parser::BinaryTokenizer::want(uint64_t size, const char *description) const
46 {
47  if (parsed_ + size > data_.length()) {
48  debugs(24, 5, (parsed_ + size - data_.length()) << " more bytes for " <<
49  context << description << BinaryTokenizer_tail(size, parsed_));
50  Must(expectMore_); // throw an error on premature input termination
51  throw InsufficientInput();
52  }
53 }
54 
55 void
56 Parser::BinaryTokenizer::got(uint64_t size, const char *description) const
57 {
58  debugs(24, 7, context << description <<
59  BinaryTokenizer_tail(size, parsed_ - size));
60 }
61 
63 void
64 Parser::BinaryTokenizer::got(uint32_t value, uint64_t size, const char *description) const
65 {
66  debugs(24, 7, context << description << '=' << value <<
67  BinaryTokenizer_tail(size, parsed_ - size));
68 }
69 
71 void
72 Parser::BinaryTokenizer::got(const SBuf &value, uint64_t size, const char *description) const
73 {
74  debugs(24, 7, context << description << '=' <<
75  Raw(nullptr, value.rawContent(), value.length()).hex() <<
76  BinaryTokenizer_tail(size, parsed_ - size));
77 
78 }
79 
81 void
82 Parser::BinaryTokenizer::got(const Ip::Address &value, uint64_t size, const char *description) const
83 {
84  debugs(24, 7, context << description << '=' << value <<
85  BinaryTokenizer_tail(size, parsed_ - size));
86 }
87 
89 void
90 Parser::BinaryTokenizer::skipped(uint64_t size, const char *description) const
91 {
92  debugs(24, 7, context << description << BinaryTokenizer_tail(size, parsed_ - size));
93 
94 }
95 
99 uint32_t
101 {
102  // While char may be signed, we view data characters as unsigned,
103  // which helps to arrive at the right 32-bit return value.
104  return static_cast<uint8_t>(data_[parsed_++]);
105 }
106 
107 void
108 Parser::BinaryTokenizer::reset(const SBuf &data, const bool expectMore)
109 {
110  *this = BinaryTokenizer(data, expectMore);
111 }
112 
113 void
115 {
116  parsed_ = syncPoint_;
117 }
118 
119 void
121 {
122  syncPoint_ = parsed_;
123 }
124 
125 bool
127 {
128  return parsed_ >= data_.length();
129 }
130 
131 uint8_t
132 Parser::BinaryTokenizer::uint8(const char *description)
133 {
134  want(1, description);
135  const uint8_t result = octet();
136  got(result, 1, description);
137  return result;
138 }
139 
140 uint16_t
141 Parser::BinaryTokenizer::uint16(const char *description)
142 {
143  want(2, description);
144  const uint16_t result = (octet() << 8) | octet();
145  got(result, 2, description);
146  return result;
147 }
148 
149 uint32_t
150 Parser::BinaryTokenizer::uint24(const char *description)
151 {
152  want(3, description);
153  const uint32_t result = (octet() << 16) | (octet() << 8) | octet();
154  got(result, 3, description);
155  return result;
156 }
157 
158 uint32_t
159 Parser::BinaryTokenizer::uint32(const char *description)
160 {
161  want(4, description);
162  const uint32_t result = (octet() << 24) | (octet() << 16) | (octet() << 8) | octet();
163  got(result, 4, description);
164  return result;
165 }
166 
167 SBuf
168 Parser::BinaryTokenizer::area(uint64_t size, const char *description)
169 {
170  want(size, description);
171  const SBuf result = data_.substr(parsed_, size);
172  parsed_ += size;
173  got(result, size, description);
174  return result;
175 }
176 
177 template <class InAddr>
179 Parser::BinaryTokenizer::inetAny(const char *description)
180 {
181  InAddr addr;
182  const auto size = sizeof(addr);
183  want(size, description);
184  memcpy(&addr, data_.rawContent() + parsed_, size);
185  parsed_ += size;
186  const Ip::Address result(addr);
187  got(result, size, description);
188  return result;
189 }
190 
192 Parser::BinaryTokenizer::inet4(const char *description)
193 {
194  return inetAny<struct in_addr>(description);
195 }
196 
198 Parser::BinaryTokenizer::inet6(const char *description)
199 {
200  return inetAny<struct in6_addr>(description);
201 }
202 
203 void
204 Parser::BinaryTokenizer::skip(uint64_t size, const char *description)
205 {
206  want(size, description);
207  parsed_ += size;
208  skipped(size, description);
209 }
210 
211 /*
212  * BinaryTokenizer::pstringN() implementations below reduce debugging noise by
213  * not parsing empty areas and not summarizing parsing context.success().
214  */
215 
216 SBuf
217 Parser::BinaryTokenizer::pstring8(const char *description)
218 {
219  BinaryTokenizerContext pstring(*this, description);
220  if (const uint8_t length = uint8(".length"))
221  return area(length, ".octets");
222  return SBuf();
223 }
224 
225 SBuf
226 Parser::BinaryTokenizer::pstring16(const char *description)
227 {
228  BinaryTokenizerContext pstring(*this, description);
229  if (const uint16_t length = uint16(".length"))
230  return area(length, ".octets");
231  return SBuf();
232 }
233 
234 SBuf
235 Parser::BinaryTokenizer::pstring24(const char *description)
236 {
237  BinaryTokenizerContext pstring(*this, description);
238  if (const uint32_t length = uint24(".length"))
239  return area(length, ".octets");
240  return SBuf();
241 }
242 
const BinaryTokenizerContext *const parent
enclosing context or nullptr
void reset(const SBuf &data, const bool expectMore)
SBuf area(uint64_t size, const char *description)
parse size consecutive bytes as an opaque blob
Ip::Address inet6(const char *description)
interpret the next 16 bytes as a raw in6_addr structure
Definition: SBuf.h:93
void commit()
make progress: future parsing failures will not rollback beyond this point
uint32_t uint24(const char *description)
parse a three-byte unsigned integer (returned as uint32_t)
const char *const name
this context description or nullptr
SBuf pstring24(const char *description)
up to 16 MiB-long p-string!
Ip::Address inetAny(const char *description)
SBuf substr(size_type pos, size_type n=npos) const
Definition: SBuf.cc:576
Ip::Address inet4(const char *description)
interpret the next 4 bytes as a raw in_addr structure
void rollback()
resume [incremental] parsing from the last commit point
void skip(uint64_t size, const char *description)
ignore the next size bytes
Definition: Raw.h:20
unsigned short uint16
Definition: rfcnb-priv.h:38
int size
Definition: ModDevPoll.cc:69
const char * rawContent() const
Definition: SBuf.cc:509
uint8_t uint8(const char *description)
parse a single-byte unsigned integer
void skipped(uint64_t size, const char *description) const
debugging helper for skipped fields
bool atEnd() const
no more bytes to parse or skip
enables efficient debugging with concise field names: Hello.version.major
void got(uint64_t size, const char *description) const
debugging helper for parsed multi-field structures
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:419
#define BinaryTokenizer_tail(size, start)
debugging helper that prints a "standard" debugs() trailer
#define Must(condition)
Definition: TextException.h:75
Raw & hex()
print data using two hex digits per byte (decoder: xxd -r -p)
Definition: Raw.h:30
SBuf pstring8(const char *description)
up to 255 byte-long p-string
void want(uint64_t size, const char *description) const
logs and throws if fewer than size octets remain; no other side effects
uint16_t uint16(const char *description)
parse a two-byte unsigned integer
uint32_t uint32(const char *description)
parse a four-byte unsigned integer
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
thrown by modern "incremental" parsers when they need more data
Definition: forward.h:18
SBuf pstring16(const char *description)
up to 64 KiB-long p-string
static std::ostream & operator<<(std::ostream &os, const Parser::BinaryTokenizerContext *context)

 

Introduction

Documentation

Support

Miscellaneous