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