Matter SDK Coverage Report
Current view: top level - app/persistence - PascalString.h (source / functions) Coverage Total Hit
Test: SHA:4d2388ac7eed75b2fe5e05e20de377999c632502 Lines: 100.0 % 36 36
Test Date: 2025-07-27 07:17:09 Functions: 100.0 % 47 47

            Line data    Source code
       1              : /**
       2              :  *    Copyright (c) 2025 Project CHIP Authors
       3              :  *
       4              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       5              :  *    you may not use this file except in compliance with the License.
       6              :  *    You may obtain a copy of the License at
       7              :  *
       8              :  *        http://www.apache.org/licenses/LICENSE-2.0
       9              :  *
      10              :  *    Unless required by applicable law or agreed to in writing, software
      11              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      12              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13              :  *    See the License for the specific language governing permissions and
      14              :  *    limitations under the License.
      15              :  */
      16              : #pragma once
      17              : 
      18              : #include <app/ConcreteAttributePath.h>
      19              : #include <lib/core/CHIPEncoding.h>
      20              : #include <lib/core/CHIPError.h>
      21              : #include <lib/core/CHIPSafeCasts.h>
      22              : #include <lib/support/CodeUtils.h>
      23              : #include <lib/support/Span.h>
      24              : 
      25              : #include <algorithm>
      26              : #include <cstdint>
      27              : #include <type_traits>
      28              : 
      29              : namespace chip {
      30              : namespace app {
      31              : namespace Storage {
      32              : 
      33              : /// Describes how to set/get the length of pascal strings
      34              : /// given a PREFIX_LEN in bytes.
      35              : template <size_t PREFIX_LEN>
      36              : struct PascalPrefixOperations;
      37              : 
      38              : template <>
      39              : struct PascalPrefixOperations<1>
      40              : {
      41              :     using LengthType                           = uint8_t;
      42              :     static constexpr LengthType kInvalidLength = 0xFF;
      43              : 
      44           30 :     static LengthType GetContentLength(const uint8_t * buffer) { return *buffer; }
      45            8 :     static void SetContentLength(uint8_t * buffer, LengthType size) { *buffer = static_cast<uint8_t>(size); }
      46              : 
      47              :     // Casts for chars as well
      48           10 :     static LengthType GetContentLength(const char * buffer) { return GetContentLength(Uint8::from_const_char(buffer)); }
      49            3 :     static void SetContentLength(char * buffer, LengthType size) { SetContentLength(Uint8::from_char(buffer), size); }
      50              : };
      51              : 
      52              : template <>
      53              : struct PascalPrefixOperations<2>
      54              : {
      55              :     using LengthType                           = uint16_t;
      56              :     static constexpr LengthType kInvalidLength = 0xFFFF;
      57              : 
      58           39 :     static LengthType GetContentLength(const uint8_t * buffer) { return Encoding::LittleEndian::Get16(buffer); }
      59           10 :     static void SetContentLength(uint8_t * buffer, LengthType size) { Encoding::LittleEndian::Put16(buffer, size); }
      60              : 
      61              :     // Casts for chars as well
      62           15 :     static LengthType GetContentLength(const char * buffer) { return GetContentLength(Uint8::from_const_char(buffer)); }
      63            5 :     static void SetContentLength(char * buffer, LengthType size) { SetContentLength(Uint8::from_char(buffer), size); }
      64              : };
      65              : 
      66              : /// Interprets a byte buffer as a pascal buffer:
      67              : ///   - a prefix that specifies the length of the data
      68              : ///   - the following characters that contain the data
      69              : ///
      70              : /// Parameters:
      71              : ///   T - the underlying data type, generally uint8_t for bytes or char for strings
      72              : ///   PREFIX_LEN - the size of the pascal prefix (generally 1 or 2 bytes)
      73              : template <typename T, uint8_t PREFIX_LEN>
      74              : class PascalBuffer
      75              : {
      76              : public:
      77              :     using LengthType                           = typename PascalPrefixOperations<PREFIX_LEN>::LengthType;
      78              :     static constexpr LengthType kInvalidLength = PascalPrefixOperations<PREFIX_LEN>::kInvalidLength;
      79              : 
      80              :     static_assert(sizeof(T) == 1);
      81              : 
      82              :     PascalBuffer(PascalBuffer &&)      = default;
      83              :     PascalBuffer(const PascalBuffer &) = default;
      84              : 
      85              :     template <size_t N>
      86           12 :     PascalBuffer(T (&data)[N]) : mData(data), mMaxSize(N - PREFIX_LEN)
      87              :     {
      88              :         static_assert(N >= PREFIX_LEN);
      89              :         static_assert(N <= kInvalidLength);
      90           12 :     }
      91              : 
      92              :     /// Returns the content of the pascal string.
      93              :     /// Uses the prefix size information
      94           13 :     Span<T> Content() { return { mData + PREFIX_LEN, GetContentLength() }; }
      95              :     Span<const T> Content() const { return { mData + PREFIX_LEN, GetContentLength() }; }
      96              : 
      97              :     /// Accesses the "PASCAL" string (i.e. valid data including the string prefix)
      98              :     ///
      99              :     /// Use this to serialize the data. Specifically to recover the original string from
     100              :     /// persistent storage one can do one of two things:
     101              :     ///   - persist pascalString.ContentWithLenPrefix (will include the data WITH the size prefix AND the prefix
     102              :     ///     will correctly identify NULL strings via a kInvalidLength marker)
     103              :     ///     - read via pascalString.RawFullBuffer
     104              :     ///   - persist pascalString.Content (will NOT include data size and NULL strings will be the same as
     105              :     ///     empty strings) and consider if IsNull requires special handling
     106              :     ///     - read into a temporary buffer and set value via pascalString.SetValue()/SetNull()
     107              :     ///     - OR read into (RawFullBuffer().data() + PREFIX_LEN) and call SetContentLength() or SetNull if applicable
     108            8 :     ByteSpan ContentWithLenPrefix() const
     109              :     {
     110            8 :         return { reinterpret_cast<const uint8_t *>(mData), static_cast<size_t>(GetContentLength() + PREFIX_LEN) };
     111              :     }
     112              : 
     113              :     /// Access to the full buffer. does NOT take into account current size
     114              :     /// and includes the "size prefix"
     115           10 :     MutableByteSpan RawFullBuffer()
     116              :     {
     117              :         static_assert(!std::is_const_v<T>, "Cannot mutate a const pascal string");
     118           10 :         return { reinterpret_cast<uint8_t *>(mData), static_cast<size_t>(mMaxSize + PREFIX_LEN) };
     119              :     }
     120              : 
     121           42 :     LengthType GetContentLength() const
     122              :     {
     123           42 :         const LengthType length = PascalPrefixOperations<PREFIX_LEN>::GetContentLength(mData);
     124           42 :         if (length == kInvalidLength)
     125              :         {
     126            3 :             return 0;
     127              :         }
     128           39 :         return std::min<LengthType>(mMaxSize, length);
     129              :     }
     130              : 
     131              :     // Returns true if the length was valid and could be set
     132           22 :     bool SetContentLength(LengthType len)
     133              :     {
     134              :         static_assert(!std::is_const_v<T>, "Cannot mutate a const pascal string");
     135           22 :         if (len != kInvalidLength)
     136              :         {
     137           19 :             VerifyOrReturnError(len <= mMaxSize, false);
     138              :         }
     139           18 :         PascalPrefixOperations<PREFIX_LEN>::SetContentLength(mData, len);
     140           18 :         return true;
     141              :     }
     142            3 :     void SetNull() { (void) SetContentLength(kInvalidLength); }
     143           13 :     bool IsNull() const { return PascalPrefixOperations<PREFIX_LEN>::GetContentLength(mData) == kInvalidLength; }
     144              : 
     145              :     // Returns true if the length of the input buffer fit in the
     146              :     // pascal buffer (and could be set)
     147           15 :     bool SetValue(Span<const T> value)
     148              :     {
     149              :         static_assert(!std::is_const_v<T>, "Cannot mutate a const pascal string");
     150           15 :         VerifyOrReturnValue(value.size() < kInvalidLength, false);
     151           15 :         VerifyOrReturnValue(SetContentLength(static_cast<LengthType>(value.size())), false);
     152           11 :         memcpy(mData + PREFIX_LEN, value.data(), value.size());
     153           11 :         return true;
     154              :     }
     155              : 
     156              :     /// Checks if the given span is a valid Pascal string: i.e. its size prefix
     157              :     /// is either Invalid (i.e. null marker) or it has a size that fits in the buffer
     158           14 :     static bool IsValid(Span<const T> span)
     159              :     {
     160           14 :         VerifyOrReturnValue(span.size() >= PREFIX_LEN, false);
     161           14 :         LengthType len = PascalPrefixOperations<PREFIX_LEN>::GetContentLength(span.data());
     162           14 :         return len == kInvalidLength || (static_cast<size_t>(len + PREFIX_LEN) <= span.size());
     163              :     }
     164              : 
     165              : private:
     166              :     T * mData;
     167              :     const LengthType mMaxSize;
     168              : };
     169              : 
     170              : using ShortPascalString = PascalBuffer<char, 1>;
     171              : using ShortPascalBytes  = PascalBuffer<uint8_t, 1>;
     172              : using LongPascalString  = PascalBuffer<char, 2>;
     173              : using LongPascalBytes   = PascalBuffer<uint8_t, 2>;
     174              : 
     175              : // same as the pascal strings, except the data is const and cannot
     176              : // be changed. Useful to get the content of data
     177              : using ShortConstPascalString = PascalBuffer<const char, 1>;
     178              : using ShortConstPascalBytes  = PascalBuffer<const uint8_t, 1>;
     179              : using LongConstPascalString  = PascalBuffer<const char, 2>;
     180              : using LongConstPascalBytes   = PascalBuffer<const uint8_t, 2>;
     181              : 
     182              : } // namespace Storage
     183              : } // namespace app
     184              : } // namespace chip
        

Generated by: LCOV version 2.0-1