Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2023 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/TLVReader.h>
19 :
20 : #include <stdint.h>
21 : #include <string.h>
22 :
23 : #include <lib/core/CHIPConfig.h>
24 : #include <lib/core/CHIPEncoding.h>
25 : #include <lib/core/CHIPError.h>
26 : #include <lib/core/CHIPSafeCasts.h>
27 : #include <lib/core/DataModelTypes.h>
28 : #include <lib/core/Optional.h>
29 : #include <lib/core/TLVBackingStore.h>
30 : #include <lib/core/TLVCommon.h>
31 : #include <lib/core/TLVTags.h>
32 : #include <lib/core/TLVTypes.h>
33 : #include <lib/support/BufferWriter.h>
34 : #include <lib/support/BytesToHex.h>
35 : #include <lib/support/CHIPMem.h>
36 : #include <lib/support/CodeUtils.h>
37 : #include <lib/support/SafeInt.h>
38 : #include <lib/support/Span.h>
39 : #include <lib/support/logging/TextOnlyLogging.h>
40 : #include <lib/support/utf8.h>
41 :
42 : namespace chip {
43 : namespace TLV {
44 :
45 : using namespace chip::Encoding;
46 :
47 : static const uint8_t sTagSizes[] = { 0, 1, 2, 4, 2, 4, 6, 8 };
48 :
49 2656032 : TLVReader::TLVReader() :
50 2656032 : ImplicitProfileId(kProfileIdNotSpecified), AppData(nullptr), mElemLenOrVal(0), mBackingStore(nullptr), mReadPoint(nullptr),
51 2656032 : mBufEnd(nullptr), mLenRead(0), mMaxLen(0), mContainerType(kTLVType_NotSpecified), mControlByte(kTLVControlByte_NotSpecified),
52 2656032 : mContainerOpen(false)
53 2656032 : {}
54 :
55 1807824 : void TLVReader::Init(const uint8_t * data, size_t dataLen)
56 : {
57 : // TODO: Maybe we can just make mMaxLen and mLenRead size_t instead?
58 1807824 : uint32_t actualDataLen = dataLen > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(dataLen);
59 1807824 : mBackingStore = nullptr;
60 1807824 : mReadPoint = data;
61 1807824 : mBufEnd = data + actualDataLen;
62 1807824 : mLenRead = 0;
63 1807824 : mMaxLen = actualDataLen;
64 1807824 : ClearElementState();
65 1807824 : mContainerType = kTLVType_NotSpecified;
66 1807824 : SetContainerOpen(false);
67 :
68 1807824 : ImplicitProfileId = kProfileIdNotSpecified;
69 1807824 : }
70 :
71 4152 : CHIP_ERROR TLVReader::Init(TLVBackingStore & backingStore, uint32_t maxLen)
72 : {
73 4152 : mBackingStore = &backingStore;
74 4152 : mReadPoint = nullptr;
75 4152 : uint32_t bufLen = 0;
76 4152 : CHIP_ERROR err = mBackingStore->OnInit(*this, mReadPoint, bufLen);
77 8304 : if (err != CHIP_NO_ERROR)
78 0 : return err;
79 :
80 4152 : mBufEnd = mReadPoint + bufLen;
81 4152 : mLenRead = 0;
82 4152 : mMaxLen = maxLen;
83 4152 : ClearElementState();
84 4152 : mContainerType = kTLVType_NotSpecified;
85 4152 : SetContainerOpen(false);
86 :
87 4152 : ImplicitProfileId = kProfileIdNotSpecified;
88 4152 : AppData = nullptr;
89 4152 : return CHIP_NO_ERROR;
90 : }
91 :
92 798321 : void TLVReader::Init(const TLVReader & aReader)
93 : {
94 : // Initialize private data members
95 :
96 798321 : mElemTag = aReader.mElemTag;
97 798321 : mElemLenOrVal = aReader.mElemLenOrVal;
98 798321 : mBackingStore = aReader.mBackingStore;
99 798321 : mReadPoint = aReader.mReadPoint;
100 798321 : mBufEnd = aReader.mBufEnd;
101 798321 : mLenRead = aReader.mLenRead;
102 798321 : mMaxLen = aReader.mMaxLen;
103 798321 : mControlByte = aReader.mControlByte;
104 798321 : mContainerType = aReader.mContainerType;
105 798321 : SetContainerOpen(aReader.IsContainerOpen());
106 :
107 : // Initialize public data members
108 :
109 798321 : ImplicitProfileId = aReader.ImplicitProfileId;
110 798321 : AppData = aReader.AppData;
111 798321 : }
112 :
113 9843206 : TLVType TLVReader::GetType() const
114 : {
115 9843206 : TLVElementType elemType = ElementType();
116 9843206 : if (elemType == TLVElementType::EndOfContainer)
117 4 : return kTLVType_NotSpecified;
118 9843202 : if (elemType == TLVElementType::FloatingPointNumber32 || elemType == TLVElementType::FloatingPointNumber64)
119 12020 : return kTLVType_FloatingPointNumber;
120 9831182 : if (elemType == TLVElementType::NotSpecified || elemType >= TLVElementType::Null)
121 3970452 : return static_cast<TLVType>(elemType);
122 5860730 : return static_cast<TLVType>(static_cast<uint8_t>(elemType) & ~kTLVTypeSizeMask);
123 : }
124 :
125 171290 : uint32_t TLVReader::GetLength() const
126 : {
127 171290 : if (TLVTypeHasLength(ElementType()))
128 158217 : return static_cast<uint32_t>(mElemLenOrVal);
129 13073 : return 0;
130 : }
131 :
132 3209036 : CHIP_ERROR TLVReader::Get(bool & v) const
133 : {
134 3209036 : TLVElementType elemType = ElementType();
135 3209036 : if (elemType == TLVElementType::BooleanFalse)
136 1597665 : v = false;
137 1611371 : else if (elemType == TLVElementType::BooleanTrue)
138 1611370 : v = true;
139 : else
140 1 : return CHIP_ERROR_WRONG_TLV_TYPE;
141 3209035 : return CHIP_NO_ERROR;
142 : }
143 :
144 1561578 : CHIP_ERROR TLVReader::Get(int8_t & v) const
145 : {
146 1561578 : int64_t v64 = 0;
147 1561578 : CHIP_ERROR err = Get(v64);
148 1561578 : if (!CanCastTo<int8_t>(v64))
149 : {
150 37 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
151 : }
152 1561541 : v = static_cast<int8_t>(v64);
153 1561541 : return err;
154 : }
155 :
156 1557293 : CHIP_ERROR TLVReader::Get(int16_t & v) const
157 : {
158 1557293 : int64_t v64 = 0;
159 1557293 : CHIP_ERROR err = Get(v64);
160 1557293 : if (!CanCastTo<int16_t>(v64))
161 : {
162 4 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
163 : }
164 1557289 : v = static_cast<int16_t>(v64);
165 1557289 : return err;
166 : }
167 :
168 1557630 : CHIP_ERROR TLVReader::Get(int32_t & v) const
169 : {
170 1557630 : int64_t v64 = 0;
171 1557630 : CHIP_ERROR err = Get(v64);
172 1557630 : if (!CanCastTo<int32_t>(v64))
173 : {
174 2 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
175 : }
176 1557628 : v = static_cast<int32_t>(v64);
177 1557628 : return err;
178 : }
179 :
180 6234919 : CHIP_ERROR TLVReader::Get(int64_t & v) const
181 : {
182 : // Internal callers of this method depend on it not modifying "v" on failure.
183 6234919 : switch (ElementType())
184 : {
185 6233420 : case TLVElementType::Int8:
186 6233420 : v = CastToSigned(static_cast<uint8_t>(mElemLenOrVal));
187 6233420 : break;
188 189 : case TLVElementType::Int16:
189 189 : v = CastToSigned(static_cast<uint16_t>(mElemLenOrVal));
190 189 : break;
191 843 : case TLVElementType::Int32:
192 843 : v = CastToSigned(static_cast<uint32_t>(mElemLenOrVal));
193 843 : break;
194 66 : case TLVElementType::Int64:
195 66 : v = CastToSigned(mElemLenOrVal);
196 66 : break;
197 401 : default:
198 401 : return CHIP_ERROR_WRONG_TLV_TYPE;
199 : }
200 :
201 6234518 : return CHIP_NO_ERROR;
202 : }
203 :
204 1636620 : CHIP_ERROR TLVReader::Get(uint8_t & v) const
205 : {
206 1636620 : uint64_t v64 = 0;
207 1636620 : CHIP_ERROR err = Get(v64);
208 1636620 : if (!CanCastTo<uint8_t>(v64))
209 : {
210 3 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
211 : }
212 1636617 : v = static_cast<uint8_t>(v64);
213 1636617 : return err;
214 : }
215 :
216 373134 : CHIP_ERROR TLVReader::Get(uint16_t & v) const
217 : {
218 373134 : uint64_t v64 = 0;
219 373134 : CHIP_ERROR err = Get(v64);
220 373134 : if (!CanCastTo<uint16_t>(v64))
221 : {
222 6 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
223 : }
224 373128 : v = static_cast<uint16_t>(v64);
225 373128 : return err;
226 : }
227 :
228 122748 : CHIP_ERROR TLVReader::Get(uint32_t & v) const
229 : {
230 122748 : uint64_t v64 = 0;
231 122748 : CHIP_ERROR err = Get(v64);
232 122748 : if (!CanCastTo<uint32_t>(v64))
233 : {
234 1 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
235 : }
236 122747 : v = static_cast<uint32_t>(v64);
237 122747 : return err;
238 : }
239 :
240 2193342 : CHIP_ERROR TLVReader::Get(uint64_t & v) const
241 : {
242 : // Internal callers of this method depend on it not modifying "v" on failure.
243 2193342 : switch (ElementType())
244 : {
245 634965 : case TLVElementType::UInt8:
246 : case TLVElementType::UInt16:
247 : case TLVElementType::UInt32:
248 : case TLVElementType::UInt64:
249 634965 : v = mElemLenOrVal;
250 634965 : break;
251 1558377 : default:
252 1558377 : return CHIP_ERROR_WRONG_TLV_TYPE;
253 : }
254 634965 : return CHIP_NO_ERROR;
255 : }
256 :
257 : namespace {
258 2567 : float BitCastToFloat(const uint64_t elemLenOrVal)
259 : {
260 : float f;
261 2567 : auto unsigned32 = static_cast<uint32_t>(elemLenOrVal);
262 2567 : memcpy(&f, &unsigned32, sizeof(f));
263 2567 : return f;
264 : }
265 : } // namespace
266 :
267 : // Note: Unlike the integer Get functions, this code avoids doing conversions
268 : // between float and double wherever possible, because these conversions are
269 : // relatively expensive on platforms that use soft-float instruction sets.
270 :
271 529 : CHIP_ERROR TLVReader::Get(float & v) const
272 : {
273 529 : switch (ElementType())
274 : {
275 527 : case TLVElementType::FloatingPointNumber32: {
276 527 : v = BitCastToFloat(mElemLenOrVal);
277 527 : break;
278 : }
279 2 : default:
280 2 : return CHIP_ERROR_WRONG_TLV_TYPE;
281 : }
282 527 : return CHIP_NO_ERROR;
283 : }
284 :
285 4228 : CHIP_ERROR TLVReader::Get(double & v) const
286 : {
287 4228 : switch (ElementType())
288 : {
289 2040 : case TLVElementType::FloatingPointNumber32: {
290 2040 : v = BitCastToFloat(mElemLenOrVal);
291 2040 : break;
292 : }
293 2187 : case TLVElementType::FloatingPointNumber64: {
294 : double d;
295 2187 : memcpy(&d, &mElemLenOrVal, sizeof(d));
296 2187 : v = d;
297 2187 : break;
298 : }
299 1 : default:
300 1 : return CHIP_ERROR_WRONG_TLV_TYPE;
301 : }
302 4227 : return CHIP_NO_ERROR;
303 : }
304 :
305 15367 : CHIP_ERROR TLVReader::Get(ByteSpan & v) const
306 : {
307 : const uint8_t * val;
308 15367 : ReturnErrorOnFailure(GetDataPtr(val));
309 15363 : v = ByteSpan(val, GetLength());
310 :
311 15363 : return CHIP_NO_ERROR;
312 : }
313 :
314 : namespace {
315 : constexpr int kUnicodeInformationSeparator1 = 0x1F;
316 : constexpr size_t kMaxLocalizedStringIdentifierLen = 2 * sizeof(LocalizedStringIdentifier);
317 :
318 : // Shared conformance predicate for TLV UTF-8 character strings (Matter spec §A.11.2 /
319 : // §7.19.2.40): the bytes must be valid UTF-8 and must not contain ANY 0x00. The spec
320 : // only forbids a *terminating* NUL, but we additionally reject interior NULs because
321 : // Matter has no field for which an embedded 0x00 is meaningful and a C/C++ string
322 : // handler downstream would mis-terminate. Both read-path Get overloads in this TU
323 : // route through this single predicate so they agree byte-for-byte on what is
324 : // conformant; tests reach it via the CHIP_CONFIG_TEST-gated ValidateCharStringForTest
325 : // shim. File-scope (anonymous-namespace) internal linkage — not part of the public API.
326 19 : CHIP_ERROR ValidateCharString(const CharSpan & str)
327 : {
328 19 : VerifyOrReturnError(Utf8::IsValid(str), CHIP_ERROR_INVALID_UTF8);
329 11 : if (!str.empty())
330 : {
331 10 : VerifyOrReturnError(memchr(str.data(), 0, str.size()) == nullptr, CHIP_ERROR_INVALID_TLV_CHAR_STRING);
332 : }
333 4 : return CHIP_NO_ERROR;
334 : }
335 : } // namespace
336 :
337 1067 : CHIP_ERROR TLVReader::Get(CharSpan & v) const
338 : {
339 1067 : if (!TLVTypeIsUTF8String(ElementType()))
340 : {
341 2 : return CHIP_ERROR_WRONG_TLV_TYPE;
342 : }
343 :
344 : const uint8_t * bytes;
345 1065 : ReturnErrorOnFailure(GetDataPtr(bytes)); // Does length sanity checks
346 1063 : if (bytes == nullptr)
347 : {
348 : // Calling memchr further down with bytes == nullptr would have undefined behaviour, exiting early.
349 131 : v = {}; // empty data
350 131 : return CHIP_NO_ERROR;
351 : }
352 :
353 932 : uint32_t len = GetLength();
354 :
355 : // If Unicode Information Separator 1 (0x1f) is present in the string then method returns
356 : // string ending at first appearance of the Information Separator 1.
357 932 : const uint8_t * infoSeparator = reinterpret_cast<const uint8_t *>(memchr(bytes, kUnicodeInformationSeparator1, len));
358 932 : if (infoSeparator != nullptr)
359 : {
360 12 : len = static_cast<uint32_t>(infoSeparator - bytes);
361 : }
362 :
363 932 : v = CharSpan(Uint8::to_const_char(bytes), len);
364 :
365 : #if CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ
366 : // Read-side strict validation is opt-in (default off in core.gni). The default keeps
367 : // the historical lenient decode because some deployed accessories ship char strings
368 : // that fail strict UTF-8 / no-NUL validation (e.g. raw FreeRTOS buffers in place of
369 : // UTF-8 text); flipping this on by default would cause controllers to start rejecting
370 : // payloads they previously accepted. Integrators who want strict enforcement set the
371 : // GN flag explicitly.
372 : //
373 : // When enabled, validation runs on the FULL on-wire span (pre- and post-IS1 alike) per
374 : // Matter spec §A.11.2 — strings MUST be UTF-8 and may contain an IS1 separator — even
375 : // though `v` is truncated at IS1 for caller convenience, so this overload's verdict
376 : // matches Get(LSID&)'s on the same bytes.
377 : CharSpan full(Uint8::to_const_char(bytes), GetLength());
378 : ReturnErrorOnFailure(ValidateCharString(full));
379 : #endif // CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ
380 :
381 932 : return CHIP_NO_ERROR;
382 : }
383 :
384 18 : CHIP_ERROR TLVReader::Get(Optional<LocalizedStringIdentifier> & lsid)
385 : {
386 : #if CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ
387 : constexpr bool validateCharString = true;
388 : #else
389 18 : constexpr bool validateCharString = false;
390 : #endif // CHIP_CONFIG_TLV_VALIDATE_CHAR_STRING_ON_READ
391 18 : return GetLocalizedStringIdentifierImpl(lsid, validateCharString);
392 : }
393 :
394 24 : CHIP_ERROR TLVReader::GetLocalizedStringIdentifierImpl(Optional<LocalizedStringIdentifier> & lsid, bool validateCharString)
395 : {
396 24 : lsid.ClearValue();
397 24 : VerifyOrReturnError(TLVTypeIsUTF8String(ElementType()), CHIP_ERROR_WRONG_TLV_TYPE);
398 :
399 : const uint8_t * bytes;
400 23 : ReturnErrorOnFailure(GetDataPtr(bytes)); // Does length sanity checks
401 23 : if (bytes == nullptr)
402 : {
403 : // Treat null/empty LSID as a NullOptional (cleared above).
404 0 : return CHIP_NO_ERROR;
405 : }
406 :
407 23 : uint32_t len = GetLength();
408 :
409 23 : const uint8_t * infoSeparator1 = static_cast<const uint8_t *>(memchr(bytes, kUnicodeInformationSeparator1, len));
410 23 : if (infoSeparator1 == nullptr)
411 : {
412 : // No IS1: by contract this overload reports only the LSID suffix and does not
413 : // UTF-8-validate the whole string (callers wanting that use Get(CharSpan&)).
414 1 : return CHIP_NO_ERROR;
415 : }
416 :
417 : // When requested, validate the entire on-wire char string so this overload's verdict
418 : // matches Get(CharSpan&)'s on the same bytes.
419 22 : if (validateCharString)
420 : {
421 4 : CharSpan full(Uint8::to_const_char(bytes), len);
422 4 : ReturnErrorOnFailure(ValidateCharString(full));
423 : }
424 :
425 19 : const uint8_t * lsidPtr = infoSeparator1 + 1;
426 19 : len -= static_cast<uint32_t>(lsidPtr - bytes);
427 :
428 19 : const uint8_t * infoSeparator2 = static_cast<const uint8_t *>(memchr(lsidPtr, kUnicodeInformationSeparator1, len));
429 19 : if (infoSeparator2 != nullptr)
430 : {
431 3 : len = static_cast<uint32_t>(infoSeparator2 - lsidPtr);
432 : }
433 19 : if (len == 0)
434 : {
435 : // This treats null/empty LSID as a NullOptional (we clear the value at the start)
436 1 : return CHIP_NO_ERROR;
437 : }
438 18 : VerifyOrReturnError(len <= kMaxLocalizedStringIdentifierLen, CHIP_ERROR_INVALID_TLV_ELEMENT);
439 : // Leading zeroes are not allowed.
440 17 : VerifyOrReturnError(static_cast<char>(lsidPtr[0]) != '0', CHIP_ERROR_INVALID_TLV_ELEMENT);
441 :
442 15 : char idStr[kMaxLocalizedStringIdentifierLen] = { '0', '0', '0', '0' };
443 15 : memcpy(&idStr[kMaxLocalizedStringIdentifierLen - len], lsidPtr, len);
444 :
445 : LocalizedStringIdentifier id;
446 15 : VerifyOrReturnError(Encoding::UppercaseHexToUint16(idStr, sizeof(idStr), id) == sizeof(LocalizedStringIdentifier),
447 : CHIP_ERROR_INVALID_TLV_ELEMENT);
448 :
449 14 : lsid.SetValue(id);
450 14 : return CHIP_NO_ERROR;
451 : }
452 :
453 : #if CHIP_CONFIG_TEST
454 15 : CHIP_ERROR ValidateCharStringForTest(const CharSpan & str)
455 : {
456 15 : return ValidateCharString(str);
457 : }
458 :
459 6 : CHIP_ERROR GetLocalizedStringIdentifierForTest(TLVReader & reader, Optional<LocalizedStringIdentifier> & lsid,
460 : bool validateCharString)
461 : {
462 6 : return reader.GetLocalizedStringIdentifierImpl(lsid, validateCharString);
463 : }
464 : #endif // CHIP_CONFIG_TEST
465 :
466 26364 : CHIP_ERROR TLVReader::GetBytes(uint8_t * buf, size_t bufSize)
467 : {
468 26364 : if (!TLVTypeIsString(ElementType()))
469 1 : return CHIP_ERROR_WRONG_TLV_TYPE;
470 :
471 26363 : if (mElemLenOrVal > bufSize)
472 0 : return CHIP_ERROR_BUFFER_TOO_SMALL;
473 :
474 26363 : CHIP_ERROR err = ReadData(buf, static_cast<uint32_t>(mElemLenOrVal));
475 52726 : if (err != CHIP_NO_ERROR)
476 0 : return err;
477 :
478 26363 : mElemLenOrVal = 0;
479 :
480 26363 : return CHIP_NO_ERROR;
481 : }
482 :
483 12491 : CHIP_ERROR TLVReader::GetString(char * buf, size_t bufSize)
484 : {
485 12491 : if (!TLVTypeIsString(ElementType()))
486 1 : return CHIP_ERROR_WRONG_TLV_TYPE;
487 :
488 12490 : if (mElemLenOrVal >= bufSize)
489 3 : return CHIP_ERROR_BUFFER_TOO_SMALL;
490 :
491 12487 : buf[mElemLenOrVal] = 0;
492 :
493 12487 : return GetBytes(reinterpret_cast<uint8_t *>(buf), static_cast<uint32_t>(mElemLenOrVal));
494 : }
495 :
496 1 : CHIP_ERROR TLVReader::DupBytes(uint8_t *& buf, uint32_t & dataLen)
497 : {
498 1 : if (!TLVTypeIsString(ElementType()))
499 0 : return CHIP_ERROR_WRONG_TLV_TYPE;
500 :
501 1 : buf = static_cast<uint8_t *>(chip::Platform::MemoryAlloc(static_cast<uint32_t>(mElemLenOrVal)));
502 1 : if (buf == nullptr)
503 0 : return CHIP_ERROR_NO_MEMORY;
504 :
505 1 : CHIP_ERROR err = ReadData(buf, static_cast<uint32_t>(mElemLenOrVal));
506 2 : if (err != CHIP_NO_ERROR)
507 : {
508 0 : chip::Platform::MemoryFree(buf);
509 0 : buf = nullptr;
510 0 : return err;
511 : }
512 :
513 1 : dataLen = static_cast<uint32_t>(mElemLenOrVal);
514 1 : mElemLenOrVal = 0;
515 :
516 1 : return CHIP_NO_ERROR;
517 : }
518 :
519 2 : CHIP_ERROR TLVReader::DupString(char *& buf)
520 : {
521 2 : if (!TLVTypeIsString(ElementType()))
522 1 : return CHIP_ERROR_WRONG_TLV_TYPE;
523 :
524 1 : if (mElemLenOrVal > UINT32_MAX - 1)
525 0 : return CHIP_ERROR_NO_MEMORY;
526 :
527 1 : buf = static_cast<char *>(chip::Platform::MemoryAlloc(static_cast<uint32_t>(mElemLenOrVal + 1)));
528 1 : if (buf == nullptr)
529 0 : return CHIP_ERROR_NO_MEMORY;
530 :
531 1 : CHIP_ERROR err = ReadData(reinterpret_cast<uint8_t *>(buf), static_cast<uint32_t>(mElemLenOrVal));
532 2 : if (err != CHIP_NO_ERROR)
533 : {
534 0 : chip::Platform::MemoryFree(buf);
535 0 : buf = nullptr;
536 0 : return err;
537 : }
538 :
539 1 : buf[mElemLenOrVal] = 0;
540 1 : mElemLenOrVal = 0;
541 :
542 1 : return err;
543 : }
544 :
545 31542 : CHIP_ERROR TLVReader::GetDataPtr(const uint8_t *& data) const
546 : {
547 31542 : VerifyOrReturnError(TLVTypeIsString(ElementType()), CHIP_ERROR_WRONG_TLV_TYPE);
548 :
549 31539 : if (GetLength() == 0)
550 : {
551 4772 : data = nullptr;
552 4772 : return CHIP_NO_ERROR;
553 : }
554 :
555 26767 : uint32_t remainingLen = static_cast<decltype(mMaxLen)>(mBufEnd - mReadPoint);
556 :
557 : // Verify that the entirety of the data is available in the buffer.
558 : // Note that this may not be possible if the reader is reading from a chain of buffers.
559 26767 : VerifyOrReturnError(remainingLen >= static_cast<uint32_t>(mElemLenOrVal), CHIP_ERROR_TLV_UNDERRUN);
560 26763 : data = mReadPoint;
561 26763 : return CHIP_NO_ERROR;
562 : }
563 :
564 1864 : CHIP_ERROR TLVReader::OpenContainer(TLVReader & containerReader)
565 : {
566 1864 : TLVElementType elemType = ElementType();
567 1864 : if (!TLVTypeIsContainer(elemType))
568 1 : return CHIP_ERROR_INCORRECT_STATE;
569 :
570 1863 : containerReader.mBackingStore = mBackingStore;
571 1863 : containerReader.mReadPoint = mReadPoint;
572 1863 : containerReader.mBufEnd = mBufEnd;
573 1863 : containerReader.mLenRead = mLenRead;
574 1863 : containerReader.mMaxLen = mMaxLen;
575 1863 : containerReader.ClearElementState();
576 1863 : containerReader.mContainerType = static_cast<TLVType>(elemType);
577 1863 : containerReader.SetContainerOpen(false);
578 1863 : containerReader.ImplicitProfileId = ImplicitProfileId;
579 1863 : containerReader.AppData = AppData;
580 :
581 1863 : SetContainerOpen(true);
582 :
583 1863 : return CHIP_NO_ERROR;
584 : }
585 :
586 1566 : CHIP_ERROR TLVReader::CloseContainer(TLVReader & containerReader)
587 : {
588 : CHIP_ERROR err;
589 :
590 1566 : if (!IsContainerOpen())
591 1 : return CHIP_ERROR_INCORRECT_STATE;
592 :
593 1565 : if (static_cast<TLVElementType>(containerReader.mContainerType) != ElementType())
594 0 : return CHIP_ERROR_INCORRECT_STATE;
595 :
596 1565 : err = containerReader.SkipToEndOfContainer();
597 3130 : if (err != CHIP_NO_ERROR)
598 0 : return err;
599 :
600 1565 : mBackingStore = containerReader.mBackingStore;
601 1565 : mReadPoint = containerReader.mReadPoint;
602 1565 : mBufEnd = containerReader.mBufEnd;
603 1565 : mLenRead = containerReader.mLenRead;
604 1565 : mMaxLen = containerReader.mMaxLen;
605 1565 : ClearElementState();
606 :
607 1565 : return CHIP_NO_ERROR;
608 : }
609 :
610 3819811 : CHIP_ERROR TLVReader::EnterContainer(TLVType & outerContainerType)
611 : {
612 3819811 : TLVElementType elemType = ElementType();
613 3819811 : if (!TLVTypeIsContainer(elemType))
614 1 : return CHIP_ERROR_INCORRECT_STATE;
615 :
616 3819810 : outerContainerType = mContainerType;
617 3819810 : mContainerType = static_cast<TLVType>(elemType);
618 :
619 3819810 : ClearElementState();
620 3819810 : SetContainerOpen(false);
621 :
622 3819810 : return CHIP_NO_ERROR;
623 : }
624 :
625 639971 : CHIP_ERROR TLVReader::ExitContainer(TLVType outerContainerType)
626 : {
627 : CHIP_ERROR err;
628 :
629 639971 : err = SkipToEndOfContainer();
630 1279942 : if (err != CHIP_NO_ERROR)
631 40 : return err;
632 :
633 639931 : mContainerType = outerContainerType;
634 639931 : ClearElementState();
635 :
636 639931 : return CHIP_NO_ERROR;
637 : }
638 :
639 8497 : CHIP_ERROR TLVReader::VerifyEndOfContainer()
640 : {
641 8497 : CHIP_ERROR err = Next();
642 16994 : if (err == CHIP_END_OF_TLV)
643 8494 : return CHIP_NO_ERROR;
644 6 : if (err == CHIP_NO_ERROR)
645 2 : return CHIP_ERROR_UNEXPECTED_TLV_ELEMENT;
646 1 : return err;
647 : }
648 :
649 9918641 : CHIP_ERROR TLVReader::Next()
650 : {
651 9918641 : ReturnErrorOnFailure(Skip());
652 9914916 : ReturnErrorOnFailure(ReadElement());
653 :
654 9886669 : TLVElementType elemType = ElementType();
655 :
656 9886669 : VerifyOrReturnError(elemType != TLVElementType::EndOfContainer, CHIP_END_OF_TLV);
657 :
658 : // Ensure that GetDataPtr calls can be called immediately after Next, so
659 : // that `Get(ByteSpan&)` does not need to advance buffers and just works
660 9617504 : if (TLVTypeIsString(elemType) && (GetLength() != 0))
661 : {
662 49103 : ReturnErrorOnFailure(EnsureData(CHIP_ERROR_TLV_UNDERRUN));
663 : }
664 :
665 9617504 : return CHIP_NO_ERROR;
666 : }
667 :
668 528642 : CHIP_ERROR TLVReader::Expect(Tag expectedTag)
669 : {
670 528642 : VerifyOrReturnError(GetType() != kTLVType_NotSpecified, CHIP_ERROR_WRONG_TLV_TYPE);
671 528638 : VerifyOrReturnError(GetTag() == expectedTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
672 528589 : return CHIP_NO_ERROR;
673 : }
674 :
675 527845 : CHIP_ERROR TLVReader::Next(Tag expectedTag)
676 : {
677 527845 : ReturnErrorOnFailure(Next());
678 524907 : ReturnErrorOnFailure(Expect(expectedTag));
679 524861 : return CHIP_NO_ERROR;
680 : }
681 :
682 8048060 : CHIP_ERROR TLVReader::Expect(TLVType expectedType, Tag expectedTag)
683 : {
684 8048060 : VerifyOrReturnError(GetType() == expectedType, CHIP_ERROR_WRONG_TLV_TYPE);
685 8038714 : VerifyOrReturnError(GetTag() == expectedTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
686 7973209 : return CHIP_NO_ERROR;
687 : }
688 :
689 8039359 : CHIP_ERROR TLVReader::Next(TLVType expectedType, Tag expectedTag)
690 : {
691 8039359 : ReturnErrorOnFailure(Next());
692 8026293 : ReturnErrorOnFailure(Expect(expectedType, expectedTag));
693 7952431 : return CHIP_NO_ERROR;
694 : }
695 :
696 9947921 : CHIP_ERROR TLVReader::Skip()
697 : {
698 9947921 : const TLVElementType elemType = ElementType();
699 9947921 : VerifyOrReturnError(elemType != TLVElementType::EndOfContainer, CHIP_END_OF_TLV);
700 :
701 9944198 : if (TLVTypeIsContainer(elemType))
702 : {
703 : TLVType outerContainerType;
704 277760 : ReturnErrorOnFailure(EnterContainer(outerContainerType));
705 277760 : return ExitContainer(outerContainerType);
706 : }
707 :
708 9666438 : ReturnErrorOnFailure(SkipData());
709 9666438 : ClearElementState();
710 :
711 9666438 : return CHIP_NO_ERROR;
712 : }
713 :
714 : /**
715 : * Clear the state of the TLVReader.
716 : * This method is used to position the reader before the first TLV,
717 : * between TLVs or after the last TLV.
718 : */
719 15941583 : void TLVReader::ClearElementState()
720 : {
721 15941583 : mElemTag = AnonymousTag();
722 15941583 : mControlByte = kTLVControlByte_NotSpecified;
723 15941583 : mElemLenOrVal = 0;
724 15941583 : }
725 :
726 : /**
727 : * Skip any data contained in the current TLV by reading over it without
728 : * a destination buffer.
729 : *
730 : * @retval #CHIP_NO_ERROR If the reader was successfully positioned at the end of the
731 : * data.
732 : * @retval other Other CHIP or platform error codes returned by the configured
733 : * TLVBackingStore.
734 : */
735 13526597 : CHIP_ERROR TLVReader::SkipData()
736 : {
737 13526597 : CHIP_ERROR err = CHIP_NO_ERROR;
738 13526597 : TLVElementType elemType = ElementType();
739 :
740 13526597 : if (TLVTypeHasLength(elemType))
741 : {
742 326854 : err = ReadData(nullptr, static_cast<uint32_t>(mElemLenOrVal));
743 : }
744 :
745 13526597 : return err;
746 : }
747 :
748 641536 : CHIP_ERROR TLVReader::SkipToEndOfContainer()
749 : {
750 : CHIP_ERROR err;
751 641536 : TLVType outerContainerType = mContainerType;
752 641536 : uint32_t nestLevel = 0;
753 :
754 : // If the user calls Next() after having called OpenContainer() but before calling
755 : // CloseContainer() they're effectively doing a close container by skipping over
756 : // the container element. So reset the 'container open' flag here to prevent them
757 : // from calling CloseContainer() with the now orphaned container reader.
758 641536 : SetContainerOpen(false);
759 :
760 : while (true)
761 : {
762 4501655 : TLVElementType elemType = ElementType();
763 :
764 4501655 : if (elemType == TLVElementType::EndOfContainer)
765 : {
766 1336978 : if (nestLevel == 0)
767 641496 : return CHIP_NO_ERROR;
768 :
769 695482 : nestLevel--;
770 695482 : mContainerType = (nestLevel == 0) ? outerContainerType : kTLVType_UnknownContainer;
771 : }
772 :
773 3164677 : else if (TLVTypeIsContainer(elemType))
774 : {
775 695483 : nestLevel++;
776 695483 : mContainerType = static_cast<TLVType>(elemType);
777 : }
778 :
779 3860159 : err = SkipData();
780 7720318 : if (err != CHIP_NO_ERROR)
781 0 : return err;
782 :
783 3860159 : err = ReadElement();
784 7720318 : if (err != CHIP_NO_ERROR)
785 40 : return err;
786 3860119 : }
787 : }
788 :
789 13775075 : CHIP_ERROR TLVReader::ReadElement()
790 : {
791 : // Make sure we have input data. Return CHIP_END_OF_TLV if no more data is available.
792 13775075 : ReturnErrorOnFailure(EnsureData(CHIP_END_OF_TLV));
793 13759304 : VerifyOrReturnError(mReadPoint != nullptr, CHIP_ERROR_INVALID_TLV_ELEMENT);
794 :
795 : // Get the element's control byte.
796 13759304 : mControlByte = *mReadPoint;
797 :
798 : // Extract the element type from the control byte. Fail if it's invalid.
799 13759304 : TLVElementType elemType = ElementType();
800 13759304 : VerifyOrReturnError(IsValidTLVType(elemType), CHIP_ERROR_INVALID_TLV_ELEMENT);
801 :
802 : // Extract the tag control from the control byte.
803 13754494 : TLVTagControl tagControl = static_cast<TLVTagControl>(mControlByte & kTLVTagControlMask);
804 :
805 : // Determine the number of bytes in the element's tag, if any.
806 13754494 : uint8_t tagBytes = sTagSizes[tagControl >> kTLVTagControlShift];
807 :
808 : // Extract the size of length/value field from the control byte.
809 13754494 : TLVFieldSize lenOrValFieldSize = GetTLVFieldSize(elemType);
810 :
811 : // Determine the number of bytes in the length/value field.
812 13754494 : const uint8_t valOrLenBytes = TLVFieldSizeToBytes(lenOrValFieldSize);
813 :
814 : // Determine the number of bytes in the element's 'head'. This includes: the control byte, the tag bytes (if present), the
815 : // length bytes (if present), and for elements that don't have a length (e.g. integers), the value bytes.
816 13754494 : const uint8_t elemHeadBytes = static_cast<uint8_t>(1 + tagBytes + valOrLenBytes);
817 :
818 : // 17 = 1 control byte + 8 tag bytes + 8 length/value bytes
819 : uint8_t stagingBuf[17];
820 :
821 : // Odd workaround: clang-tidy claims garbage value otherwise as it does not
822 : // understand that ReadData initializes stagingBuf
823 13754494 : stagingBuf[1] = 0;
824 :
825 : // If the head of the element goes past the end of the current input buffer,
826 : // we need to read it into the staging buffer to parse it. Just do that unconditionally,
827 : // even if the head does not go past end of current buffer, to save codesize.
828 13754494 : ReturnErrorOnFailure(ReadData(stagingBuf, elemHeadBytes));
829 :
830 : // +1 to skip over the control byte
831 13754490 : const uint8_t * p = stagingBuf + 1;
832 :
833 : // Read the tag field, if present.
834 13754490 : mElemTag = ReadTag(tagControl, p);
835 13754490 : mElemLenOrVal = 0;
836 :
837 : // Read the length/value field, if present.
838 : // NOTE: this is works because even though we only memcpy a subset of values and leave
839 : // the rest 0. Value looks like "<le-byte> <le-byte> ... <le-byte> 0 0 ... 0"
840 : // which is the TLV format. HostSwap ensures this becomes a real host value
841 : // (should be a NOOP on LE machines, will full-swap on big-endian machines)
842 13754490 : memcpy(&mElemLenOrVal, p, valOrLenBytes);
843 13754490 : LittleEndian::HostSwap(mElemLenOrVal);
844 :
845 13754490 : VerifyOrReturnError(!TLVTypeHasLength(elemType) || (mElemLenOrVal <= UINT32_MAX), CHIP_ERROR_NOT_IMPLEMENTED);
846 :
847 13753138 : return VerifyElement();
848 : }
849 :
850 13753138 : CHIP_ERROR TLVReader::VerifyElement()
851 : {
852 13753138 : if (ElementType() == TLVElementType::EndOfContainer)
853 : {
854 1401063 : if (mContainerType == kTLVType_NotSpecified)
855 131 : return CHIP_ERROR_INVALID_TLV_ELEMENT;
856 1400932 : if (mElemTag != AnonymousTag())
857 450 : return CHIP_ERROR_INVALID_TLV_TAG;
858 : }
859 : else
860 : {
861 12352075 : if (mElemTag == UnknownImplicitTag())
862 0 : return CHIP_ERROR_UNKNOWN_IMPLICIT_TLV_TAG;
863 12352075 : switch (mContainerType)
864 : {
865 1820274 : case kTLVType_NotSpecified:
866 1820274 : if (IsContextTag(mElemTag))
867 377 : return CHIP_ERROR_INVALID_TLV_TAG;
868 1819897 : break;
869 6994330 : case kTLVType_Structure:
870 6994330 : if (mElemTag == AnonymousTag())
871 1129 : return CHIP_ERROR_INVALID_TLV_TAG;
872 6993201 : break;
873 1994830 : case kTLVType_Array:
874 1994830 : if (mElemTag != AnonymousTag())
875 2591 : return CHIP_ERROR_INVALID_TLV_TAG;
876 1992239 : break;
877 1542641 : case kTLVType_UnknownContainer:
878 : case kTLVType_List:
879 1542641 : break;
880 0 : default:
881 0 : return CHIP_ERROR_INCORRECT_STATE;
882 : }
883 : }
884 :
885 : // If the current element encodes a specific length (e.g. a UTF8 string or a byte string), verify
886 : // that the purported length fits within the remaining bytes of the encoding (as delineated by mMaxLen).
887 : //
888 : // Note that this check is not strictly necessary to prevent runtime errors, as any attempt to access
889 : // the data of an element with an invalid length will result in an error. However checking the length
890 : // here catches the error earlier, and ensures that the application will never see the erroneous length
891 : // value.
892 : //
893 13748460 : if (TLVTypeHasLength(ElementType()))
894 : {
895 333473 : uint32_t overallLenRemaining = mMaxLen - mLenRead;
896 333473 : if (overallLenRemaining < static_cast<uint32_t>(mElemLenOrVal))
897 1672 : return CHIP_ERROR_TLV_UNDERRUN;
898 : }
899 :
900 13746788 : return CHIP_NO_ERROR;
901 : }
902 :
903 13754490 : Tag TLVReader::ReadTag(TLVTagControl tagControl, const uint8_t *& p) const
904 : {
905 : uint16_t vendorId;
906 : uint16_t profileNum;
907 :
908 13754490 : switch (tagControl)
909 : {
910 5289614 : case TLVTagControl::ContextSpecific:
911 5289614 : return ContextTag(Read8(p));
912 2127 : case TLVTagControl::CommonProfile_2Bytes:
913 2127 : return CommonTag(LittleEndian::Read16(p));
914 2419 : case TLVTagControl::CommonProfile_4Bytes:
915 2419 : return CommonTag(LittleEndian::Read32(p));
916 1585304 : case TLVTagControl::ImplicitProfile_2Bytes:
917 1585304 : if (ImplicitProfileId == kProfileIdNotSpecified)
918 0 : return UnknownImplicitTag();
919 1585304 : return ProfileTag(ImplicitProfileId, LittleEndian::Read16(p));
920 3358 : case TLVTagControl::ImplicitProfile_4Bytes:
921 3358 : if (ImplicitProfileId == kProfileIdNotSpecified)
922 0 : return UnknownImplicitTag();
923 3358 : return ProfileTag(ImplicitProfileId, LittleEndian::Read32(p));
924 3259521 : case TLVTagControl::FullyQualified_6Bytes:
925 3259521 : vendorId = LittleEndian::Read16(p);
926 3259521 : profileNum = LittleEndian::Read16(p);
927 3259521 : return ProfileTag(vendorId, profileNum, LittleEndian::Read16(p));
928 2177 : case TLVTagControl::FullyQualified_8Bytes:
929 2177 : vendorId = LittleEndian::Read16(p);
930 2177 : profileNum = LittleEndian::Read16(p);
931 2177 : return ProfileTag(vendorId, profileNum, LittleEndian::Read32(p));
932 3609970 : case TLVTagControl::Anonymous:
933 : default:
934 3609970 : return AnonymousTag();
935 : }
936 : }
937 :
938 14130340 : CHIP_ERROR TLVReader::ReadData(uint8_t * buf, uint32_t len)
939 : {
940 27981438 : while (len > 0)
941 : {
942 13851102 : ReturnErrorOnFailure(EnsureData(CHIP_ERROR_TLV_UNDERRUN));
943 :
944 13851098 : uint32_t remainingLen = static_cast<decltype(mMaxLen)>(mBufEnd - mReadPoint);
945 :
946 13851098 : uint32_t readLen = len;
947 13851098 : if (readLen > remainingLen)
948 161 : readLen = remainingLen;
949 :
950 13851098 : if (buf != nullptr)
951 : {
952 13785715 : memcpy(buf, mReadPoint, readLen);
953 13785715 : buf += readLen;
954 : }
955 13851098 : mReadPoint += readLen;
956 13851098 : mLenRead += readLen;
957 13851098 : len -= readLen;
958 : }
959 :
960 14130336 : return CHIP_NO_ERROR;
961 : }
962 :
963 27675280 : CHIP_ERROR TLVReader::EnsureData(CHIP_ERROR noDataErr)
964 : {
965 27675280 : if (mReadPoint == mBufEnd)
966 : {
967 16062 : VerifyOrReturnError((mLenRead != mMaxLen) && (mBackingStore != nullptr), noDataErr);
968 :
969 : uint32_t bufLen;
970 287 : ReturnErrorOnFailure(mBackingStore->GetNextBuffer(*this, mReadPoint, bufLen));
971 287 : VerifyOrReturnError(bufLen > 0, noDataErr);
972 :
973 : // Cap mBufEnd so that we don't read beyond the user's specified maximum length, even
974 : // if the underlying buffer is larger.
975 287 : bufLen = std::min(bufLen, mMaxLen - mLenRead);
976 287 : mBufEnd = mReadPoint + bufLen;
977 : }
978 :
979 27659505 : return CHIP_NO_ERROR;
980 : }
981 :
982 : /**
983 : * This is a private method used to compute the length of a TLV element head.
984 : */
985 2 : CHIP_ERROR TLVReader::GetElementHeadLength(uint8_t & elemHeadBytes) const
986 : {
987 : uint8_t tagBytes;
988 : uint8_t valOrLenBytes;
989 : TLVTagControl tagControl;
990 : TLVFieldSize lenOrValFieldSize;
991 2 : TLVElementType elemType = ElementType();
992 :
993 : // Verify element is of valid TLVType.
994 2 : VerifyOrReturnError(IsValidTLVType(elemType), CHIP_ERROR_INVALID_TLV_ELEMENT);
995 :
996 : // Extract the tag control from the control byte.
997 2 : tagControl = static_cast<TLVTagControl>(mControlByte & kTLVTagControlMask);
998 :
999 : // Determine the number of bytes in the element's tag, if any.
1000 2 : tagBytes = sTagSizes[tagControl >> kTLVTagControlShift];
1001 :
1002 : // Extract the size of length/value field from the control byte.
1003 2 : lenOrValFieldSize = GetTLVFieldSize(elemType);
1004 :
1005 : // Determine the number of bytes in the length/value field.
1006 2 : valOrLenBytes = TLVFieldSizeToBytes(lenOrValFieldSize);
1007 :
1008 : // Determine the number of bytes in the element's 'head'. This includes: the
1009 : // control byte, the tag bytes (if present), the length bytes (if present),
1010 : // and for elements that don't have a length (e.g. integers), the value
1011 : // bytes.
1012 2 : VerifyOrReturnError(CanCastTo<uint8_t>(1 + tagBytes + valOrLenBytes), CHIP_ERROR_INTERNAL);
1013 2 : elemHeadBytes = static_cast<uint8_t>(1 + tagBytes + valOrLenBytes);
1014 :
1015 2 : return CHIP_NO_ERROR;
1016 : }
1017 :
1018 : /**
1019 : * This is a private method that returns the TLVElementType from mControlByte
1020 : */
1021 104702729 : TLVElementType TLVReader::ElementType() const
1022 : {
1023 104702729 : if (mControlByte == static_cast<uint16_t>(kTLVControlByte_NotSpecified))
1024 11941300 : return TLVElementType::NotSpecified;
1025 92761429 : return static_cast<TLVElementType>(mControlByte & kTLVTypeMask);
1026 : }
1027 :
1028 216079 : CHIP_ERROR TLVReader::FindElementWithTag(Tag tag, TLVReader & destReader) const
1029 : {
1030 216079 : CHIP_ERROR err = CHIP_NO_ERROR;
1031 :
1032 216079 : chip::TLV::TLVReader reader;
1033 216079 : reader.Init(*this);
1034 :
1035 1001174 : while (CHIP_NO_ERROR == (err = reader.Next()))
1036 : {
1037 465511 : VerifyOrExit(chip::TLV::kTLVType_NotSpecified != reader.GetType(), err = CHIP_ERROR_INVALID_TLV_ELEMENT);
1038 :
1039 465511 : if (tag == reader.GetTag())
1040 : {
1041 181003 : destReader.Init(reader);
1042 181003 : break;
1043 : }
1044 : }
1045 :
1046 35076 : exit:
1047 467234 : ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
1048 :
1049 216079 : return err;
1050 : }
1051 :
1052 1612 : CHIP_ERROR TLVReader::CountRemainingInContainer(size_t * size) const
1053 : {
1054 1612 : if (mContainerType == kTLVType_NotSpecified)
1055 : {
1056 0 : return CHIP_ERROR_INCORRECT_STATE;
1057 : }
1058 :
1059 1612 : TLVReader tempReader(*this);
1060 1612 : size_t count = 0;
1061 : CHIP_ERROR err;
1062 14088 : while ((err = tempReader.Next()) == CHIP_NO_ERROR)
1063 : {
1064 5432 : ++count;
1065 : };
1066 3224 : if (err == CHIP_END_OF_TLV)
1067 : {
1068 1612 : *size = count;
1069 1612 : return CHIP_NO_ERROR;
1070 : }
1071 0 : return err;
1072 : }
1073 :
1074 10 : CHIP_ERROR ContiguousBufferTLVReader::OpenContainer(ContiguousBufferTLVReader & containerReader)
1075 : {
1076 : // We are going to initialize containerReader by calling our superclass
1077 : // OpenContainer method. The superclass only knows how to initialize
1078 : // members the superclass knows about, so we assert that we don't have any
1079 : // extra members that need initializing. If such members ever get added,
1080 : // they would need to be initialized in this method.
1081 : static_assert(sizeof(ContiguousBufferTLVReader) == sizeof(TLVReader), "We have state the superclass is not initializing?");
1082 10 : return TLVReader::OpenContainer(containerReader);
1083 : }
1084 :
1085 11 : CHIP_ERROR ContiguousBufferTLVReader::GetStringView(Span<const char> & data)
1086 : {
1087 11 : return Get(data);
1088 : }
1089 :
1090 670 : CHIP_ERROR ContiguousBufferTLVReader::GetByteView(ByteSpan & data)
1091 : {
1092 670 : if (!TLVTypeIsByteString(ElementType()))
1093 : {
1094 2 : return CHIP_ERROR_WRONG_TLV_TYPE;
1095 : }
1096 :
1097 668 : return Get(data);
1098 : }
1099 :
1100 : } // namespace TLV
1101 : } // namespace chip
|