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