7c5f7cd544875c55ebc7baa0cda92c70bf107ce5
[platform/upstream/connectedhomeip.git] / src / app / MessageDef.cpp
1 /**
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2018 Google LLC.
5  *    Copyright (c) 2016-2017 Nest Labs, Inc.
6  *    Licensed under the Apache License, Version 2.0 (the "License");
7  *    you may not use this file except in compliance with the License.
8  *    You may obtain a copy of the License at
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  *    @file
20  *      This file defines CHIP interaction model message parsers and encoders
21  *      Interaction model profile.
22  *
23  */
24
25 // __STDC_FORMAT_MACROS must be defined for PRIX64 to be defined for pre-C++11 clib
26 #ifndef __STDC_FORMAT_MACROS
27 #define __STDC_FORMAT_MACROS
28 #endif // __STDC_FORMAT_MACROS
29
30 // __STDC_LIMIT_MACROS must be defined for UINT8_MAX and INT32_MAX to be defined for pre-C++11 clib
31 #ifndef __STDC_LIMIT_MACROS
32 #define __STDC_LIMIT_MACROS
33 #endif // __STDC_LIMIT_MACROS
34
35 // __STDC_CONSTANT_MACROS must be defined for INT64_C and UINT64_C to be defined for pre-C++11 clib
36 #ifndef __STDC_CONSTANT_MACROS
37 #define __STDC_CONSTANT_MACROS
38 #endif // __STDC_CONSTANT_MACROS
39
40 #include "MessageDef.h"
41 #include <algorithm>
42 #include <inttypes.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45
46 using namespace chip;
47 using namespace chip::TLV;
48
49 #ifndef CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
50 #define CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK 1
51 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
52
53 namespace chip {
54 namespace app {
55
56 #if CHIP_DETAIL_LOGGING
57
58 namespace {
59 // this is used to run in signle thread for IM message debug purpose
60 uint32_t gPrettyPrintingDepthLevel = 0;
61 char gLineBuffer[256];
62 size_t gCurLineBufferSize = 0;
63 } // namespace
64
65 class PrettyPrintCheckpoint
66 {
67 public:
68     PrettyPrintCheckpoint() { mLevel = gPrettyPrintingDepthLevel; }
69     ~PrettyPrintCheckpoint() { gPrettyPrintingDepthLevel = mLevel; }
70
71 private:
72     uint32_t mLevel;
73 };
74 #define PRETTY_PRINT_CHECKPOINT() PrettyPrintCheckpoint lPrettyPrintCheckpoint;
75
76 #define PRETTY_PRINT(fmt, ...)                                                                                                     \
77     do                                                                                                                             \
78     {                                                                                                                              \
79         PrettyPrintIM(true, fmt, ##__VA_ARGS__);                                                                                   \
80     } while (0)
81 #define PRETTY_PRINT_SAMELINE(fmt, ...)                                                                                            \
82     do                                                                                                                             \
83     {                                                                                                                              \
84         PrettyPrintIM(false, fmt, ##__VA_ARGS__);                                                                                  \
85     } while (0)
86 #define PRETTY_PRINT_INCDEPTH()                                                                                                    \
87     do                                                                                                                             \
88     {                                                                                                                              \
89         gPrettyPrintingDepthLevel++;                                                                                               \
90     } while (0)
91 #define PRETTY_PRINT_DECDEPTH()                                                                                                    \
92     do                                                                                                                             \
93     {                                                                                                                              \
94         gPrettyPrintingDepthLevel--;                                                                                               \
95     } while (0)
96
97 static void PrettyPrintIM(bool aIsNewLine, const char * aFmt, ...)
98 {
99     va_list args;
100     size_t ret;
101     size_t sizeLeft;
102
103     va_start(args, aFmt);
104
105     if (aIsNewLine)
106     {
107         if (gCurLineBufferSize)
108         {
109             // Don't need to explicitly NULL-terminate the string because
110             // snprintf takes care of that.
111             ChipLogDetail(DataManagement, "%s", gLineBuffer);
112             gCurLineBufferSize = 0;
113         }
114
115         for (uint32_t i = 0; i < gPrettyPrintingDepthLevel; i++)
116         {
117             if (sizeof(gLineBuffer) > gCurLineBufferSize)
118             {
119                 sizeLeft = sizeof(gLineBuffer) - gCurLineBufferSize;
120                 ret      = (size_t)(snprintf(gLineBuffer + gCurLineBufferSize, sizeLeft, "\t"));
121                 if (ret > 0)
122                 {
123                     gCurLineBufferSize += std::min(ret, sizeLeft);
124                 }
125             }
126         }
127     }
128
129     if (sizeof(gLineBuffer) > gCurLineBufferSize)
130     {
131         sizeLeft = sizeof(gLineBuffer) - gCurLineBufferSize;
132         ret      = (size_t)(vsnprintf(gLineBuffer + gCurLineBufferSize, sizeLeft, aFmt, args));
133         if (ret > 0)
134         {
135             gCurLineBufferSize += std::min(ret, sizeLeft);
136         }
137     }
138
139     va_end(args);
140 }
141 #else // CHIP_DETAIL_LOGGING
142 #define PRETTY_PRINT_CHECKPOINT()
143 #define PRETTY_PRINT(fmt, ...)
144 #define PRETTY_PRINT(fmt, ...)
145 #define PRETTY_PRINT_INCDEPTH()
146 #define PRETTY_PRINT_DECDEPTH()
147 #endif // CHIP_DETAIL_LOGGING
148
149 Parser::Parser() : mOuterContainerType(chip::TLV::kTLVType_NotSpecified) {}
150
151 void Parser::Init(const chip::TLV::TLVReader & aReader, chip::TLV::TLVType aOuterContainerType)
152 {
153     mReader.Init(aReader);
154     mOuterContainerType = aOuterContainerType;
155 }
156
157 CHIP_ERROR Parser::GetReaderOnTag(const uint64_t aTagToFind, chip::TLV::TLVReader * const apReader) const
158 {
159     return mReader.FindElementWithTag(aTagToFind, *apReader);
160 }
161
162 template <typename T>
163 CHIP_ERROR Parser::GetUnsignedInteger(const uint8_t aContextTag, T * const apLValue) const
164 {
165     return GetSimpleValue(aContextTag, chip::TLV::kTLVType_UnsignedInteger, apLValue);
166 }
167
168 template <typename T>
169 CHIP_ERROR Parser::GetSimpleValue(const uint8_t aContextTag, const chip::TLV::TLVType aTLVType, T * const apLValue) const
170 {
171     CHIP_ERROR err = CHIP_NO_ERROR;
172     chip::TLV::TLVReader reader;
173
174     *apLValue = 0;
175
176     err = mReader.FindElementWithTag(chip::TLV::ContextTag(aContextTag), reader);
177     SuccessOrExit(err);
178
179     VerifyOrExit(aTLVType == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
180
181     err = reader.Get(*apLValue);
182     SuccessOrExit(err);
183
184 exit:
185     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
186
187     return err;
188 }
189
190 void Parser::GetReader(chip::TLV::TLVReader * const apReader)
191 {
192     apReader->Init(mReader);
193 }
194
195 ListParser::ListParser() {}
196
197 CHIP_ERROR ListParser::Init(const chip::TLV::TLVReader & aReader)
198 {
199     CHIP_ERROR err = CHIP_NO_ERROR;
200
201     // make a copy of the reader here
202     mReader.Init(aReader);
203
204     VerifyOrExit(chip::TLV::kTLVType_Array == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
205
206     // This is just a dummy, as we're not going to exit this container ever
207     chip::TLV::TLVType OuterContainerType;
208     err = mReader.EnterContainer(OuterContainerType);
209
210 exit:
211     ChipLogFunctError(err);
212
213     return err;
214 }
215
216 CHIP_ERROR ListParser::InitIfPresent(const chip::TLV::TLVReader & aReader, const uint8_t aContextTagToFind)
217 {
218     CHIP_ERROR err = CHIP_NO_ERROR;
219     chip::TLV::TLVReader reader;
220
221     err = mReader.FindElementWithTag(chip::TLV::ContextTag(aContextTagToFind), reader);
222     SuccessOrExit(err);
223
224     err = Init(reader);
225     SuccessOrExit(err);
226
227 exit:
228     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
229
230     return err;
231 }
232
233 CHIP_ERROR ListParser::Next()
234 {
235     CHIP_ERROR err = mReader.Next();
236
237     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
238
239     return err;
240 }
241
242 Builder::Builder() : mError(CHIP_ERROR_INCORRECT_STATE), mpWriter(NULL), mOuterContainerType(chip::TLV::kTLVType_NotSpecified) {}
243
244 void Builder::Init(chip::TLV::TLVWriter * const apWriter, chip::TLV::TLVType aOuterContainerType)
245 {
246     mpWriter            = apWriter;
247     mOuterContainerType = aOuterContainerType;
248 }
249
250 void Builder::ResetError()
251 {
252     ResetError(CHIP_NO_ERROR);
253 }
254
255 void Builder::ResetError(CHIP_ERROR aErr)
256 {
257     mError              = aErr;
258     mOuterContainerType = chip::TLV::kTLVType_NotSpecified;
259 }
260
261 void Builder::EndOfContainer()
262 {
263     // skip if error has already been set
264     SuccessOrExit(mError);
265
266     mError = mpWriter->EndContainer(mOuterContainerType);
267     SuccessOrExit(mError);
268
269     // we've just closed properly
270     // mark it so we do not panic when the build object destructor is called
271     mOuterContainerType = chip::TLV::kTLVType_NotSpecified;
272
273 exit:;
274 }
275
276 CHIP_ERROR Builder::InitAnonymousStructure(chip::TLV::TLVWriter * const apWriter)
277 {
278     mpWriter            = apWriter;
279     mOuterContainerType = chip::TLV::kTLVType_NotSpecified;
280     mError              = mpWriter->StartContainer(chip::TLV::AnonymousTag, chip::TLV::kTLVType_Structure, mOuterContainerType);
281     ChipLogFunctError(mError);
282
283     return mError;
284 }
285
286 ListBuilder::ListBuilder() {}
287
288 CHIP_ERROR ListBuilder::Init(chip::TLV::TLVWriter * const apWriter, const uint8_t aContextTagToUse)
289 {
290     mpWriter = apWriter;
291     mError   = mpWriter->StartContainer(chip::TLV::ContextTag(aContextTagToUse), chip::TLV::kTLVType_Array, mOuterContainerType);
292     ChipLogFunctError(mError);
293
294     return mError;
295 }
296
297 CHIP_ERROR ListBuilder::Init(chip::TLV::TLVWriter * const apWriter)
298 {
299     mpWriter = apWriter;
300     mError   = mpWriter->StartContainer(chip::TLV::AnonymousTag, chip::TLV::kTLVType_Array, mOuterContainerType);
301     ChipLogFunctError(mError);
302
303     return mError;
304 }
305
306 CHIP_ERROR AttributePath::Parser::Init(const chip::TLV::TLVReader & aReader)
307 {
308     CHIP_ERROR err = CHIP_NO_ERROR;
309
310     // make a copy of the reader here
311     mReader.Init(aReader);
312
313     VerifyOrExit(chip::TLV::kTLVType_Path == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
314
315     // This is just a dummy, as we're not going to exit this container ever
316     chip::TLV::TLVType dummyContainerType;
317     // enter into the Path
318     err = mReader.EnterContainer(dummyContainerType);
319     SuccessOrExit(err);
320
321 exit:
322     ChipLogFunctError(err);
323
324     return err;
325 }
326
327 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
328 CHIP_ERROR AttributePath::Parser::CheckSchemaValidity() const
329 {
330     CHIP_ERROR err           = CHIP_NO_ERROR;
331     uint16_t TagPresenceMask = 0;
332     chip::TLV::TLVReader reader;
333
334     PRETTY_PRINT("AttributePath =");
335     PRETTY_PRINT("{");
336
337     // make a copy of the Path reader
338     reader.Init(mReader);
339
340     while (CHIP_NO_ERROR == (err = reader.Next()))
341     {
342         VerifyOrExit(chip::TLV::IsContextTag(reader.GetTag()), err = CHIP_ERROR_INVALID_TLV_TAG);
343         switch (chip::TLV::TagNumFromTag(reader.GetTag()))
344         {
345         case kCsTag_NodeId:
346             // check if this tag has appeared before
347             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_NodeId)), err = CHIP_ERROR_INVALID_TLV_TAG);
348             TagPresenceMask |= (1 << kCsTag_NodeId);
349             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
350
351 #if CHIP_DETAIL_LOGGING
352             {
353                 uint64_t nodeId;
354                 reader.Get(nodeId);
355                 PRETTY_PRINT("\tNodeId = 0x%" PRIx64 ",", nodeId);
356             }
357 #endif // CHIP_DETAIL_LOGGING
358             break;
359         case kCsTag_EndpointId:
360             // check if this tag has appeared before
361             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_EndpointId)), err = CHIP_ERROR_INVALID_TLV_TAG);
362             TagPresenceMask |= (1 << kCsTag_EndpointId);
363             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
364 #if CHIP_DETAIL_LOGGING
365             {
366                 uint16_t endpointId;
367                 reader.Get(endpointId);
368                 PRETTY_PRINT("\tEndpointId = 0x%" PRIx16 ",", endpointId);
369             }
370 #endif // CHIP_DETAIL_LOGGING
371             break;
372         case kCsTag_NamespacedClusterId:
373             // check if this tag has appeared before
374             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_NamespacedClusterId)), err = CHIP_ERROR_INVALID_TLV_TAG);
375             TagPresenceMask |= (1 << kCsTag_NamespacedClusterId);
376             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
377
378 #if CHIP_DETAIL_LOGGING
379             if (chip::TLV::kTLVType_UnsignedInteger == reader.GetType())
380             {
381                 chip::ClusterId namespacedClusterId;
382                 reader.Get(namespacedClusterId);
383                 PRETTY_PRINT("\tNamespacedClusterId = 0x%" PRIx32 ",", namespacedClusterId);
384             }
385 #endif // CHIP_DETAIL_LOGGING
386             break;
387         case kCsTag_FieldId:
388             // check if this tag has appeared before
389             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_FieldId)), err = CHIP_ERROR_INVALID_TLV_TAG);
390             TagPresenceMask |= (1 << kCsTag_FieldId);
391             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
392 #if CHIP_DETAIL_LOGGING
393             {
394                 uint8_t fieldTag;
395                 reader.Get(fieldTag);
396                 PRETTY_PRINT("\tFieldTag = 0x%" PRIx8 ",", fieldTag);
397             }
398 #endif // CHIP_DETAIL_LOGGING
399             break;
400         case kCsTag_ListIndex:
401             // check if this tag has appeared before
402             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_ListIndex)), err = CHIP_ERROR_INVALID_TLV_TAG);
403             TagPresenceMask |= (1 << kCsTag_ListIndex);
404             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
405 #if CHIP_DETAIL_LOGGING
406             if (chip::TLV::kTLVType_UnsignedInteger == reader.GetType())
407             {
408                 uint16_t listIndex;
409                 reader.Get(listIndex);
410                 PRETTY_PRINT("\tListIndex = 0x%" PRIx16 ",", listIndex);
411             }
412 #endif // CHIP_DETAIL_LOGGING
413             break;
414         default:
415             ExitNow(err = CHIP_ERROR_INVALID_TLV_TAG);
416         }
417     }
418
419     PRETTY_PRINT("}");
420     PRETTY_PRINT("\t");
421     // if we have exhausted this container
422     if (CHIP_END_OF_TLV == err)
423     {
424         // check for required fields:
425         const uint16_t RequiredFields = (1 << kCsTag_EndpointId) | (1 << kCsTag_NamespacedClusterId);
426
427         if ((TagPresenceMask & RequiredFields) == RequiredFields)
428         {
429             err = CHIP_NO_ERROR;
430         }
431         else
432         {
433             err = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH;
434         }
435     }
436     SuccessOrExit(err);
437
438 exit:
439     ChipLogFunctError(err);
440
441     return err;
442 }
443 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
444
445 CHIP_ERROR AttributePath::Parser::GetNodeId(chip::NodeId * const apNodeId) const
446 {
447     return GetUnsignedInteger(kCsTag_NodeId, apNodeId);
448 }
449
450 CHIP_ERROR AttributePath::Parser::GetEndpointId(chip::EndpointId * const apEndpointId) const
451 {
452     return GetUnsignedInteger(kCsTag_EndpointId, apEndpointId);
453 }
454
455 CHIP_ERROR AttributePath::Parser::GetNamespacedClusterId(chip::ClusterId * const apClusterId) const
456 {
457     return GetUnsignedInteger(kCsTag_NamespacedClusterId, apClusterId);
458 }
459
460 CHIP_ERROR AttributePath::Parser::GetFieldId(uint8_t * const apFieldId) const
461 {
462     return GetUnsignedInteger(kCsTag_FieldId, apFieldId);
463 }
464
465 CHIP_ERROR AttributePath::Parser::GetListIndex(uint16_t * const apListIndex) const
466 {
467     return GetUnsignedInteger(kCsTag_ListIndex, apListIndex);
468 }
469
470 CHIP_ERROR AttributePath::Builder::_Init(chip::TLV::TLVWriter * const apWriter, const uint64_t aTag)
471 {
472     mpWriter = apWriter;
473     mError   = mpWriter->StartContainer(aTag, chip::TLV::kTLVType_Path, mOuterContainerType);
474     SuccessOrExit(mError);
475
476 exit:
477     ChipLogFunctError(mError);
478     return mError;
479 }
480
481 CHIP_ERROR AttributePath::Builder::Init(chip::TLV::TLVWriter * const apWriter)
482 {
483     return _Init(apWriter, chip::TLV::AnonymousTag);
484 }
485
486 CHIP_ERROR AttributePath::Builder::Init(chip::TLV::TLVWriter * const apWriter, const uint8_t aContextTagToUse)
487 {
488     return _Init(apWriter, chip::TLV::ContextTag(aContextTagToUse));
489 }
490
491 AttributePath::Builder & AttributePath::Builder::NodeId(const uint64_t aNodeId)
492 {
493     // skip if error has already been set
494     SuccessOrExit(mError);
495
496     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_NodeId), aNodeId);
497     ChipLogFunctError(mError);
498
499 exit:
500
501     return *this;
502 }
503
504 AttributePath::Builder & AttributePath::Builder::EndpointId(const chip::EndpointId aEndpointId)
505 {
506     // skip if error has already been set
507     SuccessOrExit(mError);
508
509     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_EndpointId), aEndpointId);
510     ChipLogFunctError(mError);
511
512 exit:
513     return *this;
514 }
515
516 AttributePath::Builder & AttributePath::Builder::NamespacedClusterId(const chip::ClusterId aClusterId)
517 {
518     // skip if error has already been set
519     SuccessOrExit(mError);
520
521     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_NamespacedClusterId), aClusterId);
522     ChipLogFunctError(mError);
523
524 exit:
525     return *this;
526 }
527
528 AttributePath::Builder & AttributePath::Builder::FieldId(const uint8_t aFieldId)
529 {
530     // skip if error has already been set
531     SuccessOrExit(mError);
532
533     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_FieldId), aFieldId);
534     ChipLogFunctError(mError);
535
536 exit:
537     return *this;
538 }
539
540 AttributePath::Builder & AttributePath::Builder::ListIndex(const uint16_t aListIndex)
541 {
542     // skip if error has already been set
543     SuccessOrExit(mError);
544
545     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_ListIndex), aListIndex);
546     ChipLogFunctError(mError);
547
548 exit:
549     return *this;
550 }
551
552 AttributePath::Builder & AttributePath::Builder::EndOfAttributePath()
553 {
554     EndOfContainer();
555     return *this;
556 }
557
558 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
559 CHIP_ERROR AttributePathList::Parser::CheckSchemaValidity() const
560 {
561     CHIP_ERROR err = CHIP_NO_ERROR;
562     size_t NumPath = 0;
563     chip::TLV::TLVReader reader;
564
565     PRETTY_PRINT("AttributePathList =");
566     PRETTY_PRINT("[");
567
568     // make a copy of the AttributePathList reader
569     reader.Init(mReader);
570
571     while (CHIP_NO_ERROR == (err = reader.Next()))
572     {
573         VerifyOrExit(chip::TLV::AnonymousTag == reader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG);
574         VerifyOrExit(chip::TLV::kTLVType_Path == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
575         {
576             AttributePath::Parser path;
577             err = path.Init(reader);
578             SuccessOrExit(err);
579
580             PRETTY_PRINT_INCDEPTH();
581             err = path.CheckSchemaValidity();
582             SuccessOrExit(err);
583             PRETTY_PRINT_DECDEPTH();
584         }
585
586         ++NumPath;
587     }
588
589     PRETTY_PRINT("],");
590     PRETTY_PRINT("\t");
591     // if we have exhausted this container
592     if (CHIP_END_OF_TLV == err)
593     {
594         err = CHIP_NO_ERROR;
595     }
596
597 exit:
598     ChipLogFunctError(err);
599
600     return err;
601 }
602 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
603
604 // Re-initialize the shared PathBuilder with anonymous tag
605 AttributePath::Builder & AttributePathList::Builder::CreateAttributePathBuilder()
606 {
607     // skip if error has already been set
608     VerifyOrExit(CHIP_NO_ERROR == mError, mAttributePathBuilder.ResetError(mError));
609
610     mError = mAttributePathBuilder.Init(mpWriter);
611     ChipLogFunctError(mError);
612
613 exit:
614     // on error, mAttributePathBuilder would be un-/partial initialized and cannot be used to write anything
615     return mAttributePathBuilder;
616 }
617
618 // Mark the end of this array and recover the type for outer container
619 AttributePathList::Builder & AttributePathList::Builder::EndOfAttributePathList()
620 {
621     EndOfContainer();
622
623     return *this;
624 }
625
626 CHIP_ERROR EventPath::Parser::Init(const chip::TLV::TLVReader & aReader)
627 {
628     CHIP_ERROR err = CHIP_NO_ERROR;
629
630     // make a copy of the reader here
631     mReader.Init(aReader);
632
633     VerifyOrExit(chip::TLV::kTLVType_Path == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
634
635     // This is just a dummy, as we're not going to exit this container ever
636     chip::TLV::TLVType dummyContainerType;
637     // enter into the Path
638     err = mReader.EnterContainer(dummyContainerType);
639     SuccessOrExit(err);
640
641 exit:
642     ChipLogFunctError(err);
643
644     return err;
645 }
646
647 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
648 CHIP_ERROR EventPath::Parser::CheckSchemaValidity() const
649 {
650     CHIP_ERROR err           = CHIP_NO_ERROR;
651     uint16_t TagPresenceMask = 0;
652     chip::TLV::TLVReader reader;
653
654     PRETTY_PRINT("EventPath =");
655     PRETTY_PRINT("{");
656
657     // make a copy of the Path reader
658     reader.Init(mReader);
659
660     while (CHIP_NO_ERROR == (err = reader.Next()))
661     {
662         VerifyOrExit(chip::TLV::IsContextTag(reader.GetTag()), err = CHIP_ERROR_INVALID_TLV_TAG);
663         switch (chip::TLV::TagNumFromTag(reader.GetTag()))
664         {
665         case kCsTag_NodeId:
666             // check if this tag has appeared before
667             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_NodeId)), err = CHIP_ERROR_INVALID_TLV_TAG);
668             TagPresenceMask |= (1 << kCsTag_NodeId);
669             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
670 #if CHIP_DETAIL_LOGGING
671             {
672                 uint64_t nodeId;
673                 reader.Get(nodeId);
674                 PRETTY_PRINT("\tNodeId = 0x%" PRIx64 ",", nodeId);
675             }
676 #endif // CHIP_DETAIL_LOGGING
677             break;
678         case kCsTag_EndpointId:
679             // check if this tag has appeared before
680             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_EndpointId)), err = CHIP_ERROR_INVALID_TLV_TAG);
681             TagPresenceMask |= (1 << kCsTag_EndpointId);
682             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
683 #if CHIP_DETAIL_LOGGING
684             {
685                 uint16_t endpointId;
686                 reader.Get(endpointId);
687                 PRETTY_PRINT("\tEndpointId = 0x%" PRIx16 ",", endpointId);
688             }
689 #endif // CHIP_DETAIL_LOGGING
690             break;
691         case kCsTag_NamespacedClusterId:
692             // check if this tag has appeared before
693             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_NamespacedClusterId)), err = CHIP_ERROR_INVALID_TLV_TAG);
694             TagPresenceMask |= (1 << kCsTag_NamespacedClusterId);
695             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
696
697 #if CHIP_DETAIL_LOGGING
698             {
699                 chip::ClusterId namespacedClusterId;
700                 reader.Get(namespacedClusterId);
701                 PRETTY_PRINT("\tNamespacedClusterId = 0x%" PRIx32 ",", namespacedClusterId);
702             }
703 #endif // CHIP_DETAIL_LOGGING
704             break;
705         case chip::app::EventPath::kCsTag_EventId:
706             // check if this tag has appeared before
707             VerifyOrExit(!(TagPresenceMask & (1 << chip::app::EventPath::kCsTag_EventId)), err = CHIP_ERROR_INVALID_TLV_TAG);
708             TagPresenceMask |= (1 << chip::app::EventPath::kCsTag_EventId);
709             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
710
711 #if CHIP_DETAIL_LOGGING
712             {
713                 chip::EventId eventId;
714                 reader.Get(eventId);
715                 PRETTY_PRINT("\tEventId = 0x%" PRIx16 ",", eventId);
716             }
717 #endif // CHIP_DETAIL_LOGGING
718             break;
719         default:
720             ExitNow(err = CHIP_ERROR_INVALID_TLV_TAG);
721         }
722     }
723
724     PRETTY_PRINT("},");
725     PRETTY_PRINT("");
726
727     // if we have exhausted this container
728     if (CHIP_END_OF_TLV == err)
729     {
730         // check for required fields:
731         const uint16_t RequiredFields = (1 << kCsTag_EndpointId) | (1 << kCsTag_NamespacedClusterId);
732
733         if ((TagPresenceMask & RequiredFields) == RequiredFields)
734         {
735             err = CHIP_NO_ERROR;
736         }
737         else
738         {
739             err = CHIP_ERROR_IM_MALFORMED_EVENT_PATH;
740         }
741     }
742     SuccessOrExit(err);
743
744 exit:
745     ChipLogFunctError(err);
746
747     return err;
748 }
749 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
750
751 CHIP_ERROR EventPath::Parser::GetNodeId(chip::NodeId * const apNodeId) const
752 {
753     return GetUnsignedInteger(kCsTag_NodeId, apNodeId);
754 }
755
756 CHIP_ERROR EventPath::Parser::GetEndpointId(chip::EndpointId * const apEndpointID) const
757 {
758     return GetUnsignedInteger(kCsTag_EndpointId, apEndpointID);
759 }
760
761 CHIP_ERROR EventPath::Parser::GetNamespacedClusterId(chip::ClusterId * const apClusterId) const
762 {
763     return GetUnsignedInteger(kCsTag_NamespacedClusterId, apClusterId);
764 }
765
766 CHIP_ERROR EventPath::Parser::GetEventId(chip::EventId * const apEventId) const
767 {
768     return GetUnsignedInteger(kCsTag_EventId, apEventId);
769 }
770
771 CHIP_ERROR EventPath::Builder::_Init(chip::TLV::TLVWriter * const apWriter, const uint64_t aTag)
772 {
773     mpWriter = apWriter;
774     mError   = mpWriter->StartContainer(aTag, chip::TLV::kTLVType_Path, mOuterContainerType);
775     SuccessOrExit(mError);
776
777 exit:
778     ChipLogFunctError(mError);
779     return mError;
780 }
781
782 CHIP_ERROR EventPath::Builder::Init(chip::TLV::TLVWriter * const apWriter)
783 {
784     return _Init(apWriter, chip::TLV::AnonymousTag);
785 }
786
787 CHIP_ERROR EventPath::Builder::Init(chip::TLV::TLVWriter * const apWriter, const uint8_t aContextTagToUse)
788 {
789     return _Init(apWriter, chip::TLV::ContextTag(aContextTagToUse));
790 }
791
792 EventPath::Builder & EventPath::Builder::NodeId(const uint64_t aNodeId)
793 {
794     // skip if error has already been set
795     SuccessOrExit(mError);
796
797     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_NodeId), aNodeId);
798     ChipLogFunctError(mError);
799
800 exit:
801     return *this;
802 }
803
804 EventPath::Builder & EventPath::Builder::EndpointId(const chip::EndpointId aEndpointId)
805 {
806     // skip if error has already been set
807     SuccessOrExit(mError);
808
809     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_EndpointId), aEndpointId);
810     ChipLogFunctError(mError);
811
812 exit:
813     return *this;
814 }
815
816 EventPath::Builder & EventPath::Builder::NamespacedClusterId(const chip::ClusterId aClusterId)
817 {
818     // skip if error has already been set
819     SuccessOrExit(mError);
820
821     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_NamespacedClusterId), aClusterId);
822     ChipLogFunctError(mError);
823
824 exit:
825     return *this;
826 }
827
828 EventPath::Builder & EventPath::Builder::EventId(const chip::EventId aEventId)
829 {
830     // skip if error has already been set
831     SuccessOrExit(mError);
832
833     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_EventId), aEventId);
834     ChipLogFunctError(mError);
835
836 exit:
837     return *this;
838 }
839
840 EventPath::Builder & EventPath::Builder::EndOfEventPath()
841 {
842     EndOfContainer();
843     return *this;
844 }
845
846 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
847 CHIP_ERROR EventPathList::Parser::CheckSchemaValidity() const
848 {
849     CHIP_ERROR err = CHIP_NO_ERROR;
850     size_t NumPath = 0;
851     chip::TLV::TLVReader reader;
852
853     PRETTY_PRINT("EventPathList =");
854     PRETTY_PRINT("[");
855
856     // make a copy of the EventPathList reader
857     reader.Init(mReader);
858
859     while (CHIP_NO_ERROR == (err = reader.Next()))
860     {
861         VerifyOrExit(chip::TLV::AnonymousTag == reader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG);
862         VerifyOrExit(chip::TLV::kTLVType_Path == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
863
864         {
865             EventPath::Parser path;
866             err = path.Init(reader);
867             SuccessOrExit(err);
868
869             PRETTY_PRINT_INCDEPTH();
870             err = path.CheckSchemaValidity();
871             SuccessOrExit(err);
872             PRETTY_PRINT_DECDEPTH();
873         }
874
875         ++NumPath;
876     }
877
878     PRETTY_PRINT("],");
879     PRETTY_PRINT("");
880
881     // if we have exhausted this container
882     if (CHIP_END_OF_TLV == err)
883     {
884         err = CHIP_NO_ERROR;
885     }
886
887 exit:
888     ChipLogFunctError(err);
889
890     return err;
891 }
892 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
893
894 EventPath::Builder & EventPathList::Builder::CreateEventPathBuilder()
895 {
896     // skip if error has already been set
897     VerifyOrExit(CHIP_NO_ERROR == mError, mEventPathBuilder.ResetError(mError));
898
899     mError = mEventPathBuilder.Init(mpWriter);
900     ChipLogFunctError(mError);
901
902 exit:
903     // on error, mPathBuilder would be un-/partial initialized and cannot be used to write anything
904     return mEventPathBuilder;
905 }
906
907 EventPathList::Builder & EventPathList::Builder::EndOfEventPathList()
908 {
909     EndOfContainer();
910
911     return *this;
912 }
913
914 CHIP_ERROR CommandPath::Parser::Init(const chip::TLV::TLVReader & aReader)
915 {
916     CHIP_ERROR err = CHIP_NO_ERROR;
917
918     // make a copy of the reader here
919     mReader.Init(aReader);
920
921     VerifyOrExit(chip::TLV::kTLVType_Path == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
922
923     // This is just a dummy, as we're not going to exit this container ever
924     chip::TLV::TLVType dummyContainerType;
925     // enter into the Path
926     err = mReader.EnterContainer(dummyContainerType);
927     SuccessOrExit(err);
928
929 exit:
930     ChipLogFunctError(err);
931
932     return err;
933 }
934
935 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
936 CHIP_ERROR CommandPath::Parser::CheckSchemaValidity() const
937 {
938     CHIP_ERROR err           = CHIP_NO_ERROR;
939     uint16_t TagPresenceMask = 0;
940     chip::TLV::TLVReader reader;
941     PRETTY_PRINT("CommandPath =");
942     PRETTY_PRINT("{");
943
944     // make a copy of the Path reader
945     reader.Init(mReader);
946
947     while (CHIP_NO_ERROR == (err = reader.Next()))
948     {
949         VerifyOrExit(chip::TLV::IsContextTag(reader.GetTag()), err = CHIP_ERROR_INVALID_TLV_TAG);
950         switch (chip::TLV::TagNumFromTag(reader.GetTag()))
951         {
952         case kCsTag_EndpointId:
953             // check if this tag has appeared before
954             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_EndpointId)), err = CHIP_ERROR_INVALID_TLV_TAG);
955             TagPresenceMask |= (1 << kCsTag_EndpointId);
956             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
957
958 #if CHIP_DETAIL_LOGGING
959             {
960                 uint16_t endpointId;
961                 reader.Get(endpointId);
962                 PRETTY_PRINT("\tEndpointId = 0x%" PRIx16 ",", endpointId);
963             }
964 #endif // CHIP_DETAIL_LOGGING
965             break;
966         case kCsTag_GroupId:
967             // check if this tag has appeared before
968             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_GroupId)), err = CHIP_ERROR_INVALID_TLV_TAG);
969             TagPresenceMask |= (1 << kCsTag_GroupId);
970             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
971 #if CHIP_DETAIL_LOGGING
972             {
973                 uint32_t groupId;
974                 reader.Get(groupId);
975                 PRETTY_PRINT("\tGroupId = 0x%" PRIx64 ",", groupId);
976             }
977 #endif // CHIP_DETAIL_LOGGING
978             break;
979         case kCsTag_NamespacedClusterId:
980             // check if this tag has appeared before
981             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_NamespacedClusterId)), err = CHIP_ERROR_INVALID_TLV_TAG);
982             TagPresenceMask |= (1 << kCsTag_NamespacedClusterId);
983             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
984 #if CHIP_DETAIL_LOGGING
985             {
986                 chip::ClusterId namespacedClusterId;
987                 reader.Get(namespacedClusterId);
988                 PRETTY_PRINT("\tNamespacedClusterId = 0x%" PRIx32 ",", namespacedClusterId);
989             }
990 #endif // CHIP_DETAIL_LOGGING
991             break;
992         case kCsTag_CommandId:
993             // check if this tag has appeared before
994             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_CommandId)), err = CHIP_ERROR_INVALID_TLV_TAG);
995             TagPresenceMask |= (1 << kCsTag_CommandId);
996             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
997 #if CHIP_DETAIL_LOGGING
998             {
999                 chip::CommandId commandId;
1000                 reader.Get(commandId);
1001                 PRETTY_PRINT("\tCommandId = 0x%" PRIx16 ",", commandId);
1002             }
1003 #endif // CHIP_DETAIL_LOGGING
1004             break;
1005         default:
1006             ExitNow(err = CHIP_ERROR_INVALID_TLV_TAG);
1007         }
1008     }
1009     PRETTY_PRINT("},");
1010     PRETTY_PRINT("");
1011     // if we have exhausted this container
1012     if (CHIP_END_OF_TLV == err)
1013     {
1014         // check for required fields:
1015         const uint16_t RequiredFields = (1 << kCsTag_CommandId) | (1 << kCsTag_NamespacedClusterId);
1016
1017         if ((TagPresenceMask & RequiredFields) == RequiredFields)
1018         {
1019             err = CHIP_NO_ERROR;
1020         }
1021         else
1022         {
1023             err = CHIP_ERROR_IM_MALFORMED_COMMAND_PATH;
1024         }
1025     }
1026     SuccessOrExit(err);
1027 exit:
1028     ChipLogFunctError(err);
1029
1030     return err;
1031 }
1032 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
1033
1034 CHIP_ERROR CommandPath::Parser::GetEndpointId(chip::EndpointId * const apEndpointID) const
1035 {
1036     return GetUnsignedInteger(kCsTag_EndpointId, apEndpointID);
1037 }
1038
1039 CHIP_ERROR CommandPath::Parser::GetGroupId(chip::GroupId * const apGroupId) const
1040 {
1041     return GetUnsignedInteger(kCsTag_GroupId, apGroupId);
1042 }
1043
1044 CHIP_ERROR CommandPath::Parser::GetNamespacedClusterId(chip::ClusterId * const apClusterId) const
1045 {
1046     return GetUnsignedInteger(kCsTag_NamespacedClusterId, apClusterId);
1047 }
1048
1049 CHIP_ERROR CommandPath::Parser::GetCommandId(chip::CommandId * const apCommandId) const
1050 {
1051     return GetUnsignedInteger(kCsTag_CommandId, apCommandId);
1052 }
1053
1054 CHIP_ERROR CommandPath::Builder::_Init(chip::TLV::TLVWriter * const apWriter, const uint64_t aTag)
1055 {
1056     mpWriter = apWriter;
1057     mError   = mpWriter->StartContainer(aTag, chip::TLV::kTLVType_Path, mOuterContainerType);
1058     SuccessOrExit(mError);
1059
1060 exit:
1061     ChipLogFunctError(mError);
1062     return mError;
1063 }
1064
1065 CHIP_ERROR CommandPath::Builder::Init(chip::TLV::TLVWriter * const apWriter)
1066 {
1067     return _Init(apWriter, chip::TLV::AnonymousTag);
1068 }
1069
1070 CHIP_ERROR CommandPath::Builder::Init(chip::TLV::TLVWriter * const apWriter, const uint8_t aContextTagToUse)
1071 {
1072     return _Init(apWriter, chip::TLV::ContextTag(aContextTagToUse));
1073 }
1074
1075 CommandPath::Builder & CommandPath::Builder::EndpointId(const chip::EndpointId aEndpointId)
1076 {
1077     // skip if error has already been set
1078     SuccessOrExit(mError);
1079
1080     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_EndpointId), aEndpointId);
1081     ChipLogFunctError(mError);
1082
1083 exit:
1084     return *this;
1085 }
1086
1087 CommandPath::Builder & CommandPath::Builder::GroupId(const chip::GroupId aGroupId)
1088 {
1089     // skip if error has already been set
1090     SuccessOrExit(mError);
1091
1092     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_GroupId), aGroupId);
1093     ChipLogFunctError(mError);
1094
1095 exit:
1096     return *this;
1097 }
1098
1099 CommandPath::Builder & CommandPath::Builder::NamespacedClusterId(const chip::ClusterId aClusterId)
1100 {
1101     // skip if error has already been set
1102     SuccessOrExit(mError);
1103
1104     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_NamespacedClusterId), aClusterId);
1105     ChipLogFunctError(mError);
1106
1107 exit:
1108     return *this;
1109 }
1110
1111 CommandPath::Builder & CommandPath::Builder::CommandId(const chip::CommandId aCommandId)
1112 {
1113     // skip if error has already been set
1114     SuccessOrExit(mError);
1115
1116     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_CommandId), aCommandId);
1117     ChipLogFunctError(mError);
1118
1119 exit:
1120     return *this;
1121 }
1122
1123 CommandPath::Builder & CommandPath::Builder::EndOfCommandPath()
1124 {
1125     EndOfContainer();
1126     return *this;
1127 }
1128
1129 CHIP_ERROR EventDataElement::Parser::Init(const chip::TLV::TLVReader & aReader)
1130 {
1131     CHIP_ERROR err = CHIP_NO_ERROR;
1132
1133     // make a copy of the reader here
1134     mReader.Init(aReader);
1135
1136     VerifyOrExit(chip::TLV::kTLVType_Structure == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1137
1138     // This is just a dummy, as we're not going to exit this container ever
1139     chip::TLV::TLVType OuterContainerType;
1140     err = mReader.EnterContainer(OuterContainerType);
1141
1142 exit:
1143     ChipLogFunctError(err);
1144
1145     return err;
1146 }
1147
1148 CHIP_ERROR
1149 EventDataElement::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) const
1150 {
1151     CHIP_ERROR err = CHIP_NO_ERROR;
1152
1153     if (aDepth == 0)
1154     {
1155         PRETTY_PRINT("EventData = ");
1156     }
1157     else
1158     {
1159         if (chip::TLV::IsContextTag(aReader.GetTag()))
1160         {
1161             PRETTY_PRINT("0x%" PRIx32 " = ", chip::TLV::TagNumFromTag(aReader.GetTag()));
1162         }
1163         else if (chip::TLV::IsProfileTag(aReader.GetTag()))
1164         {
1165             PRETTY_PRINT("0x%" PRIx32 "::0x%" PRIx32 " = ", chip::TLV::ProfileIdFromTag(aReader.GetTag()),
1166                          chip::TLV::TagNumFromTag(aReader.GetTag()));
1167         }
1168         else
1169         {
1170             // Anonymous tag, don't print anything
1171         }
1172     }
1173
1174     switch (aReader.GetType())
1175     {
1176     case chip::TLV::kTLVType_Structure:
1177         PRETTY_PRINT("{");
1178         break;
1179
1180     case chip::TLV::kTLVType_Array:
1181         PRETTY_PRINT_SAMELINE("[");
1182         PRETTY_PRINT("\t\t");
1183         break;
1184
1185     case chip::TLV::kTLVType_SignedInteger: {
1186         int64_t value_s64;
1187
1188         err = aReader.Get(value_s64);
1189         SuccessOrExit(err);
1190
1191         PRETTY_PRINT_SAMELINE("%" PRId64 ", ", value_s64);
1192         break;
1193     }
1194
1195     case chip::TLV::kTLVType_UnsignedInteger: {
1196         uint64_t value_u64;
1197
1198         err = aReader.Get(value_u64);
1199         SuccessOrExit(err);
1200
1201         PRETTY_PRINT_SAMELINE("%" PRIu64 ", ", value_u64);
1202         break;
1203     }
1204
1205     case chip::TLV::kTLVType_Boolean: {
1206         bool value_b;
1207
1208         err = aReader.Get(value_b);
1209         SuccessOrExit(err);
1210
1211         PRETTY_PRINT_SAMELINE("%s, ", value_b ? "true" : "false");
1212         break;
1213     }
1214
1215     case chip::TLV::kTLVType_UTF8String: {
1216         char value_s[256];
1217
1218         err = aReader.GetString(value_s, sizeof(value_s));
1219         VerifyOrExit(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, );
1220
1221         if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
1222         {
1223             PRETTY_PRINT_SAMELINE("... (byte string too long) ...");
1224             err = CHIP_NO_ERROR;
1225         }
1226         else
1227         {
1228             PRETTY_PRINT_SAMELINE("\"%s\", ", value_s);
1229         }
1230         break;
1231     }
1232
1233     case chip::TLV::kTLVType_ByteString: {
1234         uint8_t value_b[256];
1235         uint32_t len, readerLen;
1236
1237         readerLen = aReader.GetLength();
1238
1239         err = aReader.GetBytes(value_b, sizeof(value_b));
1240         VerifyOrExit(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, );
1241
1242         PRETTY_PRINT_SAMELINE("[");
1243         PRETTY_PRINT("\t\t");
1244
1245         if (readerLen < sizeof(value_b))
1246         {
1247             len = readerLen;
1248         }
1249         else
1250         {
1251             len = sizeof(value_b);
1252         }
1253
1254         if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
1255         {
1256             PRETTY_PRINT_SAMELINE("... (byte string too long) ...");
1257         }
1258         else
1259         {
1260             for (size_t i = 0; i < len; i++)
1261             {
1262                 PRETTY_PRINT_SAMELINE("0x%" PRIx8 ", ", value_b[i]);
1263             }
1264         }
1265
1266         err = CHIP_NO_ERROR;
1267         PRETTY_PRINT("\t\t]");
1268         break;
1269     }
1270
1271     case chip::TLV::kTLVType_Null:
1272         PRETTY_PRINT_SAMELINE("NULL");
1273         break;
1274
1275     default:
1276         PRETTY_PRINT_SAMELINE("--");
1277         break;
1278     }
1279
1280     if (aReader.GetType() == chip::TLV::kTLVType_Structure || aReader.GetType() == chip::TLV::kTLVType_Array)
1281     {
1282         const char terminating_char = (aReader.GetType() == chip::TLV::kTLVType_Structure) ? '}' : ']';
1283         chip::TLV::TLVType type;
1284
1285         IgnoreUnusedVariable(terminating_char);
1286
1287         err = aReader.EnterContainer(type);
1288         SuccessOrExit(err);
1289
1290         while ((err = aReader.Next()) == CHIP_NO_ERROR)
1291         {
1292             PRETTY_PRINT_INCDEPTH();
1293
1294             err = ParseData(aReader, aDepth + 1);
1295             SuccessOrExit(err);
1296
1297             PRETTY_PRINT_DECDEPTH();
1298         }
1299
1300         PRETTY_PRINT("%c,", terminating_char);
1301
1302         err = aReader.ExitContainer(type);
1303         SuccessOrExit(err);
1304     }
1305
1306 exit:
1307     ChipLogFunctError(err);
1308     return err;
1309 }
1310
1311 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
1312 CHIP_ERROR EventDataElement::Parser::CheckSchemaValidity() const
1313 {
1314     CHIP_ERROR err           = CHIP_NO_ERROR;
1315     uint16_t TagPresenceMask = 0;
1316     chip::TLV::TLVReader reader;
1317
1318     PRETTY_PRINT("EventDataElement =");
1319     PRETTY_PRINT("{");
1320
1321     // make a copy of the Path reader
1322     reader.Init(mReader);
1323
1324     while (CHIP_NO_ERROR == (err = reader.Next()))
1325     {
1326         VerifyOrExit(chip::TLV::IsContextTag(reader.GetTag()), err = CHIP_ERROR_INVALID_TLV_TAG);
1327         switch (chip::TLV::TagNumFromTag(reader.GetTag()))
1328         {
1329         case kCsTag_EventPath:
1330             // check if this tag has appeared before
1331             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_EventPath)), err = CHIP_ERROR_INVALID_TLV_TAG);
1332             TagPresenceMask |= (1 << kCsTag_EventPath);
1333
1334             VerifyOrExit(chip::TLV::kTLVType_Path == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1335
1336 #if CHIP_DETAIL_LOGGING
1337             {
1338                 EventPath::Parser path;
1339                 err = path.Init(reader);
1340                 SuccessOrExit(err);
1341
1342                 PRETTY_PRINT_INCDEPTH();
1343                 err = path.CheckSchemaValidity();
1344                 SuccessOrExit(err);
1345                 PRETTY_PRINT_DECDEPTH();
1346             }
1347 #endif // CHIP_DETAIL_LOGGING
1348             break;
1349         case kCsTag_ImportanceLevel:
1350             // check if this tag has appeared before
1351             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_ImportanceLevel)), err = CHIP_ERROR_INVALID_TLV_TAG);
1352             TagPresenceMask |= (1 << kCsTag_ImportanceLevel);
1353             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1354
1355 #if CHIP_DETAIL_LOGGING
1356             {
1357                 uint64_t value;
1358                 err = reader.Get(value);
1359                 SuccessOrExit(err);
1360
1361                 PRETTY_PRINT("\tImportanceLevel = 0x%" PRIx64 ",", value);
1362             }
1363 #endif // CHIP_DETAIL_LOGGING
1364             break;
1365         case kCsTag_Number:
1366             // check if this tag has appeared before
1367             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_Number)), err = CHIP_ERROR_INVALID_TLV_TAG);
1368             TagPresenceMask |= (1 << kCsTag_Number);
1369
1370             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1371
1372 #if CHIP_DETAIL_LOGGING
1373             {
1374                 uint64_t value;
1375                 err = reader.Get(value);
1376                 SuccessOrExit(err);
1377
1378                 PRETTY_PRINT("\tNumber = 0x%" PRIx64 ",", value);
1379             }
1380 #endif // CHIP_DETAIL_LOGGING
1381             break;
1382         case kCsTag_UTCTimestamp:
1383             // check if this tag has appeared before
1384             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_UTCTimestamp)), err = CHIP_ERROR_INVALID_TLV_TAG);
1385             TagPresenceMask |= (1 << kCsTag_UTCTimestamp);
1386
1387             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1388
1389 #if CHIP_DETAIL_LOGGING
1390             {
1391                 uint64_t value;
1392                 err = reader.Get(value);
1393                 SuccessOrExit(err);
1394
1395                 PRETTY_PRINT("\tUTCTimestamp = 0x%" PRIx64 ",", value);
1396             }
1397 #endif // CHIP_DETAIL_LOGGING
1398             break;
1399
1400         case kCsTag_SystemTimestamp:
1401             // check if this tag has appeared before
1402             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_SystemTimestamp)), err = CHIP_ERROR_INVALID_TLV_TAG);
1403             TagPresenceMask |= (1 << kCsTag_SystemTimestamp);
1404
1405             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1406
1407 #if CHIP_DETAIL_LOGGING
1408             {
1409                 uint64_t value;
1410                 err = reader.Get(value);
1411                 SuccessOrExit(err);
1412
1413                 PRETTY_PRINT("\tSystemTimestamp = 0x%" PRIx64 ",", value);
1414             }
1415 #endif // CHIP_DETAIL_LOGGING
1416             break;
1417         case kCsTag_DeltaUTCTimestamp:
1418             // check if this tag has appeared before
1419             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_DeltaUTCTimestamp)), err = CHIP_ERROR_INVALID_TLV_TAG);
1420             TagPresenceMask |= (1 << kCsTag_DeltaUTCTimestamp);
1421
1422             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1423
1424 #if CHIP_DETAIL_LOGGING
1425             {
1426                 uint64_t value;
1427                 err = reader.Get(value);
1428                 SuccessOrExit(err);
1429
1430                 PRETTY_PRINT("\tDeltaUTCTimestamp= 0x%" PRIx64 ",", value);
1431             }
1432 #endif // CHIP_DETAIL_LOGGING
1433             break;
1434         case kCsTag_DeltaSystemTimestamp:
1435             // check if this tag has appeared before
1436             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_DeltaSystemTimestamp)), err = CHIP_ERROR_INVALID_TLV_TAG);
1437             TagPresenceMask |= (1 << kCsTag_DeltaSystemTimestamp);
1438
1439             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1440
1441 #if CHIP_DETAIL_LOGGING
1442             {
1443                 uint64_t value;
1444                 err = reader.Get(value);
1445                 SuccessOrExit(err);
1446
1447                 PRETTY_PRINT("\tDeltaSystemTimestamp= 0x%" PRIx64 ",", value);
1448             }
1449 #endif // CHIP_DETAIL_LOGGING
1450             break;
1451         case kCsTag_Data:
1452             // check if this tag has appeared before
1453             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_Data)), err = CHIP_ERROR_INVALID_TLV_TAG);
1454             TagPresenceMask |= (1 << kCsTag_Data);
1455
1456             PRETTY_PRINT_INCDEPTH();
1457             err = ParseData(reader, 0);
1458             SuccessOrExit(err);
1459             PRETTY_PRINT_DECDEPTH();
1460             break;
1461         default:
1462             ExitNow(err = CHIP_ERROR_INVALID_TLV_TAG);
1463         }
1464     }
1465     PRETTY_PRINT("},");
1466     PRETTY_PRINT("");
1467     // if we have exhausted this container
1468     if (CHIP_END_OF_TLV == err)
1469     {
1470         // check for required fields:
1471         const uint16_t RequiredFields =
1472             (1 << kCsTag_EventPath) | (1 << kCsTag_ImportanceLevel) | (1 << kCsTag_Number) | (1 << kCsTag_Data);
1473
1474         if ((TagPresenceMask & RequiredFields) == RequiredFields)
1475         {
1476             err = CHIP_NO_ERROR;
1477         }
1478         else
1479         {
1480             err = CHIP_ERROR_IM_MALFORMED_EVENT_DATA_ELEMENT;
1481         }
1482     }
1483     SuccessOrExit(err);
1484
1485 exit:
1486     ChipLogFunctError(err);
1487
1488     return err;
1489 }
1490 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
1491
1492 CHIP_ERROR EventDataElement::Parser::GetEventPath(EventPath::Parser * const apEventPath)
1493 {
1494     CHIP_ERROR err = CHIP_NO_ERROR;
1495     chip::TLV::TLVReader reader;
1496
1497     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_EventPath), reader);
1498     SuccessOrExit(err);
1499
1500     VerifyOrExit(chip::TLV::kTLVType_Path == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1501
1502     err = apEventPath->Init(reader);
1503     SuccessOrExit(err);
1504
1505 exit:
1506     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
1507
1508     return err;
1509 }
1510
1511 CHIP_ERROR EventDataElement::Parser::GetImportanceLevel(uint8_t * const apImportanceLevel)
1512 {
1513     return GetUnsignedInteger(kCsTag_ImportanceLevel, apImportanceLevel);
1514 }
1515
1516 CHIP_ERROR EventDataElement::Parser::GetNumber(uint64_t * const apNumber)
1517 {
1518     return GetUnsignedInteger(kCsTag_Number, apNumber);
1519 }
1520
1521 CHIP_ERROR EventDataElement::Parser::GetUTCTimestamp(uint64_t * const apUTCTimestamp)
1522 {
1523     return GetUnsignedInteger(kCsTag_UTCTimestamp, apUTCTimestamp);
1524 }
1525
1526 CHIP_ERROR EventDataElement::Parser::GetSystemTimestamp(uint64_t * const apSystemTimestamp)
1527 {
1528     return GetUnsignedInteger(kCsTag_SystemTimestamp, apSystemTimestamp);
1529 }
1530
1531 CHIP_ERROR EventDataElement::Parser::GetDeltaUTCTime(uint64_t * const apDeltaUTCTimestamp)
1532 {
1533     return GetUnsignedInteger(kCsTag_DeltaUTCTimestamp, apDeltaUTCTimestamp);
1534 }
1535
1536 CHIP_ERROR EventDataElement::Parser::GetDeltaSystemTime(uint64_t * const apDeltaSystemTimestamp)
1537 {
1538     return GetUnsignedInteger(kCsTag_DeltaSystemTimestamp, apDeltaSystemTimestamp);
1539 }
1540
1541 CHIP_ERROR EventDataElement::Parser::GetData(chip::TLV::TLVReader * const apReader) const
1542 {
1543     CHIP_ERROR err = CHIP_NO_ERROR;
1544
1545     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_Data), *apReader);
1546     ChipLogFunctError(err);
1547
1548     return err;
1549 }
1550
1551 CHIP_ERROR EventDataElement::Builder::Init(chip::TLV::TLVWriter * const apWriter)
1552 {
1553     return InitAnonymousStructure(apWriter);
1554 }
1555
1556 EventPath::Builder & EventDataElement::Builder::CreateEventPathBuilder()
1557 {
1558     // skip if error has already been set
1559     VerifyOrExit(CHIP_NO_ERROR == mError, mEventPathBuilder.ResetError(mError));
1560
1561     mError = mEventPathBuilder.Init(mpWriter, kCsTag_EventPath);
1562     ChipLogFunctError(mError);
1563
1564 exit:
1565     return mEventPathBuilder;
1566 }
1567
1568 EventDataElement::Builder EventDataElement::Builder::ImportanceLevel(const uint8_t aImportanceLevel)
1569 {
1570     // skip if error has already been set
1571     SuccessOrExit(mError);
1572
1573     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_ImportanceLevel), aImportanceLevel);
1574     ChipLogFunctError(mError);
1575
1576 exit:
1577     return *this;
1578 }
1579
1580 EventDataElement::Builder EventDataElement::Builder::Number(const uint64_t aNumber)
1581 {
1582     // skip if error has already been set
1583     SuccessOrExit(mError);
1584
1585     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_Number), aNumber);
1586     ChipLogFunctError(mError);
1587
1588 exit:
1589     return *this;
1590 }
1591
1592 EventDataElement::Builder EventDataElement::Builder::UTCTimestamp(const uint64_t aUTCTimestamp)
1593 {
1594     // skip if error has already been set
1595     SuccessOrExit(mError);
1596
1597     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_UTCTimestamp), aUTCTimestamp);
1598     ChipLogFunctError(mError);
1599
1600 exit:
1601     return *this;
1602 }
1603
1604 EventDataElement::Builder EventDataElement::Builder::SystemTimestamp(const uint64_t aSystemTimestamp)
1605 {
1606     // skip if error has already been set
1607     SuccessOrExit(mError);
1608
1609     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_SystemTimestamp), aSystemTimestamp);
1610     ChipLogFunctError(mError);
1611
1612 exit:
1613     return *this;
1614 }
1615
1616 EventDataElement::Builder EventDataElement::Builder::DeltaUTCTime(const uint64_t aDeltaUTCTimestamp)
1617 {
1618     // skip if error has already been set
1619     SuccessOrExit(mError);
1620
1621     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_DeltaUTCTimestamp), aDeltaUTCTimestamp);
1622     ChipLogFunctError(mError);
1623
1624 exit:
1625     return *this;
1626 }
1627
1628 EventDataElement::Builder EventDataElement::Builder::DeltaSystemTime(const uint64_t aDeltaSystemTimestamp)
1629 {
1630     // skip if error has already been set
1631     SuccessOrExit(mError);
1632
1633     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_DeltaSystemTimestamp), aDeltaSystemTimestamp);
1634     ChipLogFunctError(mError);
1635
1636 exit:
1637     return *this;
1638 }
1639
1640 // Mark the end of this element and recover the type for outer container
1641 EventDataElement::Builder & EventDataElement::Builder::EndOfEventDataElement()
1642 {
1643     EndOfContainer();
1644     return *this;
1645 }
1646
1647 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
1648 CHIP_ERROR EventList::Parser::CheckSchemaValidity() const
1649 {
1650     CHIP_ERROR err        = CHIP_NO_ERROR;
1651     size_t NumDataElement = 0;
1652     chip::TLV::TLVReader reader;
1653
1654     PRETTY_PRINT("EventList =");
1655     PRETTY_PRINT("[");
1656
1657     // make a copy of the EventList reader
1658     reader.Init(mReader);
1659
1660     while (CHIP_NO_ERROR == (err = reader.Next()))
1661     {
1662         VerifyOrExit(chip::TLV::AnonymousTag == reader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG);
1663         VerifyOrExit(chip::TLV::kTLVType_Structure == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1664
1665         {
1666             EventDataElement::Parser event;
1667             err = event.Init(reader);
1668             SuccessOrExit(err);
1669
1670             PRETTY_PRINT_INCDEPTH();
1671             err = event.CheckSchemaValidity();
1672             SuccessOrExit(err);
1673             PRETTY_PRINT_DECDEPTH();
1674         }
1675
1676         ++NumDataElement;
1677     }
1678
1679     PRETTY_PRINT("],");
1680     PRETTY_PRINT("");
1681
1682     // if we have exhausted this container
1683     if (CHIP_END_OF_TLV == err)
1684     {
1685         // if we have at least one data element
1686         if (NumDataElement > 0)
1687         {
1688             err = CHIP_NO_ERROR;
1689         }
1690         // NOTE: temporarily disable this check, to allow test to continue
1691         else
1692         {
1693             ChipLogError(DataManagement, "PROTOCOL ERROR: Empty event list");
1694             err = CHIP_NO_ERROR;
1695         }
1696     }
1697
1698 exit:
1699     ChipLogFunctError(err);
1700
1701     return err;
1702 }
1703 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
1704
1705 EventDataElement::Builder & EventList::Builder::CreateEventBuilder()
1706 {
1707     // skip if error has already been set
1708     VerifyOrExit(CHIP_NO_ERROR == mError, mEventDataElementBuilder.ResetError(mError));
1709
1710     mError = mEventDataElementBuilder.Init(mpWriter);
1711     ChipLogFunctError(mError);
1712
1713 exit:
1714     // on error, mEventDataElementBuilder would be un-/partial initialized and cannot be used to write anything
1715     return mEventDataElementBuilder;
1716 }
1717
1718 EventList::Builder & EventList::Builder::EndOfEventList()
1719 {
1720     EndOfContainer();
1721     return *this;
1722 }
1723
1724 CHIP_ERROR StatusElement::Parser::Init(const chip::TLV::TLVReader & aReader)
1725 {
1726     CHIP_ERROR err = CHIP_NO_ERROR;
1727
1728     // make a copy of the reader here
1729     mReader.Init(aReader);
1730     VerifyOrExit(chip::TLV::kTLVType_Array == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1731
1732     // This is just a dummy, as we're not going to exit this container ever
1733     chip::TLV::TLVType OuterContainerType;
1734     err = mReader.EnterContainer(OuterContainerType);
1735
1736 exit:
1737     ChipLogFunctError(err);
1738     return err;
1739 }
1740
1741 CHIP_ERROR StatusElement::Parser::DecodeStatusElement(uint16_t * apGeneralCode, uint32_t * apProtocolId, uint16_t * apProtocolCode,
1742                                                       chip::ClusterId * apClusterId) const
1743 {
1744     CHIP_ERROR err = CHIP_NO_ERROR;
1745     chip::TLV::TLVReader lReader;
1746
1747     lReader.Init(mReader);
1748
1749     err = lReader.Next();
1750     SuccessOrExit(err);
1751     VerifyOrExit(lReader.GetType() == chip::TLV::kTLVType_UnsignedInteger, err = CHIP_ERROR_WRONG_TLV_TYPE);
1752     err = lReader.Get(*apGeneralCode);
1753     SuccessOrExit(err);
1754
1755     err = lReader.Next();
1756     SuccessOrExit(err);
1757     VerifyOrExit(lReader.GetType() == chip::TLV::kTLVType_UnsignedInteger, err = CHIP_ERROR_WRONG_TLV_TYPE);
1758     err = lReader.Get(*apProtocolId);
1759     SuccessOrExit(err);
1760
1761     err = lReader.Next();
1762     SuccessOrExit(err);
1763     VerifyOrExit(lReader.GetType() == chip::TLV::kTLVType_UnsignedInteger, err = CHIP_ERROR_WRONG_TLV_TYPE);
1764     err = lReader.Get(*apProtocolCode);
1765     SuccessOrExit(err);
1766
1767     err = lReader.Next();
1768     SuccessOrExit(err);
1769     VerifyOrExit(lReader.GetType() == chip::TLV::kTLVType_UnsignedInteger, err = CHIP_ERROR_WRONG_TLV_TYPE);
1770     err = lReader.Get(*apClusterId);
1771     SuccessOrExit(err);
1772
1773 exit:
1774     ChipLogFunctError(err);
1775     return err;
1776 }
1777
1778 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
1779 CHIP_ERROR StatusElement::Parser::CheckSchemaValidity() const
1780 {
1781     CHIP_ERROR err           = CHIP_NO_ERROR;
1782     uint16_t TagPresenceMask = 0;
1783     chip::TLV::TLVReader reader;
1784
1785     PRETTY_PRINT("StatusElement =");
1786     PRETTY_PRINT("{");
1787
1788     // make a copy of the reader
1789     reader.Init(mReader);
1790
1791     while (CHIP_NO_ERROR == (err = reader.Next()))
1792     {
1793         // This is an array; all elements are anonymous.
1794         VerifyOrExit(chip::TLV::AnonymousTag == reader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG);
1795
1796         if (!(TagPresenceMask & (1 << kCsTag_GeneralCode)))
1797         {
1798             TagPresenceMask |= (1 << kCsTag_GeneralCode);
1799             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1800
1801 #if CHIP_DETAIL_LOGGING
1802             {
1803                 uint16_t generalCode;
1804                 err = reader.Get(generalCode);
1805                 SuccessOrExit(err);
1806
1807                 PRETTY_PRINT("\tGeneralCode = 0x%" PRIx16 ",", generalCode);
1808             }
1809 #endif // CHIP_DETAIL_LOGGING
1810         }
1811         else if (!(TagPresenceMask & (1 << kCsTag_ProtocolId)))
1812         {
1813             TagPresenceMask |= (1 << kCsTag_ProtocolId);
1814             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1815
1816 #if CHIP_DETAIL_LOGGING
1817             {
1818                 uint32_t kCsTag_ProtocolId;
1819                 err = reader.Get(kCsTag_ProtocolId);
1820                 SuccessOrExit(err);
1821
1822                 PRETTY_PRINT("\tProtocolId = 0x%" PRIx32 ",", kCsTag_ProtocolId);
1823             }
1824 #endif // CHIP_DETAIL_LOGGING
1825         }
1826         else if (!(TagPresenceMask & (1 << kCsTag_ProtocolCode)))
1827         {
1828             TagPresenceMask |= (1 << kCsTag_ProtocolCode);
1829             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1830
1831 #if CHIP_DETAIL_LOGGING
1832             {
1833                 uint16_t protocolCode;
1834                 err = reader.Get(protocolCode);
1835                 SuccessOrExit(err);
1836
1837                 PRETTY_PRINT("\tprotocolCode = 0x%" PRIx16 ",", protocolCode);
1838             }
1839 #endif // CHIP_DETAIL_LOGGING
1840         }
1841         else if (!(TagPresenceMask & (1 << kCsTag_NamespacedClusterId)))
1842         {
1843             TagPresenceMask |= (1 << kCsTag_NamespacedClusterId);
1844
1845             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1846
1847 #if CHIP_DETAIL_LOGGING
1848             {
1849                 chip::ClusterId namespacedClusterId;
1850                 err = reader.Get(namespacedClusterId);
1851                 SuccessOrExit(err);
1852
1853                 PRETTY_PRINT("\tNamespacedClusterId = 0x%" PRIx32 ",", namespacedClusterId);
1854             }
1855 #endif // CHIP_DETAIL_LOGGING
1856         }
1857         else
1858         {
1859             PRETTY_PRINT("\tExtra element in StatusElement");
1860         }
1861     }
1862
1863     PRETTY_PRINT("},");
1864     PRETTY_PRINT("");
1865     // if we have exhausted this container
1866     if (CHIP_END_OF_TLV == err)
1867     {
1868         // check for required fields:
1869         const uint16_t RequiredFields = (1 << kCsTag_GeneralCode) | (1 << kCsTag_ProtocolId) | (1 << kCsTag_ProtocolCode);
1870
1871         if ((TagPresenceMask & RequiredFields) == RequiredFields)
1872         {
1873             err = CHIP_NO_ERROR;
1874         }
1875         else
1876         {
1877             err = CHIP_ERROR_IM_MALFORMED_STATUS_CODE;
1878         }
1879     }
1880
1881 exit:
1882     ChipLogFunctError(err);
1883
1884     return err;
1885 }
1886 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
1887
1888 CHIP_ERROR StatusElement::Builder::Init(chip::TLV::TLVWriter * const apWriter)
1889 {
1890     return ListBuilder::Init(apWriter);
1891 }
1892
1893 CHIP_ERROR StatusElement::Builder::Init(chip::TLV::TLVWriter * const apWriter, const uint8_t aContextTagToUse)
1894 {
1895     return ListBuilder::Init(apWriter, aContextTagToUse);
1896 }
1897
1898 StatusElement::Builder & StatusElement::Builder::EncodeStatusElement(const uint16_t aGeneralCode, const uint32_t aProtocolId,
1899                                                                      const uint16_t aStatusElement,
1900                                                                      const chip::ClusterId aNamespacedClusterId)
1901 {
1902     uint64_t tag = chip::TLV::AnonymousTag;
1903
1904     SuccessOrExit(mError);
1905
1906     mError = mpWriter->Put(tag, aGeneralCode);
1907     SuccessOrExit(mError);
1908
1909     mError = mpWriter->Put(tag, aProtocolId);
1910     SuccessOrExit(mError);
1911
1912     mError = mpWriter->Put(tag, aStatusElement);
1913     SuccessOrExit(mError);
1914
1915     mError = mpWriter->Put(tag, aNamespacedClusterId);
1916     SuccessOrExit(mError);
1917
1918 exit:
1919     ChipLogFunctError(mError);
1920     return *this;
1921 }
1922
1923 StatusElement::Builder & StatusElement::Builder::EndOfStatusElement()
1924 {
1925     EndOfContainer();
1926     return *this;
1927 }
1928
1929 CHIP_ERROR AttributeStatusElement::Builder::Init(chip::TLV::TLVWriter * const apWriter)
1930 {
1931     return InitAnonymousStructure(apWriter);
1932 }
1933
1934 AttributePath::Builder & AttributeStatusElement::Builder::CreateAttributePathBuilder()
1935 {
1936     // skip if error has already been set
1937     VerifyOrExit(CHIP_NO_ERROR == mError, mAttributePathBuilder.ResetError(mError));
1938
1939     mError = mAttributePathBuilder.Init(mpWriter, kCsTag_AttributePath);
1940
1941 exit:
1942     ChipLogFunctError(mError);
1943     return mAttributePathBuilder;
1944 }
1945
1946 StatusElement::Builder & AttributeStatusElement::Builder::CreateStatusElementBuilder()
1947 {
1948     // skip if error has already been set
1949     VerifyOrExit(CHIP_NO_ERROR == mError, mStatusElementBuilder.ResetError(mError));
1950
1951     mError = mStatusElementBuilder.Init(mpWriter, kCsTag_StatusElement);
1952
1953 exit:
1954     ChipLogFunctError(mError);
1955     return mStatusElementBuilder;
1956 }
1957
1958 AttributeStatusElement::Builder & AttributeStatusElement::Builder::EndOfAttributeStatusElement()
1959 {
1960     EndOfContainer();
1961     return *this;
1962 }
1963
1964 CHIP_ERROR AttributeStatusElement::Parser::Init(const chip::TLV::TLVReader & aReader)
1965 {
1966     CHIP_ERROR err = CHIP_NO_ERROR;
1967
1968     // make a copy of the reader here
1969     mReader.Init(aReader);
1970     VerifyOrExit(chip::TLV::kTLVType_Structure == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
1971
1972     // This is just a dummy, as we're not going to exit this container ever
1973     chip::TLV::TLVType OuterContainerType;
1974     err = mReader.EnterContainer(OuterContainerType);
1975
1976 exit:
1977     ChipLogFunctError(err);
1978     return err;
1979 }
1980
1981 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
1982 CHIP_ERROR AttributeStatusElement::Parser::CheckSchemaValidity() const
1983 {
1984     CHIP_ERROR err           = CHIP_NO_ERROR;
1985     uint16_t TagPresenceMask = 0;
1986     chip::TLV::TLVReader reader;
1987
1988     PRETTY_PRINT("AttributeStatusElement =");
1989     PRETTY_PRINT("{");
1990
1991     // make a copy of the reader
1992     reader.Init(mReader);
1993
1994     while (CHIP_NO_ERROR == (err = reader.Next()))
1995     {
1996         VerifyOrExit(chip::TLV::IsContextTag(reader.GetTag()), err = CHIP_ERROR_INVALID_TLV_TAG);
1997         switch (chip::TLV::TagNumFromTag(reader.GetTag()))
1998         {
1999         case kCsTag_AttributePath:
2000             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_AttributePath)), err = CHIP_ERROR_INVALID_TLV_TAG);
2001             TagPresenceMask |= (1 << kCsTag_AttributePath);
2002             {
2003                 AttributePath::Parser path;
2004                 err = path.Init(reader);
2005                 SuccessOrExit(err);
2006
2007                 PRETTY_PRINT_INCDEPTH();
2008                 err = path.CheckSchemaValidity();
2009                 SuccessOrExit(err);
2010                 PRETTY_PRINT_DECDEPTH();
2011             }
2012             break;
2013         case kCsTag_StatusElement:
2014             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_StatusElement)), err = CHIP_ERROR_INVALID_TLV_TAG);
2015             TagPresenceMask |= (1 << kCsTag_StatusElement);
2016             {
2017                 StatusElement::Parser status;
2018                 err = status.Init(reader);
2019                 SuccessOrExit(err);
2020
2021                 PRETTY_PRINT_INCDEPTH();
2022                 err = status.CheckSchemaValidity();
2023                 SuccessOrExit(err);
2024                 PRETTY_PRINT_DECDEPTH();
2025             }
2026             break;
2027         default:
2028             ExitNow(err = CHIP_ERROR_INVALID_TLV_TAG);
2029         }
2030     }
2031
2032     PRETTY_PRINT("},");
2033     PRETTY_PRINT("");
2034
2035     // if we have exhausted this container
2036     if (CHIP_END_OF_TLV == err)
2037     {
2038         // check for required fields:
2039         const uint16_t RequiredFields = (1 << kCsTag_AttributePath) | (1 << kCsTag_StatusElement);
2040
2041         if ((TagPresenceMask & RequiredFields) == RequiredFields)
2042         {
2043             err = CHIP_NO_ERROR;
2044         }
2045         else
2046         {
2047             err = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_STATUS_ELEMENT;
2048         }
2049     }
2050
2051 exit:
2052     ChipLogFunctError(err);
2053
2054     return err;
2055 }
2056 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
2057
2058 CHIP_ERROR AttributeStatusElement::Parser::GetAttributePath(AttributePath::Parser * const apAttributePath) const
2059 {
2060     CHIP_ERROR err = CHIP_NO_ERROR;
2061     chip::TLV::TLVReader reader;
2062
2063     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_AttributePath), reader);
2064     SuccessOrExit(err);
2065
2066     VerifyOrExit(chip::TLV::kTLVType_Path == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2067
2068     err = apAttributePath->Init(reader);
2069     SuccessOrExit(err);
2070
2071 exit:
2072     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
2073
2074     return err;
2075 }
2076
2077 CHIP_ERROR AttributeStatusElement::Parser::GetStatusElement(StatusElement::Parser * const apStatusElement) const
2078 {
2079     CHIP_ERROR err = CHIP_NO_ERROR;
2080     chip::TLV::TLVReader reader;
2081
2082     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_StatusElement), reader);
2083     SuccessOrExit(err);
2084
2085     VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2086
2087     err = apStatusElement->Init(reader);
2088     SuccessOrExit(err);
2089
2090 exit:
2091     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
2092
2093     return err;
2094 }
2095
2096 AttributeStatusElement::Builder & AttributeStatusList::Builder::CreateAttributeStatusBuilder()
2097 {
2098     // skip if error has already been set
2099     VerifyOrExit(CHIP_NO_ERROR == mError, mAttributeStatusBuilder.ResetError(mError));
2100
2101     mError = mAttributeStatusBuilder.Init(mpWriter);
2102     ChipLogFunctError(mError);
2103
2104 exit:
2105     // on error, mAttributeStatusBuilder would be un-/partial initialized and cannot be used to write anything
2106     return mAttributeStatusBuilder;
2107 }
2108
2109 AttributeStatusList::Builder & AttributeStatusList::Builder::EndOfAttributeStatusList()
2110 {
2111     EndOfContainer();
2112     return *this;
2113 }
2114
2115 CHIP_ERROR AttributeStatusList::Parser::CheckSchemaValidity() const
2116 {
2117     CHIP_ERROR err                  = CHIP_NO_ERROR;
2118     size_t NumAttributeStateElement = 0;
2119     chip::TLV::TLVReader reader;
2120
2121     PRETTY_PRINT("AttributeStatusList =");
2122     PRETTY_PRINT("[");
2123
2124     // make a copy of the EventList reader
2125     reader.Init(mReader);
2126
2127     while (CHIP_NO_ERROR == (err = reader.Next()))
2128     {
2129         VerifyOrExit(chip::TLV::AnonymousTag == reader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG);
2130         VerifyOrExit(chip::TLV::kTLVType_Structure == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2131
2132         {
2133             AttributeStatusElement::Parser status;
2134             err = status.Init(reader);
2135             SuccessOrExit(err);
2136
2137             PRETTY_PRINT_INCDEPTH();
2138             err = status.CheckSchemaValidity();
2139             SuccessOrExit(err);
2140             PRETTY_PRINT_DECDEPTH();
2141         }
2142
2143         ++NumAttributeStateElement;
2144     }
2145
2146     PRETTY_PRINT("],");
2147     PRETTY_PRINT("");
2148     // if we have exhausted this container
2149     if (CHIP_END_OF_TLV == err)
2150     {
2151         // if we have at least one data element
2152         if (NumAttributeStateElement > 0)
2153         {
2154             err = CHIP_NO_ERROR;
2155         }
2156         // NOTE: temporarily disable this check, to allow test to continue
2157         else
2158         {
2159             ChipLogError(DataManagement, "PROTOCOL ERROR: Empty attribute status list");
2160             err = CHIP_NO_ERROR;
2161         }
2162     }
2163
2164 exit:
2165     ChipLogFunctError(err);
2166
2167     return err;
2168 }
2169
2170 CHIP_ERROR AttributeDataElement::Parser::Init(const chip::TLV::TLVReader & aReader)
2171 {
2172     CHIP_ERROR err = CHIP_NO_ERROR;
2173
2174     // make a copy of the reader here
2175     mReader.Init(aReader);
2176
2177     VerifyOrExit(chip::TLV::kTLVType_Structure == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2178
2179     // This is just a dummy, as we're not going to exit this container ever
2180     chip::TLV::TLVType OuterContainerType;
2181     err = mReader.EnterContainer(OuterContainerType);
2182
2183 exit:
2184     ChipLogFunctError(err);
2185
2186     return err;
2187 }
2188
2189 CHIP_ERROR
2190 AttributeDataElement::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) const
2191 {
2192     CHIP_ERROR err = CHIP_NO_ERROR;
2193
2194     if (aDepth == 0)
2195     {
2196         PRETTY_PRINT("\tData = ");
2197     }
2198     else
2199     {
2200         if (chip::TLV::IsContextTag(aReader.GetTag()))
2201         {
2202             PRETTY_PRINT("\t0x%" PRIx32 " = ", chip::TLV::TagNumFromTag(aReader.GetTag()));
2203         }
2204         else if (chip::TLV::IsProfileTag(aReader.GetTag()))
2205         {
2206             PRETTY_PRINT("\t0x%" PRIx32 "::0x%" PRIx32 " = ", chip::TLV::ProfileIdFromTag(aReader.GetTag()),
2207                          chip::TLV::TagNumFromTag(aReader.GetTag()));
2208         }
2209         else
2210         {
2211             // Anonymous tag, don't print anything
2212         }
2213     }
2214
2215     switch (aReader.GetType())
2216     {
2217     case chip::TLV::kTLVType_Structure:
2218         PRETTY_PRINT("\t{");
2219         break;
2220
2221     case chip::TLV::kTLVType_Array:
2222         PRETTY_PRINT_SAMELINE("[");
2223         PRETTY_PRINT("\t\t");
2224         break;
2225
2226     case chip::TLV::kTLVType_SignedInteger: {
2227         int64_t value_s64;
2228
2229         err = aReader.Get(value_s64);
2230         SuccessOrExit(err);
2231
2232         PRETTY_PRINT_SAMELINE("%" PRId64 ", ", value_s64);
2233         break;
2234     }
2235
2236     case chip::TLV::kTLVType_UnsignedInteger: {
2237         uint64_t value_u64;
2238
2239         err = aReader.Get(value_u64);
2240         SuccessOrExit(err);
2241
2242         PRETTY_PRINT_SAMELINE("%" PRIu64 ", ", value_u64);
2243         break;
2244     }
2245
2246     case chip::TLV::kTLVType_Boolean: {
2247         bool value_b;
2248
2249         err = aReader.Get(value_b);
2250         SuccessOrExit(err);
2251
2252         PRETTY_PRINT_SAMELINE("%s, ", value_b ? "true" : "false");
2253         break;
2254     }
2255
2256     case chip::TLV::kTLVType_UTF8String: {
2257         char value_s[256];
2258
2259         err = aReader.GetString(value_s, sizeof(value_s));
2260         VerifyOrExit(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, );
2261
2262         if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
2263         {
2264             PRETTY_PRINT_SAMELINE("... (byte string too long) ...");
2265             err = CHIP_NO_ERROR;
2266         }
2267         else
2268         {
2269             PRETTY_PRINT_SAMELINE("\"%s\", ", value_s);
2270         }
2271         break;
2272     }
2273
2274     case chip::TLV::kTLVType_ByteString: {
2275         uint8_t value_b[256];
2276         uint32_t len, readerLen;
2277
2278         readerLen = aReader.GetLength();
2279
2280         err = aReader.GetBytes(value_b, sizeof(value_b));
2281         VerifyOrExit(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, );
2282
2283         PRETTY_PRINT_SAMELINE("[");
2284         PRETTY_PRINT("\t\t");
2285
2286         if (readerLen < sizeof(value_b))
2287         {
2288             len = readerLen;
2289         }
2290         else
2291         {
2292             len = sizeof(value_b);
2293         }
2294
2295         if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
2296         {
2297             PRETTY_PRINT_SAMELINE("... (byte string too long) ...");
2298         }
2299         else
2300         {
2301             for (size_t i = 0; i < len; i++)
2302             {
2303                 PRETTY_PRINT_SAMELINE("0x%" PRIx8 ", ", value_b[i]);
2304             }
2305         }
2306
2307         err = CHIP_NO_ERROR;
2308         PRETTY_PRINT("\t]");
2309         break;
2310     }
2311
2312     case chip::TLV::kTLVType_Null:
2313         PRETTY_PRINT_SAMELINE("NULL");
2314         break;
2315
2316     default:
2317         PRETTY_PRINT_SAMELINE("--");
2318         break;
2319     }
2320
2321     if (aReader.GetType() == chip::TLV::kTLVType_Structure || aReader.GetType() == chip::TLV::kTLVType_Array)
2322     {
2323         const char terminating_char = (aReader.GetType() == chip::TLV::kTLVType_Structure) ? '}' : ']';
2324         chip::TLV::TLVType type;
2325
2326         IgnoreUnusedVariable(terminating_char);
2327
2328         err = aReader.EnterContainer(type);
2329         SuccessOrExit(err);
2330
2331         while ((err = aReader.Next()) == CHIP_NO_ERROR)
2332         {
2333             PRETTY_PRINT_INCDEPTH();
2334
2335             err = ParseData(aReader, aDepth + 1);
2336             SuccessOrExit(err);
2337
2338             PRETTY_PRINT_DECDEPTH();
2339         }
2340
2341         PRETTY_PRINT("\t%c,", terminating_char);
2342
2343         err = aReader.ExitContainer(type);
2344         SuccessOrExit(err);
2345     }
2346
2347 exit:
2348     ChipLogFunctError(err);
2349     return err;
2350 }
2351
2352 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
2353 CHIP_ERROR AttributeDataElement::Parser::CheckSchemaValidity() const
2354 {
2355     CHIP_ERROR err           = CHIP_NO_ERROR;
2356     uint16_t TagPresenceMask = 0;
2357     chip::TLV::TLVReader reader;
2358     uint32_t tagNum = 0;
2359
2360     PRETTY_PRINT("AttributeDataElement =");
2361     PRETTY_PRINT("{");
2362
2363     // make a copy of the reader
2364     reader.Init(mReader);
2365
2366     while (CHIP_NO_ERROR == (err = reader.Next()))
2367     {
2368         VerifyOrExit(chip::TLV::IsContextTag(reader.GetTag()), err = CHIP_ERROR_INVALID_TLV_TAG);
2369
2370         tagNum = chip::TLV::TagNumFromTag(reader.GetTag());
2371
2372         switch (tagNum)
2373         {
2374         case kCsTag_AttributePath:
2375             // check if this tag has appeared before
2376             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_AttributePath)), err = CHIP_ERROR_INVALID_TLV_TAG);
2377             TagPresenceMask |= (1 << kCsTag_AttributePath);
2378             VerifyOrExit(chip::TLV::kTLVType_Path == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2379
2380             {
2381                 AttributePath::Parser path;
2382                 err = path.Init(reader);
2383                 SuccessOrExit(err);
2384
2385                 PRETTY_PRINT_INCDEPTH();
2386                 err = path.CheckSchemaValidity();
2387                 SuccessOrExit(err);
2388                 PRETTY_PRINT_DECDEPTH();
2389             }
2390
2391             break;
2392         case kCsTag_DataVersion:
2393             // check if this tag has appeared before
2394             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_DataVersion)), err = CHIP_ERROR_INVALID_TLV_TAG);
2395             TagPresenceMask |= (1 << kCsTag_DataVersion);
2396             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2397
2398 #if CHIP_DETAIL_LOGGING
2399             {
2400                 chip::DataVersion version;
2401                 err = reader.Get(version);
2402                 SuccessOrExit(err);
2403
2404                 PRETTY_PRINT("\tDataElementVersion = 0x%" PRIx64 ",", version);
2405             }
2406 #endif // CHIP_DETAIL_LOGGING
2407             break;
2408         case kCsTag_Data:
2409             // check if this tag has appeared before
2410             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_Data)), err = CHIP_ERROR_INVALID_TLV_TAG);
2411             TagPresenceMask |= (1 << kCsTag_Data);
2412
2413             err = ParseData(reader, 0);
2414             SuccessOrExit(err);
2415             break;
2416         case kCsTag_MoreClusterDataFlag:
2417             // check if this tag has appeared before
2418             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_MoreClusterDataFlag)), err = CHIP_ERROR_INVALID_TLV_TAG);
2419             TagPresenceMask |= (1 << kCsTag_MoreClusterDataFlag);
2420             VerifyOrExit(chip::TLV::kTLVType_Boolean == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2421
2422 #if CHIP_DETAIL_LOGGING
2423             {
2424                 bool flag;
2425                 err = reader.Get(flag);
2426                 SuccessOrExit(err);
2427
2428                 PRETTY_PRINT("\tMoreClusterDataFlag = %s,", flag ? "true" : "false");
2429             }
2430
2431 #endif // CHIP_DETAIL_LOGGING
2432             break;
2433
2434         default:
2435             PRETTY_PRINT("\tUnknown tag num %" PRIu32, tagNum);
2436             break;
2437         }
2438     }
2439
2440     PRETTY_PRINT("},");
2441     PRETTY_PRINT("");
2442
2443     // if we have exhausted this container
2444     if (CHIP_END_OF_TLV == err)
2445     {
2446         // check for required fields:
2447         // Either the data or deleted keys should be present.
2448         const uint16_t RequiredFields = (1 << kCsTag_AttributePath) | (1 << kCsTag_DataVersion) | (1 << kCsTag_Data);
2449         if ((TagPresenceMask & RequiredFields) == RequiredFields)
2450         {
2451             err = CHIP_NO_ERROR;
2452         }
2453         else
2454         {
2455             err = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_DATA_ELEMENT;
2456         }
2457     }
2458
2459 exit:
2460     ChipLogFunctError(err);
2461
2462     return err;
2463 }
2464 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
2465
2466 CHIP_ERROR AttributeDataElement::Parser::GetAttributePath(AttributePath::Parser * const apAttributePath) const
2467 {
2468     CHIP_ERROR err = CHIP_NO_ERROR;
2469     chip::TLV::TLVReader reader;
2470
2471     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_AttributePath), reader);
2472     SuccessOrExit(err);
2473
2474     VerifyOrExit(chip::TLV::kTLVType_Path == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2475
2476     err = apAttributePath->Init(reader);
2477     SuccessOrExit(err);
2478
2479 exit:
2480     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
2481
2482     return err;
2483 }
2484
2485 CHIP_ERROR AttributeDataElement::Parser::GetDataVersion(chip::DataVersion * const apVersion) const
2486 {
2487     return GetUnsignedInteger(kCsTag_DataVersion, apVersion);
2488 }
2489
2490 CHIP_ERROR AttributeDataElement::Parser::GetData(chip::TLV::TLVReader * const apReader) const
2491 {
2492     CHIP_ERROR err = CHIP_NO_ERROR;
2493
2494     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_Data), *apReader);
2495     SuccessOrExit(err);
2496
2497 exit:
2498     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
2499
2500     return err;
2501 }
2502
2503 CHIP_ERROR AttributeDataElement::Parser::GetMoreClusterDataFlag(bool * const apGetMoreClusterDataFlag) const
2504 {
2505     return GetSimpleValue(kCsTag_MoreClusterDataFlag, chip::TLV::kTLVType_Boolean, apGetMoreClusterDataFlag);
2506 }
2507
2508 CHIP_ERROR AttributeDataElement::Builder::Init(chip::TLV::TLVWriter * const apWriter)
2509 {
2510     return InitAnonymousStructure(apWriter);
2511 }
2512
2513 AttributePath::Builder & AttributeDataElement::Builder::CreateAttributePathBuilder()
2514 {
2515     // skip if error has already been set
2516     VerifyOrExit(CHIP_NO_ERROR == mError, mAttributePathBuilder.ResetError(mError));
2517
2518     mError = mAttributePathBuilder.Init(mpWriter, kCsTag_AttributePath);
2519     ChipLogFunctError(mError);
2520
2521 exit:
2522     // on error, mAttributePathBuilder would be un-/partial initialized and cannot be used to write anything
2523     return mAttributePathBuilder;
2524 }
2525
2526 AttributeDataElement::Builder & AttributeDataElement::Builder::DataVersion(const chip::DataVersion aDataVersion)
2527 {
2528     // skip if error has already been set
2529     SuccessOrExit(mError);
2530
2531     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_DataVersion), aDataVersion);
2532     ChipLogFunctError(mError);
2533
2534 exit:
2535     return *this;
2536 }
2537
2538 AttributeDataElement::Builder & AttributeDataElement::Builder::MoreClusterData(const bool aMoreClusterData)
2539 {
2540     // skip if error has already been set
2541     SuccessOrExit(mError);
2542
2543     if (aMoreClusterData)
2544     {
2545         mError = mpWriter->PutBoolean(chip::TLV::ContextTag(kCsTag_MoreClusterDataFlag), true);
2546         ChipLogFunctError(mError);
2547     }
2548
2549 exit:
2550     return *this;
2551 }
2552
2553 AttributeDataElement::Builder & AttributeDataElement::Builder::EndOfAttributeDataElement()
2554 {
2555     EndOfContainer();
2556
2557     return *this;
2558 }
2559
2560 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
2561 CHIP_ERROR AttributeDataList::Parser::CheckSchemaValidity() const
2562 {
2563     CHIP_ERROR err        = CHIP_NO_ERROR;
2564     size_t NumDataElement = 0;
2565     chip::TLV::TLVReader reader;
2566
2567     PRETTY_PRINT("AttributeDataList =");
2568     PRETTY_PRINT("[");
2569
2570     // make a copy of the reader
2571     reader.Init(mReader);
2572
2573     while (CHIP_NO_ERROR == (err = reader.Next()))
2574     {
2575         VerifyOrExit(chip::TLV::AnonymousTag == reader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG);
2576         VerifyOrExit(chip::TLV::kTLVType_Structure == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2577
2578         {
2579             AttributeDataElement::Parser data;
2580             err = data.Init(reader);
2581             SuccessOrExit(err);
2582
2583             PRETTY_PRINT_INCDEPTH();
2584             err = data.CheckSchemaValidity();
2585             SuccessOrExit(err);
2586             PRETTY_PRINT_DECDEPTH();
2587         }
2588
2589         ++NumDataElement;
2590     }
2591
2592     PRETTY_PRINT("],");
2593     PRETTY_PRINT("");
2594
2595     // if we have exhausted this container
2596     if (CHIP_END_OF_TLV == err)
2597     {
2598         // if we have at least one data element
2599         if (NumDataElement > 0)
2600         {
2601             err = CHIP_NO_ERROR;
2602         }
2603     }
2604
2605 exit:
2606     ChipLogFunctError(err);
2607
2608     return err;
2609 }
2610 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
2611
2612 AttributeDataElement::Builder & AttributeDataList::Builder::CreateAttributeDataElementBuilder()
2613 {
2614     // skip if error has already been set
2615     VerifyOrExit(CHIP_NO_ERROR == mError, mAttributeDataElementBuilder.ResetError(mError));
2616
2617     mError = mAttributeDataElementBuilder.Init(mpWriter);
2618     ChipLogFunctError(mError);
2619
2620 exit:
2621
2622     // on error, mAttributeDataElementBuilder would be un-/partial initialized and cannot be used to write anything
2623     return mAttributeDataElementBuilder;
2624 }
2625
2626 AttributeDataList::Builder & AttributeDataList::Builder::EndOfAttributeDataList()
2627 {
2628     EndOfContainer();
2629
2630     return *this;
2631 }
2632
2633 CHIP_ERROR CommandDataElement::Parser::Init(const chip::TLV::TLVReader & aReader)
2634 {
2635     CHIP_ERROR err = CHIP_NO_ERROR;
2636
2637     // make a copy of the reader here
2638     mReader.Init(aReader);
2639
2640     VerifyOrExit(chip::TLV::kTLVType_Structure == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2641
2642     // This is just a dummy, as we're not going to exit this container ever
2643     chip::TLV::TLVType OuterContainerType;
2644     err = mReader.EnterContainer(OuterContainerType);
2645
2646 exit:
2647     ChipLogFunctError(err);
2648     return err;
2649 }
2650
2651 CHIP_ERROR
2652 CommandDataElement::Parser::ParseData(chip::TLV::TLVReader & aReader, int aDepth) const
2653 {
2654     CHIP_ERROR err = CHIP_NO_ERROR;
2655
2656     if (aDepth == 0)
2657     {
2658         PRETTY_PRINT("\tCommandDataElement = ");
2659     }
2660     else
2661     {
2662         if (chip::TLV::IsContextTag(aReader.GetTag()))
2663         {
2664             PRETTY_PRINT("\t0x%" PRIx32 " = ", chip::TLV::TagNumFromTag(aReader.GetTag()));
2665         }
2666         else if (chip::TLV::IsProfileTag(aReader.GetTag()))
2667         {
2668             PRETTY_PRINT("\t0x%" PRIx32 "::0x%" PRIx32 " = ", chip::TLV::ProfileIdFromTag(aReader.GetTag()),
2669                          chip::TLV::TagNumFromTag(aReader.GetTag()));
2670         }
2671         else
2672         {
2673             // Anonymous tag, don't print anything
2674         }
2675     }
2676
2677     switch (aReader.GetType())
2678     {
2679     case chip::TLV::kTLVType_Structure:
2680         PRETTY_PRINT("\t{");
2681         break;
2682
2683     case chip::TLV::kTLVType_Array:
2684         PRETTY_PRINT_SAMELINE("[");
2685         PRETTY_PRINT("\t\t");
2686         break;
2687
2688     case chip::TLV::kTLVType_SignedInteger: {
2689         int64_t value_s64;
2690
2691         err = aReader.Get(value_s64);
2692         SuccessOrExit(err);
2693
2694         PRETTY_PRINT_SAMELINE("%" PRId64 ", ", value_s64);
2695         break;
2696     }
2697
2698     case chip::TLV::kTLVType_UnsignedInteger: {
2699         uint64_t value_u64;
2700
2701         err = aReader.Get(value_u64);
2702         SuccessOrExit(err);
2703
2704         PRETTY_PRINT_SAMELINE("%" PRIu64 ", ", value_u64);
2705         break;
2706     }
2707
2708     case chip::TLV::kTLVType_FloatingPointNumber: {
2709         double value_fp;
2710
2711         err = aReader.Get(value_fp);
2712         SuccessOrExit(err);
2713
2714         PRETTY_PRINT_SAMELINE("%lf, ", value_fp);
2715         break;
2716     }
2717     case chip::TLV::kTLVType_Boolean: {
2718         bool value_b;
2719
2720         err = aReader.Get(value_b);
2721         SuccessOrExit(err);
2722
2723         PRETTY_PRINT_SAMELINE("%s, ", value_b ? "true" : "false");
2724         break;
2725     }
2726
2727     case chip::TLV::kTLVType_UTF8String: {
2728         char value_s[256];
2729
2730         err = aReader.GetString(value_s, sizeof(value_s));
2731         VerifyOrExit(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, );
2732
2733         if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
2734         {
2735             PRETTY_PRINT_SAMELINE("... (byte string too long) ...");
2736             err = CHIP_NO_ERROR;
2737         }
2738         else
2739         {
2740             PRETTY_PRINT_SAMELINE("\"%s\", ", value_s);
2741         }
2742         break;
2743     }
2744
2745     case chip::TLV::kTLVType_ByteString: {
2746         uint8_t value_b[256];
2747         uint32_t len, readerLen;
2748
2749         readerLen = aReader.GetLength();
2750
2751         err = aReader.GetBytes(value_b, sizeof(value_b));
2752         VerifyOrExit(err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL, );
2753
2754         PRETTY_PRINT_SAMELINE("[");
2755         PRETTY_PRINT("\t\t");
2756
2757         if (readerLen < sizeof(value_b))
2758         {
2759             len = readerLen;
2760         }
2761         else
2762         {
2763             len = sizeof(value_b);
2764         }
2765
2766         if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
2767         {
2768             PRETTY_PRINT_SAMELINE("... (byte string too long) ...");
2769         }
2770         else
2771         {
2772             for (size_t i = 0; i < len; i++)
2773             {
2774                 PRETTY_PRINT_SAMELINE("0x%" PRIx8 ", ", value_b[i]);
2775             }
2776         }
2777
2778         err = CHIP_NO_ERROR;
2779         PRETTY_PRINT("]");
2780         break;
2781     }
2782
2783     case chip::TLV::kTLVType_Null:
2784         PRETTY_PRINT_SAMELINE("NULL");
2785         break;
2786
2787     default:
2788         PRETTY_PRINT_SAMELINE("--");
2789         break;
2790     }
2791
2792     if (aReader.GetType() == chip::TLV::kTLVType_Structure || aReader.GetType() == chip::TLV::kTLVType_Array)
2793     {
2794         const char terminating_char = (aReader.GetType() == chip::TLV::kTLVType_Structure) ? '}' : ']';
2795         chip::TLV::TLVType type;
2796
2797         IgnoreUnusedVariable(terminating_char);
2798
2799         err = aReader.EnterContainer(type);
2800         SuccessOrExit(err);
2801
2802         while ((err = aReader.Next()) == CHIP_NO_ERROR)
2803         {
2804             PRETTY_PRINT_INCDEPTH();
2805
2806             err = ParseData(aReader, aDepth + 1);
2807             SuccessOrExit(err);
2808
2809             PRETTY_PRINT_DECDEPTH();
2810         }
2811
2812         PRETTY_PRINT("\t%c,", terminating_char);
2813
2814         err = aReader.ExitContainer(type);
2815         SuccessOrExit(err);
2816     }
2817
2818 exit:
2819     ChipLogFunctError(err);
2820     return err;
2821 }
2822
2823 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
2824 CHIP_ERROR CommandDataElement::Parser::CheckSchemaValidity() const
2825 {
2826     CHIP_ERROR err           = CHIP_NO_ERROR;
2827     uint16_t TagPresenceMask = 0;
2828     chip::TLV::TLVReader reader;
2829     uint32_t tagNum = 0;
2830
2831     PRETTY_PRINT("CommandDataElement =");
2832     PRETTY_PRINT("{");
2833
2834     // make a copy of the reader
2835     reader.Init(mReader);
2836
2837     while (CHIP_NO_ERROR == (err = reader.Next()))
2838     {
2839         VerifyOrExit(chip::TLV::IsContextTag(reader.GetTag()), err = CHIP_ERROR_INVALID_TLV_TAG);
2840
2841         tagNum = chip::TLV::TagNumFromTag(reader.GetTag());
2842
2843         switch (tagNum)
2844         {
2845         case kCsTag_CommandPath:
2846             // check if this tag has appeared before
2847             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_CommandPath)), err = CHIP_ERROR_INVALID_TLV_TAG);
2848             TagPresenceMask |= (1 << kCsTag_CommandPath);
2849             VerifyOrExit(chip::TLV::kTLVType_Path == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2850
2851             {
2852                 CommandPath::Parser path;
2853                 err = path.Init(reader);
2854                 SuccessOrExit(err);
2855
2856                 PRETTY_PRINT_INCDEPTH();
2857                 err = path.CheckSchemaValidity();
2858                 SuccessOrExit(err);
2859                 PRETTY_PRINT_DECDEPTH();
2860             }
2861
2862             break;
2863         case kCsTag_Data:
2864             // check if this tag has appeared before
2865             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_Data)), err = CHIP_ERROR_INVALID_TLV_TAG);
2866             TagPresenceMask |= (1 << kCsTag_Data);
2867
2868             err = ParseData(reader, 0);
2869             SuccessOrExit(err);
2870             break;
2871         case kCsTag_StatusElement:
2872             // check if this tag has appeared before
2873             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_StatusElement)), err = CHIP_ERROR_INVALID_TLV_TAG);
2874             TagPresenceMask |= (1 << kCsTag_StatusElement);
2875             VerifyOrExit(chip::TLV::kTLVType_Structure == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2876
2877             {
2878                 StatusElement::Parser status;
2879                 err = status.Init(reader);
2880                 SuccessOrExit(err);
2881
2882                 PRETTY_PRINT_INCDEPTH();
2883                 err = status.CheckSchemaValidity();
2884                 SuccessOrExit(err);
2885                 PRETTY_PRINT_DECDEPTH();
2886             }
2887
2888             break;
2889         default:
2890             PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum);
2891             break;
2892         }
2893     }
2894
2895     PRETTY_PRINT("},");
2896     PRETTY_PRINT("");
2897
2898     // if we have exhausted this container
2899     if (CHIP_END_OF_TLV == err)
2900     {
2901         // check for required fields:
2902         const uint16_t RequiredFields = (1 << kCsTag_CommandPath);
2903         if ((TagPresenceMask & RequiredFields) == RequiredFields)
2904         {
2905             err = CHIP_NO_ERROR;
2906         }
2907         else
2908         {
2909             err = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
2910         }
2911     }
2912
2913 exit:
2914     ChipLogFunctError(err);
2915     return err;
2916 }
2917 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
2918
2919 CHIP_ERROR CommandDataElement::Parser::GetCommandPath(CommandPath::Parser * const apCommandPath) const
2920 {
2921     CHIP_ERROR err = CHIP_NO_ERROR;
2922     chip::TLV::TLVReader reader;
2923
2924     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_CommandPath), reader);
2925     SuccessOrExit(err);
2926
2927     VerifyOrExit(chip::TLV::kTLVType_Path == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2928
2929     err = apCommandPath->Init(reader);
2930     SuccessOrExit(err);
2931
2932 exit:
2933     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
2934
2935     return err;
2936 }
2937
2938 CHIP_ERROR CommandDataElement::Parser::GetData(chip::TLV::TLVReader * const apReader) const
2939 {
2940     CHIP_ERROR err = CHIP_NO_ERROR;
2941
2942     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_Data), *apReader);
2943     SuccessOrExit(err);
2944
2945 exit:
2946     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
2947
2948     return err;
2949 }
2950
2951 CHIP_ERROR CommandDataElement::Parser::GetStatusElement(StatusElement::Parser * const apStatusElement) const
2952 {
2953     CHIP_ERROR err = CHIP_NO_ERROR;
2954     chip::TLV::TLVReader reader;
2955
2956     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_StatusElement), reader);
2957     SuccessOrExit(err);
2958
2959     VerifyOrExit(chip::TLV::kTLVType_Structure == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
2960
2961     err = apStatusElement->Init(reader);
2962     SuccessOrExit(err);
2963
2964 exit:
2965     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
2966
2967     return err;
2968 }
2969
2970 CHIP_ERROR CommandDataElement::Builder::Init(chip::TLV::TLVWriter * const apWriter)
2971 {
2972     return InitAnonymousStructure(apWriter);
2973 }
2974
2975 CommandPath::Builder & CommandDataElement::Builder::CreateCommandPathBuilder()
2976 {
2977     // skip if error has already been set
2978     VerifyOrExit(CHIP_NO_ERROR == mError, mCommandPathBuilder.ResetError(mError));
2979
2980     mError = mCommandPathBuilder.Init(mpWriter, kCsTag_CommandPath);
2981     ChipLogFunctError(mError);
2982
2983 exit:
2984     // on error, mAttributePathBuilder would be un-/partial initialized and cannot be used to write anything
2985     return mCommandPathBuilder;
2986 }
2987
2988 StatusElement::Builder & CommandDataElement::Builder::CreateStatusElementBuilder()
2989 {
2990     // skip if error has already been set
2991     VerifyOrExit(CHIP_NO_ERROR == mError, mStatusElementBuilder.ResetError(mError));
2992
2993     mError = mStatusElementBuilder.Init(mpWriter, kCsTag_StatusElement);
2994     ChipLogFunctError(mError);
2995
2996 exit:
2997     // on error, mStatusElementBuilder would be un-/partial initialized and cannot be used to write anything
2998     return mStatusElementBuilder;
2999 }
3000
3001 CommandDataElement::Builder & CommandDataElement::Builder::EndOfCommandDataElement()
3002 {
3003     EndOfContainer();
3004
3005     return *this;
3006 }
3007
3008 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
3009 CHIP_ERROR CommandList::Parser::CheckSchemaValidity() const
3010 {
3011     CHIP_ERROR err     = CHIP_NO_ERROR;
3012     size_t NumCommands = 0;
3013     chip::TLV::TLVReader reader;
3014
3015     PRETTY_PRINT("CommandList =");
3016     PRETTY_PRINT("[");
3017
3018     // make a copy of the reader
3019     reader.Init(mReader);
3020
3021     while (CHIP_NO_ERROR == (err = reader.Next()))
3022     {
3023         VerifyOrExit(chip::TLV::AnonymousTag == reader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG);
3024         VerifyOrExit(chip::TLV::kTLVType_Structure == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3025
3026         {
3027             CommandDataElement::Parser data;
3028             err = data.Init(reader);
3029             SuccessOrExit(err);
3030
3031             PRETTY_PRINT_INCDEPTH();
3032             err = data.CheckSchemaValidity();
3033             SuccessOrExit(err);
3034
3035             PRETTY_PRINT_DECDEPTH();
3036         }
3037
3038         ++NumCommands;
3039     }
3040
3041     PRETTY_PRINT("],");
3042     PRETTY_PRINT("");
3043
3044     // if we have exhausted this container
3045     if (CHIP_END_OF_TLV == err)
3046     {
3047         // if we have at least one data element
3048         if (NumCommands > 0)
3049         {
3050             err = CHIP_NO_ERROR;
3051         }
3052     }
3053
3054 exit:
3055     ChipLogFunctError(err);
3056
3057     return err;
3058 }
3059 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
3060
3061 CommandDataElement::Builder & CommandList::Builder::CreateCommandDataElementBuilder()
3062 {
3063     // skip if error has already been set
3064     VerifyOrExit(CHIP_NO_ERROR == mError, mCommandDataElementBuilder.ResetError(mError));
3065
3066     mError = mCommandDataElementBuilder.Init(mpWriter);
3067     ChipLogFunctError(mError);
3068
3069 exit:
3070     // on error, mCommandDataElementBuilder would be un-/partial initialized and cannot be used to write anything
3071     return mCommandDataElementBuilder;
3072 }
3073
3074 CommandList::Builder & CommandList::Builder::EndOfCommandList()
3075 {
3076     EndOfContainer();
3077     return *this;
3078 }
3079
3080 CHIP_ERROR ReportData::Parser::Init(const chip::TLV::TLVReader & aReader)
3081 {
3082     CHIP_ERROR err = CHIP_NO_ERROR;
3083
3084     // make a copy of the reader here
3085     mReader.Init(aReader);
3086
3087     VerifyOrExit(chip::TLV::kTLVType_Structure == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3088
3089     // This is just a dummy, as we're not going to exit this container ever
3090     chip::TLV::TLVType OuterContainerType;
3091     err = mReader.EnterContainer(OuterContainerType);
3092
3093 exit:
3094     ChipLogFunctError(err);
3095
3096     return err;
3097 }
3098
3099 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
3100 CHIP_ERROR ReportData::Parser::CheckSchemaValidity() const
3101 {
3102     CHIP_ERROR err           = CHIP_NO_ERROR;
3103     uint16_t TagPresenceMask = 0;
3104     chip::TLV::TLVReader reader;
3105     AttributeStatusList::Parser attributeStatusList;
3106     AttributeDataList::Parser attributeDataList;
3107     EventList::Parser eventList;
3108
3109     PRETTY_PRINT("ReportData =");
3110     PRETTY_PRINT("{");
3111
3112     // make a copy of the reader
3113     reader.Init(mReader);
3114
3115     while (CHIP_NO_ERROR == (err = reader.Next()))
3116     {
3117         VerifyOrExit(chip::TLV::IsContextTag(reader.GetTag()), err = CHIP_ERROR_INVALID_TLV_TAG);
3118
3119         switch (chip::TLV::TagNumFromTag(reader.GetTag()))
3120         {
3121         case kCsTag_RequestResponse:
3122             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_RequestResponse)), err = CHIP_ERROR_INVALID_TLV_TAG);
3123             TagPresenceMask |= (1 << kCsTag_RequestResponse);
3124             VerifyOrExit(chip::TLV::kTLVType_Boolean == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3125 #if CHIP_DETAIL_LOGGING
3126             {
3127                 bool RequestResponse;
3128                 err = reader.Get(RequestResponse);
3129                 SuccessOrExit(err);
3130                 PRETTY_PRINT("\tRequestResponse = %s, ", RequestResponse ? "true" : "false");
3131             }
3132 #endif // CHIP_DETAIL_LOGGING
3133             break;
3134         case kCsTag_SubscriptionId:
3135             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_SubscriptionId)), err = CHIP_ERROR_INVALID_TLV_TAG);
3136             TagPresenceMask |= (1 << kCsTag_SubscriptionId);
3137             VerifyOrExit(chip::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3138 #if CHIP_DETAIL_LOGGING
3139             {
3140                 uint64_t subscriptionId;
3141                 err = reader.Get(subscriptionId);
3142                 SuccessOrExit(err);
3143                 PRETTY_PRINT("\tSubscriptionId = 0x%" PRIx64 ",", subscriptionId);
3144             }
3145 #endif // CHIP_DETAIL_LOGGING
3146             break;
3147         case kCsTag_AttributeStatusList:
3148             // check if this tag has appeared before
3149             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_AttributeStatusList)), err = CHIP_ERROR_INVALID_TLV_TAG);
3150             TagPresenceMask |= (1 << kCsTag_AttributeStatusList);
3151             VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3152 #if CHIP_DETAIL_LOGGING
3153             {
3154                 attributeStatusList.Init(reader);
3155
3156                 PRETTY_PRINT_INCDEPTH();
3157                 err = attributeStatusList.CheckSchemaValidity();
3158                 SuccessOrExit(err);
3159                 PRETTY_PRINT_DECDEPTH();
3160             }
3161 #endif // CHIP_DETAIL_LOGGING
3162             break;
3163         case kCsTag_AttributeDataList:
3164             // check if this tag has appeared before
3165             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_AttributeDataList)), err = CHIP_ERROR_INVALID_TLV_TAG);
3166             TagPresenceMask |= (1 << kCsTag_AttributeDataList);
3167             VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3168 #if CHIP_DETAIL_LOGGING
3169             {
3170                 attributeDataList.Init(reader);
3171
3172                 PRETTY_PRINT_INCDEPTH();
3173                 err = attributeDataList.CheckSchemaValidity();
3174                 SuccessOrExit(err);
3175                 PRETTY_PRINT_DECDEPTH();
3176             }
3177 #endif // CHIP_DETAIL_LOGGING
3178             break;
3179         case kCsTag_EventDataList:
3180             // check if this tag has appeared before
3181             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_EventDataList)), err = CHIP_ERROR_INVALID_TLV_TAG);
3182             TagPresenceMask |= (1 << kCsTag_EventDataList);
3183             VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3184 #if CHIP_DETAIL_LOGGING
3185             {
3186                 eventList.Init(reader);
3187
3188                 PRETTY_PRINT_INCDEPTH();
3189                 err = eventList.CheckSchemaValidity();
3190                 SuccessOrExit(err);
3191                 PRETTY_PRINT_DECDEPTH();
3192             }
3193 #endif // CHIP_DETAIL_LOGGING
3194             break;
3195         case kCsTag_IsLastReport:
3196             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_IsLastReport)), err = CHIP_ERROR_INVALID_TLV_TAG);
3197             TagPresenceMask |= (1 << kCsTag_IsLastReport);
3198             VerifyOrExit(chip::TLV::kTLVType_Boolean == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3199 #if CHIP_DETAIL_LOGGING
3200             {
3201                 bool isLastReport;
3202                 err = reader.Get(isLastReport);
3203                 SuccessOrExit(err);
3204                 PRETTY_PRINT("\tisLastReport = %s, ", isLastReport ? "true" : "false");
3205             }
3206 #endif // CHIP_DETAIL_LOGGING
3207             break;
3208         default:
3209             ExitNow(err = CHIP_ERROR_INVALID_TLV_TAG);
3210         }
3211     }
3212
3213     PRETTY_PRINT("}");
3214     PRETTY_PRINT("");
3215     // if we have exhausted this container
3216     if (CHIP_END_OF_TLV == err)
3217     {
3218         err = CHIP_NO_ERROR;
3219     }
3220
3221 exit:
3222     ChipLogFunctError(err);
3223
3224     return err;
3225 }
3226 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
3227
3228 CHIP_ERROR ReportData::Parser::GetRequestResponse(bool * const apRequestResponse) const
3229 {
3230     return GetSimpleValue(kCsTag_RequestResponse, chip::TLV::kTLVType_Boolean, apRequestResponse);
3231 }
3232
3233 CHIP_ERROR ReportData::Parser::GetSubscriptionId(uint64_t * const apSubscriptionId) const
3234 {
3235     return GetUnsignedInteger(kCsTag_SubscriptionId, apSubscriptionId);
3236 }
3237
3238 CHIP_ERROR ReportData::Parser::GetAttributeStatusList(AttributeStatusList::Parser * const apAttributeStatusList) const
3239 {
3240     CHIP_ERROR err = CHIP_NO_ERROR;
3241     chip::TLV::TLVReader reader;
3242
3243     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_AttributeStatusList), reader);
3244     SuccessOrExit(err);
3245
3246     VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3247
3248     err = apAttributeStatusList->Init(reader);
3249     SuccessOrExit(err);
3250
3251 exit:
3252     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
3253
3254     return err;
3255 }
3256
3257 CHIP_ERROR ReportData::Parser::GetAttributeDataList(AttributeDataList::Parser * const apAttributeDataList) const
3258 {
3259     CHIP_ERROR err = CHIP_NO_ERROR;
3260     chip::TLV::TLVReader reader;
3261
3262     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_AttributeDataList), reader);
3263     SuccessOrExit(err);
3264
3265     VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3266
3267     err = apAttributeDataList->Init(reader);
3268     SuccessOrExit(err);
3269
3270 exit:
3271     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
3272
3273     return err;
3274 }
3275
3276 CHIP_ERROR ReportData::Parser::GetEventDataList(EventList::Parser * const apEventDataList) const
3277 {
3278     CHIP_ERROR err = CHIP_NO_ERROR;
3279     chip::TLV::TLVReader reader;
3280
3281     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_EventDataList), reader);
3282     SuccessOrExit(err);
3283
3284     VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3285
3286     err = apEventDataList->Init(reader);
3287     SuccessOrExit(err);
3288
3289 exit:
3290     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
3291
3292     return err;
3293 }
3294
3295 CHIP_ERROR ReportData::Parser::GetIsLastReport(bool * const apIsLastReport) const
3296 {
3297     return GetSimpleValue(kCsTag_IsLastReport, chip::TLV::kTLVType_Boolean, apIsLastReport);
3298 }
3299
3300 CHIP_ERROR ReportData::Builder::Init(chip::TLV::TLVWriter * const apWriter)
3301 {
3302     return InitAnonymousStructure(apWriter);
3303 }
3304
3305 ReportData::Builder & ReportData::Builder::RequestResponse(const bool aRequestResponse)
3306 {
3307     // skip if error has already been set
3308     SuccessOrExit(mError);
3309
3310     mError = mpWriter->PutBoolean(chip::TLV::ContextTag(kCsTag_RequestResponse), aRequestResponse);
3311     ChipLogFunctError(mError);
3312
3313 exit:
3314     return *this;
3315 }
3316
3317 ReportData::Builder & ReportData::Builder::SubscriptionId(const uint64_t aSubscriptionId)
3318 {
3319     // skip if error has already been set
3320     SuccessOrExit(mError);
3321
3322     mError = mpWriter->Put(chip::TLV::ContextTag(kCsTag_SubscriptionId), aSubscriptionId);
3323     ChipLogFunctError(mError);
3324
3325 exit:
3326     return *this;
3327 }
3328
3329 AttributeStatusList::Builder & ReportData::Builder::CreateAttributeStatusListBuilder()
3330 {
3331     // skip if error has already been set
3332     VerifyOrExit(CHIP_NO_ERROR == mError, mAttributeStatusListBuilder.ResetError(mError));
3333
3334     mError = mAttributeStatusListBuilder.Init(mpWriter, kCsTag_AttributeStatusList);
3335     ChipLogFunctError(mError);
3336
3337 exit:
3338     return mAttributeStatusListBuilder;
3339 }
3340
3341 AttributeDataList::Builder & ReportData::Builder::CreateAttributeDataListBuilder()
3342 {
3343     // skip if error has already been set
3344     VerifyOrExit(CHIP_NO_ERROR == mError, mAttributeDataListBuilder.ResetError(mError));
3345
3346     mError = mAttributeDataListBuilder.Init(mpWriter, kCsTag_AttributeDataList);
3347     ChipLogFunctError(mError);
3348
3349 exit:
3350     return mAttributeDataListBuilder;
3351 }
3352
3353 EventList::Builder & ReportData::Builder::CreateEventDataListBuilder()
3354 {
3355     // skip if error has already been set
3356     VerifyOrExit(CHIP_NO_ERROR == mError, mAttributeDataListBuilder.ResetError(mError));
3357
3358     mError = mEventDataListBuilder.Init(mpWriter, kCsTag_EventDataList);
3359     ChipLogFunctError(mError);
3360
3361 exit:
3362     return mEventDataListBuilder;
3363 }
3364
3365 ReportData::Builder & ReportData::Builder::IsLastReport(const bool aIsLastReport)
3366 {
3367     // skip if error has already been set
3368     SuccessOrExit(mError);
3369
3370     mError = mpWriter->PutBoolean(chip::TLV::ContextTag(kCsTag_IsLastReport), aIsLastReport);
3371     ChipLogFunctError(mError);
3372
3373 exit:
3374     return *this;
3375 }
3376
3377 ReportData::Builder & ReportData::Builder::EndOfReportData()
3378 {
3379     EndOfContainer();
3380     return *this;
3381 }
3382
3383 CHIP_ERROR InvokeCommand::Parser::Init(const chip::TLV::TLVReader & aReader)
3384 {
3385     CHIP_ERROR err = CHIP_NO_ERROR;
3386
3387     // make a copy of the reader here
3388     mReader.Init(aReader);
3389
3390     VerifyOrExit(chip::TLV::kTLVType_Structure == mReader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3391
3392     // This is just a dummy, as we're not going to exit this container ever
3393     chip::TLV::TLVType OuterContainerType;
3394     err = mReader.EnterContainer(OuterContainerType);
3395
3396 exit:
3397     ChipLogFunctError(err);
3398
3399     return err;
3400 }
3401
3402 #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
3403 CHIP_ERROR InvokeCommand::Parser::CheckSchemaValidity() const
3404 {
3405     CHIP_ERROR err           = CHIP_NO_ERROR;
3406     uint16_t TagPresenceMask = 0;
3407     chip::TLV::TLVReader reader;
3408     CommandList::Parser commandList;
3409
3410     PRETTY_PRINT("InvokeCommand =");
3411     PRETTY_PRINT("{");
3412
3413     // make a copy of the reader
3414     reader.Init(mReader);
3415
3416     while (CHIP_NO_ERROR == (err = reader.Next()))
3417     {
3418         const uint64_t tag = reader.GetTag();
3419
3420         if (chip::TLV::ContextTag(kCsTag_CommandList) == tag)
3421         {
3422             VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_CommandList)), err = CHIP_ERROR_INVALID_TLV_TAG);
3423             TagPresenceMask |= (1 << kCsTag_CommandList);
3424             VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3425
3426             commandList.Init(reader);
3427
3428             PRETTY_PRINT_INCDEPTH();
3429
3430             err = commandList.CheckSchemaValidity();
3431             SuccessOrExit(err);
3432
3433             PRETTY_PRINT_DECDEPTH();
3434         }
3435         else
3436         {
3437             PRETTY_PRINT("\tUnknown tag 0x%" PRIx64, tag);
3438         }
3439     }
3440
3441     PRETTY_PRINT("}");
3442     PRETTY_PRINT("");
3443
3444     // if we have exhausted this container
3445     if (CHIP_END_OF_TLV == err)
3446     {
3447         // if we have at least the DataList or EventList field
3448         if ((TagPresenceMask & (1 << kCsTag_CommandList)))
3449         {
3450             err = CHIP_NO_ERROR;
3451         }
3452     }
3453
3454 exit:
3455     ChipLogFunctError(err);
3456
3457     return err;
3458 }
3459 #endif // CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK
3460
3461 CHIP_ERROR InvokeCommand::Parser::GetCommandList(CommandList::Parser * const apCommandList) const
3462 {
3463     CHIP_ERROR err = CHIP_NO_ERROR;
3464     chip::TLV::TLVReader reader;
3465
3466     err = mReader.FindElementWithTag(chip::TLV::ContextTag(kCsTag_CommandList), reader);
3467     SuccessOrExit(err);
3468
3469     VerifyOrExit(chip::TLV::kTLVType_Array == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
3470
3471     err = apCommandList->Init(reader);
3472     SuccessOrExit(err);
3473
3474 exit:
3475     ChipLogIfFalse((CHIP_NO_ERROR == err) || (CHIP_END_OF_TLV == err));
3476
3477     return err;
3478 }
3479
3480 CHIP_ERROR InvokeCommand::Builder::Init(chip::TLV::TLVWriter * const apWriter)
3481 {
3482     return InitAnonymousStructure(apWriter);
3483 }
3484
3485 CommandList::Builder & InvokeCommand::Builder::CreateCommandListBuilder()
3486 {
3487     // skip if error has already been set
3488     VerifyOrExit(CHIP_NO_ERROR == mError, mCommandListBuilder.ResetError(mError));
3489
3490     mError = mCommandListBuilder.Init(mpWriter, kCsTag_CommandList);
3491     ChipLogFunctError(mError);
3492
3493 exit:
3494     // on error, mCommandListBuilder would be un-/partial initialized and cannot be used to write anything
3495     return mCommandListBuilder;
3496 }
3497
3498 InvokeCommand::Builder & InvokeCommand::Builder::EndOfInvokeCommand()
3499 {
3500     EndOfContainer();
3501     return *this;
3502 }
3503
3504 }; // namespace app
3505 }; // namespace chip