Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / lib / core / CHIPTLVDebug.cpp
1 /*
2  *
3  *    Copyright (c) 2020-2021 Project CHIP Authors
4  *    Copyright (c) 2015-2017 Nest Labs, Inc.
5  *
6  *    Licensed under the Apache License, Version 2.0 (the "License");
7  *    you may not use this file except in compliance with the License.
8  *    You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *    Unless required by applicable law or agreed to in writing, software
13  *    distributed under the License is distributed on an "AS IS" BASIS,
14  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *    See the License for the specific language governing permissions and
16  *    limitations under the License.
17  */
18
19 /**
20  *    @file
21  *      This file implements interfaces for debugging and logging
22  *      CHIP TLV.
23  *
24  */
25
26 #ifndef __STDC_FORMAT_MACROS
27 #define __STDC_FORMAT_MACROS
28 #endif
29
30 #include <ctype.h>
31 #include <inttypes.h>
32 #include <string.h>
33
34 #include <core/CHIPTLV.h>
35 #include <core/CHIPTLVDebug.hpp>
36 #include <core/CHIPTLVUtilities.hpp>
37 #include <support/CodeUtils.h>
38 #include <support/logging/CHIPLogging.h>
39
40 namespace chip {
41
42 namespace TLV {
43
44 namespace Debug {
45
46 /**
47  *  Dump the TLV element referenced by @a aReader in human-readable form using
48  *  @a aWriter.
49  *
50  *  @param[in]     aWriter   The writer to log the TLV data.
51  *  @param[in]     aIndent   The indentation for logging the current depth into
52  *                           the TLV data.
53  *  @param[in]     aReader   A read-only reference to the TLV reader containing
54  *                           the TLV data to log.
55  *  @param[in]     aDepth    The current depth into the TLV data.
56  *
57  */
58 static void DumpHandler(DumpWriter aWriter, const char * aIndent, const TLVReader & aReader, size_t aDepth)
59 {
60     const TLVType type     = aReader.GetType();
61     const uint64_t tag     = aReader.GetTag();
62     const uint32_t len     = aReader.GetLength();
63     const uint8_t * strbuf = nullptr;
64     CHIP_ERROR err         = CHIP_NO_ERROR;
65     TLVReader temp;
66     TLVTagControl tagControl;
67
68     temp.Init(aReader);
69     tagControl = static_cast<TLVTagControl>(temp.GetControlByte() & kTLVTagControlMask);
70
71     aWriter("%zd ", aDepth);
72
73     for (size_t i = 0; i < aDepth; i++)
74         aWriter("%s", aIndent);
75
76     aWriter("%p, ", temp.GetReadPoint());
77
78     if (IsProfileTag(tag))
79     {
80         aWriter("tag[%s]: 0x%x::0x%x::0x%x, ", DecodeTagControl(tagControl), VendorIdFromTag(tag), ProfileNumFromTag(tag),
81                 TagNumFromTag(tag));
82     }
83     else if (IsContextTag(tag))
84     {
85         aWriter("tag[%s]: 0x%x, ", DecodeTagControl(tagControl), TagNumFromTag(tag));
86     }
87     else if (IsSpecialTag(tag))
88     {
89
90         aWriter("tag[%s]: 0x%x, ", DecodeTagControl(tagControl), tag);
91     }
92     else
93     {
94         aWriter("tag[unknown]: 0x%x, ", tag);
95     }
96
97     aWriter("type: %s (0x%02x), ", DecodeType(type), type);
98
99     if (TLVTypeIsContainer(type))
100     {
101         aWriter("container: ");
102     }
103     else
104     {
105         if (type == kTLVType_UTF8String || type == kTLVType_ByteString)
106             aWriter("length: %" PRIu32 ", ", len);
107
108         aWriter("value: ");
109
110         switch (type)
111         {
112
113         case kTLVType_SignedInteger:
114             int64_t sVal;
115             err = temp.Get(sVal);
116             VerifyOrExit(err == CHIP_NO_ERROR, aWriter("Error in kTLVType_SignedInteger"));
117             aWriter("%" PRIi64, sVal);
118             break;
119
120         case kTLVType_UnsignedInteger:
121             uint64_t uVal;
122             err = temp.Get(uVal);
123             VerifyOrExit(err == CHIP_NO_ERROR, aWriter("Error in kTLVType_UnsignedInteger"));
124             aWriter("%" PRIu64, uVal);
125             break;
126
127         case kTLVType_Boolean:
128             bool bVal;
129             err = temp.Get(bVal);
130             VerifyOrExit(err == CHIP_NO_ERROR, aWriter("Error in kTLVType_Boolean"));
131             aWriter("%s", bVal ? "true" : "false");
132             break;
133
134         case kTLVType_FloatingPointNumber:
135             double fpVal;
136             err = temp.Get(fpVal);
137             VerifyOrExit(err == CHIP_NO_ERROR, aWriter("Error in kTLVType_FloatingPointNumber"));
138             aWriter("%lf", fpVal);
139             break;
140
141         case kTLVType_UTF8String:
142             err = temp.GetDataPtr(strbuf);
143             VerifyOrExit(err == CHIP_NO_ERROR, aWriter("Error in kTLVType_UTF8String"));
144             aWriter("\"%-.*s\"", static_cast<int>(len), strbuf);
145             break;
146
147         case kTLVType_ByteString:
148             err = temp.GetDataPtr(strbuf);
149             VerifyOrExit(err == CHIP_NO_ERROR, aWriter("Error in kTLVType_ByteString"));
150             aWriter("%p\n", strbuf);
151             break;
152
153         case kTLVType_Null:
154             aWriter("NULL");
155             break;
156
157         case kTLVType_NotSpecified:
158             aWriter("Not Specified");
159             break;
160
161         default:
162             aWriter("Error: Type is not primitive.");
163             break;
164         }
165     }
166
167 exit:
168     aWriter("\n");
169 }
170
171 /**
172  *  Decode a TLV tag control with a descriptive string.
173  *
174  *  @param[in]     aTagControl  The TLV tag control to decode and for which to return
175  *                              a descriptive string.
176  *
177  *  @return  A pointer to a NULL-terminated string describing the specified
178  *           tag control on success; otherwise, NULL.
179  *
180  */
181 const char * DecodeTagControl(const TLVTagControl aTagControl)
182 {
183     const char * retval;
184
185     switch (aTagControl)
186     {
187
188     case TLVTagControl::Anonymous:
189         retval = "Anonymous";
190         break;
191
192     case TLVTagControl::ContextSpecific:
193         retval = "Context Specific";
194         break;
195
196     case TLVTagControl::CommonProfile_2Bytes:
197         retval = "Common Profile (2 Bytes)";
198         break;
199
200     case TLVTagControl::CommonProfile_4Bytes:
201         retval = "Common Profile (4 Bytes)";
202         break;
203
204     case TLVTagControl::ImplicitProfile_2Bytes:
205         retval = "Implicit Profile (2 Bytes)";
206         break;
207
208     case TLVTagControl::ImplicitProfile_4Bytes:
209         retval = "Implicit Profile (4 Bytes)";
210         break;
211
212     case TLVTagControl::FullyQualified_6Bytes:
213         retval = "Fully Qualified (6 Bytes)";
214         break;
215
216     case TLVTagControl::FullyQualified_8Bytes:
217         retval = "Fully Qualified (8 Bytes)";
218         break;
219
220     default:
221         retval = nullptr;
222         break;
223     }
224
225     return retval;
226 }
227
228 /**
229  *  Decode a TLV type with a descriptive string.
230  *
231  *  @param[in]     aType     The TLV type to decode and for which to return
232  *                           a descriptive string.
233  *
234  *  @return  A pointer to a NULL-terminated string describing the specified
235  *           type on success; otherwise, NULL.
236  *
237  */
238 const char * DecodeType(const TLVType aType)
239 {
240     const char * retval;
241
242     switch (aType)
243     {
244
245     case kTLVType_NotSpecified:
246         retval = "Not Specified";
247         break;
248
249     case kTLVType_SignedInteger:
250         retval = "Signed Fixed Point";
251         break;
252
253     case kTLVType_UnsignedInteger:
254         retval = "Unsigned Fixed Point";
255         break;
256
257     case kTLVType_Boolean:
258         retval = "Boolean";
259         break;
260
261     case kTLVType_FloatingPointNumber:
262         retval = "Floating Point";
263         break;
264
265     case kTLVType_UTF8String:
266         retval = "UTF-8 String";
267         break;
268
269     case kTLVType_ByteString:
270         retval = "Data";
271         break;
272
273     case kTLVType_Null:
274         retval = "Null";
275         break;
276
277     case kTLVType_Structure:
278         retval = "Structure";
279         break;
280
281     case kTLVType_Array:
282         retval = "Array";
283         break;
284
285     case kTLVType_List:
286         retval = "Path";
287         break;
288
289     default:
290         retval = nullptr;
291         break;
292     }
293
294     return retval;
295 }
296
297 /**
298  *  Log the TLV data within the specified reader in human-readable form to
299  *  the specified writer.
300  *
301  *  @param[in]     aWriter   The writer to log the TLV data.
302  *  @param[in]     aReader   A read-only reference to the TLV reader containing
303  *                           the TLV data to log.
304  *
305  *  @retval  #CHIP_NO_ERROR  Unconditionally.
306  *
307  */
308 CHIP_ERROR DumpIterator(DumpWriter aWriter, const TLVReader & aReader)
309 {
310     const char * tabs  = "";
311     const size_t depth = 0;
312     CHIP_ERROR retval  = CHIP_NO_ERROR;
313
314     DumpHandler(aWriter, tabs, aReader, depth);
315
316     return retval;
317 }
318
319 /**
320  *  Log the TLV data within the specified reader in human-readable form.
321  *
322  *  @param[in]     aReader   A read-only reference to the TLV reader containing
323  *                           the TLV data to log.
324  *  @param[in]     aDepth    The current depth into the TLV data.
325  *  @param[in,out] aContext  A pointer to the handler-specific context.
326  *
327  *  @retval  #CHIP_NO_ERROR                On success.
328  *
329  *  @retval  #CHIP_ERROR_INVALID_ARGUMENT  If aContext is NULL or if
330  *                                          aContext->mWriter is NULL.
331  *
332  */
333 CHIP_ERROR DumpHandler(const TLVReader & aReader, size_t aDepth, void * aContext)
334 {
335     static const char indent[] = "    ";
336     DumpContext * context;
337
338     VerifyOrReturnError(aContext != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
339
340     context = static_cast<DumpContext *>(aContext);
341
342     VerifyOrReturnError(context->mWriter != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
343
344     DumpHandler(context->mWriter, indent, aReader, aDepth);
345
346     return CHIP_NO_ERROR;
347 }
348
349 /**
350  *  Dump the TLV data within the specified reader in human-readable form with
351  *  the specified writer.
352  *
353  *  @param[in]     aReader          A read-only reference to the TLV reader containing
354  *                                  the TLV data to log.
355  *
356  *  @param[in]     aWriter          A dump writer to log the TLV data of the TLV reader.
357  *
358  *  @retval  #CHIP_NO_ERROR        On success.
359  *
360  */
361 CHIP_ERROR Dump(const TLVReader & aReader, DumpWriter aWriter)
362 {
363     void * context          = nullptr;
364     DumpContext dumpContext = { aWriter, context };
365     CHIP_ERROR retval;
366
367     retval = Utilities::Iterate(aReader, DumpHandler, &dumpContext);
368
369     return retval;
370 }
371
372 } // namespace Debug
373
374 } // namespace TLV
375
376 } // namespace chip