]> git.ipfire.org Git - thirdparty/squid.git/blob - src/parser/BinaryTokenizer.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / parser / BinaryTokenizer.cc
1 /*
2 * Copyright (C) 1996-2020 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 "ip/Address.h"
13 #include "parser/BinaryTokenizer.h"
14
15 Parser::BinaryTokenizer::BinaryTokenizer(): BinaryTokenizer(SBuf())
16 {
17 }
18
19 Parser::BinaryTokenizer::BinaryTokenizer(const SBuf &data, const bool expectMore):
20 context(nullptr),
21 data_(data),
22 parsed_(0),
23 syncPoint_(0),
24 expectMore_(expectMore)
25 {
26 }
27
28 static inline
29 std::ostream &
30 operator <<(std::ostream &os, const Parser::BinaryTokenizerContext *context)
31 {
32 if (context)
33 os << context->parent << context->name;
34 return os;
35 }
36
37 /// debugging helper that prints a "standard" debugs() trailer
38 #define BinaryTokenizer_tail(size, start) \
39 " occupying " << (size) << " bytes @" << (start) << " in " << this << \
40 (expectMore_ ? ';' : '.');
41
42 /// logs and throws if fewer than size octets remain; no other side effects
43 void
44 Parser::BinaryTokenizer::want(uint64_t size, const char *description) const
45 {
46 if (parsed_ + size > data_.length()) {
47 debugs(24, 5, (parsed_ + size - data_.length()) << " more bytes for " <<
48 context << description << BinaryTokenizer_tail(size, parsed_));
49 Must(expectMore_); // throw an error on premature input termination
50 throw InsufficientInput();
51 }
52 }
53
54 void
55 Parser::BinaryTokenizer::got(uint64_t size, const char *description) const
56 {
57 debugs(24, 7, context << description <<
58 BinaryTokenizer_tail(size, parsed_ - size));
59 }
60
61 /// debugging helper for parsed number fields
62 void
63 Parser::BinaryTokenizer::got(uint32_t value, uint64_t size, const char *description) const
64 {
65 debugs(24, 7, context << description << '=' << value <<
66 BinaryTokenizer_tail(size, parsed_ - size));
67 }
68
69 /// debugging helper for parsed areas/blobs
70 void
71 Parser::BinaryTokenizer::got(const SBuf &value, uint64_t size, const char *description) const
72 {
73 debugs(24, 7, context << description << '=' <<
74 Raw(nullptr, value.rawContent(), value.length()).hex() <<
75 BinaryTokenizer_tail(size, parsed_ - size));
76
77 }
78
79 /// debugging helper for parsed addresses
80 void
81 Parser::BinaryTokenizer::got(const Ip::Address &value, uint64_t size, const char *description) const
82 {
83 debugs(24, 7, context << description << '=' << value <<
84 BinaryTokenizer_tail(size, parsed_ - size));
85 }
86
87 /// debugging helper for skipped fields
88 void
89 Parser::BinaryTokenizer::skipped(uint64_t size, const char *description) const
90 {
91 debugs(24, 7, context << description << BinaryTokenizer_tail(size, parsed_ - size));
92
93 }
94
95 /// Returns the next ready-for-shift byte, adjusting the number of parsed bytes.
96 /// The larger 32-bit return type helps callers shift/merge octets into numbers.
97 /// This internal method does not perform out-of-bounds checks.
98 uint32_t
99 Parser::BinaryTokenizer::octet()
100 {
101 // While char may be signed, we view data characters as unsigned,
102 // which helps to arrive at the right 32-bit return value.
103 return static_cast<uint8_t>(data_[parsed_++]);
104 }
105
106 void
107 Parser::BinaryTokenizer::reset(const SBuf &data, const bool expectMore)
108 {
109 *this = BinaryTokenizer(data, expectMore);
110 }
111
112 void
113 Parser::BinaryTokenizer::rollback()
114 {
115 parsed_ = syncPoint_;
116 }
117
118 void
119 Parser::BinaryTokenizer::commit()
120 {
121 syncPoint_ = parsed_;
122 }
123
124 bool
125 Parser::BinaryTokenizer::atEnd() const
126 {
127 return parsed_ >= data_.length();
128 }
129
130 uint8_t
131 Parser::BinaryTokenizer::uint8(const char *description)
132 {
133 want(1, description);
134 const uint8_t result = octet();
135 got(result, 1, description);
136 return result;
137 }
138
139 uint16_t
140 Parser::BinaryTokenizer::uint16(const char *description)
141 {
142 want(2, description);
143 const uint16_t result = (octet() << 8) | octet();
144 got(result, 2, description);
145 return result;
146 }
147
148 uint32_t
149 Parser::BinaryTokenizer::uint24(const char *description)
150 {
151 want(3, description);
152 const uint32_t result = (octet() << 16) | (octet() << 8) | octet();
153 got(result, 3, description);
154 return result;
155 }
156
157 uint32_t
158 Parser::BinaryTokenizer::uint32(const char *description)
159 {
160 want(4, description);
161 const uint32_t result = (octet() << 24) | (octet() << 16) | (octet() << 8) | octet();
162 got(result, 4, description);
163 return result;
164 }
165
166 SBuf
167 Parser::BinaryTokenizer::area(uint64_t size, const char *description)
168 {
169 want(size, description);
170 const SBuf result = data_.substr(parsed_, size);
171 parsed_ += size;
172 got(result, size, description);
173 return result;
174 }
175
176 template <class InAddr>
177 Ip::Address
178 Parser::BinaryTokenizer::inetAny(const char *description)
179 {
180 InAddr addr;
181 const auto size = sizeof(addr);
182 want(size, description);
183 memcpy(&addr, data_.rawContent() + parsed_, size);
184 parsed_ += size;
185 const Ip::Address result(addr);
186 got(result, size, description);
187 return result;
188 }
189
190 Ip::Address
191 Parser::BinaryTokenizer::inet4(const char *description)
192 {
193 return inetAny<struct in_addr>(description);
194 }
195
196 Ip::Address
197 Parser::BinaryTokenizer::inet6(const char *description)
198 {
199 return inetAny<struct in6_addr>(description);
200 }
201
202 void
203 Parser::BinaryTokenizer::skip(uint64_t size, const char *description)
204 {
205 want(size, description);
206 parsed_ += size;
207 skipped(size, description);
208 }
209
210 /*
211 * BinaryTokenizer::pstringN() implementations below reduce debugging noise by
212 * not parsing empty areas and not summarizing parsing context.success().
213 */
214
215 SBuf
216 Parser::BinaryTokenizer::pstring8(const char *description)
217 {
218 BinaryTokenizerContext pstring(*this, description);
219 if (const uint8_t length = uint8(".length"))
220 return area(length, ".octets");
221 return SBuf();
222 }
223
224 SBuf
225 Parser::BinaryTokenizer::pstring16(const char *description)
226 {
227 BinaryTokenizerContext pstring(*this, description);
228 if (const uint16_t length = uint16(".length"))
229 return area(length, ".octets");
230 return SBuf();
231 }
232
233 SBuf
234 Parser::BinaryTokenizer::pstring24(const char *description)
235 {
236 BinaryTokenizerContext pstring(*this, description);
237 if (const uint32_t length = uint24(".length"))
238 return area(length, ".octets");
239 return SBuf();
240 }
241