Matter SDK Coverage Report
Current view: top level - lib/core - TLVWriter.cpp (source / functions) Coverage Total Hit
Test: SHA:1560a87972ec2c7a76cec101927a563a6862bc2a Lines: 93.3 % 374 349
Test Date: 2025-03-30 07:08:27 Functions: 100.0 % 45 45

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4              :  *    Copyright (c) 2013-2017 Nest Labs, Inc.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : #include <lib/core/TLVWriter.h>
      19              : 
      20              : #include <stdarg.h>
      21              : #include <stdint.h>
      22              : #include <stdio.h>
      23              : #include <string.h>
      24              : 
      25              : #include <lib/core/CHIPConfig.h>
      26              : #include <lib/core/CHIPEncoding.h>
      27              : #include <lib/core/CHIPError.h>
      28              : #include <lib/core/TLVBackingStore.h>
      29              : #include <lib/core/TLVCommon.h>
      30              : #include <lib/core/TLVReader.h>
      31              : #include <lib/core/TLVTags.h>
      32              : #include <lib/core/TLVTypes.h>
      33              : #include <lib/support/BufferWriter.h>
      34              : #include <lib/support/CHIPMem.h>
      35              : #include <lib/support/CodeUtils.h>
      36              : #include <lib/support/SafeInt.h>
      37              : #include <lib/support/Span.h>
      38              : #include <lib/support/logging/Constants.h>
      39              : #include <lib/support/logging/TextOnlyLogging.h>
      40              : #include <lib/support/utf8.h>
      41              : #include <system/SystemConfig.h>
      42              : 
      43              : // Doxygen is confused by the __attribute__ annotation
      44              : #ifndef DOXYGEN
      45              : #define NO_INLINE __attribute__((noinline))
      46              : #endif // DOXYGEN
      47              : 
      48              : // You can enable this block manually to abort on usage of uninitialized writers in
      49              : // your codebase. There are no such usages in the SDK (outside of tests).
      50              : #if 0
      51              : #define ABORT_ON_UNINITIALIZED_IF_ENABLED() VerifyOrDie(IsInitialized() == true)
      52              : #else
      53              : #define ABORT_ON_UNINITIALIZED_IF_ENABLED()                                                                                        \
      54              :     do                                                                                                                             \
      55              :     {                                                                                                                              \
      56              :     } while (0)
      57              : #endif
      58              : 
      59              : namespace chip {
      60              : namespace TLV {
      61              : 
      62              : using namespace chip::Encoding;
      63              : 
      64        51952 : TLVWriter::TLVWriter() :
      65        51952 :     ImplicitProfileId(kProfileIdNotSpecified), AppData(nullptr), mBackingStore(nullptr), mBufStart(nullptr), mWritePoint(nullptr),
      66        51952 :     mRemainingLen(0), mLenWritten(0), mMaxLen(0), mReservedSize(0), mContainerType(kTLVType_NotSpecified), mInitializationCookie(0),
      67        51952 :     mContainerOpen(false), mCloseContainerReserved(true)
      68        51952 : {}
      69              : 
      70        32961 : NO_INLINE void TLVWriter::Init(uint8_t * buf, size_t maxLen)
      71              : {
      72              :     // TODO: Maybe we can just make mMaxLen, mLenWritten, mRemainingLen size_t instead?
      73        32961 :     uint32_t actualMaxLen = maxLen > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(maxLen);
      74              : 
      75              :     // TODO(#30825): Need to ensure a single init path for this complex data.
      76        32961 :     mInitializationCookie = 0;
      77        32961 :     mBackingStore         = nullptr;
      78        32961 :     mBufStart             = buf;
      79        32961 :     mWritePoint           = buf;
      80        32961 :     mRemainingLen         = actualMaxLen;
      81        32961 :     mLenWritten           = 0;
      82        32961 :     mMaxLen               = actualMaxLen;
      83        32961 :     mContainerType        = kTLVType_NotSpecified;
      84        32961 :     mReservedSize         = 0;
      85        32961 :     SetContainerOpen(false);
      86        32961 :     SetCloseContainerReserved(true);
      87              : 
      88        32961 :     ImplicitProfileId     = kProfileIdNotSpecified;
      89        32961 :     mInitializationCookie = kExpectedInitializationCookie;
      90        32961 : }
      91              : 
      92        20936 : CHIP_ERROR TLVWriter::Init(TLVBackingStore & backingStore, uint32_t maxLen /* = UINT32_MAX */)
      93              : {
      94              :     // TODO(#30825): Need to ensure a single init path for this complex data.
      95        20936 :     Init(nullptr, maxLen);
      96        20936 :     mInitializationCookie = 0;
      97              : 
      98        20936 :     mBackingStore  = &backingStore;
      99        20936 :     mBufStart      = nullptr;
     100        20936 :     mRemainingLen  = 0;
     101        20936 :     CHIP_ERROR err = mBackingStore->OnInit(*this, mBufStart, mRemainingLen);
     102        20936 :     if (err != CHIP_NO_ERROR)
     103            0 :         return err;
     104              : 
     105        20936 :     VerifyOrReturnError(mBufStart != nullptr, CHIP_ERROR_INTERNAL);
     106        20936 :     mWritePoint           = mBufStart;
     107        20936 :     mInitializationCookie = kExpectedInitializationCookie;
     108        20936 :     return CHIP_NO_ERROR;
     109              : }
     110              : 
     111        25184 : CHIP_ERROR TLVWriter::Finalize()
     112              : {
     113              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     114              : 
     115        25184 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     116              : 
     117        25183 :     CHIP_ERROR err = CHIP_NO_ERROR;
     118        25183 :     if (IsContainerOpen())
     119            0 :         return CHIP_ERROR_TLV_CONTAINER_OPEN;
     120        25183 :     if (mBackingStore != nullptr)
     121        22414 :         err = mBackingStore->FinalizeBuffer(*this, mBufStart, static_cast<uint32_t>(mWritePoint - mBufStart));
     122              : 
     123              :         // TODO(#30825) The following should be safe, but in some cases (without mBackingStore), there are incremental writes that
     124              :         // start failing.
     125              : #if 0
     126              :     if (err == CHIP_NO_ERROR)
     127              :         mInitializationCookie = 0;
     128              : #endif
     129              : 
     130        25183 :     return err;
     131              : }
     132              : 
     133        13653 : CHIP_ERROR TLVWriter::ReserveBuffer(uint32_t aBufferSize)
     134              : {
     135        13653 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     136        13652 :     VerifyOrReturnError(mRemainingLen >= aBufferSize, CHIP_ERROR_NO_MEMORY);
     137              : 
     138        13639 :     if (mBackingStore)
     139              :     {
     140        13621 :         VerifyOrReturnError(mBackingStore->GetNewBufferWillAlwaysFail(), CHIP_ERROR_INCORRECT_STATE);
     141              :     }
     142        13638 :     mReservedSize += aBufferSize;
     143        13638 :     mRemainingLen -= aBufferSize;
     144        13638 :     return CHIP_NO_ERROR;
     145              : }
     146              : 
     147        21038 : CHIP_ERROR TLVWriter::PutBoolean(Tag tag, bool v)
     148              : {
     149        21038 :     return WriteElementHead((v) ? TLVElementType::BooleanTrue : TLVElementType::BooleanFalse, tag, 0);
     150              : }
     151              : 
     152        27241 : CHIP_ERROR TLVWriter::Put(Tag tag, uint8_t v)
     153              : {
     154        27241 :     return Put(tag, static_cast<uint64_t>(v));
     155              : }
     156              : 
     157            3 : CHIP_ERROR TLVWriter::Put(Tag tag, uint8_t v, bool preserveSize)
     158              : {
     159            3 :     if (preserveSize)
     160            3 :         return WriteElementHead(TLVElementType::UInt8, tag, v);
     161            0 :     return Put(tag, v);
     162              : }
     163              : 
     164        26195 : CHIP_ERROR TLVWriter::Put(Tag tag, uint16_t v)
     165              : {
     166        26195 :     return Put(tag, static_cast<uint64_t>(v));
     167              : }
     168              : 
     169            3 : CHIP_ERROR TLVWriter::Put(Tag tag, uint16_t v, bool preserveSize)
     170              : {
     171            3 :     if (preserveSize)
     172            3 :         return WriteElementHead(TLVElementType::UInt16, tag, v);
     173            0 :     return Put(tag, v);
     174              : }
     175              : 
     176        44405 : CHIP_ERROR TLVWriter::Put(Tag tag, uint32_t v)
     177              : {
     178        44405 :     return Put(tag, static_cast<uint64_t>(v));
     179              : }
     180              : 
     181            3 : CHIP_ERROR TLVWriter::Put(Tag tag, uint32_t v, bool preserveSize)
     182              : {
     183            3 :     if (preserveSize)
     184            3 :         return WriteElementHead(TLVElementType::UInt32, tag, v);
     185            0 :     return Put(tag, v);
     186              : }
     187              : 
     188       117384 : CHIP_ERROR TLVWriter::Put(Tag tag, uint64_t v)
     189              : {
     190              :     TLVElementType elemType;
     191       117384 :     if (v <= UINT8_MAX)
     192        84240 :         elemType = TLVElementType::UInt8;
     193        33144 :     else if (v <= UINT16_MAX)
     194         9415 :         elemType = TLVElementType::UInt16;
     195        23729 :     else if (v <= UINT32_MAX)
     196        21902 :         elemType = TLVElementType::UInt32;
     197              :     else
     198         1827 :         elemType = TLVElementType::UInt64;
     199       117384 :     return WriteElementHead(elemType, tag, v);
     200              : }
     201              : 
     202            5 : CHIP_ERROR TLVWriter::Put(Tag tag, uint64_t v, bool preserveSize)
     203              : {
     204            5 :     if (preserveSize)
     205            3 :         return WriteElementHead(TLVElementType::UInt64, tag, v);
     206            2 :     return Put(tag, v);
     207              : }
     208              : 
     209           37 : CHIP_ERROR TLVWriter::Put(Tag tag, int8_t v)
     210              : {
     211           37 :     return Put(tag, static_cast<int64_t>(v));
     212              : }
     213              : 
     214            3 : CHIP_ERROR TLVWriter::Put(Tag tag, int8_t v, bool preserveSize)
     215              : {
     216            3 :     if (preserveSize)
     217            3 :         return WriteElementHead(TLVElementType::Int8, tag, static_cast<uint8_t>(v));
     218            0 :     return Put(tag, v);
     219              : }
     220              : 
     221           71 : CHIP_ERROR TLVWriter::Put(Tag tag, int16_t v)
     222              : {
     223           71 :     return Put(tag, static_cast<int64_t>(v));
     224              : }
     225              : 
     226            5 : CHIP_ERROR TLVWriter::Put(Tag tag, int16_t v, bool preserveSize)
     227              : {
     228            5 :     if (preserveSize)
     229            5 :         return WriteElementHead(TLVElementType::Int16, tag, static_cast<uint16_t>(v));
     230            0 :     return Put(tag, v);
     231              : }
     232              : 
     233         1483 : CHIP_ERROR TLVWriter::Put(Tag tag, int32_t v)
     234              : {
     235         1483 :     return Put(tag, static_cast<int64_t>(v));
     236              : }
     237              : 
     238            3 : CHIP_ERROR TLVWriter::Put(Tag tag, int32_t v, bool preserveSize)
     239              : {
     240            3 :     if (preserveSize)
     241            3 :         return WriteElementHead(TLVElementType::Int32, tag, static_cast<uint32_t>(v));
     242            0 :     return Put(tag, v);
     243              : }
     244              : 
     245         1808 : CHIP_ERROR TLVWriter::Put(Tag tag, int64_t v)
     246              : {
     247              :     TLVElementType elemType;
     248         1808 :     if (v >= INT8_MIN && v <= INT8_MAX)
     249         1264 :         elemType = TLVElementType::Int8;
     250          544 :     else if (v >= INT16_MIN && v <= INT16_MAX)
     251           54 :         elemType = TLVElementType::Int16;
     252          490 :     else if (v >= INT32_MIN && v <= INT32_MAX)
     253          436 :         elemType = TLVElementType::Int32;
     254              :     else
     255           54 :         elemType = TLVElementType::Int64;
     256         1808 :     return WriteElementHead(elemType, tag, static_cast<uint64_t>(v));
     257              : }
     258              : 
     259            9 : CHIP_ERROR TLVWriter::Put(Tag tag, int64_t v, bool preserveSize)
     260              : {
     261            9 :     if (preserveSize)
     262            5 :         return WriteElementHead(TLVElementType::Int64, tag, static_cast<uint64_t>(v));
     263            4 :     return Put(tag, v);
     264              : }
     265              : 
     266          684 : CHIP_ERROR TLVWriter::Put(Tag tag, const float v)
     267              : {
     268              :     uint32_t u32;
     269          684 :     memcpy(&u32, &v, sizeof(u32));
     270          684 :     return WriteElementHead(TLVElementType::FloatingPointNumber32, tag, u32);
     271              : }
     272              : 
     273          700 : CHIP_ERROR TLVWriter::Put(Tag tag, const double v)
     274              : {
     275              :     uint64_t u64;
     276          700 :     memcpy(&u64, &v, sizeof(u64));
     277          700 :     return WriteElementHead(TLVElementType::FloatingPointNumber64, tag, u64);
     278              : }
     279              : 
     280        10967 : CHIP_ERROR TLVWriter::Put(Tag tag, ByteSpan data)
     281              : {
     282        10967 :     VerifyOrReturnError(CanCastTo<uint32_t>(data.size()), CHIP_ERROR_MESSAGE_TOO_LONG);
     283        10967 :     return PutBytes(tag, data.data(), static_cast<uint32_t>(data.size()));
     284              : }
     285              : 
     286        11783 : CHIP_ERROR TLVWriter::PutBytes(Tag tag, const uint8_t * buf, uint32_t len)
     287              : {
     288        11783 :     return WriteElementWithData(kTLVType_ByteString, tag, buf, len);
     289              : }
     290              : 
     291          848 : CHIP_ERROR TLVWriter::PutString(Tag tag, const char * buf)
     292              : {
     293          848 :     if (buf == nullptr)
     294            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     295          848 :     if (mMaxLen == 0)
     296            1 :         return CHIP_ERROR_INCORRECT_STATE;
     297              : 
     298              :     // Calculate length with a hard limit to prevent unbounded reads.
     299              :     // Use mMaxLen instead of mRemainingLen to account for CircularTLVWriter.
     300              :     // Note: Overrun is still possible if buf is not null-terminated, and this
     301              :     // check cannot prevent all invalid memory reads.
     302          847 :     size_t len = strnlen(buf, mMaxLen);
     303              : 
     304          847 :     if (!CanCastTo<uint32_t>(len))
     305            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     306              : 
     307          847 :     uint32_t stringLen = static_cast<uint32_t>(len);
     308              : 
     309              :     // Null terminator was not found within the allocated space.
     310          847 :     if (stringLen == mMaxLen)
     311            1 :         return CHIP_ERROR_BUFFER_TOO_SMALL;
     312          846 :     return PutString(tag, buf, stringLen);
     313              : }
     314              : 
     315         2324 : CHIP_ERROR TLVWriter::PutString(Tag tag, const char * buf, uint32_t len)
     316              : {
     317              : #if CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_WRITE
     318              :     // Spec requirement: A.11.2. UTF-8 and Octet Strings
     319              :     //
     320              :     // For UTF-8 strings, the value octets SHALL encode a valid
     321              :     // UTF-8 character (code points) sequence.
     322              :     //
     323              :     // Senders SHALL NOT include a terminating null character to
     324              :     // mark the end of a string.
     325              : 
     326         2324 :     if (!Utf8::IsValid(CharSpan(buf, len)))
     327              :     {
     328            0 :         return CHIP_ERROR_INVALID_UTF8;
     329              :     }
     330              : 
     331         2324 :     if ((len > 0) && (buf[len - 1] == 0))
     332              :     {
     333            0 :         return CHIP_ERROR_INVALID_TLV_CHAR_STRING;
     334              :     }
     335              : #endif // CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_WRITE
     336              : 
     337         2324 :     return WriteElementWithData(kTLVType_UTF8String, tag, reinterpret_cast<const uint8_t *>(buf), len);
     338              : }
     339              : 
     340         1197 : CHIP_ERROR TLVWriter::PutString(Tag tag, CharSpan str)
     341              : {
     342         1197 :     if (!CanCastTo<uint32_t>(str.size()))
     343              :     {
     344            1 :         return CHIP_ERROR_INVALID_ARGUMENT;
     345              :     }
     346              : 
     347         1196 :     return PutString(tag, str.data(), static_cast<uint32_t>(str.size()));
     348              : }
     349              : 
     350            4 : CHIP_ERROR TLVWriter::PutStringF(Tag tag, const char * fmt, ...)
     351              : {
     352              :     CHIP_ERROR err;
     353              :     va_list ap;
     354              : 
     355            4 :     va_start(ap, fmt);
     356              : 
     357            4 :     err = VPutStringF(tag, fmt, ap);
     358              : 
     359            4 :     va_end(ap);
     360              : 
     361            4 :     return err;
     362              : }
     363              : 
     364              : #if CONFIG_HAVE_VCBPRINTF
     365              : // We have a variant of the printf function that takes a callback that
     366              : // emits a single character.  The callback performs a function
     367              : // identical to putchar.
     368              : 
     369              : void TLVWriter::TLVWriterPutcharCB(uint8_t c, void * appState)
     370              : {
     371              :     TLVWriter * w = static_cast<TLVWriter *>(appState);
     372              :     w->WriteData(&c, sizeof(c));
     373              : }
     374              : #endif
     375              : 
     376            4 : CHIP_ERROR TLVWriter::VPutStringF(Tag tag, const char * fmt, va_list ap)
     377              : {
     378              :     va_list aq;
     379              :     size_t dataLen;
     380            4 :     CHIP_ERROR err = CHIP_NO_ERROR;
     381              :     TLVFieldSize lenFieldSize;
     382              : #if !CONFIG_HAVE_VCBPRINTF
     383              :     char * tmpBuf;
     384              : #endif
     385            4 :     va_copy(aq, ap);
     386              : 
     387            4 :     dataLen = static_cast<size_t>(vsnprintf(nullptr, 0, fmt, aq));
     388              : 
     389            4 :     va_end(aq);
     390              : 
     391            4 :     if (!CanCastTo<uint32_t>(dataLen))
     392              :     {
     393            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     394              :     }
     395              : 
     396            4 :     if (dataLen <= UINT8_MAX)
     397            4 :         lenFieldSize = kTLVFieldSize_1Byte;
     398            0 :     else if (dataLen <= UINT16_MAX)
     399            0 :         lenFieldSize = kTLVFieldSize_2Byte;
     400              :     else
     401            0 :         lenFieldSize = kTLVFieldSize_4Byte;
     402              : 
     403              :     // write length.
     404            8 :     err = WriteElementHead(
     405            4 :         static_cast<TLVElementType>(static_cast<uint8_t>(kTLVType_UTF8String) | static_cast<uint8_t>(lenFieldSize)), tag, dataLen);
     406            4 :     SuccessOrExit(err);
     407              : 
     408            3 :     VerifyOrExit((mLenWritten + dataLen) <= mMaxLen, err = CHIP_ERROR_BUFFER_TOO_SMALL);
     409              : 
     410              :     // write data
     411              : #if CONFIG_HAVE_VCBPRINTF
     412              : 
     413              :     va_copy(aq, ap);
     414              : 
     415              :     vcbprintf(TLVWriterPutcharCB, this, dataLen, fmt, aq);
     416              : 
     417              :     va_end(aq);
     418              : #else // CONFIG_HAVE_VCBPRINTF
     419              : 
     420            3 :     tmpBuf = static_cast<char *>(chip::Platform::MemoryAlloc(dataLen + 1));
     421            3 :     VerifyOrExit(tmpBuf != nullptr, err = CHIP_ERROR_NO_MEMORY);
     422              : 
     423            3 :     va_copy(aq, ap);
     424              : 
     425            3 :     vsnprintf(tmpBuf, dataLen + 1, fmt, aq);
     426              : 
     427            3 :     va_end(aq);
     428              : 
     429            3 :     err = WriteData(reinterpret_cast<uint8_t *>(tmpBuf), static_cast<uint32_t>(dataLen));
     430            3 :     chip::Platform::MemoryFree(tmpBuf);
     431              : 
     432              : #endif // CONFIG_HAVE_VCBPRINTF
     433              : 
     434            4 : exit:
     435              : 
     436            4 :     return err;
     437              : }
     438              : 
     439         7139 : CHIP_ERROR TLVWriter::PutNull(Tag tag)
     440              : {
     441         7139 :     return WriteElementHead(TLVElementType::Null, tag, 0);
     442              : }
     443              : 
     444        10489 : CHIP_ERROR TLVWriter::CopyElement(TLVReader & reader)
     445              : {
     446        10489 :     return CopyElement(reader.GetTag(), reader);
     447              : }
     448              : 
     449              : const size_t kTLVCopyChunkSize = 16;
     450              : 
     451        25162 : CHIP_ERROR TLVWriter::CopyElement(Tag tag, TLVReader & reader)
     452              : {
     453        25162 :     TLVElementType elemType = reader.ElementType();
     454        25162 :     uint64_t elemLenOrVal   = reader.mElemLenOrVal;
     455        25162 :     TLVReader readerHelper; // used to figure out the length of the element and read data of the element
     456              :     uint32_t copyDataLen;
     457              :     uint8_t chunk[kTLVCopyChunkSize];
     458              : 
     459        25162 :     VerifyOrReturnError(elemType != TLVElementType::NotSpecified && elemType != TLVElementType::EndOfContainer,
     460              :                         CHIP_ERROR_INCORRECT_STATE);
     461              : 
     462              :     // Initialize the helper
     463        25160 :     readerHelper.Init(reader);
     464              : 
     465              :     // Skip to the end of the element.
     466        25160 :     ReturnErrorOnFailure(reader.Skip());
     467              : 
     468              :     // Compute the amount of value data to copy from the reader.
     469        25160 :     copyDataLen = reader.GetLengthRead() - readerHelper.GetLengthRead();
     470              : 
     471              :     // Write the head of the new element with the same type and length/value, but using the
     472              :     // specified tag.
     473        25160 :     ReturnErrorOnFailure(WriteElementHead(elemType, tag, elemLenOrVal));
     474              : 
     475        46457 :     while (copyDataLen > 0)
     476              :     {
     477        21759 :         uint32_t chunkSize = copyDataLen > kTLVCopyChunkSize ? kTLVCopyChunkSize : copyDataLen;
     478        21759 :         ReturnErrorOnFailure(readerHelper.ReadData(chunk, chunkSize));
     479              : 
     480        21759 :         ReturnErrorOnFailure(WriteData(chunk, chunkSize));
     481              : 
     482        21406 :         copyDataLen -= chunkSize;
     483              :     }
     484              : 
     485        24698 :     return CHIP_NO_ERROR;
     486              : }
     487              : 
     488         1641 : CHIP_ERROR TLVWriter::OpenContainer(Tag tag, TLVType containerType, TLVWriter & containerWriter)
     489              : {
     490              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     491              : 
     492         1641 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     493         1640 :     CHIP_ERROR err = CHIP_NO_ERROR;
     494              : 
     495         1640 :     VerifyOrReturnError(TLVTypeIsContainer(containerType), CHIP_ERROR_WRONG_TLV_TYPE);
     496              : 
     497         1639 :     if (IsCloseContainerReserved())
     498              :     {
     499         1636 :         VerifyOrReturnError(mMaxLen >= kEndOfContainerMarkerSize, CHIP_ERROR_BUFFER_TOO_SMALL);
     500         1631 :         mMaxLen -= kEndOfContainerMarkerSize;
     501              :     }
     502         1634 :     err = WriteElementHead(static_cast<TLVElementType>(containerType), tag, 0);
     503              : 
     504         1634 :     if (err != CHIP_NO_ERROR)
     505              :     {
     506              :         // undo the space reservation, as the container is not actually open
     507            4 :         if (IsCloseContainerReserved())
     508            4 :             mMaxLen += kEndOfContainerMarkerSize;
     509              : 
     510            4 :         return err;
     511              :     }
     512              : 
     513              :     // TODO(#30825): Clean-up this separate init path path.
     514         1630 :     containerWriter.mBackingStore  = mBackingStore;
     515         1630 :     containerWriter.mBufStart      = mBufStart;
     516         1630 :     containerWriter.mWritePoint    = mWritePoint;
     517         1630 :     containerWriter.mRemainingLen  = mRemainingLen;
     518         1630 :     containerWriter.mLenWritten    = 0;
     519         1630 :     containerWriter.mMaxLen        = mMaxLen - mLenWritten;
     520         1630 :     containerWriter.mContainerType = containerType;
     521         1630 :     containerWriter.SetContainerOpen(false);
     522         1630 :     containerWriter.SetCloseContainerReserved(IsCloseContainerReserved());
     523         1630 :     containerWriter.ImplicitProfileId     = ImplicitProfileId;
     524         1630 :     containerWriter.mInitializationCookie = kExpectedInitializationCookie;
     525              : 
     526         1630 :     SetContainerOpen(true);
     527              : 
     528         1630 :     return CHIP_NO_ERROR;
     529              : }
     530              : 
     531         1615 : CHIP_ERROR TLVWriter::CloseContainer(TLVWriter & containerWriter)
     532              : {
     533              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     534              : 
     535         1615 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     536              : 
     537         1614 :     if (!TLVTypeIsContainer(containerWriter.mContainerType))
     538            2 :         return CHIP_ERROR_INCORRECT_STATE;
     539              : 
     540         1612 :     if (containerWriter.IsContainerOpen())
     541            1 :         return CHIP_ERROR_TLV_CONTAINER_OPEN;
     542              : 
     543         1611 :     mBackingStore = containerWriter.mBackingStore;
     544         1611 :     mBufStart     = containerWriter.mBufStart;
     545         1611 :     mWritePoint   = containerWriter.mWritePoint;
     546         1611 :     mRemainingLen = containerWriter.mRemainingLen;
     547         1611 :     mLenWritten += containerWriter.mLenWritten;
     548              : 
     549         1611 :     if (IsCloseContainerReserved())
     550         1608 :         mMaxLen += kEndOfContainerMarkerSize;
     551              : 
     552         1611 :     SetContainerOpen(false);
     553              : 
     554              :     // Reset the container writer so that it can't accidentally be used again.
     555         1611 :     containerWriter.Init(static_cast<uint8_t *>(nullptr), 0);
     556              : 
     557         1611 :     return WriteElementHead(TLVElementType::EndOfContainer, AnonymousTag(), 0);
     558              : }
     559              : 
     560        92663 : CHIP_ERROR TLVWriter::StartContainer(Tag tag, TLVType containerType, TLVType & outerContainerType)
     561              : {
     562              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     563              : 
     564        92663 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     565        92662 :     CHIP_ERROR err = CHIP_NO_ERROR;
     566              : 
     567        92662 :     VerifyOrReturnError(TLVTypeIsContainer(containerType), CHIP_ERROR_WRONG_TLV_TYPE);
     568              : 
     569        92661 :     if (IsCloseContainerReserved())
     570              :     {
     571        92648 :         VerifyOrReturnError(mMaxLen >= kEndOfContainerMarkerSize, CHIP_ERROR_BUFFER_TOO_SMALL);
     572        92647 :         mMaxLen -= kEndOfContainerMarkerSize;
     573              :     }
     574              : 
     575        92660 :     err = WriteElementHead(static_cast<TLVElementType>(containerType), tag, 0);
     576        92660 :     if (err != CHIP_NO_ERROR)
     577              :     {
     578              :         // undo the space reservation, as the container is not actually open
     579          176 :         if (IsCloseContainerReserved())
     580          176 :             mMaxLen += kEndOfContainerMarkerSize;
     581              : 
     582          176 :         return err;
     583              :     }
     584        92484 :     outerContainerType = mContainerType;
     585        92484 :     mContainerType     = containerType;
     586              : 
     587        92484 :     SetContainerOpen(false);
     588              : 
     589        92484 :     return CHIP_NO_ERROR;
     590              : }
     591              : 
     592        87505 : CHIP_ERROR TLVWriter::EndContainer(TLVType outerContainerType)
     593              : {
     594              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     595              : 
     596        87505 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     597              : 
     598        87504 :     if (!TLVTypeIsContainer(mContainerType))
     599            2 :         return CHIP_ERROR_INCORRECT_STATE;
     600              : 
     601        87502 :     mContainerType = outerContainerType;
     602              : 
     603        87502 :     if (IsCloseContainerReserved())
     604        87489 :         mMaxLen += kEndOfContainerMarkerSize;
     605              : 
     606        87502 :     return WriteElementHead(TLVElementType::EndOfContainer, AnonymousTag(), 0);
     607              : }
     608              : 
     609            4 : CHIP_ERROR TLVWriter::PutPreEncodedContainer(Tag tag, TLVType containerType, const uint8_t * data, uint32_t dataLen)
     610              : {
     611            4 :     if (!TLVTypeIsContainer(containerType))
     612            1 :         return CHIP_ERROR_INVALID_ARGUMENT;
     613              : 
     614            3 :     CHIP_ERROR err = WriteElementHead(static_cast<TLVElementType>(containerType), tag, 0);
     615            3 :     if (err != CHIP_NO_ERROR)
     616            1 :         return err;
     617              : 
     618            2 :     return WriteData(data, dataLen);
     619              : }
     620              : 
     621            2 : CHIP_ERROR TLVWriter::CopyContainer(TLVReader & container)
     622              : {
     623            2 :     return CopyContainer(container.GetTag(), container);
     624              : }
     625              : 
     626            3 : CHIP_ERROR TLVWriter::CopyContainer(Tag tag, TLVReader & container)
     627              : {
     628              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     629              : 
     630            3 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     631              : 
     632              :     // NOTE: This function MUST be used with a TVLReader that is reading from a contiguous buffer.
     633            1 :     if (container.mBackingStore != nullptr)
     634            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     635              : 
     636              :     CHIP_ERROR err;
     637              :     TLVType containerType, outerContainerType;
     638              :     const uint8_t * containerStart;
     639              : 
     640            1 :     containerType = container.GetType();
     641              : 
     642            1 :     err = container.EnterContainer(outerContainerType);
     643            1 :     if (err != CHIP_NO_ERROR)
     644            0 :         return err;
     645              : 
     646            1 :     containerStart = container.GetReadPoint();
     647              : 
     648            1 :     err = container.ExitContainer(outerContainerType);
     649            1 :     if (err != CHIP_NO_ERROR)
     650            0 :         return err;
     651              : 
     652            1 :     return PutPreEncodedContainer(tag, containerType, containerStart,
     653            1 :                                   static_cast<uint32_t>(container.GetReadPoint() - containerStart));
     654              : }
     655              : 
     656            2 : CHIP_ERROR TLVWriter::CopyContainer(Tag tag, const uint8_t * encodedContainer, uint16_t encodedContainerLen)
     657              : {
     658            2 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     659              : 
     660            1 :     TLVReader reader;
     661              : 
     662            1 :     reader.Init(encodedContainer, encodedContainerLen);
     663              : 
     664            1 :     ReturnErrorOnFailure(reader.Next());
     665              : 
     666            1 :     ReturnErrorOnFailure(PutPreEncodedContainer(tag, reader.GetType(), reader.GetReadPoint(), reader.GetRemainingLength()));
     667              : 
     668            1 :     return CHIP_NO_ERROR;
     669              : }
     670              : 
     671       371459 : CHIP_ERROR TLVWriter::WriteElementHead(TLVElementType elemType, Tag tag, uint64_t lenOrVal)
     672              : {
     673              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     674              : 
     675       371459 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     676       371436 :     VerifyOrReturnError(!IsContainerOpen(), CHIP_ERROR_TLV_CONTAINER_OPEN);
     677              : 
     678              :     uint8_t stagingBuf[17]; // 17 = 1 control byte + 8 tag bytes + 8 length/value bytes
     679       371436 :     uint32_t tagNum = TagNumFromTag(tag);
     680              : 
     681       371436 :     Encoding::LittleEndian::BufferWriter writer(stagingBuf, sizeof(stagingBuf));
     682              : 
     683       371436 :     if (IsSpecialTag(tag))
     684              :     {
     685       367280 :         if (tagNum <= Tag::kContextTagMaxNum)
     686              :         {
     687       193244 :             if (mContainerType != kTLVType_Structure && mContainerType != kTLVType_List)
     688            0 :                 return CHIP_ERROR_INVALID_TLV_TAG;
     689              : 
     690       193244 :             writer.Put8(TLVTagControl::ContextSpecific | elemType);
     691       193244 :             writer.Put8(static_cast<uint8_t>(tagNum));
     692              :         }
     693              :         else
     694              :         {
     695       174036 :             if (elemType != TLVElementType::EndOfContainer && mContainerType != kTLVType_NotSpecified &&
     696        45483 :                 mContainerType != kTLVType_Array && mContainerType != kTLVType_List)
     697            0 :                 return CHIP_ERROR_INVALID_TLV_TAG;
     698              : 
     699       174036 :             writer.Put8(TLVTagControl::Anonymous | elemType);
     700              :         }
     701              :     }
     702              :     else
     703              :     {
     704         4156 :         uint32_t profileId = ProfileIdFromTag(tag);
     705              : 
     706         4156 :         if (mContainerType != kTLVType_NotSpecified && mContainerType != kTLVType_Structure && mContainerType != kTLVType_List)
     707            0 :             return CHIP_ERROR_INVALID_TLV_TAG;
     708              : 
     709         4156 :         if (profileId == kCommonProfileId)
     710              :         {
     711          415 :             if (tagNum <= std::numeric_limits<uint16_t>::max())
     712              :             {
     713           27 :                 writer.Put8(TLVTagControl::CommonProfile_2Bytes | elemType);
     714           27 :                 writer.Put16(static_cast<uint16_t>(tagNum));
     715              :             }
     716              :             else
     717              :             {
     718          388 :                 writer.Put8(TLVTagControl::CommonProfile_4Bytes | elemType);
     719          388 :                 writer.Put32(tagNum);
     720              :             }
     721              :         }
     722         3741 :         else if (profileId == ImplicitProfileId)
     723              :         {
     724         2014 :             if (tagNum <= std::numeric_limits<uint16_t>::max())
     725              :             {
     726          850 :                 writer.Put8(TLVTagControl::ImplicitProfile_2Bytes | elemType);
     727          850 :                 writer.Put16(static_cast<uint16_t>(tagNum));
     728              :             }
     729              :             else
     730              :             {
     731         1164 :                 writer.Put8(TLVTagControl::ImplicitProfile_4Bytes | elemType);
     732         1164 :                 writer.Put32(tagNum);
     733              :             }
     734              :         }
     735              :         else
     736              :         {
     737         1727 :             uint16_t vendorId   = static_cast<uint16_t>(profileId >> 16);
     738         1727 :             uint16_t profileNum = static_cast<uint16_t>(profileId);
     739              : 
     740         1727 :             if (tagNum <= std::numeric_limits<uint16_t>::max())
     741              :             {
     742              : 
     743         1714 :                 writer.Put8(TLVTagControl::FullyQualified_6Bytes | elemType);
     744         1714 :                 writer.Put16(vendorId);
     745         1714 :                 writer.Put16(profileNum);
     746         1714 :                 writer.Put16(static_cast<uint16_t>(tagNum));
     747              :             }
     748              :             else
     749              :             {
     750           13 :                 writer.Put8(TLVTagControl::FullyQualified_8Bytes | elemType);
     751           13 :                 writer.Put16(vendorId);
     752           13 :                 writer.Put16(profileNum);
     753           13 :                 writer.Put32(tagNum);
     754              :             }
     755              :         }
     756              :     }
     757              : 
     758       371436 :     uint8_t lengthSize = TLVFieldSizeToBytes(GetTLVFieldSize(elemType));
     759       371436 :     if (lengthSize > 0)
     760              :     {
     761       148595 :         writer.EndianPut(lenOrVal, lengthSize);
     762              :     }
     763              : 
     764       371436 :     size_t written = 0;
     765       371436 :     VerifyOrDie(writer.Fit(written));
     766       371436 :     return WriteData(stagingBuf, static_cast<uint32_t>(written));
     767              : }
     768              : 
     769        14107 : CHIP_ERROR TLVWriter::WriteElementWithData(TLVType type, Tag tag, const uint8_t * data, uint32_t dataLen)
     770              : {
     771              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     772              : 
     773        14107 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     774        14104 :     if (static_cast<uint64_t>(type) & kTLVTypeSizeMask)
     775              :     {
     776              :         // We won't be able to recover this type properly!
     777            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     778              :     }
     779              : 
     780              :     TLVFieldSize lenFieldSize;
     781              : 
     782        14104 :     if (dataLen <= UINT8_MAX)
     783        10693 :         lenFieldSize = kTLVFieldSize_1Byte;
     784         3411 :     else if (dataLen <= UINT16_MAX)
     785         3411 :         lenFieldSize = kTLVFieldSize_2Byte;
     786              :     else
     787            0 :         lenFieldSize = kTLVFieldSize_4Byte;
     788              : 
     789        14104 :     CHIP_ERROR err = WriteElementHead(static_cast<TLVElementType>(static_cast<uint8_t>(type) | static_cast<uint8_t>(lenFieldSize)),
     790              :                                       tag, dataLen);
     791        14104 :     if (err != CHIP_NO_ERROR)
     792           34 :         return err;
     793              : 
     794        14070 :     return WriteData(data, dataLen);
     795              : }
     796              : 
     797       407270 : CHIP_ERROR TLVWriter::WriteData(const uint8_t * p, uint32_t len)
     798              : {
     799              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     800              : 
     801       407270 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     802       407270 :     VerifyOrReturnError((mLenWritten + len) <= mMaxLen, CHIP_ERROR_BUFFER_TOO_SMALL);
     803              : 
     804       807885 :     while (len > 0)
     805              :     {
     806       403018 :         if (mRemainingLen == 0)
     807              :         {
     808         3104 :             VerifyOrReturnError(mBackingStore != nullptr, CHIP_ERROR_NO_MEMORY);
     809              : 
     810         3104 :             VerifyOrReturnError(CanCastTo<uint32_t>(mWritePoint - mBufStart), CHIP_ERROR_INCORRECT_STATE);
     811         3104 :             ReturnErrorOnFailure(mBackingStore->FinalizeBuffer(*this, mBufStart, static_cast<uint32_t>(mWritePoint - mBufStart)));
     812              : 
     813         3104 :             ReturnErrorOnFailure(mBackingStore->GetNewBuffer(*this, mBufStart, mRemainingLen));
     814          893 :             VerifyOrReturnError(mRemainingLen > 0, CHIP_ERROR_NO_MEMORY);
     815              : 
     816          893 :             mWritePoint = mBufStart;
     817              : 
     818          893 :             if (mRemainingLen > (mMaxLen - mLenWritten))
     819            0 :                 mRemainingLen = (mMaxLen - mLenWritten);
     820              :         }
     821              : 
     822       400807 :         uint32_t writeLen = len;
     823       400807 :         if (writeLen > mRemainingLen)
     824         2748 :             writeLen = mRemainingLen;
     825              : 
     826       400807 :         memmove(mWritePoint, p, writeLen);
     827       400807 :         mWritePoint += writeLen;
     828       400807 :         mRemainingLen -= writeLen;
     829       400807 :         mLenWritten += writeLen;
     830       400807 :         p += writeLen;
     831       400807 :         len -= writeLen;
     832              :     }
     833              : 
     834       404867 :     return CHIP_NO_ERROR;
     835              : }
     836              : 
     837              : } // namespace TLV
     838              : } // namespace chip
        

Generated by: LCOV version 2.0-1