blob: 22af6b605c2713cad937c6e14ac49fe8b62090c9 [file] [log] [blame]
/*
*
* Copyright (c) 2015-2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file implements utility interfaces for managing and
* working with Weave TLV.
*
*/
#include <Weave/Core/WeaveTLVDebug.hpp>
#include <Weave/Core/WeaveTLVUtilities.hpp>
#include <Weave/Support/CodeUtils.h>
namespace nl {
namespace Weave {
namespace TLV {
namespace Utilities {
struct FindContext {
const uint64_t & mTag;
TLVReader & mReader;
};
/**
* Iterate through the TLV data referenced by @a aReader and invoke @a aHandler
* for each visited TLV element in the context of @a aContext.
* The iteration is aborted if @a aHandler returns anything other than #WEAVE_NO_ERROR
*
* @param[in] aReader A reference to the TLV reader containing the TLV
* data to iterate.
* @param[in] aDepth The current depth into the TLV data.
* @param[in] aHandler A callback to invoke for the current TLV element
* being visited.
* @param[inout] aContext An optional pointer to caller-provided context data.
* @param[in] aRecurse A Boolean indicating whether (true) or not (false)
* any encountered arrays or structures should be
* descended into.
*
* @retval #WEAVE_END_OF_TLV On a successful iteration to the end of a TLV encoding,
* or to the end of a TLV container.
*
* @retval The last value returned by @a aHandler, if different than #WEAVE_NO_ERROR
*/
static WEAVE_ERROR Iterate(TLVReader &aReader, size_t aDepth, IterateHandler aHandler, void *aContext, bool aRecurse)
{
WEAVE_ERROR retval = WEAVE_NO_ERROR;
if (aReader.GetType() == kTLVType_NotSpecified)
{
retval = aReader.Next();
SuccessOrExit(retval);
}
do
{
const TLVType theType = aReader.GetType();
retval = (aHandler)(aReader, aDepth, aContext);
SuccessOrExit(retval);
if (aRecurse && TLVTypeIsContainer(theType))
{
TLVType containerType;
retval = aReader.EnterContainer(containerType);
SuccessOrExit(retval);
retval = Iterate(aReader, aDepth + 1, aHandler, aContext, aRecurse);
if (retval != WEAVE_END_OF_TLV)
SuccessOrExit(retval);
retval = aReader.ExitContainer(containerType);
SuccessOrExit(retval);
}
} while ((retval = aReader.Next()) == WEAVE_NO_ERROR);
exit:
return retval;
}
/**
* Iterate through the TLV data referenced by @a aReader and invoke @a aHandler
* for each visited TLV element in the context of @a aContext.
* The iteration is aborted if @a aHandler returns anything other than #WEAVE_NO_ERROR
*
* @param[in] aReader A reference to the TLV reader containing the TLV
* data to iterate.
* @param[in] aHandler A callback to invoke for the current TLV element
* being visited.
* @param[inout] aContext An optional pointer to caller-provided context data.
*
* @retval #WEAVE_END_OF_TLV On a successful iteration to the end of a TLV encoding,
* or to the end of a TLV container.
*
* @retval #WEAVE_ERROR_INVALID_ARGUMENT If @a aHandler is NULL.
*
* @retval The last value returned by @a aHandler, if different than #WEAVE_NO_ERROR
*
*/
WEAVE_ERROR Iterate(const TLVReader &aReader, IterateHandler aHandler, void *aContext)
{
const bool recurse = true;
WEAVE_ERROR retval;
retval = Iterate(aReader, aHandler, aContext, recurse);
return retval;
}
/**
* Iterate through the TLV data referenced by @a aReader and invoke @a aHandler
* for each visited TLV element in the context of @a aContext.
* The iteration is aborted if @a aHandler returns anything other than #WEAVE_NO_ERROR
*
* @param[in] aReader A reference to the TLV reader containing the TLV
* data to iterate.
* @param[in] aHandler A callback to invoke for the current TLV element
* being visited.
* @param[inout] aContext An optional pointer to caller-provided context data.
* @param[in] aRecurse A Boolean indicating whether (true) or not (false)
* any encountered arrays or structures should be
* descended into.
*
* @retval #WEAVE_END_OF_TLV On a successful iteration to the end of a TLV encoding,
* or to the end of a TLV container.
*
* @retval #WEAVE_ERROR_INVALID_ARGUMENT If @a aHandler is NULL.
*
* @retval The last value returned by @a aHandler, if different than #WEAVE_NO_ERROR
*
*/
WEAVE_ERROR Iterate(const TLVReader &aReader, IterateHandler aHandler, void *aContext, const bool aRecurse)
{
const size_t depth = 0;
TLVReader temp;
WEAVE_ERROR retval = WEAVE_ERROR_NOT_IMPLEMENTED;
VerifyOrExit(aHandler != NULL, retval = WEAVE_ERROR_INVALID_ARGUMENT);
temp.Init(aReader);
retval = Iterate(temp, depth, aHandler, aContext, aRecurse);
exit:
return retval;
}
/**
* Increment the counter when iterating through the TLV data.
*
* @param[in] aReader A reference to the TLV reader containing the TLV
* data to count the number of TLV elements.
* @param[in] aDepth The current depth into the TLV data.
* @param[inout] aContext A pointer to the handler-specific context which
* is a pointer to storage for the count value.
*
* @retval #WEAVE_NO_ERROR On success.
*
* @retval #WEAVE_ERROR_INVALID_ARGUMENT If @a aContext is NULL.
*
*/
static WEAVE_ERROR CountHandler(const TLVReader &aReader, size_t aDepth, void *aContext)
{
WEAVE_ERROR retval = WEAVE_NO_ERROR;
VerifyOrExit(aContext != NULL, retval = WEAVE_ERROR_INVALID_ARGUMENT);
*static_cast<size_t *>(aContext) += 1;
exit:
return retval;
}
/**
* Count the number of TLV elements within the specified TLV reader,
* descending into arrays or structures.
*
* @param[in] aReader A read-only reference to the TLV reader for
* which to count the number of TLV elements.
* @param[inout] aCount A reference to storage for the returned count.
* This is initialized to zero (0) prior to counting
* and is set to the number of elements counted on
* success.
*
* @retval #WEAVE_NO_ERROR On success.
*
*/
WEAVE_ERROR Count(const TLVReader &aReader, size_t &aCount)
{
const bool recurse = true;
WEAVE_ERROR retval;
retval = Count(aReader, aCount, recurse);
return retval;
}
/**
* Count the number of TLV elements within the specified TLV reader,
* optionally descending into arrays or structures.
*
* @param[in] aReader A read-only reference to the TLV reader for
* which to count the number of TLV elements.
* @param[inout] aCount A reference to storage for the returned count.
* This is initialized to zero (0) prior to counting
* and is set to the number of elements counted on
* success.
* @param[in] aRecurse A Boolean indicating whether (true) or not (false)
* any encountered arrays or structures should be
* descended into.
*
* @retval #WEAVE_NO_ERROR On success.
*
*/
WEAVE_ERROR Count(const TLVReader &aReader, size_t &aCount, const bool aRecurse)
{
WEAVE_ERROR retval;
aCount = 0;
retval = Iterate(aReader, CountHandler, &aCount, aRecurse);
if (retval == WEAVE_END_OF_TLV)
retval = WEAVE_NO_ERROR;
return retval;
}
/**
* Search for the specified tag within the provided TLV reader.
*
* @param[in] aReader A read-only reference to the TLV reader in
* which to find the specified tag.
* @param[in] aDepth The current depth into the TLV data.
* @param[inout] aContext A pointer to the handler-specific context.
*
* @retval #WEAVE_NO_ERROR On success.
*
* @retval #WEAVE_ERROR_INVALID_ARGUMENT If @a aContext is NULL.
*
* @retval #WEAVE_ERROR_MAX If the specified tag is found.
*
*/
static WEAVE_ERROR FindHandler(const TLVReader &aReader, size_t aDepth, void *aContext)
{
const FindContext * theContext = static_cast<const FindContext *>(aContext);
WEAVE_ERROR retval = WEAVE_NO_ERROR;
VerifyOrExit(aContext != NULL, retval = WEAVE_ERROR_INVALID_ARGUMENT);
if (theContext->mTag == aReader.GetTag())
{
theContext->mReader.Init(aReader);
// terminate the iteration when the specified tag is found
retval = WEAVE_ERROR_MAX;
}
exit:
return retval;
}
/**
* Search for the specified tag within the provided TLV reader.
*
* @param[in] aReader A read-only reference to the TLV reader in
* which to find the specified tag.
* @param[in] aTag A read-only reference to the TLV tag to find.
* @param[out] aResult A reference to storage to a TLV reader which
* will be positioned at the specified tag
* on success.
*
* @retval #WEAVE_NO_ERROR On success.
*
* @retval #WEAVE_ERROR_TLV_TAG_NOT_FOUND If the specified tag @a aTag was not found.
*
*/
WEAVE_ERROR Find(const TLVReader &aReader, const uint64_t &aTag, TLVReader &aResult)
{
const bool recurse = true;
WEAVE_ERROR retval;
retval = Find(aReader, aTag, aResult, recurse);
return retval;
}
/**
* Search for the specified tag within the provided TLV reader,
* optionally descending into arrays or structures.
*
* @param[in] aReader A read-only reference to the TLV reader in
* which to find the specified tag.
* @param[in] aTag A read-only reference to the TLV tag to find.
* @param[out] aResult A reference to storage to a TLV reader which
* will be positioned at the specified tag
* on success.
* @param[in] aRecurse A Boolean indicating whether (true) or not (false)
* any encountered arrays or structures should be
* descended into.
*
* @retval #WEAVE_NO_ERROR On success.
*
* @retval #WEAVE_ERROR_TLV_TAG_NOT_FOUND If the specified tag @a aTag was not found.
*
*/
WEAVE_ERROR Find(const TLVReader &aReader, const uint64_t &aTag, TLVReader &aResult, const bool aRecurse)
{
FindContext theContext = { aTag, aResult };
WEAVE_ERROR retval;
retval = Iterate(aReader, FindHandler, &theContext, aRecurse);
if (retval == WEAVE_ERROR_MAX)
retval = WEAVE_NO_ERROR;
else
retval = WEAVE_ERROR_TLV_TAG_NOT_FOUND;
return retval;
}
} // namespace Utilities
} // namespace TLV
} // namespace Weave
} // namespace nl