blob: dede6835017194f5289998b7fc4bac7a85b59b6a [file] [log] [blame]
/*
*
* Copyright (c) 2018 Google LLC.
* Copyright (c) 2016-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 parsers and encoders for messages in Weave
* Data Management (WDM) profile.
*
*/
// __STDC_FORMAT_MACROS must be defined for PRIX64 to be defined for pre-C++11 clib
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif // __STDC_FORMAT_MACROS
// __STDC_LIMIT_MACROS must be defined for UINT8_MAX and INT32_MAX to be defined for pre-C++11 clib
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif // __STDC_LIMIT_MACROS
// __STDC_CONSTANT_MACROS must be defined for INT64_C and UINT64_C to be defined for pre-C++11 clib
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif // __STDC_CONSTANT_MACROS
#include <Weave/Profiles/data-management/Current/WdmManagedNamespace.h>
#include <Weave/Profiles/data-management/DataManagement.h>
#include <Weave/Profiles/security/WeaveSecurity.h>
#include <Weave/Support/WeaveFaultInjection.h>
#include <stdio.h>
using namespace ::nl;
using namespace ::nl::Weave;
using namespace ::nl::Weave::TLV;
#ifndef MIN
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif
namespace nl {
namespace Weave {
namespace Profiles {
namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current) {
#if WEAVE_DETAIL_LOGGING
static uint32_t gPrettyPrintingDepthLevel = 0;
static char gLineBuffer[256];
static uint32_t gCurLineBufferSize = 0;
/**
* Simple object to checkpoint the pretty-print indentation level and make
* sure it is restored at the end of a block (even in case of early exit).
*/
class PrettyPrintCheckpoint
{
public:
PrettyPrintCheckpoint()
{
mLevel = gPrettyPrintingDepthLevel;
}
~PrettyPrintCheckpoint()
{
gPrettyPrintingDepthLevel = mLevel;
}
private:
uint32_t mLevel;
};
#define PRETTY_PRINT_CHECKPOINT() PrettyPrintCheckpoint lPrettyPrintCheckpoint;
#define PRETTY_PRINT(fmt, ...) \
do \
{ \
PrettyPrintWDM(true, fmt, ##__VA_ARGS__); \
} while (0)
#define PRETTY_PRINT_SAMELINE(fmt, ...) \
do \
{ \
PrettyPrintWDM(false, fmt, ##__VA_ARGS__); \
} while (0)
#define PRETTY_PRINT_INCDEPTH() \
do \
{ \
gPrettyPrintingDepthLevel++; \
} while (0)
#define PRETTY_PRINT_DECDEPTH() \
do \
{ \
gPrettyPrintingDepthLevel--; \
} while (0)
static void PrettyPrintWDM(bool aIsNewLine, const char * aFmt, ...)
{
va_list args;
int ret;
int sizeLeft;
va_start(args, aFmt);
if (aIsNewLine)
{
if (gCurLineBufferSize)
{
// Don't need to explicitly NULL-terminate the string because
// snprintf takes care of that.
WeaveLogDetail(DataManagement, "%s", gLineBuffer);
gCurLineBufferSize = 0;
}
for (uint32_t i = 0; i < gPrettyPrintingDepthLevel; i++)
{
if (sizeof(gLineBuffer) > gCurLineBufferSize)
{
sizeLeft = sizeof(gLineBuffer) - gCurLineBufferSize;
ret = snprintf(gLineBuffer + gCurLineBufferSize, sizeLeft, "\t");
if (ret > 0)
{
gCurLineBufferSize += MIN(ret, sizeLeft);
}
}
}
}
if (sizeof(gLineBuffer) > gCurLineBufferSize)
{
sizeLeft = sizeof(gLineBuffer) - gCurLineBufferSize;
ret = vsnprintf(gLineBuffer + gCurLineBufferSize, sizeLeft, aFmt, args);
if (ret > 0)
{
gCurLineBufferSize += MIN(ret, sizeLeft);
}
}
va_end(args);
}
#else // WEAVE_DETAIL_LOGGING
#define PRETTY_PRINT_CHECKPOINT()
#define PRETTY_PRINT(fmt, ...)
#define PRETTY_PRINT_SAMELINE(fmt, ...)
#define PRETTY_PRINT_INCDEPTH()
#define PRETTY_PRINT_DECDEPTH()
#endif // WEAVE_DETAIL_LOGGING
WEAVE_ERROR LookForElementWithTag(const nl::Weave::TLV::TLVReader & aSrcReader, const uint64_t aTagInApiForm,
nl::Weave::TLV::TLVReader * apDstReader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// make a copy of the Path reader
nl::Weave::TLV::TLVReader reader;
reader.Init(aSrcReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
// Documentation says the result of GetType must be verified before calling GetTag
VerifyOrExit(nl::Weave::TLV::kTLVType_NotSpecified != reader.GetType(), err = WEAVE_ERROR_INVALID_TLV_ELEMENT);
if (aTagInApiForm == reader.GetTag())
{
apDstReader->Init(reader);
break;
}
}
exit:
WeaveLogIfFalse((WEAVE_NO_ERROR == err) || (WEAVE_END_OF_TLV == err));
return err;
}
ParserBase::ParserBase() { }
WEAVE_ERROR ParserBase::GetReaderOnTag(const uint64_t aTagToFind, nl::Weave::TLV::TLVReader * const apReader) const
{
return LookForElementWithTag(mReader, aTagToFind, apReader);
}
template <typename T>
WEAVE_ERROR ParserBase::GetUnsignedInteger(const uint8_t aContextTag, T * const apLValue) const
{
return GetSimpleValue(aContextTag, nl::Weave::TLV::kTLVType_UnsignedInteger, apLValue);
}
template <typename T>
WEAVE_ERROR ParserBase::GetSimpleValue(const uint8_t aContextTag, const nl::Weave::TLV::TLVType aTLVType, T * const apLValue) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
nl::Weave::TLV::TLVReader reader;
*apLValue = 0;
err = LookForElementWithTag(mReader, nl::Weave::TLV::ContextTag(aContextTag), &reader);
SuccessOrExit(err);
VerifyOrExit(aTLVType == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(*apLValue);
SuccessOrExit(err);
exit:
WeaveLogIfFalse((WEAVE_NO_ERROR == err) || (WEAVE_END_OF_TLV == err));
return err;
}
ListParserBase::ListParserBase() { }
WEAVE_ERROR ListParserBase::Init(const nl::Weave::TLV::TLVReader & aReader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// make a copy of the reader here
mReader.Init(aReader);
VerifyOrExit(nl::Weave::TLV::kTLVType_Array == mReader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
// This is just a dummy, as we're not going to exit this container ever
nl::Weave::TLV::TLVType OuterContainerType;
err = mReader.EnterContainer(OuterContainerType);
exit:
WeaveLogFunctError(err);
return err;
}
WEAVE_ERROR ListParserBase::InitIfPresent(const nl::Weave::TLV::TLVReader & aReader, const uint8_t aContextTagToFind)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
nl::Weave::TLV::TLVReader reader;
err = LookForElementWithTag(aReader, nl::Weave::TLV::ContextTag(aContextTagToFind), &reader);
SuccessOrExit(err);
err = Init(reader);
SuccessOrExit(err);
exit:
WeaveLogIfFalse((WEAVE_NO_ERROR == err) || (WEAVE_END_OF_TLV == err));
return err;
}
WEAVE_ERROR ListParserBase::Next(void)
{
WEAVE_ERROR err = mReader.Next();
WeaveLogIfFalse((WEAVE_NO_ERROR == err) || (WEAVE_END_OF_TLV == err));
return err;
}
void ListParserBase::GetReader(nl::Weave::TLV::TLVReader * const apReader)
{
apReader->Init(mReader);
}
BuilderBase::BuilderBase() :
mError(WEAVE_ERROR_INCORRECT_STATE), mpWriter(NULL), mOuterContainerType(nl::Weave::TLV::kTLVType_NotSpecified)
{ }
void BuilderBase::ResetError()
{
return ResetError(WEAVE_NO_ERROR);
}
void BuilderBase::ResetError(WEAVE_ERROR aErr)
{
mError = aErr;
mOuterContainerType = nl::Weave::TLV::kTLVType_NotSpecified;
}
void BuilderBase::EndOfContainer()
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->EndContainer(mOuterContainerType);
SuccessOrExit(mError);
// we've just closed properly
// mark it so we do not panic when the build object destructor is called
mOuterContainerType = nl::Weave::TLV::kTLVType_NotSpecified;
exit:;
}
WEAVE_ERROR BuilderBase::InitAnonymousStructure(nl::Weave::TLV::TLVWriter * const apWriter)
{
mpWriter = apWriter;
mOuterContainerType = nl::Weave::TLV::kTLVType_NotSpecified;
mError = mpWriter->StartContainer(nl::Weave::TLV::AnonymousTag, nl::Weave::TLV::kTLVType_Structure, mOuterContainerType);
WeaveLogFunctError(mError);
return mError;
}
ListBuilderBase::ListBuilderBase(void) { }
WEAVE_ERROR ListBuilderBase::Init(nl::Weave::TLV::TLVWriter * const apWriter, const uint8_t aContextTagToUse)
{
mpWriter = apWriter;
mOuterContainerType = nl::Weave::TLV::kTLVType_NotSpecified;
mError =
mpWriter->StartContainer(nl::Weave::TLV::ContextTag(aContextTagToUse), nl::Weave::TLV::kTLVType_Array, mOuterContainerType);
WeaveLogFunctError(mError);
return mError;
}
/**
* Init the TLV array container with an anonymous tag.
* Required to implement arrays of arrays, and to test ListBuilderBase.
* There is no WDM message that has an array as the outermost container.
*
* @param[in] apWriter Pointer to the TLVWriter that is encoding the message.
*
* @return WEAVE_ERROR codes returned by Weave::TLV objects.
*/
WEAVE_ERROR ListBuilderBase::Init(nl::Weave::TLV::TLVWriter * const apWriter)
{
mpWriter = apWriter;
mOuterContainerType = nl::Weave::TLV::kTLVType_NotSpecified;
mError =
mpWriter->StartContainer(nl::Weave::TLV::AnonymousTag, nl::Weave::TLV::kTLVType_Array, mOuterContainerType);
WeaveLogFunctError(mError);
return mError;
}
WEAVE_ERROR Path::Parser::Init(const nl::Weave::TLV::TLVReader & aReader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// make a copy of the reader here
mReader.Init(aReader);
VerifyOrExit(nl::Weave::TLV::kTLVType_Path == mReader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
// This is just a dummy, as we're not going to exit this container ever
nl::Weave::TLV::TLVType dummyContainerType;
// enter into the Path
err = mReader.EnterContainer(dummyContainerType);
SuccessOrExit(err);
err = mReader.Next();
SuccessOrExit(err);
VerifyOrExit(nl::Weave::TLV::ContextTag(kCsTag_InstanceLocator) == mReader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_ELEMENT);
VerifyOrExit(nl::Weave::TLV::kTLVType_Structure == mReader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
// enter into the root section, we still need to call Next to access the first element
err = mReader.EnterContainer(dummyContainerType);
SuccessOrExit(err);
exit:
WeaveLogFunctError(err);
return err;
}
// Get a TLVReader at the additional tags section. Next() must be called before accessing it.
WEAVE_ERROR Path::Parser::GetTags(nl::Weave::TLV::TLVReader * const apReader) const
{
nl::Weave::TLV::TLVType pathContainerType = nl::Weave::TLV::kTLVType_Path;
apReader->Init(mReader);
apReader->ExitContainer(pathContainerType);
return WEAVE_NO_ERROR;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Roughly verify the schema is right, including
// 1) all mandatory tags are present
// 2) no unknown tags
// 3) all elements have expected data type
// 4) any tag can only appear once
WEAVE_ERROR Path::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint16_t TagPresenceMask = 0;
nl::Weave::TLV::TLVReader reader;
PRETTY_PRINT_SAMELINE("<Resource = {");
// make a copy of the Path reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
VerifyOrExit(nl::Weave::TLV::IsContextTag(reader.GetTag()), err = WEAVE_ERROR_INVALID_TLV_TAG);
switch (nl::Weave::TLV::TagNumFromTag(reader.GetTag()))
{
case kCsTag_ResourceID:
// check if this tag has appeared before
VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_ResourceID)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kCsTag_ResourceID);
// Resource ID can be of any type, so no checking is done here
#if WEAVE_DETAIL_LOGGING
{
ResourceIdentifier resourceId;
char strResource[ResourceIdentifier::MAX_STRING_LENGTH];
err = resourceId.FromTLV(reader);
if (err == WEAVE_NO_ERROR)
{
resourceId.ToString(strResource, sizeof(strResource));
PRETTY_PRINT_SAMELINE("ResourceId = %s,", strResource);
}
else
{
PRETTY_PRINT_SAMELINE("ResourceId = ??,");
}
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_TraitInstanceID:
// check if this tag has appeared before
VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_TraitInstanceID)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kCsTag_TraitInstanceID);
// Instance ID can be of any type, so no checking is done here
#if WEAVE_DETAIL_LOGGING
if (nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType())
{
uint64_t InstanceID;
reader.Get(InstanceID);
PRETTY_PRINT_SAMELINE("InstanceId = 0x%" PRIx64 ",", InstanceID);
}
else
{
PRETTY_PRINT_SAMELINE("InstanceId = ??");
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_TraitProfileID:
{
SchemaVersionRange requestedVersion;
uint32_t ProfileID;
// check if this tag has appeared before
VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_TraitProfileID)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kCsTag_TraitProfileID);
if (reader.GetType() == nl::Weave::TLV::kTLVType_Array)
{
TLV::TLVType type;
err = reader.EnterContainer(type);
SuccessOrExit(err);
err = reader.Next();
SuccessOrExit(err);
VerifyOrExit(reader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(ProfileID);
SuccessOrExit(err);
err = reader.Next();
VerifyOrExit(err == WEAVE_NO_ERROR || err == WEAVE_END_OF_TLV, );
if (err == WEAVE_NO_ERROR)
{
VerifyOrExit(reader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(requestedVersion.mMaxVersion);
SuccessOrExit(err);
}
err = reader.Next();
VerifyOrExit(err == WEAVE_NO_ERROR || err == WEAVE_END_OF_TLV, );
if (err == WEAVE_NO_ERROR)
{
VerifyOrExit(reader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(requestedVersion.mMinVersion);
SuccessOrExit(err);
}
TagPresenceMask |= (1 << kCsTag_RequestedVersion);
err = reader.Next();
VerifyOrExit(err == WEAVE_END_OF_TLV, err = WEAVE_ERROR_WDM_MALFORMED_DATA_ELEMENT);
err = reader.ExitContainer(type);
}
else
{
VerifyOrExit(reader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(ProfileID);
SuccessOrExit(err);
}
#if WEAVE_DETAIL_LOGGING
{
if (TagPresenceMask & (1 << kCsTag_RequestedVersion))
{
PRETTY_PRINT_SAMELINE("[ProfileId = 0x%" PRIx32, ProfileID);
if (requestedVersion.mMaxVersion > 1)
{
PRETTY_PRINT_SAMELINE(", MaxVersion = %" PRIu32, requestedVersion.mMaxVersion);
}
if (requestedVersion.mMaxVersion > 1)
{
PRETTY_PRINT_SAMELINE(", MinVersion = %" PRIu32 "],", requestedVersion.mMinVersion);
}
else
{
PRETTY_PRINT_SAMELINE("],");
}
}
else
{
PRETTY_PRINT_SAMELINE("ProfileId = 0x%" PRIx32 ",", ProfileID);
}
}
#endif // WEAVE_DETAIL_LOGGING
break;
}
default:
ExitNow(err = WEAVE_ERROR_INVALID_TLV_TAG);
}
}
// if we have exhausted this container
if (WEAVE_END_OF_TLV == err)
{
// okay if we have at least the Profile ID field
if (TagPresenceMask & (1 << kCsTag_TraitProfileID))
{
err = WEAVE_NO_ERROR;
}
}
SuccessOrExit(err);
PRETTY_PRINT_SAMELINE("}");
err = GetTags(&reader);
SuccessOrExit(err);
// Verify that the remaining additional tag section has only TAG=NULL elements, and the tags cannot be anonymous
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
// Cannot have an anonymous element in this section
VerifyOrExit(nl::Weave::TLV::AnonymousTag != reader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
// Can only have NULL value in this section
VerifyOrExit(nl::Weave::TLV::kTLVType_Null == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
const uint64_t tag = reader.GetTag();
if (nl::Weave::TLV::IsContextTag(tag))
{
PRETTY_PRINT_SAMELINE("/0x%" PRIx32 " = null", nl::Weave::TLV::TagNumFromTag(tag));
}
else if (nl::Weave::TLV::IsProfileTag(tag))
{
PRETTY_PRINT_SAMELINE("/0x%" PRIx32 "::0x%" PRIx32 " = null", nl::Weave::TLV::ProfileIdFromTag(tag),
nl::Weave::TLV::TagNumFromTag(tag));
}
else
{
PRETTY_PRINT_SAMELINE("?");
}
#endif // WEAVE_DETAIL_LOGGING
}
PRETTY_PRINT_SAMELINE(">,");
if (WEAVE_END_OF_TLV == err)
{
err = WEAVE_NO_ERROR;
}
SuccessOrExit(err);
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Resource ID could be of any type, so we can only position the reader so the caller has
// full information of tag, element type, length, and value
// WEAVE_END_OF_TLV if there is no such element
WEAVE_ERROR Path::Parser::GetResourceID(nl::Weave::TLV::TLVReader * const apReader) const
{
WEAVE_ERROR err = LookForElementWithTag(mReader, nl::Weave::TLV::ContextTag(kCsTag_ResourceID), apReader);
WeaveLogIfFalse((WEAVE_NO_ERROR == err) || (WEAVE_END_OF_TLV == err));
return err;
}
// Instance ID could be of any type, so we can only position the reader so the caller has
// full information of tag, element type, length, and value
WEAVE_ERROR Path::Parser::GetInstanceID(nl::Weave::TLV::TLVReader * const apReader) const
{
WEAVE_ERROR err = LookForElementWithTag(mReader, nl::Weave::TLV::ContextTag(kCsTag_TraitInstanceID), apReader);
WeaveLogIfFalse((WEAVE_NO_ERROR == err) || (WEAVE_END_OF_TLV == err));
return err;
}
// WEAVE_END_OF_TLV if there is no such element
// WEAVE_ERROR_WRONG_TLV_TYPE if there is such element but it's not any of the defined unsigned integer types
WEAVE_ERROR Path::Parser::GetInstanceID(uint64_t * const apInstanceID) const
{
return GetUnsignedInteger(kCsTag_TraitInstanceID, apInstanceID);
}
// Profile ID can only be uint32_t and not any other type
// WEAVE_END_OF_TLV if there is no such element
// WEAVE_ERROR_WRONG_TLV_TYPE if there is such element but it's not any of the defined unsigned integer types
WEAVE_ERROR Path::Parser::GetProfileID(uint32_t * const apProfileID, SchemaVersionRange * const apSchemaVersionRange)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
nl::Weave::TLV::TLVReader reader;
nl::Weave::TLV::TLVType outerContainerType;
apSchemaVersionRange->mMinVersion = 1;
apSchemaVersionRange->mMaxVersion = 1;
err = LookForElementWithTag(mReader, nl::Weave::TLV::ContextTag(kCsTag_TraitProfileID), &reader);
SuccessOrExit(err);
if (reader.GetType() == nl::Weave::TLV::kTLVType_Array)
{
err = reader.EnterContainer(outerContainerType);
SuccessOrExit(err);
err = reader.Next();
SuccessOrExit(err);
VerifyOrExit(reader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(*apProfileID);
SuccessOrExit(err);
err = reader.Next();
VerifyOrExit(err == WEAVE_NO_ERROR || err == WEAVE_END_OF_TLV, );
if (err == WEAVE_NO_ERROR)
{
VerifyOrExit(reader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(apSchemaVersionRange->mMaxVersion);
SuccessOrExit(err);
}
err = reader.Next();
VerifyOrExit(err == WEAVE_NO_ERROR || err == WEAVE_END_OF_TLV, );
if (err == WEAVE_NO_ERROR)
{
VerifyOrExit(reader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(apSchemaVersionRange->mMinVersion);
SuccessOrExit(err);
}
err = reader.Next();
VerifyOrExit(err == WEAVE_END_OF_TLV, err = WEAVE_ERROR_WDM_MALFORMED_DATA_ELEMENT);
}
else
{
VerifyOrExit(reader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(*apProfileID);
}
exit:
if (err == WEAVE_END_OF_TLV)
{
err = WEAVE_NO_ERROR;
}
return err;
}
WEAVE_ERROR Path::Builder::_Init(nl::Weave::TLV::TLVWriter * const apWriter, const uint64_t aTagInApiForm)
{
mpWriter = apWriter;
mOuterContainerType = nl::Weave::TLV::kTLVType_NotSpecified;
mError = mpWriter->StartContainer(aTagInApiForm, nl::Weave::TLV::kTLVType_Path, mOuterContainerType);
SuccessOrExit(mError);
// We don't care about storing the outer container's type here, for we know it's a Path
nl::Weave::TLV::TLVType dummyContainerType;
mError = mpWriter->StartContainer(nl::Weave::TLV::ContextTag(kCsTag_InstanceLocator), nl::Weave::TLV::kTLVType_Structure,
dummyContainerType);
SuccessOrExit(mError);
mInTagSection = false;
exit:
WeaveLogFunctError(mError);
return mError;
}
WEAVE_ERROR Path::Builder::Init(nl::Weave::TLV::TLVWriter * const apWriter)
{
return _Init(apWriter, nl::Weave::TLV::AnonymousTag);
}
WEAVE_ERROR Path::Builder::Init(nl::Weave::TLV::TLVWriter * const apWriter, const uint8_t aContextTagToUse)
{
return _Init(apWriter, nl::Weave::TLV::ContextTag(aContextTagToUse));
}
Path::Builder & Path::Builder::ResourceID(const uint64_t aResourceID)
{
// skip if error has already been set
SuccessOrExit(mError);
// we can only add this field when we're already in the tag section of a Path
VerifyOrExit(!mInTagSection, mError = WEAVE_ERROR_INCORRECT_STATE);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_ResourceID), aResourceID);
exit:
WeaveLogFunctError(mError);
return *this;
}
Path::Builder & Path::Builder::ResourceID(const ResourceIdentifier& aResourceID)
{
// skip if error has already been set
SuccessOrExit(mError);
// we can only add this field when we're already in the tag section of a Path
VerifyOrExit(!mInTagSection, mError = WEAVE_ERROR_INCORRECT_STATE);
mError = aResourceID.ToTLV(*mpWriter);
SuccessOrExit(mError);
exit:
WeaveLogFunctError(mError);
return *this;
}
Path::Builder & Path::Builder::InstanceID(const uint64_t aInstanceID)
{
// skip if error has already been set
SuccessOrExit(mError);
// we can only add this field when we're already in the tag section of a Path
VerifyOrExit(!mInTagSection, mError = WEAVE_ERROR_INCORRECT_STATE);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_TraitInstanceID), aInstanceID);
WeaveLogFunctError(mError);
exit:
return *this;
}
Path::Builder & Path::Builder::ProfileID(const uint32_t aProfileID)
{
SchemaVersionRange versionRange;
return ProfileID(aProfileID, versionRange);
}
Path::Builder & Path::Builder::ProfileID(const uint32_t aProfileID, const SchemaVersionRange & aSchemaVersionRange)
{
// skip if error has already been set
SuccessOrExit(mError);
// we can only add this field when we're already in the tag section of a Path
VerifyOrExit(!mInTagSection, mError = WEAVE_ERROR_INCORRECT_STATE);
VerifyOrExit(aSchemaVersionRange.IsValid(), mError = WEAVE_ERROR_INVALID_ARGUMENT);
if (aSchemaVersionRange.mMaxVersion != 1 || aSchemaVersionRange.mMinVersion != 1)
{
TLV::TLVType type2;
mError = mpWriter->StartContainer(TLV::ContextTag(Path::kCsTag_TraitProfileID), TLV::kTLVType_Array, type2);
SuccessOrExit(mError);
mError = mpWriter->Put(TLV::AnonymousTag, aProfileID);
SuccessOrExit(mError);
if (aSchemaVersionRange.mMaxVersion != 1)
{
mError = mpWriter->Put(TLV::AnonymousTag, aSchemaVersionRange.mMaxVersion);
SuccessOrExit(mError);
}
if (aSchemaVersionRange.mMinVersion != 1)
{
mError = mpWriter->Put(TLV::AnonymousTag, aSchemaVersionRange.mMinVersion);
SuccessOrExit(mError);
}
mError = mpWriter->EndContainer(type2);
SuccessOrExit(mError);
}
else
{
mError = mpWriter->Put(TLV::ContextTag(Path::kCsTag_TraitProfileID), aProfileID);
SuccessOrExit(mError);
}
exit:
return *this;
}
Path::Builder & Path::Builder::TagSection(void)
{
// skip if error has already been set
SuccessOrExit(mError);
// we can only add this field when we're already in the tag section of a Path
VerifyOrExit(!mInTagSection, mError = WEAVE_ERROR_INCORRECT_STATE);
mError = mpWriter->EndContainer(nl::Weave::TLV::kTLVType_Path);
WeaveLogFunctError(mError);
mInTagSection = true;
exit:
return *this;
}
Path::Builder & Path::Builder::AdditionalTag(const uint64_t aTagInApiForm)
{
// skip if error has already been set
SuccessOrExit(mError);
// we can only add additional tags if we're in the tag section of a Path
VerifyOrExit(mInTagSection, mError = WEAVE_ERROR_INCORRECT_STATE);
mError = mpWriter->PutNull(aTagInApiForm);
WeaveLogFunctError(mError);
exit:
return *this;
}
Path::Builder & Path::Builder::EndOfPath(void)
{
// skip if error has already been set
SuccessOrExit(mError);
if (!mInTagSection)
{
// leave the first level container only if TagSection() hasn't been called
mError = mpWriter->EndContainer(nl::Weave::TLV::kTLVType_Path);
SuccessOrExit(mError);
}
EndOfContainer();
exit:
return *this;
}
// aReader has to be on the element of StatusElement
WEAVE_ERROR StatusElement::Parser::Init(const nl::Weave::TLV::TLVReader & aReader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// make a copy of the reader here
mReader.Init(aReader);
switch (mReader.GetType())
{
case nl::Weave::TLV::kTLVType_Structure:
mDeprecatedFormat = true;
break;
case nl::Weave::TLV::kTLVType_Array:
mDeprecatedFormat = false;
break;
default:
ExitNow(err = WEAVE_ERROR_WRONG_TLV_TYPE);
break;
}
// This is just a dummy, as we're not going to exit this container ever
nl::Weave::TLV::TLVType OuterContainerType;
err = mReader.EnterContainer(OuterContainerType);
exit:
WeaveLogFunctError(err);
return err;
}
/**
* Read the ProfileID and the StatusCode from the StatusElement.
*
* @param[out] apProfileID Pointer to the storage for the ProfileID
* @param[out] apStatusCode Pointer to the storage for the StatusCode
*
* @return WEAVE_ERROR codes returned by Weave::TLV objects. WEAVE_END_OF_TLV if either
* element is missing. WEAVE_ERROR_WRONG_TLV_TYPE if the elements are of the wrong
* type.
*/
WEAVE_ERROR StatusElement::Parser::GetProfileIDAndStatusCode(uint32_t * const apProfileID,
uint16_t *const apStatusCode) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
if (mDeprecatedFormat)
{
err = GetUnsignedInteger(kCsTag_ProfileID, apProfileID);
SuccessOrExit(err);
err = GetUnsignedInteger(kCsTag_Status, apStatusCode);
SuccessOrExit(err);
}
else
{
nl::Weave::TLV::TLVReader lReader;
lReader.Init(mReader);
err = lReader.Next();
SuccessOrExit(err);
VerifyOrExit(lReader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = lReader.Get(*apProfileID);
SuccessOrExit(err);
err = lReader.Next();
SuccessOrExit(err);
VerifyOrExit(lReader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = lReader.Get(*apStatusCode);
SuccessOrExit(err);
}
exit:
return err;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
/**
* Roughly verify the schema is right, including
* 1) all mandatory tags are present
* 2) all elements have expected data type
* 3) any tag can only appear once
* At the top level of the structure, unknown tags are ignored for forward compatibility.
*
* @return WEAVE_NO_ERROR in case of success; WEAVE_ERROR codes
* returned by Weave::TLV objects otherwise.
*/
WEAVE_ERROR StatusElement::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err;
if (mDeprecatedFormat)
{
err = CheckSchemaValidityDeprecated();
}
else
{
err = CheckSchemaValidityCurrent();
}
return err;
}
/**
* Check the StatusElement is a structure with two elements with the
* required context tags.
* This format was deprecated for a more compact array based one.
*
* @return WEAVE_NO_ERROR in case of success; WEAVE_ERROR codes
* returned by Weave::TLV objects otherwise.
*/
WEAVE_ERROR StatusElement::Parser::CheckSchemaValidityDeprecated(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint16_t TagPresenceMask = 0;
nl::Weave::TLV::TLVReader reader;
uint32_t tagNum = 0;
PRETTY_PRINT("\t{");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
VerifyOrExit(nl::Weave::TLV::IsContextTag(reader.GetTag()), err = WEAVE_ERROR_INVALID_TLV_TAG);
tagNum = nl::Weave::TLV::TagNumFromTag(reader.GetTag());
switch (tagNum)
{
case kCsTag_ProfileID:
// check if this tag has appeared before
VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_ProfileID)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kCsTag_ProfileID);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint32_t profileID;
err = reader.Get(profileID);
SuccessOrExit(err);
PRETTY_PRINT("\t\tProfileID = 0x%" PRIx32 ",", profileID);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_Status:
// check if this tag has appeared before
VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_Status)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kCsTag_Status);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint16_t status;
err = reader.Get(status);
SuccessOrExit(err);
PRETTY_PRINT("\t\tStatus = 0x%" PRIx16 ",", status);
}
#endif // WEAVE_DETAIL_LOGGING
break;
default:
PRETTY_PRINT("\t\tUnknown tag num %" PRIu32, tagNum);
break;
}
}
PRETTY_PRINT("\t},");
// if we have exhausted this container
if (WEAVE_END_OF_TLV == err)
{
// check for required fields:
const uint16_t RequiredFields = (1 << kCsTag_Status) | (1 << kCsTag_ProfileID);
if ((TagPresenceMask & RequiredFields) == RequiredFields)
{
err = WEAVE_NO_ERROR;
}
else
{
err = WEAVE_ERROR_WDM_MALFORMED_STATUS_ELEMENT;
}
}
exit:
WeaveLogFunctError(err);
return err;
}
/**
* Check the StatusElement is an array with at least two unsigned integers.
* The first one is the ProfileID, the second one is the StatusCode.
*
* @return WEAVE_NO_ERROR in case of success; WEAVE_ERROR codes
* returned by Weave::TLV objects otherwise.
*/
WEAVE_ERROR StatusElement::Parser::CheckSchemaValidityCurrent(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint16_t TagPresenceMask = 0;
nl::Weave::TLV::TLVReader reader;
PRETTY_PRINT("\t{");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
// This is an array; all elements are anonymous.
VerifyOrExit(nl::Weave::TLV::AnonymousTag == reader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
if (!(TagPresenceMask & (1 << kCsTag_ProfileID)))
{
// The first element has to be the ProfileID.
TagPresenceMask |= (1 << kCsTag_ProfileID);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint32_t profileID;
err = reader.Get(profileID);
SuccessOrExit(err);
PRETTY_PRINT("\t\tProfileID = 0x%" PRIx32 ",", profileID);
}
#endif // WEAVE_DETAIL_LOGGING
}
else if (!(TagPresenceMask & (1 << kCsTag_Status)))
{
// The second element has to be the StatusCode.
TagPresenceMask |= (1 << kCsTag_Status);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint16_t status;
err = reader.Get(status);
SuccessOrExit(err);
PRETTY_PRINT("\t\tStatus = 0x%" PRIx16 ",", status);
}
#endif // WEAVE_DETAIL_LOGGING
}
else
{
PRETTY_PRINT("\t\tExtra element in StatusElement");
}
}
PRETTY_PRINT("\t},");
// if we have exhausted this container
if (WEAVE_END_OF_TLV == err)
{
// check for required fields:
const uint16_t RequiredFields = (1 << kCsTag_Status) | (1 << kCsTag_ProfileID);
if ((TagPresenceMask & RequiredFields) == RequiredFields)
{
err = WEAVE_NO_ERROR;
}
else
{
err = WEAVE_ERROR_WDM_MALFORMED_STATUS_ELEMENT;
}
}
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
WEAVE_ERROR StatusElement::Builder::Init(nl::Weave::TLV::TLVWriter * const apWriter)
{
mDeprecatedFormat = false;
return ListBuilderBase::Init(apWriter);
}
WEAVE_ERROR StatusElement::Builder::InitDeprecated(nl::Weave::TLV::TLVWriter * const apWriter)
{
mDeprecatedFormat = true;
return InitAnonymousStructure(apWriter);
}
StatusElement::Builder & StatusElement::Builder::ProfileIDAndStatus(const uint32_t aProfileID, const uint16_t aStatusCode)
{
uint64_t tag = nl::Weave::TLV::AnonymousTag;
SuccessOrExit(mError);
if (mDeprecatedFormat)
{
tag = nl::Weave::TLV::ContextTag(kCsTag_ProfileID);
}
mError = mpWriter->Put(tag, aProfileID);
if (mDeprecatedFormat)
{
tag = nl::Weave::TLV::ContextTag(kCsTag_Status);
}
mError = mpWriter->Put(tag, aStatusCode);
exit:
WeaveLogFunctError(mError);
return *this;
}
StatusElement::Builder & StatusElement::Builder::EndOfStatusElement(void)
{
EndOfContainer();
return *this;
}
// aReader has to be on the element of DataElement
WEAVE_ERROR DataElement::Parser::Init(const nl::Weave::TLV::TLVReader & aReader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// make a copy of the reader here
mReader.Init(aReader);
VerifyOrExit(nl::Weave::TLV::kTLVType_Structure == mReader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
// This is just a dummy, as we're not going to exit this container ever
nl::Weave::TLV::TLVType OuterContainerType;
err = mReader.EnterContainer(OuterContainerType);
exit:
WeaveLogFunctError(err);
return err;
}
WEAVE_ERROR
DataElement::Parser::ParseData(nl::Weave::TLV::TLVReader & aReader, int aDepth) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
if (aDepth == 0)
{
PRETTY_PRINT("\t\tData = ");
}
else
{
if (nl::Weave::TLV::IsContextTag(aReader.GetTag()))
{
PRETTY_PRINT("\t\t0x%" PRIx32 " = ", nl::Weave::TLV::TagNumFromTag(aReader.GetTag()));
}
else if (nl::Weave::TLV::IsProfileTag(aReader.GetTag()))
{
PRETTY_PRINT("\t\t0x%" PRIx32 "::0x%" PRIx32 " = ", nl::Weave::TLV::ProfileIdFromTag(aReader.GetTag()),
nl::Weave::TLV::TagNumFromTag(aReader.GetTag()));
}
else
{
// Anonymous tag, don't print anything
}
}
switch (aReader.GetType())
{
case nl::Weave::TLV::kTLVType_Structure:
PRETTY_PRINT("\t\t{");
break;
case nl::Weave::TLV::kTLVType_Array:
PRETTY_PRINT_SAMELINE("[");
PRETTY_PRINT("\t\t\t");
break;
case nl::Weave::TLV::kTLVType_SignedInteger:
{
int64_t value_s64;
err = aReader.Get(value_s64);
SuccessOrExit(err);
PRETTY_PRINT_SAMELINE("%" PRId64 ", ", value_s64);
break;
}
case nl::Weave::TLV::kTLVType_UnsignedInteger:
{
uint64_t value_u64;
err = aReader.Get(value_u64);
SuccessOrExit(err);
PRETTY_PRINT_SAMELINE("%" PRIu64 ", ", value_u64);
break;
}
case nl::Weave::TLV::kTLVType_Boolean:
{
bool value_b;
err = aReader.Get(value_b);
SuccessOrExit(err);
PRETTY_PRINT_SAMELINE("%s, ", value_b ? "true" : "false");
break;
}
case nl::Weave::TLV::kTLVType_UTF8String:
{
char value_s[256];
err = aReader.GetString(value_s, sizeof(value_s));
VerifyOrExit(err == WEAVE_NO_ERROR || err == WEAVE_ERROR_BUFFER_TOO_SMALL, );
if (err == WEAVE_ERROR_BUFFER_TOO_SMALL)
{
PRETTY_PRINT_SAMELINE("... (byte string too long) ...");
err = WEAVE_NO_ERROR;
}
else
{
PRETTY_PRINT_SAMELINE("\"%s\", ", value_s);
}
break;
}
case nl::Weave::TLV::kTLVType_ByteString:
{
uint8_t value_b[256];
uint32_t len, readerLen;
readerLen = aReader.GetLength();
err = aReader.GetBytes(value_b, sizeof(value_b));
VerifyOrExit(err == WEAVE_NO_ERROR || err == WEAVE_ERROR_BUFFER_TOO_SMALL, );
PRETTY_PRINT_SAMELINE("[");
PRETTY_PRINT("\t\t\t");
if (readerLen < sizeof(value_b))
{
len = readerLen;
}
else
{
len = sizeof(value_b);
}
if (err == WEAVE_ERROR_BUFFER_TOO_SMALL)
{
PRETTY_PRINT_SAMELINE("... (byte string too long) ...");
}
else
{
for (size_t i = 0; i < len; i++)
{
PRETTY_PRINT_SAMELINE("0x%" PRIx8 ", ", value_b[i]);
}
}
err = WEAVE_NO_ERROR;
PRETTY_PRINT("\t\t]");
break;
}
case nl::Weave::TLV::kTLVType_Null:
PRETTY_PRINT_SAMELINE("NULL");
break;
default:
PRETTY_PRINT_SAMELINE("--");
break;
}
if (aReader.GetType() == nl::Weave::TLV::kTLVType_Structure || aReader.GetType() == nl::Weave::TLV::kTLVType_Array)
{
const char terminating_char = (aReader.GetType() == nl::Weave::TLV::kTLVType_Structure) ? '}' : ']';
nl::Weave::TLV::TLVType type;
IgnoreUnusedVariable(terminating_char);
err = aReader.EnterContainer(type);
SuccessOrExit(err);
while ((err = aReader.Next()) == WEAVE_NO_ERROR)
{
PRETTY_PRINT_INCDEPTH();
err = ParseData(aReader, aDepth + 1);
SuccessOrExit(err);
PRETTY_PRINT_DECDEPTH();
}
PRETTY_PRINT("\t\t%c,", terminating_char);
err = aReader.ExitContainer(type);
SuccessOrExit(err);
}
exit:
WeaveLogFunctError(err);
return err;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Roughly verify the schema is right, including
// 1) all mandatory tags are present
// 2) all elements have expected data type
// 3) any tag can only appear once
// At the top level of the structure, unknown tags are ignored for foward compatibility
WEAVE_ERROR DataElement::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint16_t TagPresenceMask = 0;
nl::Weave::TLV::TLVReader reader;
uint32_t tagNum = 0;
PRETTY_PRINT("\t{");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
VerifyOrExit(nl::Weave::TLV::IsContextTag(reader.GetTag()), err = WEAVE_ERROR_INVALID_TLV_TAG);
tagNum = nl::Weave::TLV::TagNumFromTag(reader.GetTag());
switch (tagNum)
{
case kCsTag_Path:
// check if this tag has appeared before
VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_Path)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kCsTag_Path);
VerifyOrExit(nl::Weave::TLV::kTLVType_Path == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
PRETTY_PRINT("\t\tDataElementPath = ");
{
Path::Parser path;
err = path.Init(reader);
SuccessOrExit(err);
err = path.CheckSchemaValidity();
SuccessOrExit(err);
}
break;
case kCsTag_Version:
// check if this tag has appeared before
VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_Version)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kCsTag_Version);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t version;
err = reader.Get(version);
SuccessOrExit(err);
PRETTY_PRINT("\t\tDataElementVersion = 0x%" PRIx64 ",", version);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_Data:
// check if this tag has appeared before
VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_Data)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kCsTag_Data);
err = ParseData(reader, 0);
SuccessOrExit(err);
break;
case kCsTag_DeletedDictionaryKeys:
nl::Weave::TLV::TLVType type;
VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_DeletedDictionaryKeys)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kCsTag_DeletedDictionaryKeys);
VerifyOrExit(nl::Weave::TLV::kTLVType_Array == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.EnterContainer(type);
SuccessOrExit(err);
PRETTY_PRINT("\t\tDataElement_DeletedDictionaryKeys =");
PRETTY_PRINT("\t\t[");
while ((err = reader.Next()) == WEAVE_NO_ERROR)
{
PropertyDictionaryKey key;
err = reader.Get(key);
SuccessOrExit(err);
PRETTY_PRINT("\t\t\t0x%" PRIx16 ",", key);
}
PRETTY_PRINT("\t\t],");
err = reader.ExitContainer(type);
SuccessOrExit(err);
break;
case kCsTag_IsPartialChange:
// check if this tag has appeared before
VerifyOrExit(!(TagPresenceMask & (1 << kCsTag_IsPartialChange)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kCsTag_IsPartialChange);
VerifyOrExit(nl::Weave::TLV::kTLVType_Boolean == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
bool flag;
err = reader.Get(flag);
SuccessOrExit(err);
PRETTY_PRINT("\t\tDataElement_IsPartialChange = %s,", flag ? "true" : "false");
}
#endif // WEAVE_DETAIL_LOGGING
break;
default:
PRETTY_PRINT("\t\tUnknown tag num %" PRIu32, tagNum);
break;
}
}
PRETTY_PRINT("\t},");
// if we have exhausted this container
if (WEAVE_END_OF_TLV == err)
{
// check for required fields:
const uint16_t RequiredFields = (1 << kCsTag_Path);
// Either the data or deleted keys should be present.
const uint16_t DataElementTypeMask = (1 << kCsTag_Data) | (1 << kCsTag_DeletedDictionaryKeys);
if ((TagPresenceMask & RequiredFields) == RequiredFields)
{
err = WEAVE_NO_ERROR;
}
else
{
err = WEAVE_ERROR_WDM_MALFORMED_DATA_ELEMENT;
}
if ((TagPresenceMask & DataElementTypeMask) == 0)
{
err = WEAVE_ERROR_WDM_MALFORMED_DATA_ELEMENT;
}
}
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// WEAVE_END_OF_TLV if there is no such element
// WEAVE_ERROR_WRONG_TLV_TYPE if there is such element but it's not a Path
WEAVE_ERROR DataElement::Parser::GetReaderOnPath(nl::Weave::TLV::TLVReader * const apReader) const
{
WEAVE_ERROR err = LookForElementWithTag(mReader, nl::Weave::TLV::ContextTag(kCsTag_Path), apReader);
WeaveLogIfFalse((WEAVE_NO_ERROR == err) || (WEAVE_END_OF_TLV == err));
return err;
}
// WEAVE_END_OF_TLV if there is no such element
// WEAVE_ERROR_WRONG_TLV_TYPE if there is such element but it's not a Path
WEAVE_ERROR DataElement::Parser::GetPath(Path::Parser * const apPath) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
nl::Weave::TLV::TLVReader reader;
err = LookForElementWithTag(mReader, nl::Weave::TLV::ContextTag(kCsTag_Path), &reader);
SuccessOrExit(err);
VerifyOrExit(nl::Weave::TLV::kTLVType_Path == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = apPath->Init(reader);
SuccessOrExit(err);
exit:
WeaveLogIfFalse((WEAVE_NO_ERROR == err) || (WEAVE_END_OF_TLV == err));
return err;
}
// WEAVE_END_OF_TLV if there is no such element
// WEAVE_ERROR_WRONG_TLV_TYPE if there is such element but it's not any of the defined unsigned integer types
WEAVE_ERROR DataElement::Parser::GetVersion(uint64_t * const apVersion) const
{
return GetUnsignedInteger(kCsTag_Version, apVersion);
}
// Data could be of any type, so we can only position the reader so the caller has
// full information of tag, element type, length, and value
WEAVE_ERROR DataElement::Parser::GetData(nl::Weave::TLV::TLVReader * const apReader) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
err = LookForElementWithTag(mReader, nl::Weave::TLV::ContextTag(kCsTag_Data), apReader);
SuccessOrExit(err);
exit:
WeaveLogIfFalse((WEAVE_NO_ERROR == err) || (WEAVE_END_OF_TLV == err));
return err;
}
// Default is false if there is no such element
// WEAVE_ERROR_WRONG_TLV_TYPE if there is such element but it's not a boolean
WEAVE_ERROR DataElement::Parser::GetPartialChangeFlag(bool * const apPartialChangeFlag) const
{
return GetSimpleValue(kCsTag_IsPartialChange, nl::Weave::TLV::kTLVType_Boolean, apPartialChangeFlag);
}
WEAVE_ERROR DataElement::Parser::CheckPresence(bool * const apDataPresentFlag, bool * const apDeletePresentFlag) const
{
nl::Weave::TLV::TLVReader reader;
WEAVE_ERROR err_datamerge, err_dictionarydelete, err = WEAVE_NO_ERROR;
err_datamerge = LookForElementWithTag(mReader, nl::Weave::TLV::ContextTag(kCsTag_Data), &reader);
err_dictionarydelete = LookForElementWithTag(mReader, nl::Weave::TLV::ContextTag(kCsTag_DeletedDictionaryKeys), &reader);
if ((err_datamerge == WEAVE_END_OF_TLV) && (err_dictionarydelete == WEAVE_END_OF_TLV))
{
err = WEAVE_ERROR_WDM_MALFORMED_DATA_ELEMENT;
}
if (err_datamerge == WEAVE_NO_ERROR)
{
*apDataPresentFlag = true;
}
if (err_dictionarydelete == WEAVE_NO_ERROR)
{
*apDeletePresentFlag = true;
}
return err;
}
WEAVE_ERROR DataElement::Parser::GetDeletedDictionaryKeys(nl::Weave::TLV::TLVReader * const apReader) const
{
WEAVE_ERROR err;
nl::Weave::TLV::TLVType containerType;
err = LookForElementWithTag(mReader, nl::Weave::TLV::ContextTag(kCsTag_DeletedDictionaryKeys), apReader);
SuccessOrExit(err);
VerifyOrExit(apReader->GetType() == nl::Weave::TLV::kTLVType_Array, err = WEAVE_ERROR_WDM_MALFORMED_DATA_ELEMENT);
err = apReader->EnterContainer(containerType);
exit:
WeaveLogFunctError(err);
return err;
}
// DataElement is only used in a Data List, which requires every path to be anonymous
// Note that both mWriter and mPathBuilder only hold reference to the actual TLVWriter
WEAVE_ERROR DataElement::Builder::Init(nl::Weave::TLV::TLVWriter * const apWriter)
{
return InitAnonymousStructure(apWriter);
}
Path::Builder & DataElement::Builder::CreatePathBuilder()
{
// skip if error has already been set
VerifyOrExit(WEAVE_NO_ERROR == mError, mPathBuilder.ResetError(mError));
mError = mPathBuilder.Init(mpWriter, nl::Weave::TLV::ContextTag(kCsTag_Path));
WeaveLogFunctError(mError);
exit:
// on error, mPathBuilder would be un-/partial initialized and cannot be used to write anything
return mPathBuilder;
}
DataElement::Builder & DataElement::Builder::Version(const uint64_t aVersion)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_Version), aVersion);
WeaveLogFunctError(mError);
exit:
return *this;
}
// Nothing would be written if aIsLastForCurrentChange == false, as that's the default value
DataElement::Builder & DataElement::Builder::PartialChange(const bool aIsPartialChange)
{
// skip if error has already been set
SuccessOrExit(mError);
if (aIsPartialChange)
{
mError = mpWriter->PutBoolean(nl::Weave::TLV::ContextTag(kCsTag_IsPartialChange), true);
WeaveLogFunctError(mError);
}
exit:
return *this;
}
DataElement::Builder & DataElement::Builder::EndOfDataElement(void)
{
EndOfContainer();
return *this;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Roughly verify the schema is right, including
// 1) at least one element is there
// 2) all elements are anonymous and of Path type
// 3) every path is also valid in schema
WEAVE_ERROR PathList::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
size_t NumPath = 0;
nl::Weave::TLV::TLVReader reader;
PRETTY_PRINT("PathList =");
PRETTY_PRINT("[");
// make a copy of the PathList reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
VerifyOrExit(nl::Weave::TLV::AnonymousTag == reader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
VerifyOrExit(nl::Weave::TLV::kTLVType_Path == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
{
Path::Parser path;
err = path.Init(reader);
SuccessOrExit(err);
PRETTY_PRINT("\t");
err = path.CheckSchemaValidity();
SuccessOrExit(err);
}
++NumPath;
}
PRETTY_PRINT("],");
// if we have exhausted this container
if (WEAVE_END_OF_TLV == err)
{
// if we have at least one Path element
if (NumPath > 0)
{
err = WEAVE_NO_ERROR;
}
}
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Re-initialize the shared PathBuilder with anonymous tag
Path::Builder & PathList::Builder::CreatePathBuilder()
{
// skip if error has already been set
VerifyOrExit(WEAVE_NO_ERROR == mError, mPathBuilder.ResetError(mError));
mError = mPathBuilder.Init(mpWriter);
WeaveLogFunctError(mError);
exit:
// on error, mPathBuilder would be un-/partial initialized and cannot be used to write anything
return mPathBuilder;
}
// Mark the end of this array and recover the type for outer container
PathList::Builder & PathList::Builder::EndOfPathList(void)
{
EndOfContainer();
return *this;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Roughly verify the schema is right, including
// 1) at least one element is there
// 2) all elements are anonymous and of Structure type
// 3) every Data Element is also valid in schema
WEAVE_ERROR DataList::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
size_t NumDataElement = 0;
nl::Weave::TLV::TLVReader reader;
PRETTY_PRINT("DataList =");
PRETTY_PRINT("[");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
VerifyOrExit(nl::Weave::TLV::AnonymousTag == reader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
VerifyOrExit(nl::Weave::TLV::kTLVType_Structure == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
{
DataElement::Parser data;
err = data.Init(reader);
SuccessOrExit(err);
err = data.CheckSchemaValidity();
SuccessOrExit(err);
}
++NumDataElement;
}
PRETTY_PRINT("],");
// if we have exhausted this container
if (WEAVE_END_OF_TLV == err)
{
// if we have at least one data element
if (NumDataElement > 0)
{
err = WEAVE_NO_ERROR;
}
}
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Re-initialize the shared PathBuilder with anonymous tag
DataElement::Builder & DataList::Builder::CreateDataElementBuilder()
{
// skip if error has already been set
VerifyOrExit(WEAVE_NO_ERROR == mError, mDataElementBuilder.ResetError(mError));
mError = mDataElementBuilder.Init(mpWriter);
WeaveLogFunctError(mError);
exit:
// on error, mPathBuilder would be un-/partial initialized and cannot be used to write anything
return mDataElementBuilder;
}
// Mark the end of this array and recover the type for outer container
DataList::Builder & DataList::Builder::EndOfDataList(void)
{
EndOfContainer();
return *this;
}
WEAVE_ERROR Event::Parser::Init(const nl::Weave::TLV::TLVReader & aReader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// make a copy of the reader here
mReader.Init(aReader);
VerifyOrExit(nl::Weave::TLV::kTLVType_Structure == mReader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
// This is just a dummy, as we're not going to exit this container ever
nl::Weave::TLV::TLVType OuterContainerType;
err = mReader.EnterContainer(OuterContainerType);
exit:
WeaveLogFunctError(err);
return err;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Roughly verify the schema is right
WEAVE_ERROR Event::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
nl::Weave::TLV::TLVReader reader;
uint32_t tagNum = 0;
struct TagPresence
{
bool Source : 1;
bool Importance : 1;
bool Id : 1;
bool RelatedImportance : 1;
bool RelatedId : 1;
bool UTCTimestamp : 1;
bool SystemTimestamp : 1;
bool ResourceId : 1;
bool TraitProfileId : 1;
bool TraitInstanceId : 1;
bool Type : 1;
bool DeltaUTCTime : 1;
bool DeltaSystemTime : 1;
bool Data : 1;
};
TagPresence tagPresence = {};
PRETTY_PRINT("\t{");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
VerifyOrExit(nl::Weave::TLV::IsContextTag(reader.GetTag()), err = WEAVE_ERROR_INVALID_TLV_TAG);
tagNum = nl::Weave::TLV::TagNumFromTag(reader.GetTag());
switch (tagNum)
{
case kCsTag_Source:
// check if this tag has appeared before
VerifyOrExit(tagPresence.Source == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Source = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\t\tSource = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_Importance:
// check if this tag has appeared before
VerifyOrExit(tagPresence.Importance == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Importance = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\t\tImportance = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_Id:
// check if this tag has appeared before
VerifyOrExit(tagPresence.Id == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Id = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\t\tId = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_RelatedImportance:
// check if this tag has appeared before
VerifyOrExit(tagPresence.RelatedImportance == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.RelatedImportance = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\t\tRelatedImportance = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_RelatedId:
// check if this tag has appeared before
VerifyOrExit(tagPresence.RelatedId == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.RelatedId = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\t\tRelatedId = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_UTCTimestamp:
// check if this tag has appeared before
VerifyOrExit(tagPresence.UTCTimestamp == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.UTCTimestamp = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\t\tUTCTimestamp = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_SystemTimestamp:
// check if this tag has appeared before
VerifyOrExit(tagPresence.SystemTimestamp == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.SystemTimestamp = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\t\tSystemTimestamp = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_ResourceId:
// check if this tag has appeared before
VerifyOrExit(tagPresence.ResourceId == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.ResourceId = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType() || nl::Weave::TLV::kTLVType_ByteString == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
ResourceIdentifier resourceId;
char strResource[ResourceIdentifier::MAX_STRING_LENGTH];
err = resourceId.FromTLV(reader);
if (err == WEAVE_NO_ERROR)
{
resourceId.ToString(strResource, sizeof(strResource));
PRETTY_PRINT("\t\t%s,", strResource);
}
else
{
PRETTY_PRINT("\t\tResourceId = ??,");
}
SuccessOrExit(err);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_TraitProfileId:
{
SchemaVersionRange requestedVersion;
uint32_t ProfileID;
// check if this tag has appeared before
VerifyOrExit(tagPresence.TraitProfileId == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.TraitProfileId = true;
if (reader.GetType() == nl::Weave::TLV::kTLVType_Array)
{
TLV::TLVType type;
err = reader.EnterContainer(type);
SuccessOrExit(err);
err = reader.Next();
SuccessOrExit(err);
VerifyOrExit(reader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(ProfileID);
SuccessOrExit(err);
err = reader.Next();
VerifyOrExit(err == WEAVE_NO_ERROR || err == WEAVE_END_OF_TLV, );
if (err == WEAVE_NO_ERROR)
{
VerifyOrExit(reader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(requestedVersion.mMaxVersion);
SuccessOrExit(err);
}
err = reader.Next();
VerifyOrExit(err == WEAVE_NO_ERROR || err == WEAVE_END_OF_TLV, );
if (err == WEAVE_NO_ERROR)
{
VerifyOrExit(reader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(requestedVersion.mMinVersion);
SuccessOrExit(err);
}
err = reader.Next();
VerifyOrExit(err == WEAVE_END_OF_TLV, err = WEAVE_ERROR_WDM_MALFORMED_DATA_ELEMENT);
err = reader.ExitContainer(type);
}
else
{
VerifyOrExit(reader.GetType() == nl::Weave::TLV::kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
err = reader.Get(ProfileID);
SuccessOrExit(err);
}
#if WEAVE_DETAIL_LOGGING
{
if (requestedVersion.mMaxVersion > 1 || requestedVersion.mMinVersion > 1)
{
PRETTY_PRINT("\t\tTraitProfileId = 0x%" PRIx32, ProfileID);
if (requestedVersion.mMaxVersion > 1)
{
PRETTY_PRINT_SAMELINE(", MaxVersion = %" PRIu32, requestedVersion.mMaxVersion);
}
if (requestedVersion.mMaxVersion > 1)
{
PRETTY_PRINT_SAMELINE(", MinVersion = %" PRIu32 ",", requestedVersion.mMinVersion);
}
else
{
PRETTY_PRINT_SAMELINE(",");
}
}
else
{
PRETTY_PRINT("\t\tTraitProfileId = 0x%" PRIx32 ",", ProfileID);
}
}
#endif // WEAVE_DETAIL_LOGGING
break;
}
case kCsTag_TraitInstanceId:
// check if this tag has appeared before
VerifyOrExit(tagPresence.TraitInstanceId == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.TraitInstanceId = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\t\tTraitInstanceId = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_Type:
// check if this tag has appeared before
VerifyOrExit(tagPresence.Type == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Type = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\t\tType = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_DeltaUTCTime:
// check if this tag has appeared before
VerifyOrExit(tagPresence.DeltaUTCTime == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.DeltaUTCTime = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_SignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\t\tDeltaUTCTime = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_DeltaSystemTime:
// check if this tag has appeared before
VerifyOrExit(tagPresence.DeltaSystemTime == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.DeltaSystemTime = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_SignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\t\tDeltaSystemTime = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_Data:
// check if this tag has appeared before
VerifyOrExit(tagPresence.Data == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Data = true;
err = ParseData(reader, 0);
SuccessOrExit(err);
break;
default:
PRETTY_PRINT("\t\tUnknown tag num %" PRIu32, tagNum);
break;
}
}
PRETTY_PRINT("\t},");
PRETTY_PRINT("");
// almost all fields in an Event are optional
if (WEAVE_END_OF_TLV == err)
{
err = WEAVE_NO_ERROR;
}
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
WEAVE_ERROR Event::Parser::GetSourceId(uint64_t * const apSourceId)
{
return GetUnsignedInteger(kCsTag_Source, apSourceId);
}
WEAVE_ERROR Event::Parser::GetImportance(uint64_t * const apImportance)
{
return GetUnsignedInteger(kCsTag_Importance, apImportance);
}
WEAVE_ERROR Event::Parser::GetEventId(uint64_t * const apEventId)
{
return GetUnsignedInteger(kCsTag_Id, apEventId);
}
WEAVE_ERROR Event::Parser::GetRelatedEventImportance(uint64_t * const apImportance)
{
return GetUnsignedInteger(kCsTag_RelatedImportance, apImportance);
}
WEAVE_ERROR Event::Parser::GetRelatedEventId(uint64_t * const apEventId)
{
return GetUnsignedInteger(kCsTag_RelatedId, apEventId);
}
WEAVE_ERROR Event::Parser::GetUTCTimestamp(uint64_t * const apUTCTimestamp)
{
return GetUnsignedInteger(kCsTag_UTCTimestamp, apUTCTimestamp);
}
WEAVE_ERROR Event::Parser::GetSystemTimestamp(uint64_t * const apSystemTimestamp)
{
return GetUnsignedInteger(kCsTag_SystemTimestamp, apSystemTimestamp);
}
WEAVE_ERROR Event::Parser::GetResourceId(uint64_t * const apResourceId)
{
return GetUnsignedInteger(kCsTag_ResourceId, apResourceId);
}
WEAVE_ERROR Event::Parser::GetTraitProfileId(uint32_t * const apTraitProfileId)
{
return GetUnsignedInteger(kCsTag_TraitProfileId, apTraitProfileId);
}
WEAVE_ERROR Event::Parser::GetTraitInstanceId(uint64_t * const apTraitInstanceId)
{
return GetUnsignedInteger(kCsTag_TraitInstanceId, apTraitInstanceId);
}
WEAVE_ERROR Event::Parser::GetEventType(uint64_t * const apEventType)
{
return GetUnsignedInteger(kCsTag_Type, apEventType);
}
WEAVE_ERROR Event::Parser::GetDeltaUTCTime(int64_t * const apDeltaUTCTime)
{
return GetSimpleValue(kCsTag_DeltaUTCTime, nl::Weave::TLV::kTLVType_SignedInteger, apDeltaUTCTime);
}
WEAVE_ERROR Event::Parser::GetDeltaSystemTime(int64_t * const apDeltaSystemTime)
{
return GetSimpleValue(kCsTag_DeltaSystemTime, nl::Weave::TLV::kTLVType_SignedInteger, apDeltaSystemTime);
}
WEAVE_ERROR Event::Parser::GetReaderOnEvent(nl::Weave::TLV::TLVReader * const apReader) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
err = LookForElementWithTag(mReader, nl::Weave::TLV::ContextTag(kCsTag_Data), apReader);
WeaveLogFunctError(err);
return err;
}
WEAVE_ERROR Event::Builder::Init(nl::Weave::TLV::TLVWriter * const apWriter)
{
return InitAnonymousStructure(apWriter);
}
Event::Builder Event::Builder::SourceId(const uint64_t aSourceId)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_Source), aSourceId);
WeaveLogFunctError(mError);
exit:
return *this;
}
Event::Builder Event::Builder::Importance(const uint64_t aImportance)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_Importance), aImportance);
WeaveLogFunctError(mError);
exit:
return *this;
}
Event::Builder Event::Builder::EventId(const uint64_t aEventId)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_Id), aEventId);
WeaveLogFunctError(mError);
exit:
return *this;
}
Event::Builder Event::Builder::RelatedEventImportance(const uint64_t aImportance)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_RelatedImportance), aImportance);
WeaveLogFunctError(mError);
exit:
return *this;
}
Event::Builder Event::Builder::RelatedEventId(const uint64_t aEventId)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_RelatedId), aEventId);
WeaveLogFunctError(mError);
exit:
return *this;
}
Event::Builder Event::Builder::UTCTimestamp(const uint64_t aUTCTimestamp)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_UTCTimestamp), aUTCTimestamp);
WeaveLogFunctError(mError);
exit:
return *this;
}
Event::Builder Event::Builder::SystemTimestamp(const uint64_t aSystemTimestamp)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_SystemTimestamp), aSystemTimestamp);
WeaveLogFunctError(mError);
exit:
return *this;
}
Event::Builder Event::Builder::ResourceId(const uint64_t aResourceId)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_ResourceId), aResourceId);
WeaveLogFunctError(mError);
exit:
return *this;
}
Event::Builder Event::Builder::TraitProfileId(const uint32_t aTraitProfileId)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_TraitProfileId), aTraitProfileId);
WeaveLogFunctError(mError);
exit:
return *this;
}
Event::Builder Event::Builder::TraitInstanceId(const uint64_t aTraitInstanceId)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_TraitInstanceId), aTraitInstanceId);
WeaveLogFunctError(mError);
exit:
return *this;
}
Event::Builder Event::Builder::EventType(const uint64_t aEventType)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_Type), aEventType);
WeaveLogFunctError(mError);
exit:
return *this;
}
Event::Builder Event::Builder::DeltaUTCTime(const int64_t aDeltaUTCTime)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_DeltaUTCTime), aDeltaUTCTime);
WeaveLogFunctError(mError);
exit:
return *this;
}
Event::Builder Event::Builder::DeltaSystemTime(const int64_t aDeltaSystemTime)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_DeltaSystemTime), aDeltaSystemTime);
WeaveLogFunctError(mError);
exit:
return *this;
}
// Mark the end of this element and recover the type for outer container
Event::Builder & Event::Builder::EndOfEvent(void)
{
EndOfContainer();
return *this;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
WEAVE_ERROR EventList::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
size_t NumDataElement = 0;
nl::Weave::TLV::TLVReader reader;
PRETTY_PRINT("EventList =");
PRETTY_PRINT("[");
// make a copy of the EventList reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
VerifyOrExit(nl::Weave::TLV::AnonymousTag == reader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
VerifyOrExit(nl::Weave::TLV::kTLVType_Structure == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
{
Event::Parser event;
err = event.Init(reader);
SuccessOrExit(err);
err = event.CheckSchemaValidity();
SuccessOrExit(err);
}
++NumDataElement;
}
PRETTY_PRINT("],");
// if we have exhausted this container
if (WEAVE_END_OF_TLV == err)
{
// if we have at least one data element
if (NumDataElement > 0)
{
err = WEAVE_NO_ERROR;
}
// NOTE: temporarily disable this check, to allow test to continue
else
{
WeaveLogError(DataManagement, "PROTOCOL ERROR: Empty event list");
err = WEAVE_NO_ERROR;
}
}
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
Event::Builder & EventList::Builder::CreateEventBuilder()
{
// skip if error has already been set
VerifyOrExit(WEAVE_NO_ERROR == mError, mEventBuilder.ResetError(mError));
mError = mEventBuilder.Init(mpWriter);
WeaveLogFunctError(mError);
exit:
// on error, mEventBuilder would be un-/partial initialized and cannot be used to write anything
return mEventBuilder;
}
// Mark the end of this array and recover the type for outer container
EventList::Builder & EventList::Builder::EndOfEventList(void)
{
EndOfContainer();
return *this;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
WEAVE_ERROR VersionList::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
nl::Weave::TLV::TLVReader reader;
uint64_t version;
size_t index = 0;
PRETTY_PRINT("VersionList = ");
PRETTY_PRINT("[");
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
VerifyOrExit(nl::Weave::TLV::AnonymousTag == reader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
switch (reader.GetType())
{
case nl::Weave::TLV::kTLVType_Null:
PRETTY_PRINT("\tNull,");
break;
case nl::Weave::TLV::kTLVType_UnsignedInteger:
err = reader.Get(version);
SuccessOrExit(err);
PRETTY_PRINT("\t0x%" PRIx64 ",", version);
break;
default:
ExitNow(err = WEAVE_ERROR_WRONG_TLV_TYPE);
break;
}
++index;
}
PRETTY_PRINT("],");
if (WEAVE_END_OF_TLV == err)
{
err = WEAVE_NO_ERROR;
}
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
/**
* Append a StatusElement to the list.
*
* @param[in] aProfileID ProfileID
* @param[in] aStatusCode StatusCode
*
* @return Reference to this builder.
*/
StatusList::Builder & StatusList::Builder::AddStatus(uint32_t aProfileID, uint16_t aStatusCode)
{
StatusElement::Builder builder;
SuccessOrExit(mError);
if (mDeprecatedFormat)
{
builder.InitDeprecated(mpWriter);
}
else
{
builder.Init(mpWriter);
}
builder.ProfileIDAndStatus(aProfileID, aStatusCode);
builder.EndOfStatusElement();
mError = builder.GetError();
exit:
WeaveLogFunctError(mError);
return *this;
}
StatusList::Builder & StatusList::Builder::EndOfStatusList()
{
EndOfContainer();
return *this;
}
/**
* Read the ProfileID and the StatusCode from the current StatusElement.
*
* @param[out] apProfileID Pointer to the storage for the ProfileID
* @param[out] apStatusCode Pointer to the storage for the StatusCode
*
* @return WEAVE_ERROR codes returned by Weave::TLV objects. WEAVE_END_OF_TLV if either
* element is missing. WEAVE_ERROR_WRONG_TLV_TYPE if the elements are of the wrong
* type.
*/
WEAVE_ERROR StatusList::Parser::GetProfileIDAndStatusCode(uint32_t * const apProfileID, uint16_t * const apStatusCode)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
StatusElement::Parser statusElement;
err = statusElement.Init(mReader);
SuccessOrExit(err);
err = statusElement.GetProfileIDAndStatusCode(apProfileID, apStatusCode);
SuccessOrExit(err);
exit:
return err;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Roughly verify the schema is right, including
// 1) at least one element is there
// 2) all elements are anonymous and of Structure type
// 3) every Data Element is also valid in schema
WEAVE_ERROR StatusList::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
size_t NumStatusElement = 0;
nl::Weave::TLV::TLVReader reader;
PRETTY_PRINT("StatusList =");
PRETTY_PRINT("[");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
TLVType type;
uint64_t tag;
// TODO: The spec says the StatusList should be an array of arrays, but in
// the current implementation it's an array of structures. The array of
// arrays is less intuitive but more space efficient.
tag = reader.GetTag();
VerifyOrExit(nl::Weave::TLV::AnonymousTag == tag, err = WEAVE_ERROR_INVALID_TLV_TAG);
type = reader.GetType();
VerifyOrExit((nl::Weave::TLV::kTLVType_Structure == type ||
nl::Weave::TLV::kTLVType_Array == type), err = WEAVE_ERROR_WRONG_TLV_TYPE);
{
StatusElement::Parser status;
err = status.Init(reader);
SuccessOrExit(err);
err = status.CheckSchemaValidity();
SuccessOrExit(err);
}
++NumStatusElement;
}
PRETTY_PRINT("],");
// if we have exhausted this container
if (WEAVE_END_OF_TLV == err)
{
// The StatusList of an UpdateResponse can be empty, in case the update
// was successful for all DataElements
err = WEAVE_NO_ERROR;
}
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// 1) current element is anonymous
// 2) current element is either unsigned integer or NULL
bool VersionList::Parser::IsElementValid(void)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
bool result = false;
VerifyOrExit(nl::Weave::TLV::AnonymousTag == mReader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
switch (mReader.GetType())
{
case nl::Weave::TLV::kTLVType_Null:
case nl::Weave::TLV::kTLVType_UnsignedInteger:
result = true;
break;
default:
// err = WEAVE_ERROR_WRONG_TLV_TYPE;
ExitNow();
break;
}
exit:
WeaveLogFunctError(err);
return result;
}
bool VersionList::Parser::IsNull(void)
{
return (nl::Weave::TLV::kTLVType_Null == mReader.GetType());
}
WEAVE_ERROR VersionList::Parser::GetVersion(uint64_t * const apVersion)
{
return mReader.Get(*apVersion);
}
VersionList::Builder & VersionList::Builder::AddVersion(const uint64_t aVersion)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::AnonymousTag, aVersion);
WeaveLogFunctError(mError);
exit:
return *this;
}
VersionList::Builder & VersionList::Builder::AddNull(void)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->PutNull(nl::Weave::TLV::AnonymousTag);
WeaveLogFunctError(mError);
exit:
return *this;
}
// Mark the end of this array and recover the type for outer container
VersionList::Builder & VersionList::Builder::EndOfVersionList(void)
{
EndOfContainer();
return *this;
}
// aReader has to be on the element of anonymous container
WEAVE_ERROR BaseMessageWithSubscribeId::Parser::Init(const nl::Weave::TLV::TLVReader & aReader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// make a copy of the reader here
mReader.Init(aReader);
VerifyOrExit(nl::Weave::TLV::AnonymousTag == mReader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
VerifyOrExit(nl::Weave::TLV::kTLVType_Structure == mReader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
// This is just a dummy, as we're not going to exit this container ever
nl::Weave::TLV::TLVType OuterContainerType;
err = mReader.EnterContainer(OuterContainerType);
mReader.ImplicitProfileId = kWeaveProfile_DictionaryKey;
exit:
WeaveLogFunctError(err);
return err;
}
// WEAVE_END_OF_TLV if there is no such element
// WEAVE_ERROR_WRONG_TLV_TYPE if there is such element but it's not any of the defined unsigned integer types
WEAVE_ERROR BaseMessageWithSubscribeId::Parser::GetSubscriptionID(uint64_t * const apSubscriptionID) const
{
return GetUnsignedInteger(kCsTag_SubscriptionId, apSubscriptionID);
}
// Path is mostly used in a Path List, which requires every path to be anonymous
WEAVE_ERROR BaseMessageWithSubscribeId::Builder::Init(nl::Weave::TLV::TLVWriter * const apWriter)
{
// error would be retained in mError and returned later
(void) InitAnonymousStructure(apWriter);
SuccessOrExit(mError);
mpWriter->ImplicitProfileId = kWeaveProfile_DictionaryKey;
exit:
return mError;
}
void BaseMessageWithSubscribeId::Builder::SetSubscriptionID(const uint64_t aSubscriptionID)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_SubscriptionId), aSubscriptionID);
WeaveLogFunctError(mError);
exit:;
}
void BaseMessageWithSubscribeId::Builder::EndOfMessage(void)
{
EndOfContainer();
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Roughly verify the schema is right, including
// 1) all mandatory tags are present
// 2) all elements have expected data type
// 3) any tag can only appear once
// At the top level of the message, unknown tags are ignored for foward compatibility
WEAVE_ERROR SubscribeRequest::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint16_t TagPresenceMask = 0;
nl::Weave::TLV::TLVReader reader;
enum
{
kBit_SubscriptionId = 1,
kBit_TimeoutMin = 2,
kBit_TimeoutMax = 3,
kBit_PathList = 4,
kBit_VersionList = 5,
kBit_SubscribeToAllEvents = 6,
kBit_LastObservedEventIdList = 7,
};
PRETTY_PRINT("{");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
const uint64_t tag = reader.GetTag();
if (nl::Weave::TLV::ContextTag(kCsTag_SubscriptionId) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_SubscriptionId)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_SubscriptionId);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t id;
err = reader.Get(id);
SuccessOrExit(err);
PRETTY_PRINT("\tSubscriptionId = 0x%" PRIx64 ",", id);
}
#endif // WEAVE_DETAIL_LOGGING
}
else if (nl::Weave::TLV::ContextTag(kCsTag_SubscribeTimeOutMin) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_TimeoutMin)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_TimeoutMin);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint32_t timeout;
err = reader.Get(timeout);
SuccessOrExit(err);
PRETTY_PRINT("\tSubscriptionTimeoutMin = %u,", timeout);
}
#endif // WEAVE_DETAIL_LOGGING
}
else if (nl::Weave::TLV::ContextTag(kCsTag_SubscribeTimeOutMax) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_TimeoutMax)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_TimeoutMax);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint32_t timeout;
err = reader.Get(timeout);
SuccessOrExit(err);
PRETTY_PRINT("\tSubscriptionTimeoutMax = %u,", timeout);
}
#endif // WEAVE_DETAIL_LOGGING
}
else if (nl::Weave::TLV::ContextTag(kCsTag_SubscribeToAllEvents) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_SubscribeToAllEvents)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_SubscribeToAllEvents);
VerifyOrExit(nl::Weave::TLV::kTLVType_Boolean == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
bool SubscribeToAllEvents;
err = reader.Get(SubscribeToAllEvents);
SuccessOrExit(err);
PRETTY_PRINT("\tSubscribeToAllEvents = %u,", SubscribeToAllEvents);
}
#endif // WEAVE_DETAIL_LOGGING
}
else if (nl::Weave::TLV::ContextTag(kCsTag_LastObservedEventIdList) == tag)
{
EventList::Parser eventList;
VerifyOrExit(!(TagPresenceMask & (1 << kBit_LastObservedEventIdList)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_LastObservedEventIdList);
err = eventList.Init(reader);
SuccessOrExit(err);
PRETTY_PRINT_INCDEPTH();
err = eventList.CheckSchemaValidity();
SuccessOrExit(err);
PRETTY_PRINT_DECDEPTH();
}
else if (nl::Weave::TLV::ContextTag(kCsTag_PathList) == tag)
{
PathList::Parser pathList;
VerifyOrExit(!(TagPresenceMask & (1 << kBit_PathList)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_PathList);
err = pathList.Init(reader);
SuccessOrExit(err);
PRETTY_PRINT_INCDEPTH();
err = pathList.CheckSchemaValidity();
SuccessOrExit(err);
PRETTY_PRINT_DECDEPTH();
}
else if (nl::Weave::TLV::ContextTag(kCsTag_VersionList) == tag)
{
VersionList::Parser versionList;
VerifyOrExit(!(TagPresenceMask & (1 << kBit_VersionList)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_VersionList);
err = versionList.Init(reader);
SuccessOrExit(err);
PRETTY_PRINT_INCDEPTH();
err = versionList.CheckSchemaValidity();
SuccessOrExit(err);
PRETTY_PRINT_DECDEPTH();
}
else
{
PRETTY_PRINT("\tUnknown tag 0x%" PRIx64, tag);
}
}
// if we have exhausted this container
if (WEAVE_END_OF_TLV == err)
{
// everything is optional
err = WEAVE_NO_ERROR;
}
PRETTY_PRINT("}");
PRETTY_PRINT("");
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// WEAVE_END_OF_TLV if there is no such element
// WEAVE_ERROR_WRONG_TLV_TYPE if there is such element but it's not one of the right types
WEAVE_ERROR SubscribeRequest::Parser::GetSubscribeTimeoutMin(uint32_t * const apTimeOutMin) const
{
return GetUnsignedInteger(kCsTag_SubscribeTimeOutMin, apTimeOutMin);
}
// WEAVE_END_OF_TLV if there is no such element
// WEAVE_ERROR_WRONG_TLV_TYPE if there is such element but it's not one of the right types
WEAVE_ERROR SubscribeRequest::Parser::GetSubscribeTimeoutMax(uint32_t * const apTimeOutMax) const
{
return GetUnsignedInteger(kCsTag_SubscribeTimeOutMax, apTimeOutMax);
}
WEAVE_ERROR SubscribeRequest::Parser::GetSubscribeToAllEvents(bool * const apAllEvents) const
{
return GetSimpleValue(kCsTag_SubscribeToAllEvents, nl::Weave::TLV::kTLVType_Boolean, apAllEvents);
}
WEAVE_ERROR SubscribeRequest::Parser::GetLastObservedEventIdList(EventList::Parser * const apEventList) const
{
return apEventList->InitIfPresent(mReader, kCsTag_LastObservedEventIdList);
}
// Get a TLVReader for the Paths. Next() must be called before accessing them.
WEAVE_ERROR SubscribeRequest::Parser::GetPathList(PathList::Parser * const apPathList) const
{
return apPathList->InitIfPresent(mReader, kCsTag_PathList);
}
// Get a TLVReader at the Versions. Next() must be called before accessing it.
// WEAVE_END_OF_TLV if there is no such element
// WEAVE_ERROR_WRONG_TLV_TYPE if there is such element but it's not one of the right types
WEAVE_ERROR SubscribeRequest::Parser::GetVersionList(VersionList::Parser * const apVersionList) const
{
return apVersionList->InitIfPresent(mReader, kCsTag_VersionList);
}
SubscribeRequest::Builder & SubscribeRequest::Builder::SubscriptionID(const uint64_t aSubscriptionID)
{
SetSubscriptionID(aSubscriptionID);
return *this;
}
SubscribeRequest::Builder & SubscribeRequest::Builder::SubscribeTimeoutMin(const uint32_t aSubscribeTimeoutMin)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_SubscribeTimeOutMin), aSubscribeTimeoutMin);
WeaveLogFunctError(mError);
exit:
return *this;
}
SubscribeRequest::Builder & SubscribeRequest::Builder::SubscribeTimeoutMax(const uint32_t aSubscribeTimeoutMax)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_SubscribeTimeOutMax), aSubscribeTimeoutMax);
WeaveLogFunctError(mError);
exit:
return *this;
}
SubscribeRequest::Builder & SubscribeRequest::Builder::SubscribeToAllEvents(const bool aSubscribeToAllEvents)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->PutBoolean(nl::Weave::TLV::ContextTag(kCsTag_SubscribeToAllEvents), aSubscribeToAllEvents);
WeaveLogFunctError(mError);
exit:
return *this;
}
EventList::Builder & SubscribeRequest::Builder::CreateLastObservedEventIdListBuilder()
{
// skip if error has already been set
VerifyOrExit(WEAVE_NO_ERROR == mError, mEventListBuilder.ResetError(mError));
mError = mEventListBuilder.Init(mpWriter, kCsTag_LastObservedEventIdList);
WeaveLogFunctError(mError);
exit:
// on error, mPathListBuilder would be un-/partial initialized and cannot be used to write anything
return mEventListBuilder;
}
PathList::Builder & SubscribeRequest::Builder::CreatePathListBuilder()
{
// skip if error has already been set
VerifyOrExit(WEAVE_NO_ERROR == mError, mPathListBuilder.ResetError(mError));
mError = mPathListBuilder.Init(mpWriter, kCsTag_PathList);
WeaveLogFunctError(mError);
exit:
// on error, mPathListBuilder would be un-/partial initialized and cannot be used to write anything
return mPathListBuilder;
}
VersionList::Builder & SubscribeRequest::Builder::CreateVersionListBuilder()
{
// skip if error has already been set
VerifyOrExit(WEAVE_NO_ERROR == mError, mVersionListBuilder.ResetError(mError));
mError = mVersionListBuilder.Init(mpWriter, kCsTag_VersionList);
WeaveLogFunctError(mError);
exit:
// on error, mVersionListBuilder would be un-/partial initialized and cannot be used to write anything
return mVersionListBuilder;
}
SubscribeRequest::Builder & SubscribeRequest::Builder::EndOfRequest(void)
{
EndOfMessage();
return *this;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Roughly verify the schema is right, including
// 1) all mandatory tags are present
// 2) all elements have expected data type
// 3) any tag can only appear once
// At the top level of the message, unknown tags are ignored for foward compatibility
WEAVE_ERROR SubscribeResponse::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint16_t TagPresenceMask = 0;
nl::Weave::TLV::TLVReader reader;
enum
{
kBit_SubscriptionId = 1,
kBit_Timeout = 2,
kBit_PossibleLossOfEvents = 3,
kBit_LastVendedEventIdList = 4,
};
PRETTY_PRINT("{");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
const uint64_t tag = reader.GetTag();
if (nl::Weave::TLV::ContextTag(kCsTag_SubscriptionId) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_SubscriptionId)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_SubscriptionId);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t id;
err = reader.Get(id);
SuccessOrExit(err);
PRETTY_PRINT("\tSubscriptionId = 0x%" PRIx64 ",", id);
}
#endif // WEAVE_DETAIL_LOGGING
}
else if (nl::Weave::TLV::ContextTag(kCsTag_SubscribeTimeOut) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_Timeout)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_Timeout);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint32_t timeout;
err = reader.Get(timeout);
SuccessOrExit(err);
PRETTY_PRINT("\tSubscribeTimeOut = %u,", timeout);
}
#endif // WEAVE_DETAIL_LOGGING
}
else if (nl::Weave::TLV::ContextTag(kCsTag_PossibleLossOfEvents) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_PossibleLossOfEvents)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_PossibleLossOfEvents);
VerifyOrExit(nl::Weave::TLV::kTLVType_Boolean == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
bool PossibleLossOfEvents;
err = reader.Get(PossibleLossOfEvents);
SuccessOrExit(err);
PRETTY_PRINT("\tPossibleLossOfEvents = %u,", PossibleLossOfEvents);
}
#endif // WEAVE_DETAIL_LOGGING
}
else if (nl::Weave::TLV::ContextTag(kCsTag_LastVendedEventIdList) == tag)
{
// TODO: this is not an event list. It's a list of structures that have SourceID, EventImportance and EventID,
// and only that.
EventList::Parser eventList;
VerifyOrExit(!(TagPresenceMask & (1 << kBit_LastVendedEventIdList)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_LastVendedEventIdList);
err = eventList.Init(reader);
SuccessOrExit(err);
PRETTY_PRINT_INCDEPTH();
err = eventList.CheckSchemaValidity();
SuccessOrExit(err);
PRETTY_PRINT_DECDEPTH();
}
else
{
PRETTY_PRINT("\tUnknown tag 0x%" PRIx64, tag);
}
}
// if we have exhausted this container
if (WEAVE_END_OF_TLV == err)
{
// if we have at least the PathList field
if (TagPresenceMask & (1 << kBit_SubscriptionId))
{
err = WEAVE_NO_ERROR;
}
}
PRETTY_PRINT("}");
PRETTY_PRINT("");
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// WEAVE_END_OF_TLV if there is no such element
// WEAVE_ERROR_WRONG_TLV_TYPE if there is such element but it's not one of the right types
WEAVE_ERROR SubscribeResponse::Parser::GetSubscribeTimeout(uint32_t * const apTimeOut) const
{
return GetUnsignedInteger(kCsTag_SubscribeTimeOut, apTimeOut);
}
WEAVE_ERROR SubscribeResponse::Parser::GetPossibleLossOfEvents(bool * const apPossibleLossOfEvents) const
{
return GetSimpleValue(kCsTag_PossibleLossOfEvents, nl::Weave::TLV::kTLVType_Boolean, apPossibleLossOfEvents);
}
WEAVE_ERROR SubscribeResponse::Parser::GetLastVendedEventIdList(EventList::Parser * const apEventList) const
{
return apEventList->InitIfPresent(mReader, kCsTag_LastVendedEventIdList);
}
SubscribeResponse::Builder & SubscribeResponse::Builder::SubscriptionID(const uint64_t aSubscriptionID)
{
SetSubscriptionID(aSubscriptionID);
return *this;
}
SubscribeResponse::Builder & SubscribeResponse::Builder::SubscribeTimeout(const uint32_t aSubscribeTimeout)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_SubscribeTimeOut), aSubscribeTimeout);
WeaveLogFunctError(mError);
exit:
return *this;
}
SubscribeResponse::Builder & SubscribeResponse::Builder::PossibleLossOfEvents(const bool aPossibleLossOfEvents)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->PutBoolean(nl::Weave::TLV::ContextTag(kCsTag_PossibleLossOfEvents), aPossibleLossOfEvents);
WeaveLogFunctError(mError);
exit:
return *this;
}
EventList::Builder & SubscribeResponse::Builder::CreateLastVendedEventIdListBuilder()
{
// skip if error has already been set
VerifyOrExit(WEAVE_NO_ERROR == mError, mEventListBuilder.ResetError(mError));
mError = mEventListBuilder.Init(mpWriter, kCsTag_LastVendedEventIdList);
WeaveLogFunctError(mError);
exit:
// on error, mPathListBuilder would be un-/partial initialized and cannot be used to write anything
return mEventListBuilder;
}
SubscribeResponse::Builder & SubscribeResponse::Builder::EndOfResponse(void)
{
EndOfMessage();
return *this;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Roughly verify the schema is right, including
// 1) all mandatory tags are present
// 2) all elements have expected data type
// 3) any tag can only appear once
// At the top level of the message, unknown tags are ignored for foward compatibility
WEAVE_ERROR SubscribeCancelRequest::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint16_t TagPresenceMask = 0;
nl::Weave::TLV::TLVReader reader;
enum
{
kBit_SubscriptionId = 1,
};
PRETTY_PRINT("{");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
const uint64_t tag = reader.GetTag();
if (nl::Weave::TLV::ContextTag(kCsTag_SubscriptionId) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_SubscriptionId)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_SubscriptionId);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t id;
err = reader.Get(id);
SuccessOrExit(err);
PRETTY_PRINT("\tSubscriptionId = 0x%" PRIx64 ",", id);
}
#endif // WEAVE_DETAIL_LOGGING
}
else
{
PRETTY_PRINT("\tUnknown tag 0x%" PRIx64, tag);
}
}
// if we have exhausted this container
if (WEAVE_END_OF_TLV == err)
{
// if we have at least the SubscriptionId field
if (TagPresenceMask & (1 << kBit_SubscriptionId))
{
err = WEAVE_NO_ERROR;
}
}
PRETTY_PRINT("}");
PRETTY_PRINT("");
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
SubscribeCancelRequest::Builder & SubscribeCancelRequest::Builder::SubscriptionID(const uint64_t aSubscriptionID)
{
SetSubscriptionID(aSubscriptionID);
return *this;
}
SubscribeCancelRequest::Builder & SubscribeCancelRequest::Builder::EndOfRequest(void)
{
EndOfMessage();
return *this;
}
SubscribeConfirmRequest::Builder & SubscribeConfirmRequest::Builder::SubscriptionID(const uint64_t aSubscriptionID)
{
SetSubscriptionID(aSubscriptionID);
return *this;
}
SubscribeConfirmRequest::Builder & SubscribeConfirmRequest::Builder::EndOfRequest(void)
{
EndOfMessage();
return *this;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Roughly verify the schema is right, including
// 1) all mandatory tags are present
// 2) all elements have expected data type
// 3) any tag can only appear once
// At the top level of the message, unknown tags are ignored for foward compatibility
WEAVE_ERROR NotificationRequest::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint16_t TagPresenceMask = 0;
nl::Weave::TLV::TLVReader reader;
DataList::Parser dataList;
EventList::Parser eventList;
enum
{
kBit_SubscriptionId = 1,
kBit_DataList = 2,
kBit_PossibleLossOfEvent = 3,
kBit_UTCTimestamp = 4,
kBit_SystemTimestamp = 5,
kBit_EventList = 6,
};
PRETTY_PRINT("{");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
const uint64_t tag = reader.GetTag();
if (nl::Weave::TLV::ContextTag(kCsTag_SubscriptionId) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_SubscriptionId)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_SubscriptionId);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t id;
err = reader.Get(id);
SuccessOrExit(err);
PRETTY_PRINT("\tSubscriptionId = 0x%" PRIx64 ",", id);
}
#endif // WEAVE_DETAIL_LOGGING
}
else if (nl::Weave::TLV::ContextTag(kCsTag_PossibleLossOfEvent) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_PossibleLossOfEvent)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_PossibleLossOfEvent);
VerifyOrExit(nl::Weave::TLV::kTLVType_Boolean == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
bool PossibleLossOfEvent;
err = reader.Get(PossibleLossOfEvent);
SuccessOrExit(err);
PRETTY_PRINT("\tPossibleLossOfEvent = %u,", PossibleLossOfEvent);
}
#endif // WEAVE_DETAIL_LOGGING
}
else if (nl::Weave::TLV::ContextTag(kCsTag_UTCTimestamp) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_UTCTimestamp)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_UTCTimestamp);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t UTCTimestamp;
err = reader.Get(UTCTimestamp);
SuccessOrExit(err);
PRETTY_PRINT("\tUTCTimestamp = 0x%" PRIx64 ",", UTCTimestamp);
}
#endif // WEAVE_DETAIL_LOGGING
}
else if (nl::Weave::TLV::ContextTag(kCsTag_SystemTimestamp) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_SystemTimestamp)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_SystemTimestamp);
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t SystemTimestamp;
err = reader.Get(SystemTimestamp);
SuccessOrExit(err);
PRETTY_PRINT("\tSystemTimestamp = 0x%" PRIx64 ",", SystemTimestamp);
}
#endif // WEAVE_DETAIL_LOGGING
}
else if (nl::Weave::TLV::ContextTag(kCsTag_EventList) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_EventList)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_EventList);
VerifyOrExit(nl::Weave::TLV::kTLVType_Array == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
eventList.Init(reader);
PRETTY_PRINT_INCDEPTH();
err = eventList.CheckSchemaValidity();
SuccessOrExit(err);
PRETTY_PRINT_DECDEPTH();
}
else if (nl::Weave::TLV::ContextTag(kCsTag_DataList) == tag)
{
VerifyOrExit(!(TagPresenceMask & (1 << kBit_DataList)), err = WEAVE_ERROR_INVALID_TLV_TAG);
TagPresenceMask |= (1 << kBit_DataList);
VerifyOrExit(nl::Weave::TLV::kTLVType_Array == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
dataList.Init(reader);
PRETTY_PRINT_INCDEPTH();
err = dataList.CheckSchemaValidity();
SuccessOrExit(err);
PRETTY_PRINT_DECDEPTH();
}
else
{
PRETTY_PRINT("\tUnknown tag 0x%" PRIx64, tag);
}
}
PRETTY_PRINT("}");
PRETTY_PRINT("");
// if we have exhausted this container
if (WEAVE_END_OF_TLV == err)
{
// if we have at least the DataList or EventList field
if ((TagPresenceMask & (1 << kBit_DataList)) ||
(TagPresenceMask & (1 << kBit_EventList)))
{
err = WEAVE_NO_ERROR;
}
}
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
// Get a TLVReader for the Paths. Next() must be called before accessing them.
WEAVE_ERROR NotificationRequest::Parser::GetDataList(DataList::Parser * const apDataList) const
{
return apDataList->InitIfPresent(mReader, kCsTag_DataList);
}
WEAVE_ERROR NotificationRequest::Parser::GetPossibleLossOfEvent(bool * const apPossibleLossOfEvent) const
{
return GetSimpleValue(kCsTag_PossibleLossOfEvent, nl::Weave::TLV::kTLVType_Boolean, apPossibleLossOfEvent);
}
WEAVE_ERROR NotificationRequest::Parser::GetUTCTimestamp(uint64_t * const apUTCTimestamp) const
{
return GetUnsignedInteger(kCsTag_UTCTimestamp, apUTCTimestamp);
}
WEAVE_ERROR NotificationRequest::Parser::GetSystemTimestamp(uint64_t * const apSystemTimestamp) const
{
return GetUnsignedInteger(kCsTag_SystemTimestamp, apSystemTimestamp);
}
WEAVE_ERROR NotificationRequest::Parser::GetEventList(EventList::Parser * const apEventList) const
{
return apEventList->InitIfPresent(mReader, kCsTag_EventList);
}
WEAVE_ERROR CustomCommand::Parser::Init(const nl::Weave::TLV::TLVReader & aReader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
VerifyOrExit(nl::Weave::TLV::AnonymousTag == aReader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
err = DataElement::Parser::Init(aReader);
SuccessOrExit(err);
mReader.ImplicitProfileId = kWeaveProfile_DictionaryKey;
exit:
WeaveLogFunctError(err);
return err;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
WEAVE_ERROR CustomCommand::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
nl::Weave::TLV::TLVReader reader;
struct TagPresence
{
bool Path;
bool CommandType;
bool InitiationTime;
bool ActionTime;
bool ExpiryTime;
bool MustBeVersion;
bool Argument;
bool Authenticator;
};
TagPresence tagPresence = {};
PRETTY_PRINT("{");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
// Authenticators carry profile tags
const uint64_t tag = reader.GetTag();
if (nl::Weave::TLV::IsContextTag(tag))
{
switch (nl::Weave::TLV::TagNumFromTag(tag))
{
case CustomCommand::kCsTag_Path:
// check if this tag has appeared before
VerifyOrExit(tagPresence.Path == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Path = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_Path == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
PRETTY_PRINT("\tCommand Path = ");
{
Path::Parser path;
err = path.Init(reader);
SuccessOrExit(err);
err = path.CheckSchemaValidity();
SuccessOrExit(err);
}
break;
case kCsTag_CommandType:
// check if this tag has appeared before
VerifyOrExit(tagPresence.CommandType == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.CommandType = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\tCommand Type = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_InitiationTime:
// check if this tag has appeared before
VerifyOrExit(tagPresence.InitiationTime == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.InitiationTime = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_SignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
int64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\tInit Time = 0x%" PRIx64 ",", static_cast<uint64_t>(value));
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_ActionTime:
// check if this tag has appeared before
VerifyOrExit(tagPresence.ActionTime == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.ActionTime = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_SignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
int64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\tAction Time = 0x%" PRIx64 ",", static_cast<uint64_t>(value));
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_ExpiryTime:
// check if this tag has appeared before
VerifyOrExit(tagPresence.ExpiryTime == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.ExpiryTime = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_SignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
int64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\tExpiry Time = 0x%" PRIx64 ",", static_cast<uint64_t>(value));
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_MustBeVersion:
// check if this tag has appeared before
VerifyOrExit(tagPresence.MustBeVersion == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.MustBeVersion = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\tMust Be Version = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_Argument:
// check if this tag has appeared before
VerifyOrExit(tagPresence.Argument == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Argument = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_Structure == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
PRETTY_PRINT("\t(Argument)");
err = ParseData(reader, 0);
SuccessOrExit(err);
}
#endif // WEAVE_DETAIL_LOGGING
break;
default:
WeaveLogDetail(DataManagement, "UNKONWN, IGNORE");
}
}
else if (nl::Weave::TLV::IsProfileTag(tag))
{
// we cannot use the normal case statement, for ProfileTag is a function instead of a macro
if (tag ==
nl::Weave::TLV::ProfileTag(nl::Weave::Profiles::kWeaveProfile_Security,
nl::Weave::Profiles::Security::kTag_WeaveSignature))
{
// certificate signature
VerifyOrExit(tagPresence.Authenticator == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Authenticator = true;
#if WEAVE_DETAIL_LOGGING
{
PRETTY_PRINT("\t(Authenticator-Certificate)");
err = ParseData(reader, 0);
SuccessOrExit(err);
}
#endif // WEAVE_DETAIL_LOGGING
}
// we cannot use the normal case statement, for ProfileTag is a function instead of a macro
// 10 is a place holder for the new group key feature in security profile
else if (tag ==
nl::Weave::TLV::ProfileTag(nl::Weave::Profiles::kWeaveProfile_Security,
nl::Weave::Profiles::Security::kTag_GroupKeySignature))
{
// group key signature
VerifyOrExit(tagPresence.Authenticator == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Authenticator = true;
#if WEAVE_DETAIL_LOGGING
{
PRETTY_PRINT("\t(Authenticator-Group Key)");
err = ParseData(reader, 0);
SuccessOrExit(err);
}
#endif // WEAVE_DETAIL_LOGGING
}
}
else
{
// a custom command can only contain, at top level, context-specific tags or profile tags
ExitNow(err = WEAVE_ERROR_INVALID_TLV_TAG);
}
}
PRETTY_PRINT("}");
PRETTY_PRINT("");
// almost all fields in an Event are optional
if (WEAVE_END_OF_TLV == err)
{
err = WEAVE_NO_ERROR;
}
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
WEAVE_ERROR CustomCommand::Parser::GetMustBeVersion(uint64_t * const apMustBeVersion) const
{
return GetUnsignedInteger(kCsTag_MustBeVersion, apMustBeVersion);
}
WEAVE_ERROR CustomCommand::Parser::GetInitiationTimeMicroSecond(int64_t * const apInitiationTimeMicroSecond) const
{
return GetSimpleValue(kCsTag_InitiationTime, nl::Weave::TLV::kTLVType_SignedInteger, apInitiationTimeMicroSecond);
}
WEAVE_ERROR CustomCommand::Parser::GetActionTimeMicroSecond(int64_t * const apActionTimeMicroSecond) const
{
return GetSimpleValue(kCsTag_ActionTime, nl::Weave::TLV::kTLVType_SignedInteger, apActionTimeMicroSecond);
}
WEAVE_ERROR CustomCommand::Parser::GetExpiryTimeMicroSecond(int64_t * const apExpiryTimeMicroSecond) const
{
return GetSimpleValue(kCsTag_ExpiryTime, nl::Weave::TLV::kTLVType_SignedInteger, apExpiryTimeMicroSecond);
}
WEAVE_ERROR CustomCommand::Parser::GetCommandType(uint64_t * const apCommandType) const
{
return GetUnsignedInteger(kCsTag_CommandType, apCommandType);
}
WEAVE_ERROR CustomCommand::Parser::GetPath(Path::Parser * const apPath) const
{
// CustomCommand::kCsTag_Path is defined to be 1, which happens to be
// the same as DataElement::kCsTag_Path
return DataElement::Parser::GetPath(apPath);
}
WEAVE_ERROR CustomCommand::Parser::GetReaderOnArgument(nl::Weave::TLV::TLVReader * const apReader) const
{
return GetReaderOnTag(nl::Weave::TLV::ContextTag(kCsTag_Argument), apReader);
}
WEAVE_ERROR CustomCommand::Parser::GetReaderOnPath(nl::Weave::TLV::TLVReader * const apReader) const
{
return GetReaderOnTag(nl::Weave::TLV::ContextTag(kCsTag_Path), apReader);
}
WEAVE_ERROR CustomCommand::Builder::Init(nl::Weave::TLV::TLVWriter * const apWriter)
{
return InitAnonymousStructure(apWriter);
}
Path::Builder & CustomCommand::Builder::CreatePathBuilder()
{
// skip if error has already been set
VerifyOrExit(WEAVE_NO_ERROR == mError, mPathBuilder.ResetError(mError));
mError = mPathBuilder.Init(mpWriter, nl::Weave::TLV::ContextTag(kCsTag_Path));
WeaveLogFunctError(mError);
exit:
// on error, mPathBuilder would be un-/partial initialized and cannot be used to write anything
return mPathBuilder;
}
CustomCommand::Builder & CustomCommand::Builder::CommandType(const uint64_t aCommandType)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_CommandType), aCommandType);
WeaveLogFunctError(mError);
exit:
return *this;
}
CustomCommand::Builder & CustomCommand::Builder::InitiationTimeMicroSecond(const int64_t aInitiationTimeMicroSecond)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_InitiationTime), aInitiationTimeMicroSecond);
WeaveLogFunctError(mError);
exit:
return *this;
}
CustomCommand::Builder & CustomCommand::Builder::ActionTimeMicroSecond(const int64_t aActionTimeMicroSecond)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_ActionTime), aActionTimeMicroSecond);
WeaveLogFunctError(mError);
exit:
return *this;
}
CustomCommand::Builder & CustomCommand::Builder::ExpiryTimeMicroSecond(const int64_t aExpiryTimeMicroSecond)
{
// skip if error has already been set
SuccessOrExit(mError);
WEAVE_FAULT_INJECT(FaultInjection::kFault_WDM_SendCommandExpired, {
int64_t * tmp = const_cast<int64_t *>(&aExpiryTimeMicroSecond);
*tmp = 0;
});
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_ExpiryTime), aExpiryTimeMicroSecond);
WeaveLogFunctError(mError);
exit:
return *this;
}
CustomCommand::Builder & CustomCommand::Builder::MustBeVersion(const uint64_t aMustBeVersion)
{
// skip if error has already been set
SuccessOrExit(mError);
WEAVE_FAULT_INJECT(FaultInjection::kFault_WDM_SendCommandBadVersion, {
uint64_t * tmp = const_cast<uint64_t *>(&aMustBeVersion);
*tmp = ~(*tmp);
});
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_MustBeVersion), aMustBeVersion);
WeaveLogFunctError(mError);
exit:
return *this;
}
CustomCommand::Builder & CustomCommand::Builder::EndOfCustomCommand(void)
{
EndOfContainer();
return *this;
}
WEAVE_ERROR CustomCommandResponse::Parser::Init(const nl::Weave::TLV::TLVReader & aReader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
VerifyOrExit(nl::Weave::TLV::AnonymousTag == aReader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
err = DataElement::Parser::Init(aReader);
SuccessOrExit(err);
mReader.ImplicitProfileId = kWeaveProfile_DictionaryKey;
exit:
WeaveLogFunctError(err);
return err;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
WEAVE_ERROR CustomCommandResponse::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
nl::Weave::TLV::TLVReader reader;
struct TagPresence
{
bool Version;
bool Response;
};
TagPresence tagPresence = {};
PRETTY_PRINT("{");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
VerifyOrExit(nl::Weave::TLV::IsContextTag(reader.GetTag()), err = WEAVE_ERROR_INVALID_TLV_TAG);
switch (nl::Weave::TLV::TagNumFromTag(reader.GetTag()))
{
case kCsTag_Version:
// check if this tag has appeared before
VerifyOrExit(tagPresence.Version == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Version = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\tVersion = 0x%" PRIx64 ",", value);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_Response:
// check if this tag has appeared before
VerifyOrExit(tagPresence.Response == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Response = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_Structure == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
PRETTY_PRINT("\t(Response)");
err = ParseData(reader, 0);
SuccessOrExit(err);
}
#endif // WEAVE_DETAIL_LOGGING
break;
default:
WeaveLogDetail(DataManagement, "UNKONWN, IGNORE");
}
}
PRETTY_PRINT("}");
PRETTY_PRINT("");
// almost all fields in an Event are optional
if (WEAVE_END_OF_TLV == err)
{
err = WEAVE_NO_ERROR;
}
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
WEAVE_ERROR CustomCommandResponse::Parser::GetVersion(uint64_t * const apVersion) const
{
return GetUnsignedInteger(kCsTag_Version, apVersion);
}
WEAVE_ERROR CustomCommandResponse::Parser::GetReaderOnResponse(nl::Weave::TLV::TLVReader * const apReader) const
{
return GetReaderOnTag(nl::Weave::TLV::ContextTag(kCsTag_Response), apReader);
}
WEAVE_ERROR CustomCommandResponse::Builder::Init(nl::Weave::TLV::TLVWriter * const apWriter)
{
return InitAnonymousStructure(apWriter);
}
CustomCommandResponse::Builder & CustomCommandResponse::Builder::Version(const uint64_t aMustBeVersion)
{
// skip if error has already been set
SuccessOrExit(mError);
mError = mpWriter->Put(nl::Weave::TLV::ContextTag(kCsTag_Version), aMustBeVersion);
WeaveLogFunctError(mError);
exit:
return *this;
}
CustomCommandResponse::Builder & CustomCommandResponse::Builder::EndOfResponse(void)
{
EndOfContainer();
return *this;
}
WEAVE_ERROR UpdateRequest::Parser::Init(const nl::Weave::TLV::TLVReader & aReader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
VerifyOrExit(nl::Weave::TLV::AnonymousTag == aReader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
err = DataElement::Parser::Init(aReader);
SuccessOrExit(err);
mReader.ImplicitProfileId = kWeaveProfile_DictionaryKey;
exit:
WeaveLogFunctError(err);
return err;
}
#if WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
WEAVE_ERROR UpdateRequest::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
nl::Weave::TLV::TLVReader reader;
DataList::Parser dataList;
struct TagPresence
{
bool ExpiryTime;
bool Argument;
bool DataList;
bool Authenticator;
bool UpdateRequestIndex;
};
TagPresence tagPresence = {};
PRETTY_PRINT("{");
// make a copy of the reader
reader.Init(mReader);
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
// Authenticators carry profile tags
const uint64_t tag = reader.GetTag();
if (nl::Weave::TLV::IsContextTag(tag))
{
switch (nl::Weave::TLV::TagNumFromTag(tag))
{
case kCsTag_ExpiryTime:
// check if this tag has appeared before
VerifyOrExit(tagPresence.ExpiryTime == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.ExpiryTime = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
int64_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\tExpiry Time = 0x%" PRIx64 ",", static_cast<uint64_t>(value));
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_UpdateRequestIndex:
// check if this tag has appeared before
VerifyOrExit(tagPresence.UpdateRequestIndex == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.UpdateRequestIndex = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_UnsignedInteger == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
uint32_t value;
err = reader.Get(value);
SuccessOrExit(err);
PRETTY_PRINT("\tUpdateRequestIndex = 0x%" PRIx32 ",", static_cast<uint32_t>(value));
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_Argument:
// check if this tag has appeared before
VerifyOrExit(tagPresence.Argument == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Argument = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_Structure == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
PRETTY_PRINT("\t(Argument)");
err = ParseData(reader, 0);
SuccessOrExit(err);
}
#endif // WEAVE_DETAIL_LOGGING
break;
case kCsTag_DataList:
// check if this tag has appeared before
VerifyOrExit(tagPresence.Argument == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Argument = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_Array == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
#if WEAVE_DETAIL_LOGGING
{
dataList.Init(reader);
PRETTY_PRINT_INCDEPTH();
err = dataList.CheckSchemaValidity();
SuccessOrExit(err);
PRETTY_PRINT_DECDEPTH();
}
#endif // WEAVE_DETAIL_LOGGING
break;
default:
WeaveLogDetail(DataManagement, "UNKONWN, IGNORE");
}
}
else if (nl::Weave::TLV::IsProfileTag(tag))
{
// we cannot use the normal case statement, for ProfileTag is a function instead of a macro
if (tag ==
nl::Weave::TLV::ProfileTag(nl::Weave::Profiles::kWeaveProfile_Security,
nl::Weave::Profiles::Security::kTag_WeaveSignature))
{
// certificate signature
VerifyOrExit(tagPresence.Authenticator == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Authenticator = true;
#if WEAVE_DETAIL_LOGGING
{
PRETTY_PRINT("\t(Authenticator-Certificate)");
err = ParseData(reader, 0);
SuccessOrExit(err);
}
#endif // WEAVE_DETAIL_LOGGING
}
// we cannot use the normal case statement, for ProfileTag is a function instead of a macro
// 10 is a place holder for the new group key feature in security profile
else if (tag ==
nl::Weave::TLV::ProfileTag(nl::Weave::Profiles::kWeaveProfile_Security,
nl::Weave::Profiles::Security::kTag_GroupKeySignature))
{
// group key signature
VerifyOrExit(tagPresence.Authenticator == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.Authenticator = true;
#if WEAVE_DETAIL_LOGGING
{
PRETTY_PRINT("\t(Authenticator-Group Key)");
err = ParseData(reader, 0);
SuccessOrExit(err);
}
#endif // WEAVE_DETAIL_LOGGING
}
}
else
{
// an UpdateRequest can only contain, at top level, context-specific tags or profile tags
ExitNow(err = WEAVE_ERROR_INVALID_TLV_TAG);
}
}
PRETTY_PRINT("}");
PRETTY_PRINT("");
if (WEAVE_END_OF_TLV == err)
{
err = WEAVE_NO_ERROR;
}
exit:
WeaveLogFunctError(err);
return err;
}
#endif // WEAVE_CONFIG_DATA_MANAGEMENT_ENABLE_SCHEMA_CHECK
WEAVE_ERROR UpdateRequest::Parser::GetExpiryTimeMicroSecond(int64_t * const apExpiryTimeMicroSecond) const
{
return GetSimpleValue(kCsTag_ExpiryTime, nl::Weave::TLV::kTLVType_UnsignedInteger, apExpiryTimeMicroSecond);
}
WEAVE_ERROR UpdateRequest::Parser::GetReaderOnArgument(nl::Weave::TLV::TLVReader * const apReader) const
{
return GetReaderOnTag(nl::Weave::TLV::ContextTag(kCsTag_Argument), apReader);
}
WEAVE_ERROR UpdateRequest::Parser::GetUpdateRequestIndex(uint32_t * const apUpdateRequestIndex) const
{
return GetSimpleValue(kCsTag_UpdateRequestIndex, nl::Weave::TLV::kTLVType_UnsignedInteger, apUpdateRequestIndex);
}
// Get a TLVReader for the Paths. Next() must be called before accessing them.
WEAVE_ERROR UpdateRequest::Parser::GetDataList (DataList::Parser * const apDataList) const
{
return apDataList->InitIfPresent(mReader, kCsTag_DataList);
}
// aReader has to be on the element of anonymous container
WEAVE_ERROR UpdateResponse::Parser::Init(const nl::Weave::TLV::TLVReader & aReader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// make a copy of the reader here
mReader.Init(aReader);
VerifyOrExit(nl::Weave::TLV::AnonymousTag == mReader.GetTag(), err = WEAVE_ERROR_INVALID_TLV_TAG);
VerifyOrExit(nl::Weave::TLV::kTLVType_Structure == mReader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
// This is just a dummy, as we're not going to exit this container ever
nl::Weave::TLV::TLVType OuterContainerType;
err = mReader.EnterContainer(OuterContainerType);
exit:
WeaveLogFunctError(err);
return err;
}
WEAVE_ERROR UpdateResponse::Parser::CheckSchemaValidity(void) const
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
nl::Weave::TLV::TLVReader reader;
StatusList::Parser statusList;
VersionList::Parser versionList;
struct TagPresence
{
bool StatusList;
bool VersionList;
};
TagPresence tagPresence = {};
reader.Init(mReader);
PRETTY_PRINT_CHECKPOINT();
PRETTY_PRINT("{");
while (WEAVE_NO_ERROR == (err = reader.Next()))
{
const uint64_t tag = reader.GetTag();
if (nl::Weave::TLV::IsContextTag(tag))
{
switch (nl::Weave::TLV::TagNumFromTag(tag))
{
case kCsTag_StatusList:
VerifyOrExit(tagPresence.StatusList == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.StatusList = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_Array == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
{
statusList.Init(reader);
PRETTY_PRINT_INCDEPTH();
err = statusList.CheckSchemaValidity();
SuccessOrExit(err);
PRETTY_PRINT_DECDEPTH();
}
break;
case kCsTag_VersionList:
VerifyOrExit(tagPresence.VersionList == false, err = WEAVE_ERROR_INVALID_TLV_TAG);
tagPresence.VersionList = true;
VerifyOrExit(nl::Weave::TLV::kTLVType_Array == reader.GetType(), err = WEAVE_ERROR_WRONG_TLV_TYPE);
{
versionList.Init(reader);
PRETTY_PRINT_INCDEPTH();
err = versionList.CheckSchemaValidity();
SuccessOrExit(err);
PRETTY_PRINT_DECDEPTH();
}
break;
default:
WeaveLogDetail(DataManagement, "UNKONWN, IGNORE");
break;
}
}
}
if (WEAVE_END_OF_TLV == err)
{
if (tagPresence.VersionList && tagPresence.StatusList)
{
err = WEAVE_NO_ERROR;
}
}
PRETTY_PRINT("}");
PRETTY_PRINT("");
exit:
WeaveLogFunctError(err);
return err;
}
// Get a TLVReader for the Status. Next() must be called before accessing them.
WEAVE_ERROR UpdateResponse::Parser::GetStatusList(StatusList::Parser * const apStatusList) const
{
return apStatusList->InitIfPresent(mReader, kCsTag_StatusList);
}
// Get a TLVReader at the Versions. Next() must be called before accessing it.
// WEAVE_END_OF_TLV if there is no such element
// WEAVE_ERROR_WRONG_TLV_TYPE if there is such element but it's not one of the right types
WEAVE_ERROR UpdateResponse::Parser::GetVersionList(VersionList::Parser * const apVersionList) const
{
return apVersionList->InitIfPresent(mReader, kCsTag_VersionList);
}
WEAVE_ERROR UpdateResponse::Builder::Init(nl::Weave::TLV::TLVWriter * const apWriter)
{
return InitAnonymousStructure(apWriter);
}
VersionList::Builder & UpdateResponse::Builder::CreateVersionListBuilder()
{
// skip if error has already been set
VerifyOrExit(WEAVE_NO_ERROR == mError, mVersionListBuilder.ResetError(mError));
mError = mVersionListBuilder.Init(mpWriter, kCsTag_VersionList);
WeaveLogFunctError(mError);
exit:
// on error, mVersionListBuilder would be un-/partial initialized and cannot be used to write anything
return mVersionListBuilder;
}
StatusList::Builder & UpdateResponse::Builder::CreateStatusListBuilder()
{
// Check if the VersionList::Builder has failed, or has not been used yet
if (WEAVE_NO_ERROR == mError)
{
mError = mVersionListBuilder.GetError();
}
// skip if error has already been set
VerifyOrExit(WEAVE_NO_ERROR == mError, mStatusListBuilder.ResetError(mError));
mError = mStatusListBuilder.Init(mpWriter, kCsTag_StatusList);
WeaveLogFunctError(mError);
exit:
// on error, mStatusListBuilder would be un-/partial initialized and cannot be used to write anything
return mStatusListBuilder;
}
UpdateResponse::Builder & UpdateResponse::Builder::EndOfResponse(void)
{
// Check if the StatusList::Builder has failed, or has not been used
if (WEAVE_NO_ERROR == mError)
{
mError = mStatusListBuilder.GetError();
}
SuccessOrExit(mError);
EndOfContainer();
exit:
return *this;
}
}; // namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Current)
}; // namespace Profiles
}; // namespace Weave
}; // namespace nl