3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2015-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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * This file implements utility interfaces for managing and
22 * working with CHIP TLV.
26 #include <core/CHIPTLVDebug.hpp>
27 #include <core/CHIPTLVUtilities.hpp>
28 #include <support/CodeUtils.h>
38 const uint64_t & mTag;
43 * Iterate through the TLV data referenced by @a aReader and invoke @a aHandler
44 * for each visited TLV element in the context of @a aContext.
45 * The iteration is aborted if @a aHandler returns anything other than #CHIP_NO_ERROR
47 * @param[in] aReader A reference to the TLV reader containing the TLV
49 * @param[in] aDepth The current depth into the TLV data.
50 * @param[in] aHandler A callback to invoke for the current TLV element
52 * @param[in,out] aContext An optional pointer to caller-provided context data.
53 * @param[in] aRecurse A Boolean indicating whether (true) or not (false)
54 * any encountered arrays or structures should be
57 * @retval #CHIP_END_OF_TLV On a successful iteration to the end of a TLV encoding,
58 * or to the end of a TLV container.
60 * @retval The last value returned by @a aHandler, if different than #CHIP_NO_ERROR
62 static CHIP_ERROR Iterate(TLVReader & aReader, size_t aDepth, IterateHandler aHandler, void * aContext, bool aRecurse)
64 CHIP_ERROR retval = CHIP_NO_ERROR;
66 if (aReader.GetType() == kTLVType_NotSpecified)
68 retval = aReader.Next();
69 SuccessOrExit(retval);
74 const TLVType theType = aReader.GetType();
76 retval = (aHandler)(aReader, aDepth, aContext);
77 SuccessOrExit(retval);
79 if (aRecurse && TLVTypeIsContainer(theType))
81 TLVType containerType;
83 retval = aReader.EnterContainer(containerType);
84 SuccessOrExit(retval);
86 retval = Iterate(aReader, aDepth + 1, aHandler, aContext, aRecurse);
87 if (retval != CHIP_END_OF_TLV)
88 SuccessOrExit(retval);
90 retval = aReader.ExitContainer(containerType);
91 SuccessOrExit(retval);
93 } while ((retval = aReader.Next()) == CHIP_NO_ERROR);
100 * Iterate through the TLV data referenced by @a aReader and invoke @a aHandler
101 * for each visited TLV element in the context of @a aContext.
102 * The iteration is aborted if @a aHandler returns anything other than #CHIP_NO_ERROR
104 * @param[in] aReader A reference to the TLV reader containing the TLV
106 * @param[in] aHandler A callback to invoke for the current TLV element
108 * @param[in,out] aContext An optional pointer to caller-provided context data.
110 * @retval #CHIP_END_OF_TLV On a successful iteration to the end of a TLV encoding,
111 * or to the end of a TLV container.
113 * @retval #CHIP_ERROR_INVALID_ARGUMENT If @a aHandler is NULL.
115 * @retval The last value returned by @a aHandler, if different than #CHIP_NO_ERROR
118 CHIP_ERROR Iterate(const TLVReader & aReader, IterateHandler aHandler, void * aContext)
120 const bool recurse = true;
123 retval = Iterate(aReader, aHandler, aContext, recurse);
129 * Iterate through the TLV data referenced by @a aReader and invoke @a aHandler
130 * for each visited TLV element in the context of @a aContext.
131 * The iteration is aborted if @a aHandler returns anything other than #CHIP_NO_ERROR
133 * @param[in] aReader A reference to the TLV reader containing the TLV
135 * @param[in] aHandler A callback to invoke for the current TLV element
137 * @param[in,out] aContext An optional pointer to caller-provided context data.
138 * @param[in] aRecurse A Boolean indicating whether (true) or not (false)
139 * any encountered arrays or structures should be
142 * @retval #CHIP_END_OF_TLV On a successful iteration to the end of a TLV encoding,
143 * or to the end of a TLV container.
145 * @retval #CHIP_ERROR_INVALID_ARGUMENT If @a aHandler is NULL.
147 * @retval The last value returned by @a aHandler, if different than #CHIP_NO_ERROR
150 CHIP_ERROR Iterate(const TLVReader & aReader, IterateHandler aHandler, void * aContext, const bool aRecurse)
152 const size_t depth = 0;
154 CHIP_ERROR retval = CHIP_ERROR_NOT_IMPLEMENTED;
156 VerifyOrExit(aHandler != nullptr, retval = CHIP_ERROR_INVALID_ARGUMENT);
160 retval = Iterate(temp, depth, aHandler, aContext, aRecurse);
167 * Increment the counter when iterating through the TLV data.
169 * @param[in] aReader A reference to the TLV reader containing the TLV
170 * data to count the number of TLV elements.
171 * @param[in] aDepth The current depth into the TLV data.
172 * @param[in,out] aContext A pointer to the handler-specific context which
173 * is a pointer to storage for the count value.
175 * @retval #CHIP_NO_ERROR On success.
177 * @retval #CHIP_ERROR_INVALID_ARGUMENT If @a aContext is NULL.
180 static CHIP_ERROR CountHandler(const TLVReader & aReader, size_t aDepth, void * aContext)
182 CHIP_ERROR retval = CHIP_NO_ERROR;
184 VerifyOrExit(aContext != nullptr, retval = CHIP_ERROR_INVALID_ARGUMENT);
186 *static_cast<size_t *>(aContext) += 1;
193 * Count the number of TLV elements within the specified TLV reader,
194 * descending into arrays or structures.
196 * @param[in] aReader A read-only reference to the TLV reader for
197 * which to count the number of TLV elements.
198 * @param[in,out] aCount A reference to storage for the returned count.
199 * This is initialized to zero (0) prior to counting
200 * and is set to the number of elements counted on
203 * @retval #CHIP_NO_ERROR On success.
206 CHIP_ERROR Count(const TLVReader & aReader, size_t & aCount)
208 const bool recurse = true;
211 retval = Count(aReader, aCount, recurse);
217 * Count the number of TLV elements within the specified TLV reader,
218 * optionally descending into arrays or structures.
220 * @param[in] aReader A read-only reference to the TLV reader for
221 * which to count the number of TLV elements.
222 * @param[in,out] aCount A reference to storage for the returned count.
223 * This is initialized to zero (0) prior to counting
224 * and is set to the number of elements counted on
226 * @param[in] aRecurse A Boolean indicating whether (true) or not (false)
227 * any encountered arrays or structures should be
230 * @retval #CHIP_NO_ERROR On success.
233 CHIP_ERROR Count(const TLVReader & aReader, size_t & aCount, const bool aRecurse)
239 retval = Iterate(aReader, CountHandler, &aCount, aRecurse);
241 if (retval == CHIP_END_OF_TLV)
242 retval = CHIP_NO_ERROR;
248 * Search for the specified tag within the provided TLV reader.
250 * @param[in] aReader A read-only reference to the TLV reader in
251 * which to find the specified tag.
252 * @param[in] aDepth The current depth into the TLV data.
253 * @param[in,out] aContext A pointer to the handler-specific context.
255 * @retval #CHIP_NO_ERROR On success.
257 * @retval #CHIP_ERROR_INVALID_ARGUMENT If @a aContext is NULL.
259 * @retval #CHIP_ERROR_MAX If the specified tag is found.
262 static CHIP_ERROR FindHandler(const TLVReader & aReader, size_t aDepth, void * aContext)
264 const FindContext * theContext = static_cast<const FindContext *>(aContext);
265 CHIP_ERROR retval = CHIP_NO_ERROR;
267 VerifyOrExit(aContext != nullptr, retval = CHIP_ERROR_INVALID_ARGUMENT);
269 if (theContext->mTag == aReader.GetTag())
271 theContext->mReader.Init(aReader);
272 // terminate the iteration when the specified tag is found
273 retval = CHIP_ERROR_MAX;
281 * Search for the specified tag within the provided TLV reader.
283 * @param[in] aReader A read-only reference to the TLV reader in
284 * which to find the specified tag.
285 * @param[in] aTag A read-only reference to the TLV tag to find.
286 * @param[out] aResult A reference to storage to a TLV reader which
287 * will be positioned at the specified tag
290 * @retval #CHIP_NO_ERROR On success.
292 * @retval #CHIP_ERROR_TLV_TAG_NOT_FOUND If the specified tag @a aTag was not found.
295 CHIP_ERROR Find(const TLVReader & aReader, const uint64_t & aTag, TLVReader & aResult)
297 const bool recurse = true;
300 retval = Find(aReader, aTag, aResult, recurse);
306 * Search for the specified tag within the provided TLV reader,
307 * optionally descending into arrays or structures.
309 * @param[in] aReader A read-only reference to the TLV reader in
310 * which to find the specified tag.
311 * @param[in] aTag A read-only reference to the TLV tag to find.
312 * @param[out] aResult A reference to storage to a TLV reader which
313 * will be positioned at the specified tag
315 * @param[in] aRecurse A Boolean indicating whether (true) or not (false)
316 * any encountered arrays or structures should be
319 * @retval #CHIP_NO_ERROR On success.
321 * @retval #CHIP_ERROR_TLV_TAG_NOT_FOUND If the specified tag @a aTag was not found.
324 CHIP_ERROR Find(const TLVReader & aReader, const uint64_t & aTag, TLVReader & aResult, const bool aRecurse)
326 FindContext theContext = { aTag, aResult };
329 retval = Iterate(aReader, FindHandler, &theContext, aRecurse);
331 if (retval == CHIP_ERROR_MAX)
332 retval = CHIP_NO_ERROR;
334 retval = CHIP_ERROR_TLV_TAG_NOT_FOUND;
339 struct FindPredicateContext
342 IterateHandler mHandler;
344 FindPredicateContext(TLVReader & inReader, IterateHandler inHandler, void * inContext);
347 FindPredicateContext::FindPredicateContext(TLVReader & inReader, IterateHandler inHandler, void * inContext) :
348 mResult(inReader), mHandler(inHandler), mContext(inContext)
351 static CHIP_ERROR FindPredicateHandler(const TLVReader & aReader, size_t aDepth, void * aContext)
353 FindPredicateContext * theContext = static_cast<FindPredicateContext *>(aContext);
356 err = theContext->mHandler(aReader, aDepth, theContext->mContext);
358 if (err == CHIP_ERROR_MAX)
359 theContext->mResult.Init(aReader);
365 * Search for the first element matching the predicate within the TLV reader
366 * descending into arrays or structures. The @a aPredicate is applied
367 * to each visited TLV element; the @a aPredicate shall return #CHIP_ERROR_MAX
368 * for the matching elements, #CHIP_NO_ERROR for non-matching elements, and any
369 * other value to terminate the search.
371 * @param[in] aReader A read-only reference to the TLV reader in which to find the
372 * element matching the predicate.
373 * @param[in] aPredicate A predicate to be applied to each TLV element. To
374 * support the code reuse, aPredicate has the
375 * IterateHandler type. The return value of aPredicate
376 * controls the search: a #CHIP_ERROR_MAX signals that
377 * desired element has been found, #CHIP_NO_ERROR
378 * signals that the desired element has not been found,
379 * and all other values signal that the saerch should be
381 * @param[in] aContext An optional pointer to caller-provided context data.
383 * @param[out] aResult A reference to storage to a TLV reader which
384 * will be positioned at the specified tag
386 * @retval #CHIP_NO_ERROR On success.
388 * @retval #CHIP_ERROR_TLV_TAG_NOT_FOUND If the specified @a aPredicate did not locate the specified element
391 CHIP_ERROR Find(const TLVReader & aReader, IterateHandler aPredicate, void * aContext, TLVReader & aResult)
393 const bool recurse = true;
394 return Find(aReader, aPredicate, aContext, aResult, recurse);
398 * Search for the first element matching the predicate within the TLV reader
399 * optionally descending into arrays or structures. The @a aPredicate is applied
400 * to each visited TLV element; the @a aPredicate shall return #CHIP_ERROR_MAX
401 * for the matching elements, #CHIP_NO_ERROR for non-matching elements, and any
402 * other value to terminate the search.
404 * @param[in] aReader A read-only reference to the TLV reader in which to find the
405 * element matching the predicate.
406 * @param[in] aPredicate A predicate to be applied to each TLV element. To
407 * support the code reuse, aPredicate has the
408 * @a IterateHandler type. The return value of aPredicate
409 * controls the search: a #CHIP_ERROR_MAX signals that
410 * desired element has been found, #CHIP_NO_ERROR
411 * signals that the desired element has not been found,
412 * and all other values signal that the saerch should be
414 * @param[in] aContext An optional pointer to caller-provided context data.
415 * @param[out] aResult A reference to storage to a TLV reader which
416 * will be positioned at the specified tag
418 * @param[in] aRecurse A boolean indicating whether (true) or not (false) any
419 * encountered arrays or structures should be descended
422 * @retval #CHIP_NO_ERROR On success.
424 * @retval #CHIP_ERROR_TLV_TAG_NOT_FOUND If the specified @a aPredicate did not locate the specified element
427 CHIP_ERROR Find(const TLVReader & aReader, IterateHandler aPredicate, void * aContext, TLVReader & aResult, const bool aRecurse)
430 FindPredicateContext theContext(aResult, aPredicate, aContext);
432 retval = Iterate(aReader, FindPredicateHandler, &theContext, aRecurse);
434 if (retval == CHIP_ERROR_MAX)
435 retval = CHIP_NO_ERROR;
437 retval = CHIP_ERROR_TLV_TAG_NOT_FOUND;
442 } // namespace Utilities