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 : namespace LittleEndian { 35 : 36 : /** 37 : * @class Reader 38 : * 39 : * Simple reader for reading little-endian things out of buffers. 40 : */ 41 : class Reader 42 : { 43 : public: 44 : /** 45 : * Create a buffer reader from a given buffer and length. 46 : * 47 : * @param buffer The octet buffer from which to read. The caller must ensure 48 : * (most simply by allocating the reader on the stack) that 49 : * the buffer outlives the reader. If `buffer` is nullptr, 50 : * length is automatically overridden to zero, to avoid accesses. 51 : * @param buf_len The number of octets in the buffer. 52 : */ 53 38304 : Reader(const uint8_t * buffer, size_t buf_len) : mBufStart(buffer), mReadPtr(buffer), mAvailable(buf_len) 54 : { 55 38304 : if (mBufStart == nullptr) 56 : { 57 0 : mAvailable = 0; 58 : } 59 38304 : } 60 : 61 : /** 62 : * Create a buffer reader from a given byte span. 63 : * 64 : * @param buffer The octet buffer byte span from which to read. The caller must ensure 65 : * that the buffer outlives the reader. The buffer's ByteSpan .data() pointer 66 : * is is nullptr, length is automatically overridden to zero, to avoid accesses. 67 : */ 68 361 : Reader(const ByteSpan & buffer) : Reader(buffer.data(), buffer.size()) {} 69 : 70 : /** 71 : * Number of octets we have read so far. 72 : */ 73 26984 : size_t OctetsRead() const { return static_cast<size_t>(mReadPtr - mBufStart); } 74 : 75 : /** 76 : * Number of octets we have remaining to read. 77 : */ 78 925 : size_t Remaining() const { return mAvailable; } 79 : 80 : /** 81 : * Test whether we have at least the given number of octets left to read. 82 : */ 83 65 : bool HasAtLeast(size_t octets) const { return octets <= Remaining(); } 84 : 85 : /** 86 : * The reader status. Once the status becomes a failure status, all later 87 : * read operations become no-ops and the status continues to be a failure 88 : * status. 89 : */ 90 : CHECK_RETURN_VALUE 91 288697 : CHIP_ERROR StatusCode() const { return mStatus; } 92 : 93 : /** 94 : * @return false if the reader is in error, true if the reader is OK. 95 : */ 96 153125 : bool IsSuccess() const { return StatusCode() == CHIP_NO_ERROR; } 97 : 98 : /** 99 : * Read a bool, assuming single byte storage. 100 : * 101 : * @param [out] dest Where the 8-bit integer goes. 102 : * 103 : * @note The read can put the reader in a failed-status state if there are 104 : * not enough octets available. Callers must either continue to do 105 : * more reads on the return value or check its status to see whether 106 : * the sequence of reads that has been performed succeeded. 107 : */ 108 : CHECK_RETURN_VALUE 109 : Reader & ReadBool(bool * dest) 110 : { 111 : static_assert(sizeof(bool) == 1, "Expect single-byte bools"); 112 : RawReadLowLevelBeCareful(dest); 113 : return *this; 114 : } 115 : 116 : /** 117 : * Read a char, assuming single byte storage. 118 : * 119 : * @param [out] dest Where the char just read should be placed. 120 : * 121 : * @note The read can put the reader in a failed-status state if there are 122 : * not enough octets available. Callers must either continue to do 123 : * more reads on the return value or check its status to see whether 124 : * the sequence of reads that has been performed succeeded. 125 : */ 126 : CHECK_RETURN_VALUE 127 : Reader & ReadChar(char * dest) 128 : { 129 : static_assert(sizeof(char) == 1, "Expect single-byte chars"); 130 : RawReadLowLevelBeCareful(dest); 131 : return *this; 132 : } 133 : 134 : /** 135 : * Read a single 8-bit unsigned integer. 136 : * 137 : * @param [out] dest Where the 8-bit integer goes. 138 : * 139 : * @note The read can put the reader in a failed-status state if there are 140 : * not enough octets available. Callers must either continue to do 141 : * more reads on the return value or check its status to see whether 142 : * the sequence of reads that has been performed succeeded. 143 : */ 144 : CHECK_RETURN_VALUE 145 81259 : Reader & Read8(uint8_t * dest) 146 : { 147 81259 : RawReadLowLevelBeCareful(dest); 148 81259 : return *this; 149 : } 150 : 151 : /** 152 : * Read a single 16-bit unsigned integer. 153 : * 154 : * @param [out] dest Where the 16-bit integer goes. 155 : * 156 : * @note The read can put the reader in a failed-status state if there are 157 : * not enough octets available. Callers must either continue to do 158 : * more reads on the return value or check its status to see whether 159 : * the sequence of reads that has been performed succeeded. 160 : */ 161 : CHECK_RETURN_VALUE 162 46120 : Reader & Read16(uint16_t * dest) 163 : { 164 46120 : RawReadLowLevelBeCareful(dest); 165 46120 : return *this; 166 : } 167 : 168 : /** 169 : * Read a single 32-bit unsigned integer. 170 : * 171 : * @param [out] dest Where the 32-bit integer goes. 172 : * 173 : * @note The read can put the reader in a failed-status state if there are 174 : * not enough octets available. Callers must either continue to do 175 : * more reads on the return value or check its status to see whether 176 : * the sequence of reads that has been performed succeeded. 177 : */ 178 : CHECK_RETURN_VALUE 179 25391 : Reader & Read32(uint32_t * dest) 180 : { 181 25391 : RawReadLowLevelBeCareful(dest); 182 25391 : return *this; 183 : } 184 : 185 : /** 186 : * Read a single 64-bit unsigned integer. 187 : * 188 : * @param [out] dest Where the 64-bit integer goes. 189 : * 190 : * @note The read can put the reader in a failed-status state if there are 191 : * not enough octets available. Callers must either continue to do 192 : * more reads on the return value or check its status to see whether 193 : * the sequence of reads that has been performed succeeded. 194 : */ 195 : CHECK_RETURN_VALUE 196 283 : Reader & Read64(uint64_t * dest) 197 : { 198 283 : RawReadLowLevelBeCareful(dest); 199 283 : return *this; 200 : } 201 : 202 : /** 203 : * Read a single 8-bit signed integer. 204 : * 205 : * @param [out] dest Where the 8-bit integer goes. 206 : * 207 : * @note The read can put the reader in a failed-status state if there are 208 : * not enough octets available. Callers must either continue to do 209 : * more reads on the return value or check its status to see whether 210 : * the sequence of reads that has been performed succeeded. 211 : */ 212 : CHECK_RETURN_VALUE 213 : Reader & ReadSigned8(int8_t * dest) 214 : { 215 : RawReadLowLevelBeCareful(dest); 216 : return *this; 217 : } 218 : 219 : /** 220 : * Read a single 16-bit signed integer. 221 : * 222 : * @param [out] dest Where the 16-bit integer goes. 223 : * 224 : * @note The read can put the reader in a failed-status state if there are 225 : * not enough octets available. Callers must either continue to do 226 : * more reads on the return value or check its status to see whether 227 : * the sequence of reads that has been performed succeeded. 228 : */ 229 : CHECK_RETURN_VALUE 230 : Reader & ReadSigned16(int16_t * dest) 231 : { 232 : RawReadLowLevelBeCareful(dest); 233 : return *this; 234 : } 235 : 236 : /** 237 : * Read a single 32-bit signed integer. 238 : * 239 : * @param [out] dest Where the 32-bit integer goes. 240 : * 241 : * @note The read can put the reader in a failed-status state if there are 242 : * not enough octets available. Callers must either continue to do 243 : * more reads on the return value or check its status to see whether 244 : * the sequence of reads that has been performed succeeded. 245 : */ 246 : CHECK_RETURN_VALUE 247 : Reader & ReadSigned32(int32_t * dest) 248 : { 249 : RawReadLowLevelBeCareful(dest); 250 : return *this; 251 : } 252 : 253 : /** 254 : * Read a single 64-bit signed integer. 255 : * 256 : * @param [out] dest Where the 64-bit integer goes. 257 : * 258 : * @note The read can put the reader in a failed-status state if there are 259 : * not enough octets available. Callers must either continue to do 260 : * more reads on the return value or check its status to see whether 261 : * the sequence of reads that has been performed succeeded. 262 : */ 263 : CHECK_RETURN_VALUE 264 : Reader & ReadSigned64(int64_t * dest) 265 : { 266 : RawReadLowLevelBeCareful(dest); 267 : return *this; 268 : } 269 : 270 : /** 271 : * Read a byte string from the BufferReader 272 : * 273 : * @param [out] dest Where the bytes read 274 : * @param [in] size How many bytes to read 275 : * 276 : * @note The read can put the reader in a failed-status state if there are 277 : * not enough octets available. Callers must either continue to do 278 : * more reads on the return value or check its status to see whether 279 : * the sequence of reads that has been performed succeeded. 280 : */ 281 : CHECK_RETURN_VALUE 282 : Reader & ReadBytes(uint8_t * dest, size_t size); 283 : 284 : /** 285 : * Helper for our various APIs so we don't have to write out various logic 286 : * multiple times. This is public so that consumers that want to read into 287 : * whatever size a logical thing they are reading into has don't have to 288 : * hardcode the right API. This is meant for other reader classes that 289 : * delegate to this one. 290 : */ 291 : template <typename T> 292 : void RawReadLowLevelBeCareful(T * retval); 293 : 294 : /** 295 : * Advance the Reader forward by the specified number of octets. 296 : * 297 : * @param len The number of octets to skip. 298 : * 299 : * @note If the len argument is greater than the number of available octets 300 : * remaining, the Reader will advance to the end of the buffer 301 : * without entering a failed-status state. 302 : */ 303 11 : Reader & Skip(size_t len) 304 : { 305 11 : len = ::chip::min(len, mAvailable); 306 11 : mReadPtr += len; 307 11 : mAvailable = static_cast<size_t>(mAvailable - len); 308 11 : return *this; 309 : } 310 : 311 : private: 312 : /** 313 : * Our buffer start. 314 : */ 315 : const uint8_t * const mBufStart; 316 : 317 : /** 318 : * Our current read point. 319 : */ 320 : const uint8_t * mReadPtr; 321 : 322 : /** 323 : * The number of octets we can still read starting at mReadPtr. 324 : */ 325 : size_t mAvailable; 326 : 327 : /** 328 : * Our current status. 329 : */ 330 : CHIP_ERROR mStatus = CHIP_NO_ERROR; 331 : }; 332 : 333 : } // namespace LittleEndian 334 : } // namespace Encoding 335 : } // namespace chip