LCOV - code coverage report
Current view: top level - app/MessageDef - AttributePathIB.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 157 163 96.3 %
Date: 2024-02-15 08:20:41 Functions: 21 21 100.0 %

          Line data    Source code
       1             : /**
       2             :  *
       3             :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4             :  *    Copyright (c) 2018 Google LLC.
       5             :  *    Copyright (c) 2016-2017 Nest Labs, Inc.
       6             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7             :  *    you may not use this file except in compliance with the License.
       8             :  *    You may obtain a copy of the License at
       9             :  *
      10             :  *        http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  *    Unless required by applicable law or agreed to in writing, software
      13             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  *    See the License for the specific language governing permissions and
      16             :  *    limitations under the License.
      17             :  */
      18             : 
      19             : #include "AttributePathIB.h"
      20             : #include "MessageDefHelper.h"
      21             : 
      22             : #include <inttypes.h>
      23             : #include <stdarg.h>
      24             : #include <stdio.h>
      25             : 
      26             : #include <app/AppConfig.h>
      27             : #include <app/data-model/Encode.h>
      28             : #include <app/data-model/Nullable.h>
      29             : 
      30             : namespace chip {
      31             : namespace app {
      32             : #if CHIP_CONFIG_IM_PRETTY_PRINT
      33       10537 : CHIP_ERROR AttributePathIB::Parser::PrettyPrint() const
      34             : {
      35       10537 :     CHIP_ERROR err = CHIP_NO_ERROR;
      36             :     TLV::TLVReader reader;
      37             : 
      38       10537 :     PRETTY_PRINT("AttributePathIB =");
      39       10537 :     PRETTY_PRINT("{");
      40             : 
      41             :     // make a copy of the Path reader
      42       10537 :     reader.Init(mReader);
      43             : 
      44       45173 :     while (CHIP_NO_ERROR == (err = reader.Next()))
      45             :     {
      46       34636 :         if (!TLV::IsContextTag(reader.GetTag()))
      47             :         {
      48           0 :             continue;
      49             :         }
      50       34636 :         uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag());
      51       34636 :         switch (tagNum)
      52             :         {
      53          14 :         case to_underlying(Tag::kEnableTagCompression):
      54             : #if CHIP_DETAIL_LOGGING
      55             :         {
      56             :             bool enableTagCompression;
      57          14 :             ReturnErrorOnFailure(reader.Get(enableTagCompression));
      58          14 :             PRETTY_PRINT("\tenableTagCompression = %s, ", enableTagCompression ? "true" : "false");
      59             :         }
      60             : #endif // CHIP_DETAIL_LOGGING
      61          14 :         break;
      62          27 :         case to_underlying(Tag::kNode):
      63          27 :             VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
      64             : 
      65             : #if CHIP_DETAIL_LOGGING
      66             :             {
      67             :                 NodeId node;
      68          27 :                 reader.Get(node);
      69          27 :                 PRETTY_PRINT("\tNode = 0x" ChipLogFormatX64 ",", ChipLogValueX64(node));
      70             :             }
      71             : #endif // CHIP_DETAIL_LOGGING
      72          27 :             break;
      73       10120 :         case to_underlying(Tag::kEndpoint):
      74       10120 :             VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
      75             : #if CHIP_DETAIL_LOGGING
      76             :             {
      77             :                 EndpointId endpoint;
      78       10120 :                 reader.Get(endpoint);
      79       10120 :                 PRETTY_PRINT("\tEndpoint = 0x%x,", endpoint);
      80             :             }
      81             : #endif // CHIP_DETAIL_LOGGING
      82       10120 :             break;
      83       10129 :         case to_underlying(Tag::kCluster):
      84       10129 :             VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
      85             : 
      86             : #if CHIP_DETAIL_LOGGING
      87             :             {
      88             :                 ClusterId cluster;
      89       10129 :                 ReturnErrorOnFailure(reader.Get(cluster));
      90       10129 :                 PRETTY_PRINT("\tCluster = 0x%" PRIx32 ",", cluster);
      91             :             }
      92             : #endif // CHIP_DETAIL_LOGGING
      93       10129 :             break;
      94        9912 :         case to_underlying(Tag::kAttribute):
      95        9912 :             VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
      96             : #if CHIP_DETAIL_LOGGING
      97             :             {
      98             :                 AttributeId attribute;
      99        9912 :                 ReturnErrorOnFailure(reader.Get(attribute));
     100        9912 :                 PRETTY_PRINT("\tAttribute = " ChipLogFormatMEI ",", ChipLogValueMEI(attribute));
     101             :             }
     102             : #endif // CHIP_DETAIL_LOGGING
     103        9912 :             break;
     104        4434 :         case to_underlying(Tag::kListIndex):
     105        4434 :             VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType() || TLV::kTLVType_Null == reader.GetType(),
     106             :                                 CHIP_ERROR_WRONG_TLV_TYPE);
     107             : #if CHIP_DETAIL_LOGGING
     108             :             // We have checked the element is either uint or null
     109        4434 :             if (TLV::kTLVType_UnsignedInteger == reader.GetType())
     110             :             {
     111             :                 uint16_t listIndex;
     112          28 :                 ReturnErrorOnFailure(reader.Get(listIndex));
     113          28 :                 PRETTY_PRINT("\tListIndex = 0x%x,", listIndex);
     114             :             }
     115             :             else
     116             :             {
     117        4406 :                 PRETTY_PRINT("\tListIndex = Null,");
     118             :             }
     119             : #endif // CHIP_DETAIL_LOGGING
     120        4434 :             break;
     121           0 :         default:
     122           0 :             PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum);
     123           0 :             break;
     124             :         }
     125             :     }
     126             : 
     127       10537 :     PRETTY_PRINT("}");
     128       10537 :     PRETTY_PRINT("\t");
     129             :     // if we have exhausted this container
     130       10537 :     if (CHIP_END_OF_TLV == err)
     131             :     {
     132       10537 :         err = CHIP_NO_ERROR;
     133             :     }
     134       10537 :     ReturnErrorOnFailure(err);
     135       10537 :     return reader.ExitContainer(mOuterContainerType);
     136             : }
     137             : #endif // CHIP_CONFIG_IM_PRETTY_PRINT
     138             : 
     139           1 : CHIP_ERROR AttributePathIB::Parser::GetEnableTagCompression(bool * const apEnableTagCompression) const
     140             : {
     141           1 :     return GetSimpleValue(to_underlying(Tag::kEnableTagCompression), TLV::kTLVType_Boolean, apEnableTagCompression);
     142             : }
     143             : 
     144           1 : CHIP_ERROR AttributePathIB::Parser::GetNode(NodeId * const apNode) const
     145             : {
     146           1 :     return GetUnsignedInteger(to_underlying(Tag::kNode), apNode);
     147             : }
     148             : 
     149       10368 : CHIP_ERROR AttributePathIB::Parser::GetEndpoint(EndpointId * const apEndpoint) const
     150             : {
     151       10368 :     return GetUnsignedInteger(to_underlying(Tag::kEndpoint), apEndpoint);
     152             : }
     153             : 
     154       10370 : CHIP_ERROR AttributePathIB::Parser::GetCluster(ClusterId * const apCluster) const
     155             : {
     156       10370 :     return GetUnsignedInteger(to_underlying(Tag::kCluster), apCluster);
     157             : }
     158             : 
     159       10370 : CHIP_ERROR AttributePathIB::Parser::GetAttribute(AttributeId * const apAttribute) const
     160             : {
     161       10370 :     return GetUnsignedInteger(to_underlying(Tag::kAttribute), apAttribute);
     162             : }
     163             : 
     164        1692 : CHIP_ERROR AttributePathIB::Parser::GetListIndex(ListIndex * const apListIndex) const
     165             : {
     166        1692 :     return GetUnsignedInteger(to_underlying(Tag::kListIndex), apListIndex);
     167             : }
     168             : 
     169        8676 : CHIP_ERROR AttributePathIB::Parser::GetListIndex(DataModel::Nullable<ListIndex> * const apListIndex) const
     170             : {
     171        8676 :     return GetNullableUnsignedInteger(to_underlying(Tag::kListIndex), apListIndex);
     172             : }
     173             : 
     174        8678 : CHIP_ERROR AttributePathIB::Parser::GetGroupAttributePath(ConcreteDataAttributePath & aAttributePath,
     175             :                                                           ValidateIdRanges aValidateRanges) const
     176             : {
     177        8678 :     ReturnErrorOnFailure(GetCluster(&aAttributePath.mClusterId));
     178        8678 :     ReturnErrorOnFailure(GetAttribute(&aAttributePath.mAttributeId));
     179             : 
     180        8676 :     if (aValidateRanges == ValidateIdRanges::kYes)
     181             :     {
     182        4969 :         VerifyOrReturnError(IsValidClusterId(aAttributePath.mClusterId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
     183        4969 :         VerifyOrReturnError(IsValidAttributeId(aAttributePath.mAttributeId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
     184             :     }
     185             : 
     186        8676 :     CHIP_ERROR err = CHIP_NO_ERROR;
     187        8676 :     DataModel::Nullable<ListIndex> listIndex;
     188        8676 :     err = GetListIndex(&(listIndex));
     189        8676 :     if (err == CHIP_NO_ERROR)
     190             :     {
     191        4404 :         if (listIndex.IsNull())
     192             :         {
     193        4404 :             aAttributePath.mListOp = ConcreteDataAttributePath::ListOperation::AppendItem;
     194             :         }
     195             :         else
     196             :         {
     197             :             // TODO: Add ListOperation::ReplaceItem support. (Attribute path with valid list index)
     198           0 :             err = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB;
     199             :         }
     200             :     }
     201        4272 :     else if (CHIP_END_OF_TLV == err)
     202             :     {
     203             :         // We do not have the context for the actual data type here. We always set the list operation to not list and the users
     204             :         // should interpret it as ReplaceAll when the attribute type is a list.
     205        4272 :         aAttributePath.mListOp = ConcreteDataAttributePath::ListOperation::NotList;
     206        4272 :         err                    = CHIP_NO_ERROR;
     207             :     }
     208        8676 :     return err;
     209        8676 : }
     210             : 
     211        8678 : CHIP_ERROR AttributePathIB::Parser::GetConcreteAttributePath(ConcreteDataAttributePath & aAttributePath,
     212             :                                                              ValidateIdRanges aValidateRanges) const
     213             : {
     214        8678 :     ReturnErrorOnFailure(GetGroupAttributePath(aAttributePath, aValidateRanges));
     215             : 
     216             :     // And now read our endpoint.
     217        8676 :     return GetEndpoint(&aAttributePath.mEndpointId);
     218             : }
     219             : 
     220        1691 : CHIP_ERROR AttributePathIB::Parser::ParsePath(AttributePathParams & aAttribute) const
     221             : {
     222        1691 :     CHIP_ERROR err = CHIP_NO_ERROR;
     223             : 
     224        1691 :     err = GetEndpoint(&(aAttribute.mEndpointId));
     225        1691 :     if (err == CHIP_NO_ERROR)
     226             :     {
     227        1664 :         VerifyOrReturnError(!aAttribute.HasWildcardEndpointId(), CHIP_IM_GLOBAL_STATUS(InvalidAction));
     228             :     }
     229          27 :     else if (err == CHIP_END_OF_TLV)
     230             :     {
     231          27 :         err = CHIP_NO_ERROR;
     232             :     }
     233        1691 :     VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
     234             : 
     235        1691 :     err = GetCluster(&aAttribute.mClusterId);
     236        1691 :     if (err == CHIP_NO_ERROR)
     237             :     {
     238        1677 :         VerifyOrReturnError(IsValidClusterId(aAttribute.mClusterId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
     239             :     }
     240          14 :     else if (err == CHIP_END_OF_TLV)
     241             :     {
     242          14 :         err = CHIP_NO_ERROR;
     243             :     }
     244        1691 :     VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
     245             : 
     246        1691 :     err = GetAttribute(&aAttribute.mAttributeId);
     247        1691 :     if (err == CHIP_NO_ERROR)
     248             :     {
     249        1460 :         VerifyOrReturnError(IsValidAttributeId(aAttribute.mAttributeId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
     250             :     }
     251         231 :     else if (err == CHIP_END_OF_TLV)
     252             :     {
     253         231 :         err = CHIP_NO_ERROR;
     254             :     }
     255        1691 :     VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
     256             : 
     257             :     // A wildcard cluster requires that the attribute path either be
     258             :     // wildcard or a global attribute.
     259        1691 :     VerifyOrReturnError(!aAttribute.HasWildcardClusterId() || aAttribute.HasWildcardAttributeId() ||
     260             :                             IsGlobalAttribute(aAttribute.mAttributeId),
     261             :                         CHIP_IM_GLOBAL_STATUS(InvalidAction));
     262             : 
     263        1691 :     err = GetListIndex(&aAttribute.mListIndex);
     264        1691 :     if (err == CHIP_NO_ERROR)
     265             :     {
     266          14 :         VerifyOrReturnError(!aAttribute.HasWildcardAttributeId() && !aAttribute.HasWildcardListIndex(),
     267             :                             CHIP_IM_GLOBAL_STATUS(InvalidAction));
     268             :     }
     269        1677 :     else if (err == CHIP_END_OF_TLV)
     270             :     {
     271        1677 :         err = CHIP_NO_ERROR;
     272             :     }
     273        1691 :     VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
     274        1691 :     return CHIP_NO_ERROR;
     275             : }
     276             : 
     277          15 : AttributePathIB::Builder & AttributePathIB::Builder::EnableTagCompression(const bool aEnableTagCompression)
     278             : {
     279             :     // skip if error has already been set
     280          15 :     if (mError == CHIP_NO_ERROR)
     281             :     {
     282          15 :         mError = mpWriter->PutBoolean(TLV::ContextTag(Tag::kEnableTagCompression), aEnableTagCompression);
     283             :     }
     284          15 :     return *this;
     285             : }
     286             : 
     287          40 : AttributePathIB::Builder & AttributePathIB::Builder::Node(const NodeId aNode)
     288             : {
     289             :     // skip if error has already been set
     290          40 :     if (mError == CHIP_NO_ERROR)
     291             :     {
     292          40 :         mError = mpWriter->Put(TLV::ContextTag(Tag::kNode), aNode);
     293             :     }
     294          40 :     return *this;
     295             : }
     296             : 
     297       11802 : AttributePathIB::Builder & AttributePathIB::Builder::Endpoint(const EndpointId aEndpoint)
     298             : {
     299             :     // skip if error has already been set
     300       11802 :     if (mError == CHIP_NO_ERROR)
     301             :     {
     302       11784 :         mError = mpWriter->Put(TLV::ContextTag(Tag::kEndpoint), aEndpoint);
     303             :     }
     304       11802 :     return *this;
     305             : }
     306             : 
     307       11811 : AttributePathIB::Builder & AttributePathIB::Builder::Cluster(const ClusterId aCluster)
     308             : {
     309             :     // skip if error has already been set
     310       11811 :     if (mError == CHIP_NO_ERROR)
     311             :     {
     312       11748 :         mError = mpWriter->Put(TLV::ContextTag(Tag::kCluster), aCluster);
     313             :     }
     314       11811 :     return *this;
     315             : }
     316             : 
     317       11598 : AttributePathIB::Builder & AttributePathIB::Builder::Attribute(const AttributeId aAttribute)
     318             : {
     319             :     // skip if error has already been set
     320       11598 :     if (mError == CHIP_NO_ERROR)
     321             :     {
     322       11444 :         mError = mpWriter->Put(TLV::ContextTag(Tag::kAttribute), aAttribute);
     323             :     }
     324       11598 :     return *this;
     325             : }
     326             : 
     327        5849 : AttributePathIB::Builder & AttributePathIB::Builder::ListIndex(const DataModel::Nullable<chip::ListIndex> & aListIndex)
     328             : {
     329             :     // skip if error has already been set
     330        5849 :     if (mError == CHIP_NO_ERROR)
     331             :     {
     332        5694 :         mError = DataModel::Encode(*mpWriter, TLV::ContextTag(Tag::kListIndex), aListIndex);
     333             :     }
     334        5849 :     return *this;
     335             : }
     336             : 
     337          33 : AttributePathIB::Builder & AttributePathIB::Builder::ListIndex(const chip::ListIndex aListIndex)
     338             : {
     339             :     // skip if error has already been set
     340          33 :     if (mError == CHIP_NO_ERROR)
     341             :     {
     342          33 :         mError = mpWriter->Put(TLV::ContextTag(Tag::kListIndex), aListIndex);
     343             :     }
     344          33 :     return *this;
     345             : }
     346             : 
     347       12225 : CHIP_ERROR AttributePathIB::Builder::EndOfAttributePathIB()
     348             : {
     349       12225 :     EndOfContainer();
     350       12225 :     return GetError();
     351             : }
     352             : 
     353        1854 : CHIP_ERROR AttributePathIB::Builder::Encode(const AttributePathParams & aAttributePathParams)
     354             : {
     355        1854 :     if (!(aAttributePathParams.HasWildcardEndpointId()))
     356             :     {
     357        1431 :         Endpoint(aAttributePathParams.mEndpointId);
     358             :     }
     359             : 
     360        1854 :     if (!(aAttributePathParams.HasWildcardClusterId()))
     361             :     {
     362        1440 :         Cluster(aAttributePathParams.mClusterId);
     363             :     }
     364             : 
     365        1854 :     if (!(aAttributePathParams.HasWildcardAttributeId()))
     366             :     {
     367        1231 :         Attribute(aAttributePathParams.mAttributeId);
     368             :     }
     369             : 
     370        1854 :     if (!(aAttributePathParams.HasWildcardListIndex()))
     371             :     {
     372          14 :         ListIndex(aAttributePathParams.mListIndex);
     373             :     }
     374             : 
     375        1854 :     return EndOfAttributePathIB();
     376             : }
     377             : 
     378        2494 : CHIP_ERROR AttributePathIB::Builder::Encode(const ConcreteDataAttributePath & aAttributePath)
     379             : {
     380        2494 :     Endpoint(aAttributePath.mEndpointId);
     381        2494 :     Cluster(aAttributePath.mClusterId);
     382        2494 :     Attribute(aAttributePath.mAttributeId);
     383             : 
     384        2494 :     if (!aAttributePath.IsListOperation() || aAttributePath.mListOp == ConcreteDataAttributePath::ListOperation::ReplaceAll)
     385             :     {
     386             :         /* noop */
     387             :     }
     388        2059 :     else if (aAttributePath.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem)
     389             :     {
     390        2059 :         ListIndex(DataModel::NullNullable);
     391             :     }
     392             :     else
     393             :     {
     394             :         // TODO: Add ListOperation::ReplaceItem support. (Attribute path with valid list index)
     395           0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     396             :     }
     397             : 
     398        2494 :     return EndOfAttributePathIB();
     399             : }
     400             : 
     401             : } // namespace app
     402             : } // namespace chip

Generated by: LCOV version 1.14