Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / lib / core / CHIPTLVReader.cpp
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
19 /**
20  *    @file
21  *      This file implements a parser for the CHIP TLV (Tag-Length-Value) encoding format.
22  *
23  */
24
25 #include <stdlib.h>
26
27 #include <core/CHIPCore.h>
28 #include <core/CHIPEncoding.h>
29 #include <core/CHIPTLV.h>
30 #include <support/CHIPMem.h>
31 #include <support/CodeUtils.h>
32 #include <support/SafeInt.h>
33
34 namespace chip {
35 namespace TLV {
36
37 using namespace chip::Encoding;
38
39 static const uint8_t sTagSizes[] = { 0, 1, 2, 4, 2, 4, 6, 8 };
40
41 void TLVReader::Init(const uint8_t * data, uint32_t dataLen)
42 {
43     mBackingStore = nullptr;
44     mReadPoint    = data;
45     mBufEnd       = data + dataLen;
46     mLenRead      = 0;
47     mMaxLen       = dataLen;
48     ClearElementState();
49     mContainerType = kTLVType_NotSpecified;
50     SetContainerOpen(false);
51
52     ImplicitProfileId = kProfileIdNotSpecified;
53 }
54
55 CHIP_ERROR TLVReader::Init(TLVBackingStore & backingStore, uint32_t maxLen)
56 {
57     mBackingStore   = &backingStore;
58     mReadPoint      = nullptr;
59     uint32_t bufLen = 0;
60     CHIP_ERROR err  = mBackingStore->OnInit(*this, mReadPoint, bufLen);
61     if (err != CHIP_NO_ERROR)
62         return err;
63
64     mBufEnd  = mReadPoint + bufLen;
65     mLenRead = 0;
66     mMaxLen  = maxLen;
67     ClearElementState();
68     mContainerType = kTLVType_NotSpecified;
69     SetContainerOpen(false);
70
71     ImplicitProfileId = kProfileIdNotSpecified;
72     AppData           = nullptr;
73     return CHIP_NO_ERROR;
74 }
75
76 void TLVReader::Init(const TLVReader & aReader)
77 {
78     // Initialize private data members
79
80     mElemTag       = aReader.mElemTag;
81     mElemLenOrVal  = aReader.mElemLenOrVal;
82     mBackingStore  = aReader.mBackingStore;
83     mReadPoint     = aReader.mReadPoint;
84     mBufEnd        = aReader.mBufEnd;
85     mLenRead       = aReader.mLenRead;
86     mMaxLen        = aReader.mMaxLen;
87     mControlByte   = aReader.mControlByte;
88     mContainerType = aReader.mContainerType;
89     SetContainerOpen(aReader.IsContainerOpen());
90
91     // Initialize public data members
92
93     ImplicitProfileId = aReader.ImplicitProfileId;
94     AppData           = aReader.AppData;
95 }
96
97 TLVType TLVReader::GetType() const
98 {
99     TLVElementType elemType = ElementType();
100     if (elemType == TLVElementType::EndOfContainer)
101         return kTLVType_NotSpecified;
102     if (elemType == TLVElementType::FloatingPointNumber32 || elemType == TLVElementType::FloatingPointNumber64)
103         return kTLVType_FloatingPointNumber;
104     if (elemType == TLVElementType::NotSpecified || elemType >= TLVElementType::Null)
105         return static_cast<TLVType>(elemType);
106     return static_cast<TLVType>(static_cast<uint8_t>(elemType) & ~kTLVTypeSizeMask);
107 }
108
109 uint32_t TLVReader::GetLength() const
110 {
111     if (TLVTypeHasLength(ElementType()))
112         return static_cast<uint32_t>(mElemLenOrVal);
113     return 0;
114 }
115
116 CHIP_ERROR TLVReader::Get(bool & v)
117 {
118     TLVElementType elemType = ElementType();
119     if (elemType == TLVElementType::BooleanFalse)
120         v = false;
121     else if (elemType == TLVElementType::BooleanTrue)
122         v = true;
123     else
124         return CHIP_ERROR_WRONG_TLV_TYPE;
125     return CHIP_NO_ERROR;
126 }
127
128 CHIP_ERROR TLVReader::Get(int8_t & v)
129 {
130     uint64_t v64   = 0;
131     CHIP_ERROR err = Get(v64);
132     v              = CastToSigned(static_cast<uint8_t>(v64));
133     return err;
134 }
135
136 CHIP_ERROR TLVReader::Get(int16_t & v)
137 {
138     uint64_t v64   = 0;
139     CHIP_ERROR err = Get(v64);
140     v              = CastToSigned(static_cast<uint16_t>(v64));
141     return err;
142 }
143
144 CHIP_ERROR TLVReader::Get(int32_t & v)
145 {
146     uint64_t v64   = 0;
147     CHIP_ERROR err = Get(v64);
148     v              = CastToSigned(static_cast<uint32_t>(v64));
149     return err;
150 }
151
152 CHIP_ERROR TLVReader::Get(int64_t & v)
153 {
154     uint64_t v64   = 0;
155     CHIP_ERROR err = Get(v64);
156     v              = CastToSigned(v64);
157     return err;
158 }
159
160 CHIP_ERROR TLVReader::Get(uint8_t & v)
161 {
162     uint64_t v64   = 0;
163     CHIP_ERROR err = Get(v64);
164     v              = static_cast<uint8_t>(v64);
165     return err;
166 }
167
168 CHIP_ERROR TLVReader::Get(uint16_t & v)
169 {
170     uint64_t v64   = 0;
171     CHIP_ERROR err = Get(v64);
172     v              = static_cast<uint16_t>(v64);
173     return err;
174 }
175
176 CHIP_ERROR TLVReader::Get(uint32_t & v)
177 {
178     uint64_t v64   = 0;
179     CHIP_ERROR err = Get(v64);
180     v              = static_cast<uint32_t>(v64);
181     return err;
182 }
183
184 CHIP_ERROR TLVReader::Get(uint64_t & v)
185 {
186     switch (ElementType())
187     {
188     case TLVElementType::Int8:
189         v = static_cast<uint64_t>(static_cast<int64_t>(CastToSigned(static_cast<uint8_t>(mElemLenOrVal))));
190         break;
191     case TLVElementType::Int16:
192         v = static_cast<uint64_t>(static_cast<int64_t>(CastToSigned(static_cast<uint16_t>(mElemLenOrVal))));
193         break;
194     case TLVElementType::Int32:
195         v = static_cast<uint64_t>(static_cast<int64_t>(CastToSigned(static_cast<uint32_t>(mElemLenOrVal))));
196         break;
197     case TLVElementType::Int64:
198     case TLVElementType::UInt8:
199     case TLVElementType::UInt16:
200     case TLVElementType::UInt32:
201     case TLVElementType::UInt64:
202         v = mElemLenOrVal;
203         break;
204     default:
205         return CHIP_ERROR_WRONG_TLV_TYPE;
206     }
207     return CHIP_NO_ERROR;
208 }
209
210 CHIP_ERROR TLVReader::Get(double & v)
211 {
212     switch (ElementType())
213     {
214     case TLVElementType::FloatingPointNumber32: {
215         union
216         {
217             uint32_t u32;
218             float f;
219         } cvt;
220         cvt.u32 = static_cast<uint32_t>(mElemLenOrVal);
221         v       = cvt.f;
222         break;
223     }
224     case TLVElementType::FloatingPointNumber64: {
225         union
226         {
227             uint64_t u64;
228             double d;
229         } cvt;
230         cvt.u64 = mElemLenOrVal;
231         v       = cvt.d;
232         break;
233     }
234     default:
235         return CHIP_ERROR_WRONG_TLV_TYPE;
236     }
237     return CHIP_NO_ERROR;
238 }
239
240 CHIP_ERROR TLVReader::GetBytes(uint8_t * buf, uint32_t bufSize)
241 {
242     if (!TLVTypeIsString(ElementType()))
243         return CHIP_ERROR_WRONG_TLV_TYPE;
244
245     if (mElemLenOrVal > bufSize)
246         return CHIP_ERROR_BUFFER_TOO_SMALL;
247
248     CHIP_ERROR err = ReadData(buf, static_cast<uint32_t>(mElemLenOrVal));
249     if (err != CHIP_NO_ERROR)
250         return err;
251
252     mElemLenOrVal = 0;
253
254     return CHIP_NO_ERROR;
255 }
256
257 CHIP_ERROR TLVReader::GetString(char * buf, uint32_t bufSize)
258 {
259     if (!TLVTypeIsString(ElementType()))
260         return CHIP_ERROR_WRONG_TLV_TYPE;
261
262     if ((mElemLenOrVal + 1) > bufSize)
263         return CHIP_ERROR_BUFFER_TOO_SMALL;
264
265     buf[mElemLenOrVal] = 0;
266
267     return GetBytes(reinterpret_cast<uint8_t *>(buf), bufSize - 1);
268 }
269
270 CHIP_ERROR TLVReader::DupBytes(uint8_t *& buf, uint32_t & dataLen)
271 {
272     if (!TLVTypeIsString(ElementType()))
273         return CHIP_ERROR_WRONG_TLV_TYPE;
274
275     buf = static_cast<uint8_t *>(chip::Platform::MemoryAlloc(static_cast<uint32_t>(mElemLenOrVal)));
276     if (buf == nullptr)
277         return CHIP_ERROR_NO_MEMORY;
278
279     CHIP_ERROR err = ReadData(buf, static_cast<uint32_t>(mElemLenOrVal));
280     if (err != CHIP_NO_ERROR)
281     {
282         chip::Platform::MemoryFree(buf);
283         buf = nullptr;
284         return err;
285     }
286
287     dataLen       = static_cast<uint32_t>(mElemLenOrVal);
288     mElemLenOrVal = 0;
289
290     return CHIP_NO_ERROR;
291 }
292
293 CHIP_ERROR TLVReader::DupString(char *& buf)
294 {
295     if (!TLVTypeIsString(ElementType()))
296         return CHIP_ERROR_WRONG_TLV_TYPE;
297
298     if (mElemLenOrVal > UINT32_MAX - 1)
299         return CHIP_ERROR_NO_MEMORY;
300
301     buf = static_cast<char *>(chip::Platform::MemoryAlloc(static_cast<uint32_t>(mElemLenOrVal + 1)));
302     if (buf == nullptr)
303         return CHIP_ERROR_NO_MEMORY;
304
305     CHIP_ERROR err = ReadData(reinterpret_cast<uint8_t *>(buf), static_cast<uint32_t>(mElemLenOrVal));
306     if (err != CHIP_NO_ERROR)
307     {
308         chip::Platform::MemoryFree(buf);
309         buf = nullptr;
310         return err;
311     }
312
313     buf[mElemLenOrVal] = 0;
314     mElemLenOrVal      = 0;
315
316     return err;
317 }
318
319 CHIP_ERROR TLVReader::GetDataPtr(const uint8_t *& data)
320 {
321     CHIP_ERROR err;
322
323     if (!TLVTypeIsString(ElementType()))
324         return CHIP_ERROR_WRONG_TLV_TYPE;
325
326     err = EnsureData(CHIP_ERROR_TLV_UNDERRUN);
327     if (err != CHIP_NO_ERROR)
328         return err;
329
330     uint32_t remainingLen = static_cast<decltype(mMaxLen)>(mBufEnd - mReadPoint);
331
332     // Verify that the entirety of the data is available in the buffer.
333     // Note that this may not be possible if the reader is reading from a chain of buffers.
334     if (remainingLen < static_cast<uint32_t>(mElemLenOrVal))
335         return CHIP_ERROR_TLV_UNDERRUN;
336
337     data = mReadPoint;
338
339     return CHIP_NO_ERROR;
340 }
341
342 CHIP_ERROR TLVReader::OpenContainer(TLVReader & containerReader)
343 {
344     TLVElementType elemType = ElementType();
345     if (!TLVTypeIsContainer(elemType))
346         return CHIP_ERROR_INCORRECT_STATE;
347
348     containerReader.mBackingStore = mBackingStore;
349     containerReader.mReadPoint    = mReadPoint;
350     containerReader.mBufEnd       = mBufEnd;
351     containerReader.mLenRead      = mLenRead;
352     containerReader.mMaxLen       = mMaxLen;
353     containerReader.ClearElementState();
354     containerReader.mContainerType = static_cast<TLVType>(elemType);
355     containerReader.SetContainerOpen(false);
356     containerReader.ImplicitProfileId = ImplicitProfileId;
357     containerReader.AppData           = AppData;
358
359     SetContainerOpen(true);
360
361     return CHIP_NO_ERROR;
362 }
363
364 CHIP_ERROR TLVReader::CloseContainer(TLVReader & containerReader)
365 {
366     CHIP_ERROR err;
367
368     if (!IsContainerOpen())
369         return CHIP_ERROR_INCORRECT_STATE;
370
371     if (static_cast<TLVElementType>(containerReader.mContainerType) != ElementType())
372         return CHIP_ERROR_INCORRECT_STATE;
373
374     err = containerReader.SkipToEndOfContainer();
375     if (err != CHIP_NO_ERROR)
376         return err;
377
378     mBackingStore = containerReader.mBackingStore;
379     mReadPoint    = containerReader.mReadPoint;
380     mBufEnd       = containerReader.mBufEnd;
381     mLenRead      = containerReader.mLenRead;
382     mMaxLen       = containerReader.mMaxLen;
383     ClearElementState();
384
385     return CHIP_NO_ERROR;
386 }
387
388 CHIP_ERROR TLVReader::EnterContainer(TLVType & outerContainerType)
389 {
390     TLVElementType elemType = ElementType();
391     if (!TLVTypeIsContainer(elemType))
392         return CHIP_ERROR_INCORRECT_STATE;
393
394     outerContainerType = mContainerType;
395     mContainerType     = static_cast<TLVType>(elemType);
396
397     ClearElementState();
398     SetContainerOpen(false);
399
400     return CHIP_NO_ERROR;
401 }
402
403 CHIP_ERROR TLVReader::ExitContainer(TLVType outerContainerType)
404 {
405     CHIP_ERROR err;
406
407     err = SkipToEndOfContainer();
408     if (err != CHIP_NO_ERROR)
409         return err;
410
411     mContainerType = outerContainerType;
412     ClearElementState();
413
414     return CHIP_NO_ERROR;
415 }
416
417 CHIP_ERROR TLVReader::VerifyEndOfContainer()
418 {
419     CHIP_ERROR err = Next();
420     if (err == CHIP_END_OF_TLV)
421         return CHIP_NO_ERROR;
422     if (err == CHIP_NO_ERROR)
423         return CHIP_ERROR_UNEXPECTED_TLV_ELEMENT;
424     return err;
425 }
426
427 CHIP_ERROR TLVReader::Next()
428 {
429     CHIP_ERROR err;
430     TLVElementType elemType = ElementType();
431
432     err = Skip();
433     if (err != CHIP_NO_ERROR)
434         return err;
435
436     err = ReadElement();
437     if (err != CHIP_NO_ERROR)
438         return err;
439
440     elemType = ElementType();
441     if (elemType == TLVElementType::EndOfContainer)
442         return CHIP_END_OF_TLV;
443
444     return CHIP_NO_ERROR;
445 }
446
447 CHIP_ERROR TLVReader::Next(TLVType expectedType, uint64_t expectedTag)
448 {
449     CHIP_ERROR err = Next();
450     if (err != CHIP_NO_ERROR)
451         return err;
452     if (GetType() != expectedType)
453         return CHIP_ERROR_WRONG_TLV_TYPE;
454     if (mElemTag != expectedTag)
455         return CHIP_ERROR_UNEXPECTED_TLV_ELEMENT;
456     return CHIP_NO_ERROR;
457 }
458
459 CHIP_ERROR TLVReader::Skip()
460 {
461     CHIP_ERROR err;
462     TLVElementType elemType = ElementType();
463
464     if (elemType == TLVElementType::EndOfContainer)
465         return CHIP_END_OF_TLV;
466
467     if (TLVTypeIsContainer(elemType))
468     {
469         TLVType outerContainerType;
470         err = EnterContainer(outerContainerType);
471         if (err != CHIP_NO_ERROR)
472             return err;
473         err = ExitContainer(outerContainerType);
474         if (err != CHIP_NO_ERROR)
475             return err;
476     }
477
478     else
479     {
480         err = SkipData();
481         if (err != CHIP_NO_ERROR)
482             return err;
483
484         ClearElementState();
485     }
486
487     return CHIP_NO_ERROR;
488 }
489
490 /**
491  * Clear the state of the TLVReader.
492  * This method is used to position the reader before the first TLV,
493  * between TLVs or after the last TLV.
494  */
495 void TLVReader::ClearElementState()
496 {
497     mElemTag      = AnonymousTag;
498     mControlByte  = kTLVControlByte_NotSpecified;
499     mElemLenOrVal = 0;
500 }
501
502 /**
503  * Skip any data contained in the current TLV by reading over it without
504  * a destination buffer.
505  *
506  * @retval #CHIP_NO_ERROR              If the reader was successfully positioned at the end of the
507  *                                      data.
508  * @retval other                        Other CHIP or platform error codes returned by the configured
509  *                                      TLVBackingStore.
510  */
511 CHIP_ERROR TLVReader::SkipData()
512 {
513     CHIP_ERROR err          = CHIP_NO_ERROR;
514     TLVElementType elemType = ElementType();
515
516     if (TLVTypeHasLength(elemType))
517     {
518         err = ReadData(nullptr, static_cast<uint32_t>(mElemLenOrVal));
519         if (err != CHIP_NO_ERROR)
520             return err;
521     }
522
523     return err;
524 }
525
526 CHIP_ERROR TLVReader::SkipToEndOfContainer()
527 {
528     CHIP_ERROR err;
529     TLVType outerContainerType = mContainerType;
530     uint32_t nestLevel         = 0;
531
532     // If the user calls Next() after having called OpenContainer() but before calling
533     // CloseContainer() they're effectively doing a close container by skipping over
534     // the container element.  So reset the 'container open' flag here to prevent them
535     // from calling CloseContainer() with the now orphaned container reader.
536     SetContainerOpen(false);
537
538     while (true)
539     {
540         TLVElementType elemType = ElementType();
541
542         if (elemType == TLVElementType::EndOfContainer)
543         {
544             if (nestLevel == 0)
545                 return CHIP_NO_ERROR;
546
547             nestLevel--;
548             mContainerType = (nestLevel == 0) ? outerContainerType : kTLVType_UnknownContainer;
549         }
550
551         else if (TLVTypeIsContainer(elemType))
552         {
553             nestLevel++;
554             mContainerType = static_cast<TLVType>(elemType);
555         }
556
557         err = SkipData();
558         if (err != CHIP_NO_ERROR)
559             return err;
560
561         err = ReadElement();
562         if (err != CHIP_NO_ERROR)
563             return err;
564     }
565 }
566
567 CHIP_ERROR TLVReader::ReadElement()
568 {
569     CHIP_ERROR err;
570     uint8_t stagingBuf[17]; // 17 = 1 control byte + 8 tag bytes + 8 length/value bytes
571     const uint8_t * p;
572     TLVElementType elemType;
573
574     // Make sure we have input data. Return CHIP_END_OF_TLV if no more data is available.
575     err = EnsureData(CHIP_END_OF_TLV);
576     if (err != CHIP_NO_ERROR)
577         return err;
578
579     // Get the element's control byte.
580     mControlByte = *mReadPoint;
581
582     // Extract the element type from the control byte. Fail if it's invalid.
583     elemType = ElementType();
584     if (!IsValidTLVType(elemType))
585         return CHIP_ERROR_INVALID_TLV_ELEMENT;
586
587     // Extract the tag control from the control byte.
588     TLVTagControl tagControl = static_cast<TLVTagControl>(mControlByte & kTLVTagControlMask);
589
590     // Determine the number of bytes in the element's tag, if any.
591     uint8_t tagBytes = sTagSizes[tagControl >> kTLVTagControlShift];
592
593     // Extract the size of length/value field from the control byte.
594     TLVFieldSize lenOrValFieldSize = GetTLVFieldSize(elemType);
595
596     // Determine the number of bytes in the length/value field.
597     uint8_t valOrLenBytes = TLVFieldSizeToBytes(lenOrValFieldSize);
598
599     // Determine the number of bytes in the element's 'head'. This includes: the control byte, the tag bytes (if present), the
600     // length bytes (if present), and for elements that don't have a length (e.g. integers), the value bytes.
601     uint8_t elemHeadBytes = static_cast<uint8_t>(1 + tagBytes + valOrLenBytes);
602
603     // If the head of the element overlaps the end of the input buffer, read the bytes into the staging buffer
604     // and arrange to parse them from there. Otherwise read them directly from the input buffer.
605     if (elemHeadBytes > (mBufEnd - mReadPoint))
606     {
607         err = ReadData(stagingBuf, elemHeadBytes);
608         if (err != CHIP_NO_ERROR)
609             return err;
610         p = stagingBuf;
611     }
612     else
613     {
614         p = mReadPoint;
615         mReadPoint += elemHeadBytes;
616         mLenRead += elemHeadBytes;
617     }
618
619     // Skip over the control byte.
620     p++;
621
622     // Read the tag field, if present.
623     mElemTag = ReadTag(tagControl, p);
624
625     // Read the length/value field, if present.
626     switch (lenOrValFieldSize)
627     {
628     case kTLVFieldSize_0Byte:
629         mElemLenOrVal = 0;
630         break;
631     case kTLVFieldSize_1Byte:
632         mElemLenOrVal = Read8(p);
633         break;
634     case kTLVFieldSize_2Byte:
635         mElemLenOrVal = LittleEndian::Read16(p);
636         break;
637     case kTLVFieldSize_4Byte:
638         mElemLenOrVal = LittleEndian::Read32(p);
639         break;
640     case kTLVFieldSize_8Byte:
641         mElemLenOrVal = LittleEndian::Read64(p);
642         break;
643     }
644
645     return VerifyElement();
646 }
647
648 CHIP_ERROR TLVReader::VerifyElement()
649 {
650     if (ElementType() == TLVElementType::EndOfContainer)
651     {
652         if (mContainerType == kTLVType_NotSpecified)
653             return CHIP_ERROR_INVALID_TLV_ELEMENT;
654         if (mElemTag != AnonymousTag)
655             return CHIP_ERROR_INVALID_TLV_TAG;
656     }
657     else
658     {
659         if (mElemTag == UnknownImplicitTag)
660             return CHIP_ERROR_UNKNOWN_IMPLICIT_TLV_TAG;
661         switch (mContainerType)
662         {
663         case kTLVType_NotSpecified:
664             if (IsContextTag(mElemTag))
665                 return CHIP_ERROR_INVALID_TLV_TAG;
666             break;
667         case kTLVType_Structure:
668             if (mElemTag == AnonymousTag)
669                 return CHIP_ERROR_INVALID_TLV_TAG;
670             break;
671         case kTLVType_Array:
672             if (mElemTag != AnonymousTag)
673                 return CHIP_ERROR_INVALID_TLV_TAG;
674             break;
675         case kTLVType_UnknownContainer:
676         case kTLVType_List:
677             break;
678         default:
679             return CHIP_ERROR_INCORRECT_STATE;
680         }
681     }
682
683     // If the current element encodes a specific length (e.g. a UTF8 string or a byte string), verify
684     // that the purported length fits within the remaining bytes of the encoding (as delineated by mMaxLen).
685     //
686     // Note that this check is not strictly necessary to prevent runtime errors, as any attempt to access
687     // the data of an element with an invalid length will result in an error.  However checking the length
688     // here catches the error earlier, and ensures that the application will never see the erroneous length
689     // value.
690     //
691     if (TLVTypeHasLength(ElementType()))
692     {
693         uint32_t overallLenRemaining = mMaxLen - mLenRead;
694         if (overallLenRemaining < static_cast<uint32_t>(mElemLenOrVal))
695             return CHIP_ERROR_TLV_UNDERRUN;
696     }
697
698     return CHIP_NO_ERROR;
699 }
700
701 uint64_t TLVReader::ReadTag(TLVTagControl tagControl, const uint8_t *& p)
702 {
703     uint16_t vendorId;
704     uint16_t profileNum;
705
706     switch (tagControl)
707     {
708     case TLVTagControl::ContextSpecific:
709         return ContextTag(Read8(p));
710     case TLVTagControl::CommonProfile_2Bytes:
711         return CommonTag(LittleEndian::Read16(p));
712     case TLVTagControl::CommonProfile_4Bytes:
713         return CommonTag(LittleEndian::Read32(p));
714     case TLVTagControl::ImplicitProfile_2Bytes:
715         if (ImplicitProfileId == kProfileIdNotSpecified)
716             return UnknownImplicitTag;
717         return ProfileTag(ImplicitProfileId, LittleEndian::Read16(p));
718     case TLVTagControl::ImplicitProfile_4Bytes:
719         if (ImplicitProfileId == kProfileIdNotSpecified)
720             return UnknownImplicitTag;
721         return ProfileTag(ImplicitProfileId, LittleEndian::Read32(p));
722     case TLVTagControl::FullyQualified_6Bytes:
723         vendorId   = LittleEndian::Read16(p);
724         profileNum = LittleEndian::Read16(p);
725         return ProfileTag(vendorId, profileNum, LittleEndian::Read16(p));
726     case TLVTagControl::FullyQualified_8Bytes:
727         vendorId   = LittleEndian::Read16(p);
728         profileNum = LittleEndian::Read16(p);
729         return ProfileTag(vendorId, profileNum, LittleEndian::Read32(p));
730     case TLVTagControl::Anonymous:
731     default:
732         return AnonymousTag;
733     }
734 }
735
736 CHIP_ERROR TLVReader::ReadData(uint8_t * buf, uint32_t len)
737 {
738     CHIP_ERROR err;
739
740     while (len > 0)
741     {
742         err = EnsureData(CHIP_ERROR_TLV_UNDERRUN);
743         if (err != CHIP_NO_ERROR)
744             return err;
745
746         uint32_t remainingLen = static_cast<decltype(mMaxLen)>(mBufEnd - mReadPoint);
747
748         uint32_t readLen = len;
749         if (readLen > remainingLen)
750             readLen = remainingLen;
751
752         if (buf != nullptr)
753         {
754             memcpy(buf, mReadPoint, readLen);
755             buf += readLen;
756         }
757         mReadPoint += readLen;
758         mLenRead += readLen;
759         len -= readLen;
760     }
761
762     return CHIP_NO_ERROR;
763 }
764
765 CHIP_ERROR TLVReader::EnsureData(CHIP_ERROR noDataErr)
766 {
767     CHIP_ERROR err;
768
769     if (mReadPoint == mBufEnd)
770     {
771         if (mLenRead == mMaxLen)
772             return noDataErr;
773
774         if (mBackingStore == nullptr)
775             return noDataErr;
776
777         uint32_t bufLen;
778         err = mBackingStore->GetNextBuffer(*this, mReadPoint, bufLen);
779         if (err != CHIP_NO_ERROR)
780             return err;
781         if (bufLen == 0)
782             return noDataErr;
783
784         // Cap mBufEnd so that we don't read beyond the user's specified maximum length, even
785         // if the underlying buffer is larger.
786         uint32_t overallLenRemaining = mMaxLen - mLenRead;
787         if (overallLenRemaining < bufLen)
788             bufLen = overallLenRemaining;
789
790         mBufEnd = mReadPoint + bufLen;
791     }
792
793     return CHIP_NO_ERROR;
794 }
795
796 /**
797  * This is a private method used to compute the length of a TLV element head.
798  */
799 CHIP_ERROR TLVReader::GetElementHeadLength(uint8_t & elemHeadBytes) const
800 {
801     uint8_t tagBytes;
802     uint8_t valOrLenBytes;
803     TLVTagControl tagControl;
804     TLVFieldSize lenOrValFieldSize;
805     TLVElementType elemType = ElementType();
806
807     // Verify element is of valid TLVType.
808     VerifyOrReturnError(IsValidTLVType(elemType), CHIP_ERROR_INVALID_TLV_ELEMENT);
809
810     // Extract the tag control from the control byte.
811     tagControl = static_cast<TLVTagControl>(mControlByte & kTLVTagControlMask);
812
813     // Determine the number of bytes in the element's tag, if any.
814     tagBytes = sTagSizes[tagControl >> kTLVTagControlShift];
815
816     // Extract the size of length/value field from the control byte.
817     lenOrValFieldSize = GetTLVFieldSize(elemType);
818
819     // Determine the number of bytes in the length/value field.
820     valOrLenBytes = TLVFieldSizeToBytes(lenOrValFieldSize);
821
822     // Determine the number of bytes in the element's 'head'. This includes: the
823     // control byte, the tag bytes (if present), the length bytes (if present),
824     // and for elements that don't have a length (e.g. integers), the value
825     // bytes.
826     VerifyOrReturnError(CanCastTo<uint8_t>(1 + tagBytes + valOrLenBytes), CHIP_ERROR_INTERNAL);
827     elemHeadBytes = static_cast<uint8_t>(1 + tagBytes + valOrLenBytes);
828
829     return CHIP_NO_ERROR;
830 }
831
832 /**
833  * This is a private method that returns the TLVElementType from mControlByte
834  */
835 TLVElementType TLVReader::ElementType() const
836 {
837     if (mControlByte == static_cast<uint16_t>(kTLVControlByte_NotSpecified))
838         return TLVElementType::NotSpecified;
839     return static_cast<TLVElementType>(mControlByte & kTLVTypeMask);
840 }
841
842 CHIP_ERROR TLVReader::FindElementWithTag(const uint64_t tag, TLVReader & destReader) const
843 {
844     CHIP_ERROR err = CHIP_NO_ERROR;
845
846     chip::TLV::TLVReader reader;
847     reader.Init(*this);
848
849     while (CHIP_NO_ERROR == (err = reader.Next()))
850     {
851         VerifyOrExit(chip::TLV::kTLVType_NotSpecified != reader.GetType(), err = CHIP_ERROR_INVALID_TLV_ELEMENT);
852
853         if (tag == reader.GetTag())
854         {
855             destReader.Init(reader);
856             break;
857         }
858     }
859
860 exit:
861     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
862
863     return err;
864 }
865
866 } // namespace TLV
867 } // namespace chip