LCOV - code coverage report
Current view: top level - lib/support - BufferReader.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 26 27 96.3 %
Date: 2024-02-15 08:20:41 Functions: 12 12 100.0 %

          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

Generated by: LCOV version 1.14