Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : /**
19 : * @file
20 : * Utility classes for safely reading from size-limited buffers.
21 : */
22 :
23 : #pragma once
24 :
25 : #include <climits>
26 : #include <lib/core/CHIPEncoding.h>
27 : #include <lib/core/CHIPError.h>
28 : #include <lib/support/CodeUtils.h>
29 : #include <lib/support/Span.h>
30 : #include <stdint.h>
31 :
32 : namespace chip {
33 : namespace Encoding {
34 :
35 : class BufferReader
36 : {
37 : public:
38 47717 : BufferReader(const uint8_t * buffer, size_t buf_len) : mBufStart(buffer), mReadPtr(buffer), mAvailable(buf_len)
39 : {
40 47717 : if (mBufStart == nullptr)
41 : {
42 0 : mAvailable = 0;
43 : }
44 47717 : }
45 :
46 : /**
47 : * Number of octets we have read so far.
48 : */
49 35774 : size_t OctetsRead() const { return static_cast<size_t>(mReadPtr - mBufStart); }
50 :
51 : /**
52 : * Number of octets we have remaining to read.
53 : */
54 931 : size_t Remaining() const { return mAvailable; }
55 :
56 : /**
57 : * Test whether we have at least the given number of octets left to read.
58 : */
59 66 : bool HasAtLeast(size_t octets) const { return octets <= Remaining(); }
60 :
61 : /**
62 : * The reader status. Once the status becomes a failure status, all later
63 : * read operations become no-ops and the status continues to be a failure
64 : * status.
65 : */
66 : CHECK_RETURN_VALUE
67 360903 : CHIP_ERROR StatusCode() const { return mStatus; }
68 :
69 : /**
70 : * @return false if the reader is in error, true if the reader is OK.
71 : */
72 189446 : bool IsSuccess() const { return StatusCode() == CHIP_NO_ERROR; }
73 :
74 : /**
75 : * Read a byte string from the BufferReader
76 : *
77 : * @param [out] dest Where the bytes read
78 : * @param [in] size How many bytes to read
79 : *
80 : * @note The read can put the reader in a failed-status state if there are
81 : * not enough octets available. Callers must either continue to do
82 : * more reads on the return value or check its status to see whether
83 : * the sequence of reads that has been performed succeeded.
84 : */
85 : CHECK_RETURN_VALUE
86 : BufferReader & ReadBytes(uint8_t * dest, size_t size);
87 :
88 : /**
89 : * Access bytes of size length, useful for in-place processing of strings
90 : *
91 : * data_ptr MUST NOT be null and will contain the data pointer with `len` bytes available
92 : * if this call is successful
93 : *
94 : * If len is greater than the number of available bytes, the object enters in a failed status.
95 : */
96 : CHECK_RETURN_VALUE
97 23 : BufferReader & ZeroCopyProcessBytes(size_t len, const uint8_t ** data_ptr)
98 : {
99 23 : if (len > mAvailable)
100 : {
101 2 : *data_ptr = nullptr;
102 2 : mStatus = CHIP_ERROR_BUFFER_TOO_SMALL;
103 : // Ensure that future reads all fail.
104 2 : mAvailable = 0;
105 : }
106 : else
107 : {
108 21 : *data_ptr = mReadPtr;
109 21 : mReadPtr += len;
110 21 : mAvailable -= len;
111 : }
112 23 : return *this;
113 : }
114 :
115 : /**
116 : * Advance the Reader forward by the specified number of octets.
117 : *
118 : * @param len The number of octets to skip.
119 : *
120 : * @note If the len argument is greater than the number of available octets
121 : * remaining, the Reader will advance to the end of the buffer
122 : * without entering a failed-status state.
123 : */
124 11 : BufferReader & Skip(size_t len)
125 : {
126 11 : len = std::min(len, mAvailable);
127 11 : mReadPtr += len;
128 11 : mAvailable = static_cast<size_t>(mAvailable - len);
129 11 : return *this;
130 : }
131 :
132 : protected:
133 : /// Our buffer start.
134 : const uint8_t * const mBufStart;
135 :
136 : /// Our current read point.
137 : const uint8_t * mReadPtr;
138 :
139 : /// The number of octets we can still read starting at mReadPtr.
140 : size_t mAvailable;
141 :
142 : /// Our current status.
143 : CHIP_ERROR mStatus = CHIP_NO_ERROR;
144 :
145 : /// Make sure we have at least the given number of bytes available (does not consume them)
146 194232 : bool EnsureAvailable(size_t size)
147 : {
148 194232 : if (mAvailable < size)
149 : {
150 309 : mStatus = CHIP_ERROR_BUFFER_TOO_SMALL;
151 : // Ensure that future reads all fail.
152 309 : mAvailable = 0;
153 309 : return false;
154 : }
155 193923 : return true;
156 : }
157 : };
158 :
159 : namespace LittleEndian {
160 :
161 : /**
162 : * @class Reader
163 : *
164 : * Simple reader for reading little-endian things out of buffers.
165 : */
166 : class Reader : public BufferReader
167 : {
168 : public:
169 : /**
170 : * Create a buffer reader from a given buffer and length.
171 : *
172 : * @param buffer The octet buffer from which to read. The caller must ensure
173 : * (most simply by allocating the reader on the stack) that
174 : * the buffer outlives the reader. If `buffer` is nullptr,
175 : * length is automatically overridden to zero, to avoid accesses.
176 : * @param buf_len The number of octets in the buffer.
177 : */
178 47717 : Reader(const uint8_t * buffer, size_t buf_len) : BufferReader(buffer, buf_len) {}
179 :
180 : /**
181 : * Create a buffer reader from a given byte span.
182 : *
183 : * @param buffer The octet buffer byte span from which to read. The caller must ensure
184 : * that the buffer outlives the reader. The buffer's ByteSpan .data() pointer
185 : * is is nullptr, length is automatically overridden to zero, to avoid accesses.
186 : */
187 365 : Reader(const ByteSpan & buffer) : Reader(buffer.data(), buffer.size()) {}
188 :
189 : /**
190 : * Read a bool, assuming single byte storage.
191 : *
192 : * @param [out] dest Where the 8-bit integer goes.
193 : *
194 : * @note The read can put the reader in a failed-status state if there are
195 : * not enough octets available. Callers must either continue to do
196 : * more reads on the return value or check its status to see whether
197 : * the sequence of reads that has been performed succeeded.
198 : */
199 : CHECK_RETURN_VALUE
200 : Reader & ReadBool(bool * dest)
201 : {
202 : static_assert(sizeof(bool) == 1, "Expect single-byte bools");
203 : RawReadLowLevelBeCareful(dest);
204 : return *this;
205 : }
206 :
207 : /**
208 : * Read a char, assuming single byte storage.
209 : *
210 : * @param [out] dest Where the char just read should be placed.
211 : *
212 : * @note The read can put the reader in a failed-status state if there are
213 : * not enough octets available. Callers must either continue to do
214 : * more reads on the return value or check its status to see whether
215 : * the sequence of reads that has been performed succeeded.
216 : */
217 : CHECK_RETURN_VALUE
218 : Reader & ReadChar(char * dest)
219 : {
220 : static_assert(sizeof(char) == 1, "Expect single-byte chars");
221 : RawReadLowLevelBeCareful(dest);
222 : return *this;
223 : }
224 :
225 : /**
226 : * Read a single 8-bit unsigned integer.
227 : *
228 : * @param [out] dest Where the 8-bit integer goes.
229 : *
230 : * @note The read can put the reader in a failed-status state if there are
231 : * not enough octets available. Callers must either continue to do
232 : * more reads on the return value or check its status to see whether
233 : * the sequence of reads that has been performed succeeded.
234 : */
235 : CHECK_RETURN_VALUE
236 99343 : Reader & Read8(uint8_t * dest)
237 : {
238 99343 : RawReadLowLevelBeCareful(dest);
239 99343 : return *this;
240 : }
241 :
242 : /**
243 : * Read a single 16-bit unsigned integer.
244 : *
245 : * @param [out] dest Where the 16-bit integer goes.
246 : *
247 : * @note The read can put the reader in a failed-status state if there are
248 : * not enough octets available. Callers must either continue to do
249 : * more reads on the return value or check its status to see whether
250 : * the sequence of reads that has been performed succeeded.
251 : */
252 : CHECK_RETURN_VALUE
253 55388 : Reader & Read16(uint16_t * dest)
254 : {
255 55388 : RawReadLowLevelBeCareful(dest);
256 55388 : return *this;
257 : }
258 :
259 : /**
260 : * Read a single 32-bit unsigned integer.
261 : *
262 : * @param [out] dest Where the 32-bit integer goes.
263 : *
264 : * @note The read can put the reader in a failed-status state if there are
265 : * not enough octets available. Callers must either continue to do
266 : * more reads on the return value or check its status to see whether
267 : * the sequence of reads that has been performed succeeded.
268 : */
269 : CHECK_RETURN_VALUE
270 34078 : Reader & Read32(uint32_t * dest)
271 : {
272 34078 : RawReadLowLevelBeCareful(dest);
273 34078 : return *this;
274 : }
275 :
276 : /**
277 : * Read a single 64-bit unsigned integer.
278 : *
279 : * @param [out] dest Where the 64-bit integer goes.
280 : *
281 : * @note The read can put the reader in a failed-status state if there are
282 : * not enough octets available. Callers must either continue to do
283 : * more reads on the return value or check its status to see whether
284 : * the sequence of reads that has been performed succeeded.
285 : */
286 : CHECK_RETURN_VALUE
287 367 : Reader & Read64(uint64_t * dest)
288 : {
289 367 : RawReadLowLevelBeCareful(dest);
290 367 : return *this;
291 : }
292 :
293 : /**
294 : * Read a single 8-bit signed integer.
295 : *
296 : * @param [out] dest Where the 8-bit integer goes.
297 : *
298 : * @note The read can put the reader in a failed-status state if there are
299 : * not enough octets available. Callers must either continue to do
300 : * more reads on the return value or check its status to see whether
301 : * the sequence of reads that has been performed succeeded.
302 : */
303 : CHECK_RETURN_VALUE
304 : Reader & ReadSigned8(int8_t * dest)
305 : {
306 : RawReadLowLevelBeCareful(dest);
307 : return *this;
308 : }
309 :
310 : /**
311 : * Read a single 16-bit signed integer.
312 : *
313 : * @param [out] dest Where the 16-bit integer goes.
314 : *
315 : * @note The read can put the reader in a failed-status state if there are
316 : * not enough octets available. Callers must either continue to do
317 : * more reads on the return value or check its status to see whether
318 : * the sequence of reads that has been performed succeeded.
319 : */
320 : CHECK_RETURN_VALUE
321 : Reader & ReadSigned16(int16_t * dest)
322 : {
323 : RawReadLowLevelBeCareful(dest);
324 : return *this;
325 : }
326 :
327 : /**
328 : * Read a single 32-bit signed integer.
329 : *
330 : * @param [out] dest Where the 32-bit integer goes.
331 : *
332 : * @note The read can put the reader in a failed-status state if there are
333 : * not enough octets available. Callers must either continue to do
334 : * more reads on the return value or check its status to see whether
335 : * the sequence of reads that has been performed succeeded.
336 : */
337 : CHECK_RETURN_VALUE
338 : Reader & ReadSigned32(int32_t * dest)
339 : {
340 : RawReadLowLevelBeCareful(dest);
341 : return *this;
342 : }
343 :
344 : /**
345 : * Read a single 64-bit signed integer.
346 : *
347 : * @param [out] dest Where the 64-bit integer goes.
348 : *
349 : * @note The read can put the reader in a failed-status state if there are
350 : * not enough octets available. Callers must either continue to do
351 : * more reads on the return value or check its status to see whether
352 : * the sequence of reads that has been performed succeeded.
353 : */
354 : CHECK_RETURN_VALUE
355 : Reader & ReadSigned64(int64_t * dest)
356 : {
357 : RawReadLowLevelBeCareful(dest);
358 : return *this;
359 : }
360 :
361 : /**
362 : * Helper for our various APIs so we don't have to write out various logic
363 : * multiple times. This is public so that consumers that want to read into
364 : * whatever size a logical thing they are reading into has don't have to
365 : * hardcode the right API. This is meant for other reader classes that
366 : * delegate to this one.
367 : */
368 : template <typename T>
369 : void RawReadLowLevelBeCareful(T * retval);
370 : };
371 :
372 : } // namespace LittleEndian
373 :
374 : namespace BigEndian {
375 :
376 : /**
377 : * @class Reader
378 : *
379 : * Simple reader for reading big-endian things out of buffers.
380 : */
381 : class Reader : public BufferReader
382 : {
383 : public:
384 : /**
385 : * Create a buffer reader from a given buffer and length.
386 : *
387 : * @param buffer The octet buffer from which to read. The caller must ensure
388 : * (most simply by allocating the reader on the stack) that
389 : * the buffer outlives the reader. If `buffer` is nullptr,
390 : * length is automatically overridden to zero, to avoid accesses.
391 : * @param buf_len The number of octets in the buffer.
392 : */
393 : Reader(const uint8_t * buffer, size_t buf_len) : BufferReader(buffer, buf_len) {}
394 :
395 : /**
396 : * Create a buffer reader from a given byte span.
397 : *
398 : * @param buffer The octet buffer byte span from which to read. The caller must ensure
399 : * that the buffer outlives the reader. If the buffer's ByteSpan .data() pointer
400 : * is nullptr, length is automatically overridden to zero, to avoid accesses.
401 : */
402 : Reader(const ByteSpan & buffer) : Reader(buffer.data(), buffer.size()) {}
403 :
404 : /**
405 : * Read a single 8-bit unsigned integer.
406 : *
407 : * @param [out] dest Where the 8-bit integer goes.
408 : *
409 : * @note The read can put the reader in a failed-status state if there are
410 : * not enough octets available. Callers must either continue to do
411 : * more reads on the return value or check its status to see whether
412 : * the sequence of reads that has been performed succeeded.
413 : */
414 : CHECK_RETURN_VALUE
415 : Reader & Read8(uint8_t * dest)
416 : {
417 : (void) ReadBytes(dest, 1);
418 : return *this;
419 : }
420 :
421 : CHECK_RETURN_VALUE
422 : Reader & ReadChar(char * dest)
423 : {
424 : (void) ReadBytes(reinterpret_cast<uint8_t *>(dest), 1);
425 : return *this;
426 : }
427 :
428 : CHECK_RETURN_VALUE
429 : Reader & ReadBool(char * dest)
430 : {
431 : (void) ReadBytes(reinterpret_cast<uint8_t *>(dest), 1);
432 : return *this;
433 : }
434 :
435 : /// NOTE: only a subset of reads are supported here, more can be added if used/needed
436 : CHECK_RETURN_VALUE
437 : Reader & Read16(uint16_t * dest);
438 :
439 : CHECK_RETURN_VALUE
440 : Reader & Read32(uint32_t * dest);
441 : };
442 :
443 : } // namespace BigEndian
444 :
445 : } // namespace Encoding
446 : } // namespace chip
|