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 16834 : CHIP_ERROR AttributePathIB::Parser::PrettyPrint() const
34 : {
35 16834 : CHIP_ERROR err = CHIP_NO_ERROR;
36 16834 : TLV::TLVReader reader;
37 :
38 16834 : PRETTY_PRINT("AttributePathIB =");
39 16834 : PRETTY_PRINT("{");
40 :
41 : // make a copy of the Path reader
42 16834 : reader.Init(mReader);
43 :
44 74363 : while (CHIP_NO_ERROR == (err = reader.Next()))
45 : {
46 57529 : if (!TLV::IsContextTag(reader.GetTag()))
47 : {
48 0 : continue;
49 : }
50 57529 : uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag());
51 57529 : 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 28 : case to_underlying(Tag::kNode):
63 28 : VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
64 :
65 : #if CHIP_DETAIL_LOGGING
66 : {
67 : NodeId node;
68 28 : reader.Get(node);
69 28 : PRETTY_PRINT("\tNode = 0x" ChipLogFormatX64 ",", ChipLogValueX64(node));
70 : }
71 : #endif // CHIP_DETAIL_LOGGING
72 28 : break;
73 16420 : case to_underlying(Tag::kEndpoint):
74 16420 : VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
75 : #if CHIP_DETAIL_LOGGING
76 : {
77 : EndpointId endpoint;
78 16420 : reader.Get(endpoint);
79 16420 : PRETTY_PRINT("\tEndpoint = 0x%x,", endpoint);
80 : }
81 : #endif // CHIP_DETAIL_LOGGING
82 16420 : break;
83 16357 : case to_underlying(Tag::kCluster):
84 16357 : VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
85 :
86 : #if CHIP_DETAIL_LOGGING
87 : {
88 : ClusterId cluster;
89 16357 : ReturnErrorOnFailure(reader.Get(cluster));
90 16357 : PRETTY_PRINT("\tCluster = 0x%" PRIx32 ",", cluster);
91 : }
92 : #endif // CHIP_DETAIL_LOGGING
93 16357 : break;
94 16140 : case to_underlying(Tag::kAttribute):
95 16140 : VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
96 : #if CHIP_DETAIL_LOGGING
97 : {
98 : AttributeId attribute;
99 16140 : ReturnErrorOnFailure(reader.Get(attribute));
100 16140 : PRETTY_PRINT("\tAttribute = " ChipLogFormatMEI ",", ChipLogValueMEI(attribute));
101 : }
102 : #endif // CHIP_DETAIL_LOGGING
103 16140 : break;
104 8570 : case to_underlying(Tag::kListIndex):
105 8570 : 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 8570 : 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 8542 : PRETTY_PRINT("\tListIndex = Null,");
118 : }
119 : #endif // CHIP_DETAIL_LOGGING
120 8570 : break;
121 0 : default:
122 0 : PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum);
123 0 : break;
124 : }
125 : }
126 :
127 16834 : PRETTY_PRINT("}");
128 16834 : PRETTY_PRINT("\t");
129 : // if we have exhausted this container
130 16834 : if (CHIP_END_OF_TLV == err)
131 : {
132 16834 : err = CHIP_NO_ERROR;
133 : }
134 16834 : ReturnErrorOnFailure(err);
135 16834 : 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 16795 : CHIP_ERROR AttributePathIB::Parser::GetEndpoint(EndpointId * const apEndpoint) const
150 : {
151 16795 : return GetUnsignedInteger(to_underlying(Tag::kEndpoint), apEndpoint);
152 : }
153 :
154 16797 : CHIP_ERROR AttributePathIB::Parser::GetCluster(ClusterId * const apCluster) const
155 : {
156 16797 : return GetUnsignedInteger(to_underlying(Tag::kCluster), apCluster);
157 : }
158 :
159 16797 : CHIP_ERROR AttributePathIB::Parser::GetAttribute(AttributeId * const apAttribute) const
160 : {
161 16797 : return GetUnsignedInteger(to_underlying(Tag::kAttribute), apAttribute);
162 : }
163 :
164 1907 : CHIP_ERROR AttributePathIB::Parser::GetListIndex(ListIndex * const apListIndex) const
165 : {
166 1907 : return GetUnsignedInteger(to_underlying(Tag::kListIndex), apListIndex);
167 : }
168 :
169 14888 : CHIP_ERROR AttributePathIB::Parser::GetListIndex(DataModel::Nullable<ListIndex> * const apListIndex) const
170 : {
171 14888 : return GetNullableUnsignedInteger(to_underlying(Tag::kListIndex), apListIndex);
172 : }
173 :
174 14890 : CHIP_ERROR AttributePathIB::Parser::GetGroupAttributePath(ConcreteDataAttributePath & aAttributePath,
175 : ValidateIdRanges aValidateRanges) const
176 : {
177 14890 : ReturnErrorOnFailure(GetCluster(&aAttributePath.mClusterId));
178 14890 : ReturnErrorOnFailure(GetAttribute(&aAttributePath.mAttributeId));
179 :
180 14888 : if (aValidateRanges == ValidateIdRanges::kYes)
181 : {
182 10402 : VerifyOrReturnError(IsValidClusterId(aAttributePath.mClusterId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
183 10402 : VerifyOrReturnError(IsValidAttributeId(aAttributePath.mAttributeId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
184 : }
185 :
186 14888 : CHIP_ERROR err = CHIP_NO_ERROR;
187 14888 : DataModel::Nullable<ListIndex> listIndex;
188 14888 : err = GetListIndex(&(listIndex));
189 14888 : if (err == CHIP_NO_ERROR)
190 : {
191 8551 : if (listIndex.IsNull())
192 : {
193 8551 : 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 6337 : 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 6337 : aAttributePath.mListOp = ConcreteDataAttributePath::ListOperation::NotList;
206 6337 : err = CHIP_NO_ERROR;
207 : }
208 14888 : return err;
209 : }
210 :
211 14890 : CHIP_ERROR AttributePathIB::Parser::GetConcreteAttributePath(ConcreteDataAttributePath & aAttributePath,
212 : ValidateIdRanges aValidateRanges) const
213 : {
214 14890 : ReturnErrorOnFailure(GetGroupAttributePath(aAttributePath, aValidateRanges));
215 :
216 : // And now read our endpoint.
217 14888 : return GetEndpoint(&aAttributePath.mEndpointId);
218 : }
219 :
220 1906 : CHIP_ERROR AttributePathIB::Parser::ParsePath(AttributePathParams & aAttribute) const
221 : {
222 1906 : CHIP_ERROR err = CHIP_NO_ERROR;
223 :
224 1906 : err = GetEndpoint(&(aAttribute.mEndpointId));
225 1906 : if (err == CHIP_NO_ERROR)
226 : {
227 1884 : VerifyOrReturnError(!aAttribute.HasWildcardEndpointId(), CHIP_IM_GLOBAL_STATUS(InvalidAction));
228 : }
229 22 : else if (err == CHIP_END_OF_TLV)
230 : {
231 22 : err = CHIP_NO_ERROR;
232 : }
233 1906 : VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
234 :
235 1906 : err = GetCluster(&aAttribute.mClusterId);
236 1906 : if (err == CHIP_NO_ERROR)
237 : {
238 1823 : VerifyOrReturnError(IsValidClusterId(aAttribute.mClusterId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
239 : }
240 83 : else if (err == CHIP_END_OF_TLV)
241 : {
242 83 : err = CHIP_NO_ERROR;
243 : }
244 1906 : VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
245 :
246 1906 : err = GetAttribute(&aAttribute.mAttributeId);
247 1906 : if (err == CHIP_NO_ERROR)
248 : {
249 1606 : VerifyOrReturnError(IsValidAttributeId(aAttribute.mAttributeId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
250 : }
251 300 : else if (err == CHIP_END_OF_TLV)
252 : {
253 300 : err = CHIP_NO_ERROR;
254 : }
255 1906 : 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 1906 : VerifyOrReturnError(!aAttribute.HasWildcardClusterId() || aAttribute.HasWildcardAttributeId() ||
260 : IsGlobalAttribute(aAttribute.mAttributeId),
261 : CHIP_IM_GLOBAL_STATUS(InvalidAction));
262 :
263 1906 : err = GetListIndex(&aAttribute.mListIndex);
264 1906 : if (err == CHIP_NO_ERROR)
265 : {
266 16 : VerifyOrReturnError(!aAttribute.HasWildcardAttributeId() && !aAttribute.HasWildcardListIndex(),
267 : CHIP_IM_GLOBAL_STATUS(InvalidAction));
268 : }
269 1890 : else if (err == CHIP_END_OF_TLV)
270 : {
271 1890 : err = CHIP_NO_ERROR;
272 : }
273 1906 : VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
274 1906 : 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 43 : AttributePathIB::Builder & AttributePathIB::Builder::Node(const NodeId aNode)
288 : {
289 : // skip if error has already been set
290 43 : if (mError == CHIP_NO_ERROR)
291 : {
292 43 : mError = mpWriter->Put(TLV::ContextTag(Tag::kNode), aNode);
293 : }
294 43 : return *this;
295 : }
296 :
297 19618 : AttributePathIB::Builder & AttributePathIB::Builder::Endpoint(const EndpointId aEndpoint)
298 : {
299 : // skip if error has already been set
300 19618 : if (mError == CHIP_NO_ERROR)
301 : {
302 19552 : mError = mpWriter->Put(TLV::ContextTag(Tag::kEndpoint), aEndpoint);
303 : }
304 19618 : return *this;
305 : }
306 :
307 19555 : AttributePathIB::Builder & AttributePathIB::Builder::Cluster(const ClusterId aCluster)
308 : {
309 : // skip if error has already been set
310 19555 : if (mError == CHIP_NO_ERROR)
311 : {
312 19369 : mError = mpWriter->Put(TLV::ContextTag(Tag::kCluster), aCluster);
313 : }
314 19555 : return *this;
315 : }
316 :
317 19342 : AttributePathIB::Builder & AttributePathIB::Builder::Attribute(const AttributeId aAttribute)
318 : {
319 : // skip if error has already been set
320 19342 : if (mError == CHIP_NO_ERROR)
321 : {
322 19010 : mError = mpWriter->Put(TLV::ContextTag(Tag::kAttribute), aAttribute);
323 : }
324 19342 : return *this;
325 : }
326 :
327 11344 : AttributePathIB::Builder & AttributePathIB::Builder::ListIndex(const DataModel::Nullable<chip::ListIndex> & aListIndex)
328 : {
329 : // skip if error has already been set
330 11344 : if (mError == CHIP_NO_ERROR)
331 : {
332 10997 : mError = DataModel::Encode(*mpWriter, TLV::ContextTag(Tag::kListIndex), aListIndex);
333 : }
334 11344 : return *this;
335 : }
336 :
337 35 : AttributePathIB::Builder & AttributePathIB::Builder::ListIndex(const chip::ListIndex aListIndex)
338 : {
339 : // skip if error has already been set
340 35 : if (mError == CHIP_NO_ERROR)
341 : {
342 35 : mError = mpWriter->Put(TLV::ContextTag(Tag::kListIndex), aListIndex);
343 : }
344 35 : return *this;
345 : }
346 :
347 20038 : CHIP_ERROR AttributePathIB::Builder::EndOfAttributePathIB()
348 : {
349 20038 : EndOfContainer();
350 20038 : return GetError();
351 : }
352 :
353 1995 : CHIP_ERROR AttributePathIB::Builder::Encode(const AttributePathParams & aAttributePathParams)
354 : {
355 1995 : if (!(aAttributePathParams.HasWildcardEndpointId()))
356 : {
357 1575 : Endpoint(aAttributePathParams.mEndpointId);
358 : }
359 :
360 1995 : if (!(aAttributePathParams.HasWildcardClusterId()))
361 : {
362 1512 : Cluster(aAttributePathParams.mClusterId);
363 : }
364 :
365 1995 : if (!(aAttributePathParams.HasWildcardAttributeId()))
366 : {
367 1303 : Attribute(aAttributePathParams.mAttributeId);
368 : }
369 :
370 1995 : if (!(aAttributePathParams.HasWildcardListIndex()))
371 : {
372 14 : ListIndex(aAttributePathParams.mListIndex);
373 : }
374 :
375 1995 : return EndOfAttributePathIB();
376 : }
377 :
378 5214 : CHIP_ERROR AttributePathIB::Builder::Encode(const ConcreteDataAttributePath & aAttributePath)
379 : {
380 5214 : Endpoint(aAttributePath.mEndpointId);
381 5214 : Cluster(aAttributePath.mClusterId);
382 5214 : Attribute(aAttributePath.mAttributeId);
383 :
384 5214 : if (!aAttributePath.IsListOperation() || aAttributePath.mListOp == ConcreteDataAttributePath::ListOperation::ReplaceAll)
385 : {
386 : /* noop */
387 : }
388 4126 : else if (aAttributePath.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem)
389 : {
390 4126 : 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 5214 : return EndOfAttributePathIB();
399 : }
400 :
401 : } // namespace app
402 : } // namespace chip
|