Matter SDK Coverage Report
Current view: top level - app/persistence - PascalString.h (source / functions) Coverage Total Hit
Test: SHA:97920baf58e6bf4a18be41e121e08f13676f36b0 Lines: 100.0 % 37 37
Test Date: 2025-08-17 07:11:11 Functions: 100.0 % 51 51

            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           96 :     static LengthType GetContentLength(const uint8_t * buffer) { return *buffer; }
      45           37 :     static void SetContentLength(uint8_t * buffer, LengthType size) { *buffer = static_cast<uint8_t>(size); }
      46              : 
      47              :     // Casts for chars as well
      48           72 :     static LengthType GetContentLength(const char * buffer) { return GetContentLength(Uint8::from_const_char(buffer)); }
      49           32 :     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              :     using ValueType                            = Span<const T>;
      79              :     static constexpr LengthType kInvalidLength = PascalPrefixOperations<PREFIX_LEN>::kInvalidLength;
      80              : 
      81              :     /// How many bytes of buffer are needed to store a max `charCount` sized buffer.
      82              :     static constexpr size_t BufferSizeFor(size_t charCount) { return PREFIX_LEN + charCount; }
      83              : 
      84              :     static_assert(sizeof(T) == 1);
      85              : 
      86              :     PascalBuffer(PascalBuffer &&)      = default;
      87              :     PascalBuffer(const PascalBuffer &) = default;
      88              : 
      89              :     /// Interprets the given data as the pascal string content.
      90              :     ///
      91              :     /// Note that this references the given data in place. Data lifetime must
      92              :     /// exceed the PascalBuffer lifetime.
      93              :     template <size_t N>
      94           12 :     PascalBuffer(T (&data)[N]) : mData(data), mMaxSize(N - PREFIX_LEN)
      95              :     {
      96              :         static_assert(N >= PREFIX_LEN);
      97              :         static_assert(N <= kInvalidLength);
      98           12 :     }
      99              : 
     100              :     /// Uses an existing buffer for the pascal string, represented as a span.
     101              :     ///
     102              :     /// The size of the span includes the prefix and must be at least PREFIX_LEN (this is NOT checked).
     103              :     ///
     104              :     /// Note that this references the given buffer in place. The buffer that the span
     105              :     /// points to must have a lifetime that exceeds the PascalBuffer lifetime.
     106           98 :     PascalBuffer(Span<T> data) : mData(data.data()), mMaxSize(static_cast<LengthType>(data.size() - PREFIX_LEN)) {}
     107              : 
     108              :     /// Returns the content of the pascal string.
     109              :     /// Uses the prefix size information
     110           41 :     Span<const T> Content() const { return { mData + PREFIX_LEN, GetContentLength() }; }
     111              : 
     112              :     /// Accesses the "PASCAL" string (i.e. valid data including the string prefix)
     113              :     ///
     114              :     /// Use this to serialize the data. Specifically to recover the original string from
     115              :     /// persistent storage one can do one of two things:
     116              :     ///   - persist pascalString.ContentWithLenPrefix (will include the data WITH the size prefix AND the prefix
     117              :     ///     will correctly identify NULL strings via a kInvalidLength marker)
     118              :     ///     - read via pascalString.RawFullBuffer
     119              :     ///   - persist pascalString.Content (will NOT include data size and NULL strings will be the same as
     120              :     ///     empty strings) and consider if IsNull requires special handling
     121              :     ///     - read into a temporary buffer and set value via pascalString.SetValue()/SetNull()
     122              :     ///     - OR read into (RawFullBuffer().data() + PREFIX_LEN) and call SetContentLength() or SetNull if applicable
     123           42 :     ByteSpan ContentWithLenPrefix() const
     124              :     {
     125           42 :         return { reinterpret_cast<const uint8_t *>(mData), static_cast<size_t>(GetContentLength() + PREFIX_LEN) };
     126              :     }
     127              : 
     128              :     /// Access to the full buffer. does NOT take into account current size
     129              :     /// and includes the "size prefix"
     130           17 :     MutableByteSpan RawFullBuffer()
     131              :     {
     132              :         static_assert(!std::is_const_v<T>, "Cannot mutate a const pascal string");
     133           17 :         return { reinterpret_cast<uint8_t *>(mData), static_cast<size_t>(mMaxSize + PREFIX_LEN) };
     134              :     }
     135              : 
     136          104 :     LengthType GetContentLength() const
     137              :     {
     138          104 :         const LengthType length = PascalPrefixOperations<PREFIX_LEN>::GetContentLength(mData);
     139          104 :         if (length == kInvalidLength)
     140              :         {
     141            3 :             return 0;
     142              :         }
     143          101 :         return std::min<LengthType>(mMaxSize, length);
     144              :     }
     145              : 
     146              :     // Returns true if the length was valid and could be set
     147           52 :     bool SetContentLength(LengthType len)
     148              :     {
     149              :         static_assert(!std::is_const_v<T>, "Cannot mutate a const pascal string");
     150           52 :         if (len != kInvalidLength)
     151              :         {
     152           49 :             VerifyOrReturnError(len <= mMaxSize, false);
     153              :         }
     154           47 :         PascalPrefixOperations<PREFIX_LEN>::SetContentLength(mData, len);
     155           47 :         return true;
     156              :     }
     157            3 :     void SetNull() { (void) SetContentLength(kInvalidLength); }
     158           13 :     bool IsNull() const { return PascalPrefixOperations<PREFIX_LEN>::GetContentLength(mData) == kInvalidLength; }
     159              : 
     160              :     // Returns true if the length of the input buffer fit in the
     161              :     // pascal buffer (and could be set)
     162           45 :     bool SetValue(Span<const T> value)
     163              :     {
     164              :         static_assert(!std::is_const_v<T>, "Cannot mutate a const pascal string");
     165           45 :         VerifyOrReturnValue(value.size() < kInvalidLength, false);
     166           45 :         VerifyOrReturnValue(SetContentLength(static_cast<LengthType>(value.size())), false);
     167           40 :         memcpy(mData + PREFIX_LEN, value.data(), value.size());
     168           40 :         return true;
     169              :     }
     170              : 
     171              :     /// Checks if the given span is a valid Pascal string: i.e. its size prefix
     172              :     /// is either Invalid (i.e. null marker) or it has a size that fits in the buffer
     173           18 :     static bool IsValid(ByteSpan span)
     174              :     {
     175           18 :         VerifyOrReturnValue(span.size() >= PREFIX_LEN, false);
     176           18 :         LengthType len = PascalPrefixOperations<PREFIX_LEN>::GetContentLength(span.data());
     177           18 :         return len == kInvalidLength || (static_cast<size_t>(len + PREFIX_LEN) <= span.size());
     178              :     }
     179              : 
     180              : private:
     181              :     T * mData;
     182              :     const LengthType mMaxSize;
     183              : };
     184              : 
     185              : using ShortPascalString = PascalBuffer<char, 1>;
     186              : using ShortPascalBytes  = PascalBuffer<uint8_t, 1>;
     187              : using LongPascalString  = PascalBuffer<char, 2>;
     188              : using LongPascalBytes   = PascalBuffer<uint8_t, 2>;
     189              : 
     190              : // same as the pascal strings, except the data is const and cannot
     191              : // be changed. Useful to get the content of data
     192              : using ShortConstPascalString = PascalBuffer<const char, 1>;
     193              : using ShortConstPascalBytes  = PascalBuffer<const uint8_t, 1>;
     194              : using LongConstPascalString  = PascalBuffer<const char, 2>;
     195              : using LongConstPascalBytes   = PascalBuffer<const uint8_t, 2>;
     196              : 
     197              : } // namespace Storage
     198              : } // namespace app
     199              : } // namespace chip
        

Generated by: LCOV version 2.0-1