LCOV - code coverage report
Current view: top level - lib/core - TLVWriter.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 353 378 93.4 %
Date: 2024-02-15 08:20:41 Functions: 45 45 100.0 %

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

Generated by: LCOV version 1.14