Matter SDK Coverage Report
Current view: top level - lib/support - BufferReader.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 97.7 % 43 42
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 15 15

            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
        

Generated by: LCOV version 2.0-1