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