3 * Copyright (c) 2020-2021 Project CHIP Authors
4 * Copyright (c) 2013-2017 Nest Labs, Inc.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * This file implements an encoder for the CHIP TLV (Tag-Length-Value) encoding format.
25 #ifndef __STDC_LIMIT_MACROS
26 #define __STDC_LIMIT_MACROS
28 #include <core/CHIPTLV.h>
30 #include <core/CHIPCore.h>
31 #include <core/CHIPEncoding.h>
33 #include <support/CHIPMem.h>
34 #include <support/CodeUtils.h>
35 #include <support/SafeInt.h>
41 // Doxygen is confused by the __attribute__ annotation
43 #define NO_INLINE __attribute__((noinline))
49 using namespace chip::Encoding;
51 NO_INLINE void TLVWriter::Init(uint8_t * buf, uint32_t maxLen)
53 mBackingStore = nullptr;
54 mBufStart = mWritePoint = buf;
55 mRemainingLen = maxLen;
58 mContainerType = kTLVType_NotSpecified;
59 SetContainerOpen(false);
60 SetCloseContainerReserved(true);
62 ImplicitProfileId = kProfileIdNotSpecified;
65 CHIP_ERROR TLVWriter::Init(TLVBackingStore & backingStore, uint32_t maxLen)
67 mBackingStore = &backingStore;
70 CHIP_ERROR err = mBackingStore->OnInit(*this, mBufStart, mRemainingLen);
71 if (err != CHIP_NO_ERROR)
74 mWritePoint = mBufStart;
77 mContainerType = kTLVType_NotSpecified;
78 SetContainerOpen(false);
79 SetCloseContainerReserved(true);
81 ImplicitProfileId = kProfileIdNotSpecified;
85 CHIP_ERROR TLVWriter::Finalize()
87 CHIP_ERROR err = CHIP_NO_ERROR;
88 if (IsContainerOpen())
89 return CHIP_ERROR_TLV_CONTAINER_OPEN;
90 if (mBackingStore != nullptr)
91 err = mBackingStore->FinalizeBuffer(*this, mBufStart, static_cast<uint32_t>(mWritePoint - mBufStart));
95 CHIP_ERROR TLVWriter::PutBoolean(uint64_t tag, bool v)
97 return WriteElementHead((v) ? TLVElementType::BooleanTrue : TLVElementType::BooleanFalse, tag, 0);
100 CHIP_ERROR TLVWriter::Put(uint64_t tag, uint8_t v)
102 return Put(tag, static_cast<uint64_t>(v));
105 CHIP_ERROR TLVWriter::Put(uint64_t tag, uint8_t v, bool preserveSize)
108 return WriteElementHead(TLVElementType::UInt8, tag, v);
112 CHIP_ERROR TLVWriter::Put(uint64_t tag, uint16_t v)
114 return Put(tag, static_cast<uint64_t>(v));
117 CHIP_ERROR TLVWriter::Put(uint64_t tag, uint16_t v, bool preserveSize)
120 return WriteElementHead(TLVElementType::UInt16, tag, v);
124 CHIP_ERROR TLVWriter::Put(uint64_t tag, uint32_t v)
126 return Put(tag, static_cast<uint64_t>(v));
129 CHIP_ERROR TLVWriter::Put(uint64_t tag, uint32_t v, bool preserveSize)
132 return WriteElementHead(TLVElementType::UInt32, tag, v);
136 CHIP_ERROR TLVWriter::Put(uint64_t tag, uint64_t v)
138 TLVElementType elemType;
140 elemType = TLVElementType::UInt8;
141 else if (v <= UINT16_MAX)
142 elemType = TLVElementType::UInt16;
143 else if (v <= UINT32_MAX)
144 elemType = TLVElementType::UInt32;
146 elemType = TLVElementType::UInt64;
147 return WriteElementHead(elemType, tag, v);
150 CHIP_ERROR TLVWriter::Put(uint64_t tag, uint64_t v, bool preserveSize)
153 return WriteElementHead(TLVElementType::UInt64, tag, v);
157 CHIP_ERROR TLVWriter::Put(uint64_t tag, int8_t v)
159 return Put(tag, static_cast<int64_t>(v));
162 CHIP_ERROR TLVWriter::Put(uint64_t tag, int8_t v, bool preserveSize)
165 return WriteElementHead(TLVElementType::Int8, tag, static_cast<uint8_t>(v));
169 CHIP_ERROR TLVWriter::Put(uint64_t tag, int16_t v)
171 return Put(tag, static_cast<int64_t>(v));
174 CHIP_ERROR TLVWriter::Put(uint64_t tag, int16_t v, bool preserveSize)
177 return WriteElementHead(TLVElementType::Int16, tag, static_cast<uint16_t>(v));
181 CHIP_ERROR TLVWriter::Put(uint64_t tag, int32_t v)
183 return Put(tag, static_cast<int64_t>(v));
186 CHIP_ERROR TLVWriter::Put(uint64_t tag, int32_t v, bool preserveSize)
189 return WriteElementHead(TLVElementType::Int32, tag, static_cast<uint32_t>(v));
193 CHIP_ERROR TLVWriter::Put(uint64_t tag, int64_t v)
195 TLVElementType elemType;
196 if (v >= INT8_MIN && v <= INT8_MAX)
197 elemType = TLVElementType::Int8;
198 else if (v >= INT16_MIN && v <= INT16_MAX)
199 elemType = TLVElementType::Int16;
200 else if (v >= INT32_MIN && v <= INT32_MAX)
201 elemType = TLVElementType::Int32;
203 elemType = TLVElementType::Int64;
204 return WriteElementHead(elemType, tag, static_cast<uint64_t>(v));
207 CHIP_ERROR TLVWriter::Put(uint64_t tag, int64_t v, bool preserveSize)
210 return WriteElementHead(TLVElementType::Int64, tag, static_cast<uint64_t>(v));
214 CHIP_ERROR TLVWriter::Put(uint64_t tag, float v)
222 return WriteElementHead(TLVElementType::FloatingPointNumber32, tag, cvt.u32);
225 CHIP_ERROR TLVWriter::Put(uint64_t tag, double v)
233 return WriteElementHead(TLVElementType::FloatingPointNumber64, tag, cvt.u64);
236 CHIP_ERROR TLVWriter::Put(uint64_t tag, ByteSpan data)
238 VerifyOrReturnError(CanCastTo<uint32_t>(data.size()), CHIP_ERROR_MESSAGE_TOO_LONG);
239 return PutBytes(tag, data.data(), static_cast<uint32_t>(data.size()));
242 CHIP_ERROR TLVWriter::PutBytes(uint64_t tag, const uint8_t * buf, uint32_t len)
244 return WriteElementWithData(kTLVType_ByteString, tag, buf, len);
247 CHIP_ERROR TLVWriter::PutString(uint64_t tag, const char * buf)
249 size_t len = strlen(buf);
250 if (!CanCastTo<uint32_t>(len))
252 return CHIP_ERROR_INVALID_ARGUMENT;
254 return PutString(tag, buf, static_cast<uint32_t>(len));
257 CHIP_ERROR TLVWriter::PutString(uint64_t tag, const char * buf, uint32_t len)
259 return WriteElementWithData(kTLVType_UTF8String, tag, reinterpret_cast<const uint8_t *>(buf), len);
262 CHIP_ERROR TLVWriter::PutStringF(uint64_t tag, const char * fmt, ...)
269 err = VPutStringF(tag, fmt, ap);
276 #if CONFIG_HAVE_VCBPRINTF
277 // We have a variant of the printf function that takes a callback that
278 // emits a single character. The callback performs a function
279 // identical to putchar.
281 void TLVWriter::CHIPTLVWriterPutcharCB(uint8_t c, void * appState)
283 TLVWriter * w = static_cast<TLVWriter *>(appState);
284 w->WriteData(&c, sizeof(c));
288 CHIP_ERROR TLVWriter::VPutStringF(uint64_t tag, const char * fmt, va_list ap)
292 CHIP_ERROR err = CHIP_NO_ERROR;
293 TLVFieldSize lenFieldSize;
294 #if CONFIG_HAVE_VSNPRINTF_EX
297 #elif CONFIG_HAVE_VCBPRINTF
298 #elif CONFIG_TLV_TRUNCATE
305 dataLen = static_cast<size_t>(vsnprintf(nullptr, 0, fmt, aq));
306 if (!CanCastTo<uint32_t>(dataLen))
308 return CHIP_ERROR_INVALID_ARGUMENT;
313 if (dataLen <= UINT8_MAX)
314 lenFieldSize = kTLVFieldSize_1Byte;
315 else if (dataLen <= UINT16_MAX)
316 lenFieldSize = kTLVFieldSize_2Byte;
318 lenFieldSize = kTLVFieldSize_4Byte;
320 #if !(CONFIG_HAVE_VCBPRINTF) && !(CONFIG_HAVE_VSNPRINTF_EX) && CONFIG_TLV_TRUNCATE
321 // no facilities for splitting the stream across multiple buffers,
322 // just write however much fits in the current buffer.
323 // assume conservative tag length at this time (8 bytes)
324 maxLen = mRemainingLen -
325 (1 + 8 + (1 << static_cast<uint8_t>(lenFieldSize)) +
326 1); // 1 : control byte, 8 : tag length, stringLen + 1 for null termination
327 if (maxLen < dataLen)
332 err = WriteElementHead(
333 static_cast<TLVElementType>(static_cast<uint8_t>(kTLVType_UTF8String) | static_cast<uint8_t>(lenFieldSize)), tag, dataLen);
336 VerifyOrExit((mLenWritten + dataLen) <= mMaxLen, err = CHIP_ERROR_BUFFER_TOO_SMALL);
339 #if CONFIG_HAVE_VSNPRINTF_EX
347 vsnprintf_ex(reinterpret_cast<char *>(mWritePoint), mRemainingLen, skipLen, fmt, aq);
351 writtenBytes = (mRemainingLen >= (dataLen - skipLen)) ? dataLen - skipLen : mRemainingLen;
352 skipLen += writtenBytes;
353 mWritePoint += writtenBytes;
354 mRemainingLen -= writtenBytes;
355 mLenWritten += writtenBytes;
356 if (skipLen < dataLen)
358 VerifyOrExit(mBackingStore != NULL, err = CHIP_ERROR_NO_MEMORY);
360 err = mBackingStore->FinalizeBuffer(*this, mBufHandle, mBufStart, mWritePoint - mBufStart);
363 err = mBackingStore->GetNewBuffer(*this, mBufHandle, mBufStart, mRemainingLen);
366 mWritePoint = mBufStart;
369 } while (skipLen < dataLen);
371 #elif CONFIG_HAVE_VCBPRINTF
375 vcbprintf(CHIPTLVWriterPutcharCB, this, dataLen, fmt, aq);
379 #else // CONFIG_HAVE_VSNPRINTF_EX
381 tmpBuf = static_cast<char *>(chip::Platform::MemoryAlloc(dataLen + 1));
382 VerifyOrExit(tmpBuf != nullptr, err = CHIP_ERROR_NO_MEMORY);
386 vsnprintf(tmpBuf, dataLen + 1, fmt, aq);
390 err = WriteData(reinterpret_cast<uint8_t *>(tmpBuf), static_cast<uint32_t>(dataLen));
391 chip::Platform::MemoryFree(tmpBuf);
393 #endif // CONFIG_HAVE_VSNPRINTF_EX
400 CHIP_ERROR TLVWriter::PutNull(uint64_t tag)
402 return WriteElementHead(TLVElementType::Null, tag, 0);
405 CHIP_ERROR TLVWriter::CopyElement(TLVReader & reader)
407 return CopyElement(reader.GetTag(), reader);
410 const size_t kCHIPTLVCopyChunkSize = 16;
412 CHIP_ERROR TLVWriter::CopyElement(uint64_t tag, TLVReader & reader)
414 TLVElementType elemType = reader.ElementType();
415 uint64_t elemLenOrVal = reader.mElemLenOrVal;
416 TLVReader readerHelper; // used to figure out the length of the element and read data of the element
417 uint32_t copyDataLen;
418 uint8_t chunk[kCHIPTLVCopyChunkSize];
420 VerifyOrReturnError(elemType != TLVElementType::NotSpecified && elemType != TLVElementType::EndOfContainer,
421 CHIP_ERROR_INCORRECT_STATE);
423 // Initialize the helper
424 readerHelper.Init(reader);
426 // Skip to the end of the element.
427 ReturnErrorOnFailure(reader.Skip());
429 // Compute the amount of value data to copy from the reader.
430 copyDataLen = reader.GetLengthRead() - readerHelper.GetLengthRead();
432 // Write the head of the new element with the same type and length/value, but using the
434 ReturnErrorOnFailure(WriteElementHead(elemType, tag, elemLenOrVal));
436 while (copyDataLen > 0)
438 uint32_t chunkSize = copyDataLen > kCHIPTLVCopyChunkSize ? kCHIPTLVCopyChunkSize : copyDataLen;
439 ReturnErrorOnFailure(readerHelper.ReadData(chunk, chunkSize));
441 ReturnErrorOnFailure(WriteData(chunk, chunkSize));
443 copyDataLen -= chunkSize;
446 return CHIP_NO_ERROR;
449 CHIP_ERROR TLVWriter::OpenContainer(uint64_t tag, TLVType containerType, TLVWriter & containerWriter)
451 CHIP_ERROR err = CHIP_NO_ERROR;
453 VerifyOrReturnError(TLVTypeIsContainer(containerType), CHIP_ERROR_WRONG_TLV_TYPE);
455 if (IsCloseContainerReserved())
457 VerifyOrReturnError(mMaxLen >= kEndOfContainerMarkerSize, CHIP_ERROR_BUFFER_TOO_SMALL);
458 mMaxLen -= kEndOfContainerMarkerSize;
460 err = WriteElementHead(static_cast<TLVElementType>(containerType), tag, 0);
462 if (err != CHIP_NO_ERROR)
464 // undo the space reservation, as the container is not actually open
465 if (IsCloseContainerReserved())
466 mMaxLen += kEndOfContainerMarkerSize;
471 containerWriter.mBackingStore = mBackingStore;
472 containerWriter.mBufStart = mBufStart;
473 containerWriter.mWritePoint = mWritePoint;
474 containerWriter.mRemainingLen = mRemainingLen;
475 containerWriter.mLenWritten = 0;
476 containerWriter.mMaxLen = mMaxLen - mLenWritten;
477 containerWriter.mContainerType = containerType;
478 containerWriter.SetContainerOpen(false);
479 containerWriter.SetCloseContainerReserved(IsCloseContainerReserved());
480 containerWriter.ImplicitProfileId = ImplicitProfileId;
482 SetContainerOpen(true);
484 return CHIP_NO_ERROR;
487 CHIP_ERROR TLVWriter::CloseContainer(TLVWriter & containerWriter)
489 if (!TLVTypeIsContainer(containerWriter.mContainerType))
490 return CHIP_ERROR_INCORRECT_STATE;
492 if (containerWriter.IsContainerOpen())
493 return CHIP_ERROR_TLV_CONTAINER_OPEN;
495 mBackingStore = containerWriter.mBackingStore;
496 mBufStart = containerWriter.mBufStart;
497 mWritePoint = containerWriter.mWritePoint;
498 mRemainingLen = containerWriter.mRemainingLen;
499 mLenWritten += containerWriter.mLenWritten;
501 if (IsCloseContainerReserved())
502 mMaxLen += kEndOfContainerMarkerSize;
504 SetContainerOpen(false);
506 // Reset the container writer so that it can't accidentally be used again.
507 containerWriter.Init(static_cast<uint8_t *>(nullptr), 0);
509 return WriteElementHead(TLVElementType::EndOfContainer, AnonymousTag, 0);
512 CHIP_ERROR TLVWriter::StartContainer(uint64_t tag, TLVType containerType, TLVType & outerContainerType)
514 CHIP_ERROR err = CHIP_NO_ERROR;
516 VerifyOrReturnError(TLVTypeIsContainer(containerType), CHIP_ERROR_WRONG_TLV_TYPE);
518 if (IsCloseContainerReserved())
520 VerifyOrReturnError(mMaxLen >= kEndOfContainerMarkerSize, CHIP_ERROR_BUFFER_TOO_SMALL);
521 mMaxLen -= kEndOfContainerMarkerSize;
524 err = WriteElementHead(static_cast<TLVElementType>(containerType), tag, 0);
525 if (err != CHIP_NO_ERROR)
527 // undo the space reservation, as the container is not actually open
528 if (IsCloseContainerReserved())
529 mMaxLen += kEndOfContainerMarkerSize;
533 outerContainerType = mContainerType;
534 mContainerType = containerType;
536 SetContainerOpen(false);
538 return CHIP_NO_ERROR;
541 CHIP_ERROR TLVWriter::EndContainer(TLVType outerContainerType)
543 if (!TLVTypeIsContainer(mContainerType))
544 return CHIP_ERROR_INCORRECT_STATE;
546 mContainerType = outerContainerType;
548 if (IsCloseContainerReserved())
549 mMaxLen += kEndOfContainerMarkerSize;
551 return WriteElementHead(TLVElementType::EndOfContainer, AnonymousTag, 0);
554 CHIP_ERROR TLVWriter::PutPreEncodedContainer(uint64_t tag, TLVType containerType, const uint8_t * data, uint32_t dataLen)
556 if (!TLVTypeIsContainer(containerType))
557 return CHIP_ERROR_INVALID_ARGUMENT;
559 CHIP_ERROR err = WriteElementHead(static_cast<TLVElementType>(containerType), tag, 0);
560 if (err != CHIP_NO_ERROR)
563 return WriteData(data, dataLen);
566 CHIP_ERROR TLVWriter::CopyContainer(TLVReader & container)
568 return CopyContainer(container.GetTag(), container);
571 CHIP_ERROR TLVWriter::CopyContainer(uint64_t tag, TLVReader & container)
573 // NOTE: This function MUST be used with a TVLReader that is reading from a contiguous buffer.
574 if (container.mBackingStore != nullptr)
575 return CHIP_ERROR_INVALID_ARGUMENT;
578 TLVType containerType, outerContainerType;
579 const uint8_t * containerStart;
581 containerType = container.GetType();
583 err = container.EnterContainer(outerContainerType);
584 if (err != CHIP_NO_ERROR)
587 containerStart = container.GetReadPoint();
589 err = container.ExitContainer(outerContainerType);
590 if (err != CHIP_NO_ERROR)
593 return PutPreEncodedContainer(tag, containerType, containerStart,
594 static_cast<uint32_t>(container.GetReadPoint() - containerStart));
597 CHIP_ERROR TLVWriter::CopyContainer(uint64_t tag, const uint8_t * encodedContainer, uint16_t encodedContainerLen)
601 reader.Init(encodedContainer, encodedContainerLen);
603 ReturnErrorOnFailure(reader.Next());
605 ReturnErrorOnFailure(PutPreEncodedContainer(tag, reader.GetType(), reader.GetReadPoint(), reader.GetRemainingLength()));
607 return CHIP_NO_ERROR;
610 CHIP_ERROR TLVWriter::WriteElementHead(TLVElementType elemType, uint64_t tag, uint64_t lenOrVal)
613 uint8_t stagingBuf[17]; // 17 = 1 control byte + 8 tag bytes + 8 length/value bytes
615 if (IsContainerOpen())
616 return CHIP_ERROR_TLV_CONTAINER_OPEN;
618 uint32_t tagNum = TagNumFromTag(tag);
620 if ((mRemainingLen >= sizeof(stagingBuf)) && (mMaxLen >= sizeof(stagingBuf)))
625 if (IsSpecialTag(tag))
629 if (mContainerType != kTLVType_Structure && mContainerType != kTLVType_List)
630 return CHIP_ERROR_INVALID_TLV_TAG;
632 Write8(p, TLVTagControl::ContextSpecific | elemType);
633 Write8(p, static_cast<uint8_t>(tagNum));
637 if (elemType != TLVElementType::EndOfContainer && mContainerType != kTLVType_NotSpecified &&
638 mContainerType != kTLVType_Array && mContainerType != kTLVType_List)
639 return CHIP_ERROR_INVALID_TLV_TAG;
641 Write8(p, TLVTagControl::Anonymous | elemType);
646 uint32_t profileId = ProfileIdFromTag(tag);
648 if (mContainerType != kTLVType_NotSpecified && mContainerType != kTLVType_Structure && mContainerType != kTLVType_List)
649 return CHIP_ERROR_INVALID_TLV_TAG;
651 if (profileId == kCommonProfileId)
655 Write8(p, TLVTagControl::CommonProfile_2Bytes | elemType);
656 LittleEndian::Write16(p, static_cast<uint16_t>(tagNum));
660 Write8(p, TLVTagControl::CommonProfile_4Bytes | elemType);
661 LittleEndian::Write32(p, tagNum);
664 else if (profileId == ImplicitProfileId)
668 Write8(p, TLVTagControl::ImplicitProfile_2Bytes | elemType);
669 LittleEndian::Write16(p, static_cast<uint16_t>(tagNum));
673 Write8(p, TLVTagControl::ImplicitProfile_4Bytes | elemType);
674 LittleEndian::Write32(p, tagNum);
679 uint16_t vendorId = static_cast<uint16_t>(profileId >> 16);
680 uint16_t profileNum = static_cast<uint16_t>(profileId);
684 Write8(p, TLVTagControl::FullyQualified_6Bytes | elemType);
685 LittleEndian::Write16(p, vendorId);
686 LittleEndian::Write16(p, profileNum);
687 LittleEndian::Write16(p, static_cast<uint16_t>(tagNum));
691 Write8(p, TLVTagControl::FullyQualified_8Bytes | elemType);
692 LittleEndian::Write16(p, vendorId);
693 LittleEndian::Write16(p, profileNum);
694 LittleEndian::Write32(p, tagNum);
699 switch (GetTLVFieldSize(elemType))
701 case kTLVFieldSize_0Byte:
703 case kTLVFieldSize_1Byte:
704 Write8(p, static_cast<uint8_t>(lenOrVal));
706 case kTLVFieldSize_2Byte:
707 LittleEndian::Write16(p, static_cast<uint16_t>(lenOrVal));
709 case kTLVFieldSize_4Byte:
710 LittleEndian::Write32(p, static_cast<uint32_t>(lenOrVal));
712 case kTLVFieldSize_8Byte:
713 LittleEndian::Write64(p, lenOrVal);
717 if ((mRemainingLen >= sizeof(stagingBuf)) && (mMaxLen >= sizeof(stagingBuf)))
719 uint32_t len = static_cast<uint32_t>(p - mWritePoint);
721 mRemainingLen -= len;
723 return CHIP_NO_ERROR;
725 return WriteData(stagingBuf, static_cast<uint32_t>(p - stagingBuf));
728 CHIP_ERROR TLVWriter::WriteElementWithData(TLVType type, uint64_t tag, const uint8_t * data, uint32_t dataLen)
730 if (static_cast<uint64_t>(type) & kTLVTypeSizeMask)
732 // We won't be able to recover this type properly!
733 return CHIP_ERROR_INVALID_ARGUMENT;
736 TLVFieldSize lenFieldSize;
738 if (dataLen <= UINT8_MAX)
739 lenFieldSize = kTLVFieldSize_1Byte;
740 else if (dataLen <= UINT16_MAX)
741 lenFieldSize = kTLVFieldSize_2Byte;
743 lenFieldSize = kTLVFieldSize_4Byte;
745 CHIP_ERROR err = WriteElementHead(static_cast<TLVElementType>(static_cast<uint8_t>(type) | static_cast<uint8_t>(lenFieldSize)),
747 if (err != CHIP_NO_ERROR)
750 return WriteData(data, dataLen);
753 CHIP_ERROR TLVWriter::WriteData(const uint8_t * p, uint32_t len)
755 VerifyOrReturnError((mLenWritten + len) <= mMaxLen, CHIP_ERROR_BUFFER_TOO_SMALL);
759 if (mRemainingLen == 0)
761 VerifyOrReturnError(mBackingStore != nullptr, CHIP_ERROR_NO_MEMORY);
763 VerifyOrReturnError(CanCastTo<uint32_t>(mWritePoint - mBufStart), CHIP_ERROR_INCORRECT_STATE);
764 ReturnErrorOnFailure(mBackingStore->FinalizeBuffer(*this, mBufStart, static_cast<uint32_t>(mWritePoint - mBufStart)));
766 ReturnErrorOnFailure(mBackingStore->GetNewBuffer(*this, mBufStart, mRemainingLen));
768 mWritePoint = mBufStart;
770 if (mRemainingLen > (mMaxLen - mLenWritten))
771 mRemainingLen = (mMaxLen - mLenWritten);
774 uint32_t writeLen = len;
775 if (writeLen > mRemainingLen)
776 writeLen = mRemainingLen;
778 memmove(mWritePoint, p, writeLen);
779 mWritePoint += writeLen;
780 mRemainingLen -= writeLen;
781 mLenWritten += writeLen;
786 return CHIP_NO_ERROR;