Matter SDK Coverage Report
Current view: top level - lib/core - TLVUtilities.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 94.7 % 75 71
Test Date: 2025-01-17 19:00:11 Functions: 92.3 % 13 12

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020 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 utility interfaces for managing and
      22              :  *      working with CHIP TLV.
      23              :  *
      24              :  */
      25              : 
      26              : #include <lib/core/TLVUtilities.h>
      27              : 
      28              : #include <lib/core/CHIPError.h>
      29              : #include <lib/core/TLVReader.h>
      30              : #include <lib/core/TLVTags.h>
      31              : #include <lib/core/TLVTypes.h>
      32              : #include <lib/support/CodeUtils.h>
      33              : 
      34              : namespace chip {
      35              : 
      36              : namespace TLV {
      37              : 
      38              : namespace Utilities {
      39              : 
      40              : namespace {
      41              : 
      42              : // Sets up a limit on recursion depth, to avoid any stack overflows
      43              : // on very deep TLV structures. Embedded has limited stack space.
      44              : constexpr size_t kMaxRecursionDepth = 10;
      45              : 
      46              : } // namespace
      47              : 
      48              : struct FindContext
      49              : {
      50              :     const Tag & mTag;
      51              :     TLVReader & mReader;
      52              : };
      53              : 
      54              : /**
      55              :  *  Iterate through the TLV data referenced by @a aReader and invoke @a aHandler
      56              :  *  for each visited TLV element in the context of @a aContext.
      57              :  *  The iteration is aborted if @a aHandler returns anything other than #CHIP_NO_ERROR
      58              :  *
      59              :  *  @param[in]     aReader      A reference to the TLV reader containing the TLV
      60              :  *                              data to iterate.
      61              :  *  @param[in]     aDepth       The current depth into the TLV data.
      62              :  *  @param[in]     aHandler     A callback to invoke for the current TLV element
      63              :  *                              being visited.
      64              :  *  @param[in,out] aContext     An optional pointer to caller-provided context data.
      65              :  *  @param[in]     aRecurse     A Boolean indicating whether (true) or not (false)
      66              :  *                              any encountered arrays or structures should be
      67              :  *                              descended into.
      68              :  *
      69              :  *  @retval  #CHIP_END_OF_TLV   On a successful iteration to the end of a TLV encoding,
      70              :  *                              or to the end of a TLV container.
      71              :  *
      72              :  *  @retval  The last value returned by @a aHandler, if different than #CHIP_NO_ERROR
      73              :  */
      74         9147 : static CHIP_ERROR Iterate(TLVReader & aReader, size_t aDepth, IterateHandler aHandler, void * aContext, bool aRecurse)
      75              : {
      76         9147 :     CHIP_ERROR retval = CHIP_NO_ERROR;
      77              : 
      78         9147 :     if (aDepth >= kMaxRecursionDepth)
      79              :     {
      80            0 :         return CHIP_ERROR_RECURSION_DEPTH_LIMIT;
      81              :     }
      82              : 
      83         9147 :     if (aReader.GetType() == kTLVType_NotSpecified)
      84              :     {
      85         9102 :         ReturnErrorOnFailure(aReader.Next());
      86              :     }
      87              : 
      88              :     do
      89              :     {
      90        39131 :         const TLVType theType = aReader.GetType();
      91              : 
      92        39131 :         ReturnErrorOnFailure((aHandler) (aReader, aDepth, aContext));
      93              : 
      94        38144 :         if (aRecurse && TLVTypeIsContainer(theType))
      95              :         {
      96              :             TLVType containerType;
      97              : 
      98          529 :             ReturnErrorOnFailure(aReader.EnterContainer(containerType));
      99              : 
     100          529 :             retval = Iterate(aReader, aDepth + 1, aHandler, aContext, aRecurse);
     101          529 :             if ((retval != CHIP_END_OF_TLV) && (retval != CHIP_NO_ERROR))
     102              :             {
     103            4 :                 return retval;
     104              :             }
     105              : 
     106          525 :             ReturnErrorOnFailure(aReader.ExitContainer(containerType));
     107              :         }
     108        38138 :     } while ((retval = aReader.Next()) == CHIP_NO_ERROR);
     109              : 
     110         8137 :     return retval;
     111              : }
     112              : 
     113              : /**
     114              :  *  Iterate through the TLV data referenced by @a aReader and invoke @a aHandler
     115              :  *  for each visited TLV element in the context of @a aContext.
     116              :  *  The iteration is aborted if @a aHandler returns anything other than #CHIP_NO_ERROR
     117              :  *
     118              :  *  @param[in]     aReader      A reference to the TLV reader containing the TLV
     119              :  *                              data to iterate.
     120              :  *  @param[in]     aHandler     A callback to invoke for the current TLV element
     121              :  *                              being visited.
     122              :  *  @param[in,out] aContext     An optional pointer to caller-provided context data.
     123              :  *
     124              :  *  @retval  #CHIP_END_OF_TLV  On a successful iteration to the end of a TLV encoding,
     125              :  *                              or to the end of a TLV container.
     126              :  *
     127              :  *  @retval  #CHIP_ERROR_INVALID_ARGUMENT  If @a aHandler is NULL.
     128              :  *
     129              :  *  @retval  The last value returned by @a aHandler, if different than #CHIP_NO_ERROR
     130              :  *
     131              :  */
     132           76 : CHIP_ERROR Iterate(const TLVReader & aReader, IterateHandler aHandler, void * aContext)
     133              : {
     134           76 :     const bool recurse = true;
     135              :     CHIP_ERROR retval;
     136              : 
     137           76 :     retval = Iterate(aReader, aHandler, aContext, recurse);
     138              : 
     139           76 :     return retval;
     140              : }
     141              : 
     142              : /**
     143              :  *  Iterate through the TLV data referenced by @a aReader and invoke @a aHandler
     144              :  *  for each visited TLV element in the context of @a aContext.
     145              :  *  The iteration is aborted if @a aHandler returns anything other than #CHIP_NO_ERROR
     146              :  *
     147              :  *  @param[in]     aReader      A reference to the TLV reader containing the TLV
     148              :  *                              data to iterate.
     149              :  *  @param[in]     aHandler     A callback to invoke for the current TLV element
     150              :  *                              being visited.
     151              :  *  @param[in,out] aContext     An optional pointer to caller-provided context data.
     152              :  *  @param[in]     aRecurse     A Boolean indicating whether (true) or not (false)
     153              :  *                              any encountered arrays or structures should be
     154              :  *                              descended into.
     155              :  *
     156              :  *  @retval  #CHIP_END_OF_TLV  On a successful iteration to the end of a TLV encoding,
     157              :  *                              or to the end of a TLV container.
     158              :  *
     159              :  *  @retval  #CHIP_ERROR_INVALID_ARGUMENT  If @a aHandler is NULL.
     160              :  *
     161              :  *  @retval  The last value returned by @a aHandler, if different than #CHIP_NO_ERROR
     162              :  *
     163              :  */
     164         8618 : CHIP_ERROR Iterate(const TLVReader & aReader, IterateHandler aHandler, void * aContext, const bool aRecurse)
     165              : {
     166         8618 :     VerifyOrReturnError(aHandler != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     167              : 
     168         8618 :     TLVReader temp;
     169         8618 :     temp.Init(aReader);
     170              : 
     171         8618 :     constexpr size_t depth = 0;
     172         8618 :     return Iterate(temp, depth, aHandler, aContext, aRecurse);
     173              : }
     174              : 
     175              : /**
     176              :  *  Increment the counter when iterating through the TLV data.
     177              :  *
     178              :  *  @param[in]     aReader      A reference to the TLV reader containing the TLV
     179              :  *                              data to count the number of TLV elements.
     180              :  *  @param[in]     aDepth       The current depth into the TLV data.
     181              :  *  @param[in,out] aContext     A pointer to the handler-specific context which
     182              :  *                              is a pointer to storage for the count value.
     183              :  *
     184              :  *  @retval  #CHIP_NO_ERROR                On success.
     185              :  *
     186              :  *  @retval  #CHIP_ERROR_INVALID_ARGUMENT  If @a aContext is NULL.
     187              :  *
     188              :  */
     189         2506 : static CHIP_ERROR CountHandler(const TLVReader & aReader, size_t aDepth, void * aContext)
     190              : {
     191         2506 :     VerifyOrReturnError(aContext != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     192              : 
     193         2506 :     *static_cast<size_t *>(aContext) += 1;
     194              : 
     195         2506 :     return CHIP_NO_ERROR;
     196              : }
     197              : 
     198              : /**
     199              :  *  Count the number of TLV elements within the specified TLV reader,
     200              :  *  descending into arrays or structures.
     201              :  *
     202              :  *  @param[in]     aReader      A read-only reference to the TLV reader for
     203              :  *                              which to count the number of TLV elements.
     204              :  *  @param[in,out] aCount       A reference to storage for the returned count.
     205              :  *                              This is initialized to zero (0) prior to counting
     206              :  *                              and is set to the number of elements counted on
     207              :  *                              success.
     208              :  *
     209              :  *  @retval  #CHIP_NO_ERROR    On success.
     210              :  *
     211              :  */
     212            2 : CHIP_ERROR Count(const TLVReader & aReader, size_t & aCount)
     213              : {
     214            2 :     constexpr bool recurse = true;
     215            2 :     return Count(aReader, aCount, recurse);
     216              : }
     217              : 
     218              : /**
     219              :  *  Count the number of TLV elements within the specified TLV reader,
     220              :  *  optionally descending into arrays or structures.
     221              :  *
     222              :  *  @param[in]     aReader      A read-only reference to the TLV reader for
     223              :  *                              which to count the number of TLV elements.
     224              :  *  @param[in,out] aCount       A reference to storage for the returned count.
     225              :  *                              This is initialized to zero (0) prior to counting
     226              :  *                              and is set to the number of elements counted on
     227              :  *                              success.
     228              :  *  @param[in]     aRecurse     A Boolean indicating whether (true) or not (false)
     229              :  *                              any encountered arrays or structures should be
     230              :  *                              descended into.
     231              :  *
     232              :  *  @retval  #CHIP_NO_ERROR    On success.
     233              :  *
     234              :  */
     235         1166 : CHIP_ERROR Count(const TLVReader & aReader, size_t & aCount, const bool aRecurse)
     236              : {
     237         1166 :     aCount = 0;
     238              : 
     239         1166 :     CHIP_ERROR retval = Iterate(aReader, CountHandler, &aCount, aRecurse);
     240              : 
     241         1166 :     if (retval == CHIP_END_OF_TLV)
     242         1166 :         retval = CHIP_NO_ERROR;
     243              : 
     244         1166 :     return retval;
     245              : }
     246              : 
     247              : /**
     248              :  *  Search for the specified tag within the provided TLV reader.
     249              :  *
     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.
     254              :  *
     255              :  *  @retval  #CHIP_NO_ERROR                On success.
     256              :  *
     257              :  *  @retval  #CHIP_ERROR_INVALID_ARGUMENT  If @a aContext is NULL.
     258              :  *
     259              :  *  @retval  #CHIP_ERROR_SENTINEL          If the specified tag is found.
     260              :  *
     261              :  */
     262           55 : static CHIP_ERROR FindHandler(const TLVReader & aReader, size_t aDepth, void * aContext)
     263              : {
     264           55 :     VerifyOrReturnError(aContext != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     265           55 :     const FindContext * const theContext = static_cast<const FindContext *>(aContext);
     266              : 
     267           55 :     if (theContext->mTag == aReader.GetTag())
     268              :     {
     269            8 :         theContext->mReader.Init(aReader);
     270              :         // terminate the iteration when the specified tag is found
     271            8 :         return CHIP_ERROR_SENTINEL;
     272              :     }
     273              : 
     274           47 :     return CHIP_NO_ERROR;
     275              : }
     276              : 
     277              : /**
     278              :  *  Search for the specified tag within the provided TLV reader.
     279              :  *
     280              :  *  @param[in]   aReader        A read-only reference to the TLV reader in
     281              :  *                              which to find the specified tag.
     282              :  *  @param[in]   aTag           A read-only reference to the TLV tag to find.
     283              :  *  @param[out]  aResult        A reference to storage to a TLV reader which
     284              :  *                              will be positioned at the specified tag
     285              :  *                              on success.
     286              :  *
     287              :  *  @retval  #CHIP_NO_ERROR                    On success.
     288              :  *
     289              :  *  @retval  #CHIP_ERROR_TLV_TAG_NOT_FOUND     If the specified tag @a aTag was not found.
     290              :  *
     291              :  */
     292            6 : CHIP_ERROR Find(const TLVReader & aReader, const Tag & aTag, TLVReader & aResult)
     293              : {
     294            6 :     constexpr bool recurse = true;
     295            6 :     return Find(aReader, aTag, aResult, recurse);
     296              : }
     297              : 
     298              : /**
     299              :  *  Search for the specified tag within the provided TLV reader,
     300              :  *  optionally descending into arrays or structures.
     301              :  *
     302              :  *  @param[in]   aReader        A read-only reference to the TLV reader in
     303              :  *                              which to find the specified tag.
     304              :  *  @param[in]   aTag           A read-only reference to the TLV tag to find.
     305              :  *  @param[out]  aResult        A reference to storage to a TLV reader which
     306              :  *                              will be positioned at the specified tag
     307              :  *                              on success.
     308              :  *  @param[in]   aRecurse       A Boolean indicating whether (true) or not (false)
     309              :  *                              any encountered arrays or structures should be
     310              :  *                              descended into.
     311              :  *
     312              :  *  @retval  #CHIP_NO_ERROR                    On success.
     313              :  *
     314              :  *  @retval  #CHIP_ERROR_TLV_TAG_NOT_FOUND     If the specified tag @a aTag was not found.
     315              :  *
     316              :  */
     317           12 : CHIP_ERROR Find(const TLVReader & aReader, const Tag & aTag, TLVReader & aResult, const bool aRecurse)
     318              : {
     319           12 :     FindContext theContext = { aTag, aResult };
     320           12 :     CHIP_ERROR retval      = Iterate(aReader, FindHandler, &theContext, aRecurse);
     321              : 
     322           12 :     if (retval == CHIP_ERROR_SENTINEL)
     323            8 :         retval = CHIP_NO_ERROR;
     324              :     else
     325            4 :         retval = CHIP_ERROR_TLV_TAG_NOT_FOUND;
     326              : 
     327           12 :     return retval;
     328              : }
     329              : 
     330              : struct FindPredicateContext
     331              : {
     332              :     TLVReader & mResult;
     333              :     IterateHandler mHandler;
     334              :     void * mContext;
     335              :     FindPredicateContext(TLVReader & inReader, IterateHandler inHandler, void * inContext);
     336              : };
     337              : 
     338            3 : FindPredicateContext::FindPredicateContext(TLVReader & inReader, IterateHandler inHandler, void * inContext) :
     339            3 :     mResult(inReader), mHandler(inHandler), mContext(inContext)
     340            3 : {}
     341              : 
     342            4 : static CHIP_ERROR FindPredicateHandler(const TLVReader & aReader, size_t aDepth, void * aContext)
     343              : {
     344            4 :     FindPredicateContext * theContext = static_cast<FindPredicateContext *>(aContext);
     345              :     CHIP_ERROR err;
     346              : 
     347            4 :     err = theContext->mHandler(aReader, aDepth, theContext->mContext);
     348              : 
     349            4 :     if (err == CHIP_ERROR_SENTINEL)
     350            2 :         theContext->mResult.Init(aReader);
     351              : 
     352            4 :     return err;
     353              : }
     354              : 
     355              : /**
     356              :  *  Search for the first element matching the predicate within the TLV reader
     357              :  *  descending into arrays or structures. The @a aPredicate is applied
     358              :  *  to each visited TLV element; the @a aPredicate shall return #CHIP_ERROR_SENTINEL
     359              :  *  for the matching elements, #CHIP_NO_ERROR for non-matching elements, and any
     360              :  *  other value to terminate the search.
     361              :  *
     362              :  *  @param[in] aReader     A read-only reference to the TLV reader in which to find the
     363              :  *                         element matching the predicate.
     364              :  *  @param[in] aPredicate  A predicate to be applied to each TLV element.  To
     365              :  *                         support the code reuse, aPredicate has the
     366              :  *                         IterateHandler type.  The return value of aPredicate
     367              :  *                         controls the search: a #CHIP_ERROR_SENTINEL signals that
     368              :  *                         desired element has been found, #CHIP_NO_ERROR
     369              :  *                         signals that the desired element has not been found,
     370              :  *                         and all other values signal that the search should be
     371              :  *                         terminated.
     372              :  *  @param[in] aContext    An optional pointer to caller-provided context data.
     373              :  *
     374              :  *  @param[out] aResult    A reference to storage to a TLV reader which
     375              :  *                         will be positioned at the specified tag
     376              :  *                         on success.
     377              :  *  @retval  #CHIP_NO_ERROR                    On success.
     378              :  *
     379              :  *  @retval  #CHIP_ERROR_TLV_TAG_NOT_FOUND     If the specified @a aPredicate did not locate the specified element
     380              :  *
     381              :  */
     382            0 : CHIP_ERROR Find(const TLVReader & aReader, IterateHandler aPredicate, void * aContext, TLVReader & aResult)
     383              : {
     384            0 :     const bool recurse = true;
     385            0 :     return Find(aReader, aPredicate, aContext, aResult, recurse);
     386              : }
     387              : 
     388              : /**
     389              :  *  Search for the first element matching the predicate within the TLV reader
     390              :  *  optionally descending into arrays or structures. The @a aPredicate is applied
     391              :  *  to each visited TLV element; the @a aPredicate shall return #CHIP_ERROR_SENTINEL
     392              :  *  for the matching elements, #CHIP_NO_ERROR for non-matching elements, and any
     393              :  *  other value to terminate the search.
     394              :  *
     395              :  *  @param[in] aReader     A read-only reference to the TLV reader in which to find the
     396              :  *                         element matching the predicate.
     397              :  *  @param[in] aPredicate  A predicate to be applied to each TLV element.  To
     398              :  *                         support the code reuse, aPredicate has the
     399              :  *                         @a IterateHandler type.  The return value of aPredicate
     400              :  *                         controls the search: a #CHIP_ERROR_SENTINEL signals that
     401              :  *                         desired element has been found, #CHIP_NO_ERROR
     402              :  *                         signals that the desired element has not been found,
     403              :  *                         and all other values signal that the saerch should be
     404              :  *                         terminated.
     405              :  *  @param[in] aContext    An optional pointer to caller-provided context data.
     406              :  *  @param[out] aResult    A reference to storage to a TLV reader which
     407              :  *                         will be positioned at the specified tag
     408              :  *                         on success.
     409              :  *  @param[in] aRecurse    A boolean indicating whether (true) or not (false) any
     410              :  *                         encountered arrays or structures should be descended
     411              :  *                         into.
     412              :  *
     413              :  *  @retval  #CHIP_NO_ERROR                    On success.
     414              :  *
     415              :  *  @retval  #CHIP_ERROR_TLV_TAG_NOT_FOUND     If the specified @a aPredicate did not locate the specified element
     416              :  *
     417              :  */
     418            3 : CHIP_ERROR Find(const TLVReader & aReader, IterateHandler aPredicate, void * aContext, TLVReader & aResult, const bool aRecurse)
     419              : {
     420              :     CHIP_ERROR retval;
     421            3 :     FindPredicateContext theContext(aResult, aPredicate, aContext);
     422              : 
     423            3 :     retval = Iterate(aReader, FindPredicateHandler, &theContext, aRecurse);
     424              : 
     425            3 :     if (retval == CHIP_ERROR_SENTINEL)
     426            2 :         retval = CHIP_NO_ERROR;
     427              :     else
     428            1 :         retval = CHIP_ERROR_TLV_TAG_NOT_FOUND;
     429              : 
     430            3 :     return retval;
     431              : }
     432              : 
     433              : } // namespace Utilities
     434              : 
     435              : } // namespace TLV
     436              : 
     437              : } // namespace chip
        

Generated by: LCOV version 2.0-1