Matter SDK Coverage Report
Current view: top level - lib/core - TLVWriter.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 93.5 % 367 343
Test Date: 2025-01-17 19:00:11 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        53013 : TLVWriter::TLVWriter() :
      65        53013 :     ImplicitProfileId(kProfileIdNotSpecified), AppData(nullptr), mBackingStore(nullptr), mBufStart(nullptr), mWritePoint(nullptr),
      66        53013 :     mRemainingLen(0), mLenWritten(0), mMaxLen(0), mReservedSize(0), mContainerType(kTLVType_NotSpecified), mInitializationCookie(0),
      67        53013 :     mContainerOpen(false), mCloseContainerReserved(true)
      68        53013 : {}
      69              : 
      70        31818 : 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        31818 :     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        31818 :     mInitializationCookie = 0;
      77        31818 :     mBackingStore         = nullptr;
      78        31818 :     mBufStart             = buf;
      79        31818 :     mWritePoint           = buf;
      80        31818 :     mRemainingLen         = actualMaxLen;
      81        31818 :     mLenWritten           = 0;
      82        31818 :     mMaxLen               = actualMaxLen;
      83        31818 :     mContainerType        = kTLVType_NotSpecified;
      84        31818 :     mReservedSize         = 0;
      85        31818 :     SetContainerOpen(false);
      86        31818 :     SetCloseContainerReserved(true);
      87              : 
      88        31818 :     ImplicitProfileId     = kProfileIdNotSpecified;
      89        31818 :     mInitializationCookie = kExpectedInitializationCookie;
      90        31818 : }
      91              : 
      92        20292 : 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        20292 :     Init(nullptr, maxLen);
      96        20292 :     mInitializationCookie = 0;
      97              : 
      98        20292 :     mBackingStore  = &backingStore;
      99        20292 :     mBufStart      = nullptr;
     100        20292 :     mRemainingLen  = 0;
     101        20292 :     CHIP_ERROR err = mBackingStore->OnInit(*this, mBufStart, mRemainingLen);
     102        20292 :     if (err != CHIP_NO_ERROR)
     103            0 :         return err;
     104              : 
     105        20292 :     VerifyOrReturnError(mBufStart != nullptr, CHIP_ERROR_INTERNAL);
     106        20292 :     mWritePoint           = mBufStart;
     107        20292 :     mInitializationCookie = kExpectedInitializationCookie;
     108        20292 :     return CHIP_NO_ERROR;
     109              : }
     110              : 
     111        24376 : CHIP_ERROR TLVWriter::Finalize()
     112              : {
     113              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     114              : 
     115        24376 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     116              : 
     117        24375 :     CHIP_ERROR err = CHIP_NO_ERROR;
     118        24375 :     if (IsContainerOpen())
     119            0 :         return CHIP_ERROR_TLV_CONTAINER_OPEN;
     120        24375 :     if (mBackingStore != nullptr)
     121        21772 :         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        24375 :     return err;
     131              : }
     132              : 
     133        12831 : CHIP_ERROR TLVWriter::ReserveBuffer(uint32_t aBufferSize)
     134              : {
     135        12831 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     136        12830 :     VerifyOrReturnError(mRemainingLen >= aBufferSize, CHIP_ERROR_NO_MEMORY);
     137              : 
     138        12818 :     if (mBackingStore)
     139              :     {
     140        12801 :         VerifyOrReturnError(mBackingStore->GetNewBufferWillAlwaysFail(), CHIP_ERROR_INCORRECT_STATE);
     141              :     }
     142        12817 :     mReservedSize += aBufferSize;
     143        12817 :     mRemainingLen -= aBufferSize;
     144        12817 :     return CHIP_NO_ERROR;
     145              : }
     146              : 
     147        20879 : CHIP_ERROR TLVWriter::PutBoolean(Tag tag, bool v)
     148              : {
     149        20879 :     return WriteElementHead((v) ? TLVElementType::BooleanTrue : TLVElementType::BooleanFalse, tag, 0);
     150              : }
     151              : 
     152        28587 : CHIP_ERROR TLVWriter::Put(Tag tag, uint8_t v)
     153              : {
     154        28587 :     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        25552 : CHIP_ERROR TLVWriter::Put(Tag tag, uint16_t v)
     165              : {
     166        25552 :     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        45425 : CHIP_ERROR TLVWriter::Put(Tag tag, uint32_t v)
     177              : {
     178        45425 :     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       115054 : CHIP_ERROR TLVWriter::Put(Tag tag, uint64_t v)
     189              : {
     190              :     TLVElementType elemType;
     191       115054 :     if (v <= UINT8_MAX)
     192        83305 :         elemType = TLVElementType::UInt8;
     193        31749 :     else if (v <= UINT16_MAX)
     194         8506 :         elemType = TLVElementType::UInt16;
     195        23243 :     else if (v <= UINT32_MAX)
     196        21416 :         elemType = TLVElementType::UInt32;
     197              :     else
     198         1827 :         elemType = TLVElementType::UInt64;
     199       115054 :     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         1485 : CHIP_ERROR TLVWriter::Put(Tag tag, int32_t v)
     234              : {
     235         1485 :     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         1810 : CHIP_ERROR TLVWriter::Put(Tag tag, int64_t v)
     246              : {
     247              :     TLVElementType elemType;
     248         1810 :     if (v >= INT8_MIN && v <= INT8_MAX)
     249         1264 :         elemType = TLVElementType::Int8;
     250          546 :     else if (v >= INT16_MIN && v <= INT16_MAX)
     251           56 :         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         1810 :     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        11375 : CHIP_ERROR TLVWriter::Put(Tag tag, ByteSpan data)
     281              : {
     282        11375 :     VerifyOrReturnError(CanCastTo<uint32_t>(data.size()), CHIP_ERROR_MESSAGE_TOO_LONG);
     283        11375 :     return PutBytes(tag, data.data(), static_cast<uint32_t>(data.size()));
     284              : }
     285              : 
     286        12168 : CHIP_ERROR TLVWriter::PutBytes(Tag tag, const uint8_t * buf, uint32_t len)
     287              : {
     288        12168 :     return WriteElementWithData(kTLVType_ByteString, tag, buf, len);
     289              : }
     290              : 
     291          847 : CHIP_ERROR TLVWriter::PutString(Tag tag, const char * buf)
     292              : {
     293          847 :     size_t len = strlen(buf);
     294          847 :     if (!CanCastTo<uint32_t>(len))
     295              :     {
     296            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     297              :     }
     298          847 :     return PutString(tag, buf, static_cast<uint32_t>(len));
     299              : }
     300              : 
     301         2297 : CHIP_ERROR TLVWriter::PutString(Tag tag, const char * buf, uint32_t len)
     302              : {
     303              : #if CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_WRITE
     304              :     // Spec requirement: A.11.2. UTF-8 and Octet Strings
     305              :     //
     306              :     // For UTF-8 strings, the value octets SHALL encode a valid
     307              :     // UTF-8 character (code points) sequence.
     308              :     //
     309              :     // Senders SHALL NOT include a terminating null character to
     310              :     // mark the end of a string.
     311              : 
     312         2297 :     if (!Utf8::IsValid(CharSpan(buf, len)))
     313              :     {
     314            0 :         return CHIP_ERROR_INVALID_UTF8;
     315              :     }
     316              : 
     317         2297 :     if ((len > 0) && (buf[len - 1] == 0))
     318              :     {
     319            0 :         return CHIP_ERROR_INVALID_TLV_CHAR_STRING;
     320              :     }
     321              : #endif // CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ
     322              : 
     323         2297 :     return WriteElementWithData(kTLVType_UTF8String, tag, reinterpret_cast<const uint8_t *>(buf), len);
     324              : }
     325              : 
     326         1177 : CHIP_ERROR TLVWriter::PutString(Tag tag, CharSpan str)
     327              : {
     328         1177 :     if (!CanCastTo<uint32_t>(str.size()))
     329              :     {
     330            1 :         return CHIP_ERROR_INVALID_ARGUMENT;
     331              :     }
     332              : 
     333         1176 :     return PutString(tag, str.data(), static_cast<uint32_t>(str.size()));
     334              : }
     335              : 
     336            4 : CHIP_ERROR TLVWriter::PutStringF(Tag tag, const char * fmt, ...)
     337              : {
     338              :     CHIP_ERROR err;
     339              :     va_list ap;
     340              : 
     341            4 :     va_start(ap, fmt);
     342              : 
     343            4 :     err = VPutStringF(tag, fmt, ap);
     344              : 
     345            4 :     va_end(ap);
     346              : 
     347            4 :     return err;
     348              : }
     349              : 
     350              : #if CONFIG_HAVE_VCBPRINTF
     351              : // We have a variant of the printf function that takes a callback that
     352              : // emits a single character.  The callback performs a function
     353              : // identical to putchar.
     354              : 
     355              : void TLVWriter::TLVWriterPutcharCB(uint8_t c, void * appState)
     356              : {
     357              :     TLVWriter * w = static_cast<TLVWriter *>(appState);
     358              :     w->WriteData(&c, sizeof(c));
     359              : }
     360              : #endif
     361              : 
     362            4 : CHIP_ERROR TLVWriter::VPutStringF(Tag tag, const char * fmt, va_list ap)
     363              : {
     364              :     va_list aq;
     365              :     size_t dataLen;
     366            4 :     CHIP_ERROR err = CHIP_NO_ERROR;
     367              :     TLVFieldSize lenFieldSize;
     368              : #if !CONFIG_HAVE_VCBPRINTF
     369              :     char * tmpBuf;
     370              : #endif
     371            4 :     va_copy(aq, ap);
     372              : 
     373            4 :     dataLen = static_cast<size_t>(vsnprintf(nullptr, 0, fmt, aq));
     374              : 
     375            4 :     va_end(aq);
     376              : 
     377            4 :     if (!CanCastTo<uint32_t>(dataLen))
     378              :     {
     379            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     380              :     }
     381              : 
     382            4 :     if (dataLen <= UINT8_MAX)
     383            4 :         lenFieldSize = kTLVFieldSize_1Byte;
     384            0 :     else if (dataLen <= UINT16_MAX)
     385            0 :         lenFieldSize = kTLVFieldSize_2Byte;
     386              :     else
     387            0 :         lenFieldSize = kTLVFieldSize_4Byte;
     388              : 
     389              :     // write length.
     390            8 :     err = WriteElementHead(
     391            4 :         static_cast<TLVElementType>(static_cast<uint8_t>(kTLVType_UTF8String) | static_cast<uint8_t>(lenFieldSize)), tag, dataLen);
     392            4 :     SuccessOrExit(err);
     393              : 
     394            3 :     VerifyOrExit((mLenWritten + dataLen) <= mMaxLen, err = CHIP_ERROR_BUFFER_TOO_SMALL);
     395              : 
     396              :     // write data
     397              : #if CONFIG_HAVE_VCBPRINTF
     398              : 
     399              :     va_copy(aq, ap);
     400              : 
     401              :     vcbprintf(TLVWriterPutcharCB, this, dataLen, fmt, aq);
     402              : 
     403              :     va_end(aq);
     404              : #else // CONFIG_HAVE_VCBPRINTF
     405              : 
     406            3 :     tmpBuf = static_cast<char *>(chip::Platform::MemoryAlloc(dataLen + 1));
     407            3 :     VerifyOrExit(tmpBuf != nullptr, err = CHIP_ERROR_NO_MEMORY);
     408              : 
     409            3 :     va_copy(aq, ap);
     410              : 
     411            3 :     vsnprintf(tmpBuf, dataLen + 1, fmt, aq);
     412              : 
     413            3 :     va_end(aq);
     414              : 
     415            3 :     err = WriteData(reinterpret_cast<uint8_t *>(tmpBuf), static_cast<uint32_t>(dataLen));
     416            3 :     chip::Platform::MemoryFree(tmpBuf);
     417              : 
     418              : #endif // CONFIG_HAVE_VCBPRINTF
     419              : 
     420            4 : exit:
     421              : 
     422            4 :     return err;
     423              : }
     424              : 
     425         7135 : CHIP_ERROR TLVWriter::PutNull(Tag tag)
     426              : {
     427         7135 :     return WriteElementHead(TLVElementType::Null, tag, 0);
     428              : }
     429              : 
     430        10489 : CHIP_ERROR TLVWriter::CopyElement(TLVReader & reader)
     431              : {
     432        10489 :     return CopyElement(reader.GetTag(), reader);
     433              : }
     434              : 
     435              : const size_t kTLVCopyChunkSize = 16;
     436              : 
     437        24413 : CHIP_ERROR TLVWriter::CopyElement(Tag tag, TLVReader & reader)
     438              : {
     439        24413 :     TLVElementType elemType = reader.ElementType();
     440        24413 :     uint64_t elemLenOrVal   = reader.mElemLenOrVal;
     441        24413 :     TLVReader readerHelper; // used to figure out the length of the element and read data of the element
     442              :     uint32_t copyDataLen;
     443              :     uint8_t chunk[kTLVCopyChunkSize];
     444              : 
     445        24413 :     VerifyOrReturnError(elemType != TLVElementType::NotSpecified && elemType != TLVElementType::EndOfContainer,
     446              :                         CHIP_ERROR_INCORRECT_STATE);
     447              : 
     448              :     // Initialize the helper
     449        24411 :     readerHelper.Init(reader);
     450              : 
     451              :     // Skip to the end of the element.
     452        24411 :     ReturnErrorOnFailure(reader.Skip());
     453              : 
     454              :     // Compute the amount of value data to copy from the reader.
     455        24411 :     copyDataLen = reader.GetLengthRead() - readerHelper.GetLengthRead();
     456              : 
     457              :     // Write the head of the new element with the same type and length/value, but using the
     458              :     // specified tag.
     459        24411 :     ReturnErrorOnFailure(WriteElementHead(elemType, tag, elemLenOrVal));
     460              : 
     461        45102 :     while (copyDataLen > 0)
     462              :     {
     463        21153 :         uint32_t chunkSize = copyDataLen > kTLVCopyChunkSize ? kTLVCopyChunkSize : copyDataLen;
     464        21153 :         ReturnErrorOnFailure(readerHelper.ReadData(chunk, chunkSize));
     465              : 
     466        21153 :         ReturnErrorOnFailure(WriteData(chunk, chunkSize));
     467              : 
     468        20800 :         copyDataLen -= chunkSize;
     469              :     }
     470              : 
     471        23949 :     return CHIP_NO_ERROR;
     472              : }
     473              : 
     474         1641 : CHIP_ERROR TLVWriter::OpenContainer(Tag tag, TLVType containerType, TLVWriter & containerWriter)
     475              : {
     476              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     477              : 
     478         1641 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     479         1640 :     CHIP_ERROR err = CHIP_NO_ERROR;
     480              : 
     481         1640 :     VerifyOrReturnError(TLVTypeIsContainer(containerType), CHIP_ERROR_WRONG_TLV_TYPE);
     482              : 
     483         1639 :     if (IsCloseContainerReserved())
     484              :     {
     485         1636 :         VerifyOrReturnError(mMaxLen >= kEndOfContainerMarkerSize, CHIP_ERROR_BUFFER_TOO_SMALL);
     486         1631 :         mMaxLen -= kEndOfContainerMarkerSize;
     487              :     }
     488         1634 :     err = WriteElementHead(static_cast<TLVElementType>(containerType), tag, 0);
     489              : 
     490         1634 :     if (err != CHIP_NO_ERROR)
     491              :     {
     492              :         // undo the space reservation, as the container is not actually open
     493            4 :         if (IsCloseContainerReserved())
     494            4 :             mMaxLen += kEndOfContainerMarkerSize;
     495              : 
     496            4 :         return err;
     497              :     }
     498              : 
     499              :     // TODO(#30825): Clean-up this separate init path path.
     500         1630 :     containerWriter.mBackingStore  = mBackingStore;
     501         1630 :     containerWriter.mBufStart      = mBufStart;
     502         1630 :     containerWriter.mWritePoint    = mWritePoint;
     503         1630 :     containerWriter.mRemainingLen  = mRemainingLen;
     504         1630 :     containerWriter.mLenWritten    = 0;
     505         1630 :     containerWriter.mMaxLen        = mMaxLen - mLenWritten;
     506         1630 :     containerWriter.mContainerType = containerType;
     507         1630 :     containerWriter.SetContainerOpen(false);
     508         1630 :     containerWriter.SetCloseContainerReserved(IsCloseContainerReserved());
     509         1630 :     containerWriter.ImplicitProfileId     = ImplicitProfileId;
     510         1630 :     containerWriter.mInitializationCookie = kExpectedInitializationCookie;
     511              : 
     512         1630 :     SetContainerOpen(true);
     513              : 
     514         1630 :     return CHIP_NO_ERROR;
     515              : }
     516              : 
     517         1615 : CHIP_ERROR TLVWriter::CloseContainer(TLVWriter & containerWriter)
     518              : {
     519              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     520              : 
     521         1615 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     522              : 
     523         1614 :     if (!TLVTypeIsContainer(containerWriter.mContainerType))
     524            2 :         return CHIP_ERROR_INCORRECT_STATE;
     525              : 
     526         1612 :     if (containerWriter.IsContainerOpen())
     527            1 :         return CHIP_ERROR_TLV_CONTAINER_OPEN;
     528              : 
     529         1611 :     mBackingStore = containerWriter.mBackingStore;
     530         1611 :     mBufStart     = containerWriter.mBufStart;
     531         1611 :     mWritePoint   = containerWriter.mWritePoint;
     532         1611 :     mRemainingLen = containerWriter.mRemainingLen;
     533         1611 :     mLenWritten += containerWriter.mLenWritten;
     534              : 
     535         1611 :     if (IsCloseContainerReserved())
     536         1608 :         mMaxLen += kEndOfContainerMarkerSize;
     537              : 
     538         1611 :     SetContainerOpen(false);
     539              : 
     540              :     // Reset the container writer so that it can't accidentally be used again.
     541         1611 :     containerWriter.Init(static_cast<uint8_t *>(nullptr), 0);
     542              : 
     543         1611 :     return WriteElementHead(TLVElementType::EndOfContainer, AnonymousTag(), 0);
     544              : }
     545              : 
     546        92022 : CHIP_ERROR TLVWriter::StartContainer(Tag tag, TLVType containerType, TLVType & outerContainerType)
     547              : {
     548              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     549              : 
     550        92022 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     551        92021 :     CHIP_ERROR err = CHIP_NO_ERROR;
     552              : 
     553        92021 :     VerifyOrReturnError(TLVTypeIsContainer(containerType), CHIP_ERROR_WRONG_TLV_TYPE);
     554              : 
     555        92020 :     if (IsCloseContainerReserved())
     556              :     {
     557        92007 :         VerifyOrReturnError(mMaxLen >= kEndOfContainerMarkerSize, CHIP_ERROR_BUFFER_TOO_SMALL);
     558        92006 :         mMaxLen -= kEndOfContainerMarkerSize;
     559              :     }
     560              : 
     561        92019 :     err = WriteElementHead(static_cast<TLVElementType>(containerType), tag, 0);
     562        92019 :     if (err != CHIP_NO_ERROR)
     563              :     {
     564              :         // undo the space reservation, as the container is not actually open
     565          177 :         if (IsCloseContainerReserved())
     566          177 :             mMaxLen += kEndOfContainerMarkerSize;
     567              : 
     568          177 :         return err;
     569              :     }
     570        91842 :     outerContainerType = mContainerType;
     571        91842 :     mContainerType     = containerType;
     572              : 
     573        91842 :     SetContainerOpen(false);
     574              : 
     575        91842 :     return CHIP_NO_ERROR;
     576              : }
     577              : 
     578        86958 : CHIP_ERROR TLVWriter::EndContainer(TLVType outerContainerType)
     579              : {
     580              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     581              : 
     582        86958 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     583              : 
     584        86957 :     if (!TLVTypeIsContainer(mContainerType))
     585            2 :         return CHIP_ERROR_INCORRECT_STATE;
     586              : 
     587        86955 :     mContainerType = outerContainerType;
     588              : 
     589        86955 :     if (IsCloseContainerReserved())
     590        86942 :         mMaxLen += kEndOfContainerMarkerSize;
     591              : 
     592        86955 :     return WriteElementHead(TLVElementType::EndOfContainer, AnonymousTag(), 0);
     593              : }
     594              : 
     595            4 : CHIP_ERROR TLVWriter::PutPreEncodedContainer(Tag tag, TLVType containerType, const uint8_t * data, uint32_t dataLen)
     596              : {
     597            4 :     if (!TLVTypeIsContainer(containerType))
     598            1 :         return CHIP_ERROR_INVALID_ARGUMENT;
     599              : 
     600            3 :     CHIP_ERROR err = WriteElementHead(static_cast<TLVElementType>(containerType), tag, 0);
     601            3 :     if (err != CHIP_NO_ERROR)
     602            1 :         return err;
     603              : 
     604            2 :     return WriteData(data, dataLen);
     605              : }
     606              : 
     607            2 : CHIP_ERROR TLVWriter::CopyContainer(TLVReader & container)
     608              : {
     609            2 :     return CopyContainer(container.GetTag(), container);
     610              : }
     611              : 
     612            3 : CHIP_ERROR TLVWriter::CopyContainer(Tag tag, TLVReader & container)
     613              : {
     614              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     615              : 
     616            3 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     617              : 
     618              :     // NOTE: This function MUST be used with a TVLReader that is reading from a contiguous buffer.
     619            1 :     if (container.mBackingStore != nullptr)
     620            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     621              : 
     622              :     CHIP_ERROR err;
     623              :     TLVType containerType, outerContainerType;
     624              :     const uint8_t * containerStart;
     625              : 
     626            1 :     containerType = container.GetType();
     627              : 
     628            1 :     err = container.EnterContainer(outerContainerType);
     629            1 :     if (err != CHIP_NO_ERROR)
     630            0 :         return err;
     631              : 
     632            1 :     containerStart = container.GetReadPoint();
     633              : 
     634            1 :     err = container.ExitContainer(outerContainerType);
     635            1 :     if (err != CHIP_NO_ERROR)
     636            0 :         return err;
     637              : 
     638            1 :     return PutPreEncodedContainer(tag, containerType, containerStart,
     639            1 :                                   static_cast<uint32_t>(container.GetReadPoint() - containerStart));
     640              : }
     641              : 
     642            2 : CHIP_ERROR TLVWriter::CopyContainer(Tag tag, const uint8_t * encodedContainer, uint16_t encodedContainerLen)
     643              : {
     644            2 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     645              : 
     646            1 :     TLVReader reader;
     647              : 
     648            1 :     reader.Init(encodedContainer, encodedContainerLen);
     649              : 
     650            1 :     ReturnErrorOnFailure(reader.Next());
     651              : 
     652            1 :     ReturnErrorOnFailure(PutPreEncodedContainer(tag, reader.GetType(), reader.GetReadPoint(), reader.GetRemainingLength()));
     653              : 
     654            1 :     return CHIP_NO_ERROR;
     655              : }
     656              : 
     657       367388 : CHIP_ERROR TLVWriter::WriteElementHead(TLVElementType elemType, Tag tag, uint64_t lenOrVal)
     658              : {
     659              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     660              : 
     661       367388 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     662       367365 :     VerifyOrReturnError(!IsContainerOpen(), CHIP_ERROR_TLV_CONTAINER_OPEN);
     663              : 
     664              :     uint8_t stagingBuf[17]; // 17 = 1 control byte + 8 tag bytes + 8 length/value bytes
     665       367365 :     uint32_t tagNum = TagNumFromTag(tag);
     666              : 
     667       367365 :     Encoding::LittleEndian::BufferWriter writer(stagingBuf, sizeof(stagingBuf));
     668              : 
     669       367365 :     if (IsSpecialTag(tag))
     670              :     {
     671       363224 :         if (tagNum <= Tag::kContextTagMaxNum)
     672              :         {
     673       191839 :             if (mContainerType != kTLVType_Structure && mContainerType != kTLVType_List)
     674            0 :                 return CHIP_ERROR_INVALID_TLV_TAG;
     675              : 
     676       191839 :             writer.Put8(TLVTagControl::ContextSpecific | elemType);
     677       191839 :             writer.Put8(static_cast<uint8_t>(tagNum));
     678              :         }
     679              :         else
     680              :         {
     681       171385 :             if (elemType != TLVElementType::EndOfContainer && mContainerType != kTLVType_NotSpecified &&
     682        44359 :                 mContainerType != kTLVType_Array && mContainerType != kTLVType_List)
     683            0 :                 return CHIP_ERROR_INVALID_TLV_TAG;
     684              : 
     685       171385 :             writer.Put8(TLVTagControl::Anonymous | elemType);
     686              :         }
     687              :     }
     688              :     else
     689              :     {
     690         4141 :         uint32_t profileId = ProfileIdFromTag(tag);
     691              : 
     692         4141 :         if (mContainerType != kTLVType_NotSpecified && mContainerType != kTLVType_Structure && mContainerType != kTLVType_List)
     693            0 :             return CHIP_ERROR_INVALID_TLV_TAG;
     694              : 
     695         4141 :         if (profileId == kCommonProfileId)
     696              :         {
     697          400 :             if (tagNum <= std::numeric_limits<uint16_t>::max())
     698              :             {
     699           12 :                 writer.Put8(TLVTagControl::CommonProfile_2Bytes | elemType);
     700           12 :                 writer.Put16(static_cast<uint16_t>(tagNum));
     701              :             }
     702              :             else
     703              :             {
     704          388 :                 writer.Put8(TLVTagControl::CommonProfile_4Bytes | elemType);
     705          388 :                 writer.Put32(tagNum);
     706              :             }
     707              :         }
     708         3741 :         else if (profileId == ImplicitProfileId)
     709              :         {
     710         2014 :             if (tagNum <= std::numeric_limits<uint16_t>::max())
     711              :             {
     712          850 :                 writer.Put8(TLVTagControl::ImplicitProfile_2Bytes | elemType);
     713          850 :                 writer.Put16(static_cast<uint16_t>(tagNum));
     714              :             }
     715              :             else
     716              :             {
     717         1164 :                 writer.Put8(TLVTagControl::ImplicitProfile_4Bytes | elemType);
     718         1164 :                 writer.Put32(tagNum);
     719              :             }
     720              :         }
     721              :         else
     722              :         {
     723         1727 :             uint16_t vendorId   = static_cast<uint16_t>(profileId >> 16);
     724         1727 :             uint16_t profileNum = static_cast<uint16_t>(profileId);
     725              : 
     726         1727 :             if (tagNum <= std::numeric_limits<uint16_t>::max())
     727              :             {
     728              : 
     729         1714 :                 writer.Put8(TLVTagControl::FullyQualified_6Bytes | elemType);
     730         1714 :                 writer.Put16(vendorId);
     731         1714 :                 writer.Put16(profileNum);
     732         1714 :                 writer.Put16(static_cast<uint16_t>(tagNum));
     733              :             }
     734              :             else
     735              :             {
     736           13 :                 writer.Put8(TLVTagControl::FullyQualified_8Bytes | elemType);
     737           13 :                 writer.Put16(vendorId);
     738           13 :                 writer.Put16(profileNum);
     739           13 :                 writer.Put32(tagNum);
     740              :             }
     741              :         }
     742              :     }
     743              : 
     744       367365 :     uint8_t lengthSize = TLVFieldSizeToBytes(GetTLVFieldSize(elemType));
     745       367365 :     if (lengthSize > 0)
     746              :     {
     747       146458 :         writer.EndianPut(lenOrVal, lengthSize);
     748              :     }
     749              : 
     750       367365 :     size_t written = 0;
     751       367365 :     VerifyOrDie(writer.Fit(written));
     752       367365 :     return WriteData(stagingBuf, static_cast<uint32_t>(written));
     753              : }
     754              : 
     755        14465 : CHIP_ERROR TLVWriter::WriteElementWithData(TLVType type, Tag tag, const uint8_t * data, uint32_t dataLen)
     756              : {
     757              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     758              : 
     759        14465 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     760        14461 :     if (static_cast<uint64_t>(type) & kTLVTypeSizeMask)
     761              :     {
     762              :         // We won't be able to recover this type properly!
     763            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     764              :     }
     765              : 
     766              :     TLVFieldSize lenFieldSize;
     767              : 
     768        14461 :     if (dataLen <= UINT8_MAX)
     769        11091 :         lenFieldSize = kTLVFieldSize_1Byte;
     770         3370 :     else if (dataLen <= UINT16_MAX)
     771         3370 :         lenFieldSize = kTLVFieldSize_2Byte;
     772              :     else
     773            0 :         lenFieldSize = kTLVFieldSize_4Byte;
     774              : 
     775        14461 :     CHIP_ERROR err = WriteElementHead(static_cast<TLVElementType>(static_cast<uint8_t>(type) | static_cast<uint8_t>(lenFieldSize)),
     776              :                                       tag, dataLen);
     777        14461 :     if (err != CHIP_NO_ERROR)
     778           34 :         return err;
     779              : 
     780        14427 :     return WriteData(data, dataLen);
     781              : }
     782              : 
     783       402950 : CHIP_ERROR TLVWriter::WriteData(const uint8_t * p, uint32_t len)
     784              : {
     785              :     ABORT_ON_UNINITIALIZED_IF_ENABLED();
     786              : 
     787       402950 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     788       402950 :     VerifyOrReturnError((mLenWritten + len) <= mMaxLen, CHIP_ERROR_BUFFER_TOO_SMALL);
     789              : 
     790       798660 :     while (len > 0)
     791              :     {
     792       398112 :         if (mRemainingLen == 0)
     793              :         {
     794         3103 :             VerifyOrReturnError(mBackingStore != nullptr, CHIP_ERROR_NO_MEMORY);
     795              : 
     796         3103 :             VerifyOrReturnError(CanCastTo<uint32_t>(mWritePoint - mBufStart), CHIP_ERROR_INCORRECT_STATE);
     797         3103 :             ReturnErrorOnFailure(mBackingStore->FinalizeBuffer(*this, mBufStart, static_cast<uint32_t>(mWritePoint - mBufStart)));
     798              : 
     799         3103 :             ReturnErrorOnFailure(mBackingStore->GetNewBuffer(*this, mBufStart, mRemainingLen));
     800          893 :             VerifyOrReturnError(mRemainingLen > 0, CHIP_ERROR_NO_MEMORY);
     801              : 
     802          893 :             mWritePoint = mBufStart;
     803              : 
     804          893 :             if (mRemainingLen > (mMaxLen - mLenWritten))
     805            0 :                 mRemainingLen = (mMaxLen - mLenWritten);
     806              :         }
     807              : 
     808       395902 :         uint32_t writeLen = len;
     809       395902 :         if (writeLen > mRemainingLen)
     810         2746 :             writeLen = mRemainingLen;
     811              : 
     812       395902 :         memmove(mWritePoint, p, writeLen);
     813       395902 :         mWritePoint += writeLen;
     814       395902 :         mRemainingLen -= writeLen;
     815       395902 :         mLenWritten += writeLen;
     816       395902 :         p += writeLen;
     817       395902 :         len -= writeLen;
     818              :     }
     819              : 
     820       400548 :     return CHIP_NO_ERROR;
     821              : }
     822              : 
     823              : } // namespace TLV
     824              : } // namespace chip
        

Generated by: LCOV version 2.0-1