| /* |
| * |
| * Copyright (c) 2015-2017 Nest Labs, Inc. |
| * All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @file |
| * |
| * @brief |
| * Implementations for the abstract ProfileDatabase auxiliary |
| * class. |
| * |
| * This file implements method definitions for the abstract Weave |
| * ProfileDatabase auxiliary class. |
| */ |
| |
| #include <Weave/Profiles/data-management/Legacy/WdmManagedNamespace.h> |
| |
| #include <stdarg.h> |
| #include <Weave/Support/CodeUtils.h> |
| |
| #include <Weave/Profiles/data-management/ProfileDatabase.h> |
| |
| namespace nl { |
| namespace Weave { |
| namespace Profiles { |
| namespace WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Legacy) { |
| |
| using namespace ::nl; |
| using namespace ::nl::Inet; |
| using namespace ::nl::Weave; |
| using namespace ::nl::Weave::TLV; |
| using namespace ::nl::Weave::Profiles; |
| using namespace ::nl::Weave::Profiles::Common; |
| |
| /** |
| * @brief |
| * Check a WDM-specific tag. |
| * |
| * Check the number of a WDM-specific tag, from |
| * .../data-management/DMConstants.h, against the actual tag at the |
| * head of a TLV reader. |
| * |
| * @param [in] aTagNum The tag number to be checked |
| * against a specific TLV element. |
| * |
| * @param [in] aReader A reference to a TLV reader |
| * pointing to the element to be |
| * checked. |
| * |
| * @return true iff aReader.GetTag() produces a tag that matches one |
| * of the expected tag forms for the given tag number. |
| */ |
| |
| bool CheckWDMTag(uint32_t aTagNum, nl::Weave::TLV::TLVReader &aReader) |
| { |
| bool returnVal; |
| uint64_t tag = aReader.GetTag(); |
| |
| switch (aTagNum) |
| { |
| case kTag_WDMPathList: |
| case kTag_WDMPathProfile: |
| case kTag_WDMPathArrayIndexSelector: |
| case kTag_WDMPathArrayValueSelector: |
| case kTag_WDMDataList: |
| |
| returnVal = (tag == CommonTag(aTagNum) || tag == ProfileTag(kWeaveProfile_WDM, aTagNum)); |
| |
| break; |
| case kTag_WDMPathProfileId: |
| |
| returnVal = (tag == CommonTag(kTag_WDMPathProfileId_Deprecated) || |
| tag == ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfileId_Deprecated) || |
| tag == ContextTag(aTagNum)); |
| |
| break; |
| case kTag_WDMPathProfileInstance: |
| |
| returnVal = (tag == CommonTag(kTag_WDMPathProfileInstance_Deprecated) || |
| tag == ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfileInstance_Deprecated) || |
| tag == ContextTag(aTagNum)); |
| |
| break; |
| case kTag_WDMDataListElementPath: |
| |
| returnVal = (tag == CommonTag(kTag_WDMDataListElementPath_Deprecated) || |
| tag == ProfileTag(kWeaveProfile_WDM, kTag_WDMDataListElementPath_Deprecated) || |
| tag == ContextTag(aTagNum)); |
| |
| break; |
| case kTag_WDMDataListElementVersion: |
| |
| returnVal = (tag == CommonTag(kTag_WDMDataListElementVersion_Deprecated) || |
| tag == ProfileTag(kWeaveProfile_WDM, kTag_WDMDataListElementVersion_Deprecated) || |
| tag == ContextTag(aTagNum)); |
| |
| break; |
| case kTag_WDMDataListElementData: |
| |
| /* |
| * this is an especially gnarly one. in the bad old days, we |
| * weren't checking this tag and it allowed the service to |
| * send a profile tag for the application protocol of interest |
| * as the tag for the data container here. this is incorrect, |
| * of course, but for purposes of backwards compatibility we |
| * should allow it until we're pretty sure the service is up |
| * to date. |
| */ |
| |
| returnVal = (tag == CommonTag(kTag_WDMDataListElementData_Deprecated) || |
| tag == ProfileTag(kWeaveProfile_WDM, kTag_WDMDataListElementData_Deprecated) || |
| tag == ContextTag(aTagNum) || |
| tag == ProfileTag(kWeaveProfile_NestProtect, 0) || |
| tag == ProfileTag(kWeaveProfile_Occupancy, 0) || |
| tag == ProfileTag(kWeaveProfile_Structure, 0) || |
| tag == ProfileTag(kWeaveProfile_Safety, 0) || |
| tag == ProfileTag(kWeaveProfile_SafetySummary, 0) || |
| tag == ProfileTag(kWeaveProfile_NestThermostat, 0)); |
| |
| break; |
| default: |
| |
| returnVal = false; |
| |
| break; |
| } |
| |
| return returnVal; |
| }; |
| |
| /** |
| * @brief |
| * Start reading a path list. |
| * |
| * Given a fresh reader and a path list, start reading the list and |
| * validate the tags and types initially encountered in the |
| * process. If all goes well, the reader stops after the list |
| * container is entered. |
| * |
| * @param [in] aPathList A path list passed as a reference |
| * to a ReferencedTLVData object. The |
| * normal use case will be where the |
| * list is actually still in a buffer |
| * after receipt. |
| * |
| * @param [out] aReader A reference to a TLV reader used |
| * to read the path list. This reader |
| * will be left pointing just before |
| * the first path in the list. |
| * |
| * @return #WEAVE_NO_ERROR on success; otherwise, a |
| * #WEAVE_ERROR reflecting a failure the open the path list and/or |
| * validate the relevant tags and types. |
| */ |
| |
| WEAVE_ERROR OpenPathList(ReferencedTLVData &aPathList, nl::Weave::TLV::TLVReader &aReader) |
| { |
| WEAVE_ERROR err; |
| TLVType container; |
| |
| aReader.Init(aPathList.theData, aPathList.theLength); |
| |
| // we should be looking at an array called a WDM path list |
| |
| err = aReader.Next(); |
| SuccessOrExit(err); |
| |
| err = ValidateTLVType(kTLVType_Array, aReader); |
| SuccessOrExit(err); |
| |
| err = ValidateWDMTag(kTag_WDMPathList, aReader); |
| SuccessOrExit(err); |
| |
| err = aReader.EnterContainer(container); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| /** |
| * @brief |
| * Start reading a data list. |
| * |
| * Given a fresh reader and a data list, start reading the list and |
| * validate the tags and types initially encountered in the |
| * process. If all goes well, the reader stops after the list |
| * container is entered. |
| * |
| * @param [in] aDataList A data list passed as a reference |
| * to a ReferencedTLVData object. The |
| * normal use case will be where the |
| * list is actually still in a buffer |
| * after receipt. |
| * |
| * @param [out] aReader A reference to a TLV reader used |
| * to read the data list. This reader |
| * will be left pointing just before |
| * the first item in the list. |
| * |
| * @return #WEAVE_NO_ERROR On success. Otherwise return a |
| * #WEAVE_ERROR reflecting a failure the open the data list and/or |
| * validate the relevant tags and types. |
| */ |
| |
| WEAVE_ERROR OpenDataList(ReferencedTLVData &aDataList, nl::Weave::TLV::TLVReader &aReader) |
| { |
| WEAVE_ERROR err; |
| TLVType container; |
| |
| aReader.Init(aDataList.theData, aDataList.theLength); |
| |
| // we should be looking at an array called a WDM data list |
| |
| err = aReader.Next(); |
| SuccessOrExit(err); |
| |
| err = ValidateTLVType(kTLVType_Array, aReader); |
| SuccessOrExit(err); |
| |
| err = ValidateWDMTag(kTag_WDMDataList, aReader); |
| SuccessOrExit(err); |
| |
| err = aReader.EnterContainer(container); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| /** |
| * @brief |
| * Start reading a data list element. |
| * |
| * Given a reader positioned at a data list element, start reading the |
| * element and validate the tags and types initially encountered in |
| * the process. If all goes well, the reader ends up positioned at the |
| * data element data and the in/out path reader is positioned at the |
| * corresponding path. |
| * |
| * @param [in] aReader A reference to a TLV reader |
| * positioned at a data list element. |
| * |
| * @param [out] aPathReader A reference to a TLV reader to be |
| * pointed at the path component of |
| * the data list element. |
| * |
| * @param [out] aVersion A reference to a 64-bit integer |
| * to be set either to the data list |
| * element version if one is present |
| * or else to kVersionNotSpecified. |
| * |
| * @return #WEAVE_NO_ERROR on success or else a #WEAVE_ERROR |
| * associated with opening and reading the data list element. |
| */ |
| |
| WEAVE_ERROR OpenDataListElement(nl::Weave::TLV::TLVReader &aReader, nl::Weave::TLV::TLVReader &aPathReader, uint64_t &aVersion) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| TLVType elementContainer; |
| |
| /* |
| * a data list element should be an anonymous structure with 3 |
| * components, one of which (the version) is optional. |
| */ |
| |
| VerifyOrExit(aReader.GetTag() == AnonymousTag, err = WEAVE_ERROR_INVALID_TLV_TAG); |
| |
| err = ValidateTLVType(kTLVType_Structure, aReader); |
| SuccessOrExit(err); |
| |
| err = aReader.EnterContainer(elementContainer); |
| SuccessOrExit(err); |
| |
| /* |
| * first get a copy of the reader that points to the |
| * path and hold it for later. |
| */ |
| |
| err = aReader.Next(); |
| SuccessOrExit(err); |
| |
| VerifyOrExit((aReader.GetType() == kTLVType_Path), err = WEAVE_ERROR_WRONG_TLV_TYPE); |
| |
| aPathReader = aReader; |
| |
| /* |
| * now get the version if there is one. |
| */ |
| |
| err = aReader.Next(); |
| SuccessOrExit(err); |
| |
| if (CheckWDMTag(kTag_WDMDataListElementVersion, aReader)) |
| { |
| err = ValidateTLVType(kTLVType_UnsignedInteger, aReader); |
| SuccessOrExit(err); |
| |
| aReader.Get(aVersion); |
| |
| err = aReader.Next(); |
| SuccessOrExit(err); |
| } |
| |
| else |
| { |
| aVersion = kVersionNotSpecified; |
| } |
| |
| err = ValidateWDMTag(kTag_WDMDataListElementData, aReader); |
| |
| exit: |
| return err; |
| } |
| |
| /* |
| * @brief |
| * An internal method to start encoding a path list |
| * |
| * @note |
| * There are a bunch of EncodePath() functions below that differ in |
| * the instance ID and tag style they use. Furthermore, they're all |
| * variadic so there's a chunk of them - the arg unpacking - that's |
| * hard to reduce. These static functions are the best bet for both |
| * reducing the resultant code size and duplication. They knock a few |
| * hundred bytes off the image and at least reduce the absolute amount |
| * of duplicated text by a bit. |
| * |
| * This method starts a container with ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfile) |
| * and then insert a context-specific tag with ContextTag(kTag_WDMPathProfileId). |
| * This is the latest version for encoding a path. |
| */ |
| |
| static WEAVE_ERROR StartEncodePath(TLVWriter &aWriter, |
| const uint64_t &aTag, |
| uint32_t aProfileId, |
| TLVType &mOuterContainer, |
| TLVType &mPath) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| err = aWriter.StartContainer(aTag, kTLVType_Path, mOuterContainer); |
| SuccessOrExit(err); |
| |
| // open a structure container and write the profile ID |
| |
| err = aWriter.StartContainer(ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfile), kTLVType_Structure, mPath); |
| SuccessOrExit(err); |
| |
| err = aWriter.Put(ContextTag(kTag_WDMPathProfileId), aProfileId); |
| SuccessOrExit(err); |
| |
| exit: |
| |
| return err; |
| } |
| |
| static WEAVE_ERROR EndEncodePath(TLVWriter &aWriter, TLVType &mOuterContainer, WEAVE_ERROR mError) |
| { |
| WEAVE_ERROR retErr = aWriter.EndContainer(mOuterContainer); |
| |
| /* |
| * take the "worst" error and return it. |
| */ |
| |
| if (mError != WEAVE_NO_ERROR) |
| retErr = mError; |
| |
| return retErr; |
| } |
| |
| /** |
| * @brief |
| * Encode a WDM path with an integer profile instance ID. |
| * |
| * @note |
| * Write a TLV path of the kind used in data management where, in |
| * particular, there is a profile designation placed at the beginning |
| * in order to allow interpretation of subsequent path elements. |
| * |
| * This version of the method takes an integer profile instance ID. |
| * |
| * This method inserts instance ID using ContextTag(kTag_WDMPathProfileInstance), |
| * which is the latest version for encoding a path. |
| * |
| * @param [in] aWriter A reference to the TLV writer used |
| * to write out the path. |
| * |
| * @param [in] aTag A reference to the fully-qualified |
| * TLV tag that applies to this path. |
| * |
| * @param [in] aProfileId The profile ID under which |
| * elements of the path are to be |
| * interpreted. |
| * |
| * @param [in] aInstanceId A reference to the optional |
| * instance identifier of the profile |
| * to be used. If no instance ID is |
| * to be used then this parameter |
| * should have a value of |
| * kInstanceIdNotSpecified. |
| * |
| * @param [in] aPathLen The, possibly 0, length of the |
| * list of path elements beyond the |
| * initial profile specifier. |
| * |
| * @param [in] ... The optional variable-length list |
| * of additional path tags. |
| * |
| * @return #WEAVE_NO_ERROR On success. Otherwise return a |
| * #WEAVE_ERROR reflecting an inability to format the given path. |
| */ |
| |
| WEAVE_ERROR EncodePath(TLVWriter &aWriter, |
| const uint64_t &aTag, |
| uint32_t aProfileId, |
| const uint64_t &aInstanceId, |
| uint16_t aPathLen, |
| ...) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| va_list pathTags; |
| TLVType outerContainer; |
| TLVType path; |
| |
| err = StartEncodePath(aWriter, aTag, aProfileId, outerContainer, path); |
| SuccessOrExit(err); |
| |
| if (aInstanceId != kInstanceIdNotSpecified) |
| { |
| err = aWriter.Put(ContextTag(kTag_WDMPathProfileInstance), aInstanceId); |
| SuccessOrExit(err); |
| } |
| |
| err = aWriter.EndContainer(path); |
| SuccessOrExit(err); |
| |
| va_start(pathTags, aPathLen); |
| |
| for (int i = 0; i < aPathLen; i++) |
| { |
| err = aWriter.PutNull(va_arg(pathTags, uint64_t)); |
| |
| if (err != WEAVE_NO_ERROR) |
| break; |
| } |
| |
| va_end(pathTags); |
| |
| exit: |
| |
| return EndEncodePath(aWriter, outerContainer, err); |
| } |
| |
| /** |
| * @brief |
| * Encode a WDM path with a byte array instance ID. |
| * |
| * @note |
| * Write a TLV path of the kind used in data management where, in |
| * particular, there is a profile designation placed at the beginning |
| * in order to allow interpretation of subsequent path elements. |
| * |
| * This version of the method takes a byte-array profile instance ID |
| * along with a length. |
| * |
| * This method inserts instance ID using ContextTag(kTag_WDMPathProfileInstance), |
| * which is the latest version for encoding a path. |
| * |
| * @param [in] aWriter A reference to the TLV writer used |
| * to write out the path. |
| * |
| * @param [in] aTag A reference to the fully-qualified |
| * TLV tag that applies to this path. |
| * |
| * @param [in] aProfileId The profile ID under which the |
| * elements of the path are to be |
| * interpreted. |
| * |
| * @param [in] aInstanceIdLen The length of the byte array |
| * that constitutes the instance |
| * ID. If there is no ID then this |
| * parameter shall have a value of 0. |
| * |
| * @param [in] aInstanceId The optional byte array used as a |
| * profile instance identifier. This |
| * argument may be NULL in the case |
| * where no instance ID is specified. |
| * |
| * @param [in] aPathLen The, possibly 0, length of the |
| * list of path elements beyond the |
| * initial profile specifier. |
| * |
| * @param [in] ... The optional, variable-length list |
| * of additional path tags. |
| * |
| * @return #WEAVE_NO_ERROR On success. Otherwise return a |
| * #WEAVE_ERROR reflecting an inability to format the given path. |
| */ |
| |
| WEAVE_ERROR EncodePath(TLVWriter &aWriter, |
| const uint64_t &aTag, |
| uint32_t aProfileId, |
| const uint32_t aInstanceIdLen, |
| const uint8_t *aInstanceId, |
| uint16_t aPathLen, |
| ...) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| va_list pathTags; |
| TLVType outerContainer; |
| TLVType path; |
| |
| err = StartEncodePath(aWriter, aTag, aProfileId, outerContainer, path); |
| SuccessOrExit(err); |
| |
| if (aInstanceId) |
| { |
| err = aWriter.PutBytes(ContextTag(kTag_WDMPathProfileInstance), aInstanceId, aInstanceIdLen); |
| SuccessOrExit(err); |
| } |
| |
| err = aWriter.EndContainer(path); |
| SuccessOrExit(err); |
| |
| va_start(pathTags, aPathLen); |
| |
| for (int i = 0; i < aPathLen; i++) |
| { |
| err = aWriter.PutNull(va_arg(pathTags, uint64_t)); |
| |
| if (err != WEAVE_NO_ERROR) |
| break; |
| } |
| |
| va_end(pathTags); |
| |
| exit: |
| |
| return EndEncodePath(aWriter, outerContainer, err); |
| } |
| |
| /** |
| * @brief |
| * Encode a WDM path with a string instance ID. |
| * |
| * @note |
| * Write a TLV path of the kind used in data management where, in |
| * particular, there is a profile designation placed at the beginning |
| * in order to allow interpretation of subsequent path elements. |
| * |
| * This version of the method takes a string profile instance ID. |
| * |
| * This method inserts instance ID using ContextTag(kTag_WDMPathProfileInstance), |
| * which is the latest version for encoding a path. |
| * |
| * @param [in] aWriter A reference to the TLV writer used |
| * to write out the path. |
| * |
| * @param [in] aTag A reference to the fully-qualified |
| * TLV tag that applies to this path. |
| * |
| * @param [in] aProfileId The profile ID under which |
| * elements of the path are to be |
| * interpreted. |
| * |
| * @param [in] aInstanceId The optional string used as a |
| * profile instance identifier. This |
| * argument may be NULL if no |
| * instance ID is specified. |
| * |
| * @param [in] aPathLen The, possibly 0, length of the |
| * list of path elements beyond the |
| * initial profile specifier. |
| * |
| * @param [in] ... The optional, variable-length list |
| * of additional path tags. |
| * |
| * @return #WEAVE_NO_ERROR On success. Otherwise return a |
| * #WEAVE_ERROR reflecting an inability to format the given path. |
| */ |
| |
| WEAVE_ERROR EncodePath(TLVWriter &aWriter, |
| const uint64_t &aTag, |
| uint32_t aProfileId, |
| const char *aInstanceId, |
| uint16_t aPathLen, |
| ...) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| va_list pathTags; |
| TLVType outerContainer; |
| TLVType path; |
| |
| err = StartEncodePath(aWriter, aTag, aProfileId, outerContainer, path); |
| SuccessOrExit(err); |
| |
| if (aInstanceId) |
| { |
| err = aWriter.PutString(ContextTag(kTag_WDMPathProfileInstance), aInstanceId); |
| SuccessOrExit(err); |
| } |
| |
| err = aWriter.EndContainer(path); |
| SuccessOrExit(err); |
| |
| va_start(pathTags, aPathLen); |
| |
| for (int i = 0; i < aPathLen; i++) |
| { |
| err = aWriter.PutNull(va_arg(pathTags, uint64_t)); |
| |
| if (err != WEAVE_NO_ERROR) |
| break; |
| } |
| |
| va_end(pathTags); |
| |
| exit: |
| |
| return EndEncodePath(aWriter, outerContainer, err); |
| } |
| |
| /** |
| * @brief |
| * Encode a WDM path with deprecated tags and an integer instance ID. |
| * |
| * @note |
| * Encode a path using the deprecated tag set accepted by the service |
| * before Weave release 2.0. This version of the method takes a numerical |
| * instance identifier. |
| * |
| * This method starts a container with ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfile) |
| * and then inserts the profile ID with ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfileId_Deprecated). |
| * It then inserts the instance ID with ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfileInstance_Deprecated). |
| * This is one of the deprecated versions for encoding a path, and new designs shall avoid |
| * using this format. |
| * |
| * @param [in] aWriter A reference to the TLV writer used |
| * to write out the path. |
| * |
| * @param [in] aTag A reference to the fully-qualified |
| * TLV tag that applies to this path. |
| * |
| * @param [in] aProfileId The profile ID under which |
| * elements of the path are to be |
| * interpreted. |
| * |
| * @param [in] aInstanceId A reference to the optional |
| * instance ID of the profile to be |
| * used. |
| * |
| * @param [in] aPathLen The, possibly 0, length of the |
| * list of path elements beyond the |
| * initial profile specifier. |
| * |
| * @param [in] ... The optional variable-length list |
| * of additional path tags. |
| * |
| * @return #WEAVE_NO_ERROR On success. Otherwise return a |
| * #WEAVE_ERROR reflecting an inability to format the given path. |
| */ |
| |
| WEAVE_ERROR EncodeDeprecatedPath(TLVWriter &aWriter, |
| const uint64_t &aTag, |
| uint32_t aProfileId, |
| const uint64_t &aInstanceId, |
| uint16_t aPathLen, |
| ...) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| va_list pathTags; |
| TLVType outerContainer; |
| TLVType path; |
| |
| err = aWriter.StartContainer(aTag, kTLVType_Path, outerContainer); |
| SuccessOrExit(err); |
| |
| // write the profile and instance (if specified) |
| |
| err = aWriter.StartContainer(ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfile), kTLVType_Structure, path); |
| SuccessOrExit(err); |
| |
| err = aWriter.Put(ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfileId_Deprecated), aProfileId); |
| SuccessOrExit(err); |
| |
| if (aInstanceId != kInstanceIdNotSpecified) |
| { |
| err = aWriter.Put(ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfileInstance_Deprecated), aInstanceId); |
| SuccessOrExit(err); |
| } |
| |
| err = aWriter.EndContainer(path); |
| SuccessOrExit(err); |
| |
| va_start(pathTags, aPathLen); |
| |
| for (int i = 0; i < aPathLen; i++) |
| { |
| err = aWriter.PutNull(va_arg(pathTags, uint64_t)); |
| |
| if (err != WEAVE_NO_ERROR) |
| break; |
| } |
| |
| va_end(pathTags); |
| |
| exit: |
| |
| return EndEncodePath(aWriter, outerContainer, err); |
| } |
| |
| /** |
| * @brief |
| * Encode a WDM path with deprecated tags and a string instance ID. |
| * |
| * @note |
| * Encode a path using the deprecated tag set (see DMConstants.h). This |
| * version of the method takes an instance ID string. |
| * |
| * This method starts a container with ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfile) |
| * and then inserts the profile ID with ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfileId_Deprecated). |
| * It then inserts the instance ID with ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfileInstance_Deprecated). |
| * This is one of the deprecated versions for encoding a path, and new designs shall avoid |
| * using this format. |
| * |
| * @param [in] aWriter A reference to the TLV writer used |
| * to write out the path. |
| * |
| * @param [in] aTag A reference to the fully-qualified |
| * TLV tag that applies to this path. |
| * |
| * @param [in] aProfileId The profile ID under which |
| * elements of the path are to be |
| * interpreted. |
| * |
| * @param [in] aInstanceId The optional string used as a |
| * profile instance identifier. This |
| * argument may be NULL if no |
| * instance ID is specified. |
| * |
| * @param [in] aPathLen The, possibly 0, length of the |
| * list of path elements beyond the |
| * initial profile specifier. |
| * |
| * @param [in] ... The optional, variable-length list |
| * of additional path tags. |
| * |
| * @return #WEAVE_NO_ERROR On success. Otherwise return a |
| * #WEAVE_ERROR reflecting an inability to format the given path. |
| */ |
| |
| WEAVE_ERROR EncodeDeprecatedPath(TLVWriter &aWriter, |
| const uint64_t &aTag, |
| uint32_t aProfileId, |
| const char *aInstanceId, |
| uint16_t aPathLen, |
| ...) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| va_list pathTags; |
| TLVType outerContainer; |
| TLVType path; |
| |
| err = aWriter.StartContainer(aTag, kTLVType_Path, outerContainer); |
| SuccessOrExit(err); |
| |
| // write the profile and instance (if specified) |
| |
| err = aWriter.StartContainer(ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfile), kTLVType_Structure, path); |
| SuccessOrExit(err); |
| |
| err = aWriter.Put(ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfileId_Deprecated), aProfileId); |
| SuccessOrExit(err); |
| |
| if (aInstanceId != NULL) |
| { |
| err = aWriter.PutString(ProfileTag(kWeaveProfile_WDM, kTag_WDMPathProfileInstance_Deprecated), aInstanceId); |
| SuccessOrExit(err); |
| } |
| |
| err = aWriter.EndContainer(path); |
| SuccessOrExit(err); |
| |
| va_start(pathTags, aPathLen); |
| |
| for (int i = 0; i < aPathLen; i++) |
| { |
| err = aWriter.PutNull(va_arg(pathTags, uint64_t)); |
| |
| if (err != WEAVE_NO_ERROR) |
| break; |
| } |
| |
| va_end(pathTags); |
| |
| exit: |
| |
| return EndEncodePath(aWriter, outerContainer, err); |
| } |
| |
| /* |
| * in both of the following methods we set the version to 0. we're |
| * assuming that, for our purposes, it's OK to start the version at 0 |
| * and count up. if something else is required, it can be handled in |
| * the concrete subclass. |
| */ |
| |
| /** |
| * @brief |
| * The default constructor for ProfileData. |
| * |
| * Initialize a fresh ProfileData item by setting its version to 0. |
| */ |
| |
| ProfileDatabase::ProfileData::ProfileData(void) |
| { |
| mVersion = 0; |
| } |
| |
| /** |
| * @brief |
| * The destructor for ProfileData |
| * |
| * Like the constructor this just clears the data verion to 0. |
| */ |
| |
| ProfileDatabase::ProfileData::~ProfileData(void) |
| { |
| mVersion = 0; |
| } |
| |
| /** |
| * @brief |
| * Store a data list item being read. |
| * |
| * This virtual method is used to store a particular data list item in |
| * an object of a concrete ProfileData subclass. The implementation |
| * here in the super-class may be used if the object is simple and |
| * "shallow", having only paths that are one element long. For a more |
| * complicated schema, implementers should override this method. |
| * |
| * @param [in] aPathReader A reference to a TLV reader |
| * positioned at the path component |
| * of the data list item. |
| * |
| * @param [in] aVersion The 64-bit version component of |
| * the data list item. |
| * |
| * @param [in] aDataReader A reference to a TLV reader |
| * positioned at the data component |
| * of the data list item. |
| * |
| * @return #WEAVE_NO_ERROR On success. Otherwise return a |
| * #WEAVE_ERROR indicating a failure to store the data of interest. |
| */ |
| |
| WEAVE_ERROR ProfileDatabase::ProfileData::Store(TLVReader &aPathReader, uint64_t aVersion, TLVReader &aDataReader) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| TLVType container; |
| |
| err = aPathReader.Next(); |
| |
| if (err == WEAVE_END_OF_TLV) |
| { |
| /* |
| * the path given was the top-level profile path so the we |
| * have to do the entire bucket, as follows. we should be |
| * looking at a structure. |
| */ |
| |
| VerifyOrExit((aDataReader.GetType() == kTLVType_Structure), err = WEAVE_ERROR_WRONG_TLV_TYPE); |
| |
| err = aDataReader.EnterContainer(container); |
| SuccessOrExit(err); |
| |
| err = aDataReader.Next(); |
| while (err == WEAVE_NO_ERROR) |
| { |
| err = StoreItem(aDataReader.GetTag(), aDataReader); |
| SuccessOrExit(err); |
| |
| err = aDataReader.Next(); |
| } |
| |
| // don't return an error if we're just out of TLV |
| |
| if (err == WEAVE_END_OF_TLV) |
| err = WEAVE_NO_ERROR; |
| |
| aDataReader.ExitContainer(container); |
| } |
| |
| else |
| { |
| /* |
| * in this case, the path contained an additional tag |
| * accessing a particular data item directly. |
| */ |
| |
| err = StoreItem(aPathReader.GetTag(), aDataReader); |
| SuccessOrExit(err); |
| } |
| |
| /* |
| * whatever happened above, we set the version here as long as it |
| * didn't go horribly wrong. |
| */ |
| |
| mVersion = aVersion; |
| |
| exit: |
| return err; |
| } |
| |
| /** |
| * @brief |
| * Store a data list. |
| * |
| * Given a TLV-encoded data list, this method goes through the process |
| * of parsing that list and calling the concrete methods provided by |
| * ProfileDatabase subclass implementers to put the referenced data |
| * where it belongs. |
| * |
| * @param [in] aDataList A reference to a ReferencedTLVData object |
| * containing the data of interest in |
| * TLV-encoded form. |
| * |
| * @return #WEAVE_NO_ERROR On success. Otherwise return a |
| * #WEAVE_ERROR indicating a failure to store the data of interest. |
| */ |
| |
| WEAVE_ERROR ProfileDatabase::Store(ReferencedTLVData &aDataList) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| TLVReader dataRdr; |
| uint64_t version; |
| TLVReader pathRdr; |
| |
| OpenDataList(aDataList, dataRdr); |
| |
| err = dataRdr.Next(); |
| while (err == WEAVE_NO_ERROR) |
| { |
| err = OpenDataListElement(dataRdr, pathRdr, version); |
| SuccessOrExit(err); |
| |
| err = StoreInternal(pathRdr, version, dataRdr); |
| SuccessOrExit(err); |
| |
| err = CloseDataListElement(dataRdr); |
| SuccessOrExit(err); |
| |
| err = dataRdr.Next(); |
| } |
| |
| err = CloseList(dataRdr); |
| |
| exit: |
| return err; |
| } |
| |
| /** |
| * @brief |
| * Retrieve a data list given a path list. |
| * |
| * Given a list of paths, retrieve a data list containing data list |
| * elements for each path in the path list the data that is the terminal of that |
| * path. |
| * |
| * @param [in] aPathList A reference to a ReferencedTLVData |
| * object containing a TLV-encoded |
| * list of paths representing data to |
| * retrieve. This parameter is kept constant |
| * throughout the execution of this function. |
| * |
| * @param [out] aDataList A reference to a ReferencedTLVData |
| * object in which to write the |
| * retrieved results. Data length is adjusted only |
| * after successful execution of this function. |
| * |
| * @return #WEAVE_NO_ERROR On success. Otherwise return a |
| * #WEAVE_ERROR indicating a failure to retrieve the data list of |
| * interest. |
| */ |
| |
| WEAVE_ERROR ProfileDatabase::Retrieve(ReferencedTLVData &aPathList, ReferencedTLVData &aDataList) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| TLVWriter writer; |
| writer.Init(aDataList.theData, aDataList.theMaxLength); |
| |
| err = Retrieve(aPathList, writer); |
| SuccessOrExit(err); |
| |
| aDataList.theLength = writer.GetLengthWritten(); |
| |
| exit: |
| return err; |
| } |
| |
| /** |
| * @brief |
| * Write out a data list given a path list. |
| * |
| * Given a list of paths and a TLV writer, write out a data list |
| * containing data list elements for each path in the path list and the data that is the |
| * terminal of that path. |
| * |
| * @param [in] aPathList A reference to a ReferencedTLVData |
| * object containing a list of TLV |
| * paths representing data to |
| * retrieve. This parameter is kept constant |
| * throughout the execution of this function. |
| * |
| * @param [in] aWriter A reference to the TLV writer to |
| * use in writing out the retrieved |
| * path list. Internal state for the writer could be |
| * unrecoverable in case of an error. |
| * |
| * |
| * @return #WEAVE_NO_ERROR On success. Otherwise return a |
| * #WEAVE_ERROR indicating a failure to retrieve the data or write |
| * out the data list of interest. |
| */ |
| |
| WEAVE_ERROR ProfileDatabase::Retrieve(ReferencedTLVData &aPathList, TLVWriter &aWriter) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| TLVReader rdr; |
| ProfileData *profileData; |
| |
| // aPathList is copied at here into rdr, and then left alone, so |
| // it stays constant no matter what will happen |
| err = OpenPathList(aPathList, rdr); |
| SuccessOrExit(err); |
| |
| // There is no useful guarantee for the state of aWriter shall anything go wrong |
| err = StartDataList(aWriter); |
| SuccessOrExit(err); |
| |
| err = rdr.Next(); |
| while (err == WEAVE_NO_ERROR) |
| { |
| TLVType containerTypePathList; |
| |
| err = rdr.EnterContainer(containerTypePathList); |
| SuccessOrExit(err); |
| |
| err = rdr.Next(); |
| SuccessOrExit(err); |
| |
| err = LookupDataFromProfileDescriptor(rdr, &profileData); |
| SuccessOrExit(err); |
| |
| /* |
| * OK. now we're poised for victory. there's a reader to read |
| * the path. there's a writer to write out the data. as the |
| * Nike ads used to say, "Just Do It". |
| */ |
| |
| err = StartDataListElement(aWriter); |
| SuccessOrExit(err); |
| |
| err = profileData->Retrieve(rdr, aWriter); |
| SuccessOrExit(err); |
| |
| err = EndDataListElement(aWriter); |
| SuccessOrExit(err); |
| |
| /* |
| * now we actually close the path we're working on and move on |
| * to the next path list element, if any. |
| */ |
| |
| err = rdr.ExitContainer(containerTypePathList); |
| SuccessOrExit(err); |
| |
| err = rdr.Next(); |
| } |
| |
| if (err == WEAVE_END_OF_TLV) |
| err = WEAVE_NO_ERROR; |
| |
| EndList(aWriter); |
| |
| // Note this isn't really necessary, as rdr should already be depleted by now. |
| // We reach this line when we get WEAVE_END_OF_TLV from rdr.Next(). |
| CloseList(rdr); |
| |
| exit: |
| |
| return err; |
| } |
| |
| /** |
| * @brief |
| * Find a ProfileData object in the database. |
| * |
| * This utility method is used to find ProfileData objects in a |
| * particular ProfileDatabase. It depends largely on lookup methods |
| * provided by the implementer of the concrete ProfileDatabase |
| * subclass. |
| * |
| * @note |
| * This is the top-level method for finding the right profile |
| * data structure to match an existing path. The path reader |
| * should be pointing at the profile descriptor, the one immediately |
| * after entering the path container. |
| * |
| * @param [in] aPathReader A reference to a TLV reader |
| * positioned at a WDM path - i.e. a |
| * TLV path that has, as its first |
| * element, a profile description. |
| * |
| * @param [out] aProfileData A pointer, intended to return a |
| * pointer to the ProfileData object |
| * of interest. |
| * |
| * @return #WEAVE_NO_ERROR on success, otherwise return a |
| * #WEAVE_ERROR indicating a failure to look up a matching |
| * ProfileData object. |
| */ |
| |
| WEAVE_ERROR ProfileDatabase::LookupDataFromProfileDescriptor(nl::Weave::TLV::TLVReader &aDescReader, ProfileData **aProfileData) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| TLVType profileContainer; |
| |
| uint32_t profileId; |
| |
| TLVReader instanceIdRdr; |
| |
| /* |
| * the first element of a path under WDM should be a structure |
| * with 2 elements, one of which (the instance) is optional. |
| */ |
| |
| err = ValidateTLVType(kTLVType_Structure, aDescReader); |
| SuccessOrExit(err); |
| |
| err = ValidateWDMTag(kTag_WDMPathProfile, aDescReader); |
| SuccessOrExit(err); |
| |
| /* |
| * parse the path profile and get the profile data object |
| */ |
| |
| err = aDescReader.EnterContainer(profileContainer); |
| SuccessOrExit(err); |
| |
| /* |
| * the first element here should be a profile ID |
| */ |
| |
| err = aDescReader.Next(); |
| SuccessOrExit(err); |
| |
| err = ValidateTLVType(kTLVType_UnsignedInteger, aDescReader); |
| SuccessOrExit(err); |
| |
| err = ValidateWDMTag(kTag_WDMPathProfileId, aDescReader); |
| SuccessOrExit(err); |
| |
| err = aDescReader.Get(profileId); |
| SuccessOrExit(err); |
| |
| /* |
| * and the second may be an instance. if there's one there, then |
| * point the NHL lookup method at a reader for it. |
| */ |
| |
| err = aDescReader.Next(); |
| |
| if (err == WEAVE_END_OF_TLV) |
| { |
| err = LookupProfileData(profileId, NULL, aProfileData); |
| } |
| |
| else if (err == WEAVE_NO_ERROR) |
| { |
| instanceIdRdr = aDescReader; |
| |
| err = LookupProfileData(profileId, &instanceIdRdr, aProfileData); |
| } |
| |
| SuccessOrExit(err); |
| |
| /* |
| * now get out. skip over the instance, if any, with the path |
| * reader and force an exit from the container with profile info |
| * in it. |
| */ |
| |
| aDescReader.ExitContainer(profileContainer); |
| |
| exit: |
| return err; |
| } |
| |
| /** |
| * @brief |
| * Find a ProfileData object in the database. |
| * |
| * This utility method is used to find ProfileData objects in a |
| * particular ProfileDatabase. It depends largely on lookup methods |
| * provided by the implementer of the concrete ProfileDatabase |
| * subclass. |
| * |
| * @note |
| * This is the top-level method for finding the right profile |
| * data structure to match an existing path. The path reader |
| * should be pointing at the whole path container. |
| * |
| * @param [in] aPathReader A reference to a TLV reader |
| * positioned at a WDM path - i.e. a |
| * TLV path that has, as its first |
| * element, a profile description. |
| * |
| * @param [out] aProfileData A pointer, intended to return a |
| * pointer to the ProfileData object |
| * of interest. |
| * |
| * @return #WEAVE_NO_ERROR on success, otherwise return a |
| * #WEAVE_ERROR indicating a failure to look up a matching |
| * ProfileData object. |
| */ |
| |
| WEAVE_ERROR ProfileDatabase::LookupProfileData(TLVReader &aPathReader, ProfileData **aProfileData) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| TLVType pathContainer; |
| |
| err = aPathReader.EnterContainer(pathContainer); |
| SuccessOrExit(err); |
| |
| /* |
| * the first element of a path under WDM should be a structure |
| * with 2 elements, one of which (the instance) is optional. |
| */ |
| |
| err = aPathReader.Next(); |
| SuccessOrExit(err); |
| |
| err = LookupDataFromProfileDescriptor(aPathReader, aProfileData); |
| SuccessOrExit(err); |
| |
| /* |
| * we explicitly DON'T exit the path container here because it may |
| * contain additional elements. |
| */ |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR ProfileDatabase::StoreInternal(TLVReader &aPathReader, uint64_t aVersion, TLVReader &aDataReader) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| ProfileData *profileData; |
| TLVType containerTypeDataElem; |
| |
| err = aPathReader.EnterContainer(containerTypeDataElem); |
| SuccessOrExit(err); |
| |
| err = aPathReader.Next(); |
| SuccessOrExit(err); |
| |
| err = LookupDataFromProfileDescriptor(aPathReader, &profileData); |
| SuccessOrExit(err); |
| |
| err = profileData->Store(aPathReader, aVersion, aDataReader); |
| SuccessOrExit(err); |
| |
| err = aPathReader.ExitContainer(containerTypeDataElem); |
| |
| exit: |
| return err; |
| } |
| |
| }; // WeaveMakeManagedNamespaceIdentifier(DataManagement, kWeaveManagedNamespaceDesignation_Legacy) |
| }; // Profiles |
| }; // Weave |
| }; // nl |