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 11252 : CHIP_ERROR AttributePathIB::Parser::PrettyPrint() const
34 : {
35 11252 : CHIP_ERROR err = CHIP_NO_ERROR;
36 11252 : TLV::TLVReader reader;
37 :
38 11252 : PRETTY_PRINT("AttributePathIB =");
39 11252 : PRETTY_PRINT("{");
40 :
41 : // make a copy of the Path reader
42 11252 : reader.Init(mReader);
43 :
44 47903 : while (CHIP_NO_ERROR == (err = reader.Next()))
45 : {
46 36651 : if (!TLV::IsContextTag(reader.GetTag()))
47 : {
48 0 : continue;
49 : }
50 36651 : uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag());
51 36651 : 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 10838 : case to_underlying(Tag::kEndpoint):
74 10838 : VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
75 : #if CHIP_DETAIL_LOGGING
76 : {
77 : EndpointId endpoint;
78 10838 : reader.Get(endpoint);
79 10838 : PRETTY_PRINT("\tEndpoint = 0x%x,", endpoint);
80 : }
81 : #endif // CHIP_DETAIL_LOGGING
82 10838 : break;
83 10775 : case to_underlying(Tag::kCluster):
84 10775 : VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
85 :
86 : #if CHIP_DETAIL_LOGGING
87 : {
88 : ClusterId cluster;
89 10775 : ReturnErrorOnFailure(reader.Get(cluster));
90 10775 : PRETTY_PRINT("\tCluster = 0x%" PRIx32 ",", cluster);
91 : }
92 : #endif // CHIP_DETAIL_LOGGING
93 10775 : break;
94 10558 : case to_underlying(Tag::kAttribute):
95 10558 : VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
96 : #if CHIP_DETAIL_LOGGING
97 : {
98 : AttributeId attribute;
99 10558 : ReturnErrorOnFailure(reader.Get(attribute));
100 10558 : PRETTY_PRINT("\tAttribute = " ChipLogFormatMEI ",", ChipLogValueMEI(attribute));
101 : }
102 : #endif // CHIP_DETAIL_LOGGING
103 10558 : break;
104 4439 : case to_underlying(Tag::kListIndex):
105 4439 : 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 4439 : 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 4411 : PRETTY_PRINT("\tListIndex = Null,");
118 : }
119 : #endif // CHIP_DETAIL_LOGGING
120 4439 : break;
121 0 : default:
122 0 : PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum);
123 0 : break;
124 : }
125 : }
126 :
127 11252 : PRETTY_PRINT("}");
128 11252 : PRETTY_PRINT("\t");
129 : // if we have exhausted this container
130 11252 : if (CHIP_END_OF_TLV == err)
131 : {
132 11252 : err = CHIP_NO_ERROR;
133 : }
134 11252 : ReturnErrorOnFailure(err);
135 11252 : 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 11140 : CHIP_ERROR AttributePathIB::Parser::GetEndpoint(EndpointId * const apEndpoint) const
150 : {
151 11140 : return GetUnsignedInteger(to_underlying(Tag::kEndpoint), apEndpoint);
152 : }
153 :
154 11142 : CHIP_ERROR AttributePathIB::Parser::GetCluster(ClusterId * const apCluster) const
155 : {
156 11142 : return GetUnsignedInteger(to_underlying(Tag::kCluster), apCluster);
157 : }
158 :
159 11142 : CHIP_ERROR AttributePathIB::Parser::GetAttribute(AttributeId * const apAttribute) const
160 : {
161 11142 : return GetUnsignedInteger(to_underlying(Tag::kAttribute), apAttribute);
162 : }
163 :
164 1763 : CHIP_ERROR AttributePathIB::Parser::GetListIndex(ListIndex * const apListIndex) const
165 : {
166 1763 : return GetUnsignedInteger(to_underlying(Tag::kListIndex), apListIndex);
167 : }
168 :
169 9377 : CHIP_ERROR AttributePathIB::Parser::GetListIndex(DataModel::Nullable<ListIndex> * const apListIndex) const
170 : {
171 9377 : return GetNullableUnsignedInteger(to_underlying(Tag::kListIndex), apListIndex);
172 : }
173 :
174 9379 : CHIP_ERROR AttributePathIB::Parser::GetGroupAttributePath(ConcreteDataAttributePath & aAttributePath,
175 : ValidateIdRanges aValidateRanges) const
176 : {
177 9379 : ReturnErrorOnFailure(GetCluster(&aAttributePath.mClusterId));
178 9379 : ReturnErrorOnFailure(GetAttribute(&aAttributePath.mAttributeId));
179 :
180 9377 : if (aValidateRanges == ValidateIdRanges::kYes)
181 : {
182 4967 : VerifyOrReturnError(IsValidClusterId(aAttributePath.mClusterId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
183 4967 : VerifyOrReturnError(IsValidAttributeId(aAttributePath.mAttributeId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
184 : }
185 :
186 9377 : CHIP_ERROR err = CHIP_NO_ERROR;
187 9377 : DataModel::Nullable<ListIndex> listIndex;
188 9377 : err = GetListIndex(&(listIndex));
189 9377 : if (err == CHIP_NO_ERROR)
190 : {
191 4420 : if (listIndex.IsNull())
192 : {
193 4420 : 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 4957 : 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 4957 : aAttributePath.mListOp = ConcreteDataAttributePath::ListOperation::NotList;
206 4957 : err = CHIP_NO_ERROR;
207 : }
208 9377 : return err;
209 : }
210 :
211 9379 : CHIP_ERROR AttributePathIB::Parser::GetConcreteAttributePath(ConcreteDataAttributePath & aAttributePath,
212 : ValidateIdRanges aValidateRanges) const
213 : {
214 9379 : ReturnErrorOnFailure(GetGroupAttributePath(aAttributePath, aValidateRanges));
215 :
216 : // And now read our endpoint.
217 9377 : return GetEndpoint(&aAttributePath.mEndpointId);
218 : }
219 :
220 1762 : CHIP_ERROR AttributePathIB::Parser::ParsePath(AttributePathParams & aAttribute) const
221 : {
222 1762 : CHIP_ERROR err = CHIP_NO_ERROR;
223 :
224 1762 : err = GetEndpoint(&(aAttribute.mEndpointId));
225 1762 : if (err == CHIP_NO_ERROR)
226 : {
227 1740 : 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 1762 : VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
234 :
235 1762 : err = GetCluster(&aAttribute.mClusterId);
236 1762 : if (err == CHIP_NO_ERROR)
237 : {
238 1679 : 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 1762 : VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
245 :
246 1762 : err = GetAttribute(&aAttribute.mAttributeId);
247 1762 : if (err == CHIP_NO_ERROR)
248 : {
249 1462 : 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 1762 : 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 1762 : VerifyOrReturnError(!aAttribute.HasWildcardClusterId() || aAttribute.HasWildcardAttributeId() ||
260 : IsGlobalAttribute(aAttribute.mAttributeId),
261 : CHIP_IM_GLOBAL_STATUS(InvalidAction));
262 :
263 1762 : err = GetListIndex(&aAttribute.mListIndex);
264 1762 : if (err == CHIP_NO_ERROR)
265 : {
266 16 : VerifyOrReturnError(!aAttribute.HasWildcardAttributeId() && !aAttribute.HasWildcardListIndex(),
267 : CHIP_IM_GLOBAL_STATUS(InvalidAction));
268 : }
269 1746 : else if (err == CHIP_END_OF_TLV)
270 : {
271 1746 : err = CHIP_NO_ERROR;
272 : }
273 1762 : VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
274 1762 : 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 42 : AttributePathIB::Builder & AttributePathIB::Builder::Node(const NodeId aNode)
288 : {
289 : // skip if error has already been set
290 42 : if (mError == CHIP_NO_ERROR)
291 : {
292 42 : mError = mpWriter->Put(TLV::ContextTag(Tag::kNode), aNode);
293 : }
294 42 : return *this;
295 : }
296 :
297 12576 : AttributePathIB::Builder & AttributePathIB::Builder::Endpoint(const EndpointId aEndpoint)
298 : {
299 : // skip if error has already been set
300 12576 : if (mError == CHIP_NO_ERROR)
301 : {
302 12558 : mError = mpWriter->Put(TLV::ContextTag(Tag::kEndpoint), aEndpoint);
303 : }
304 12576 : return *this;
305 : }
306 :
307 12513 : AttributePathIB::Builder & AttributePathIB::Builder::Cluster(const ClusterId aCluster)
308 : {
309 : // skip if error has already been set
310 12513 : if (mError == CHIP_NO_ERROR)
311 : {
312 12449 : mError = mpWriter->Put(TLV::ContextTag(Tag::kCluster), aCluster);
313 : }
314 12513 : return *this;
315 : }
316 :
317 12300 : AttributePathIB::Builder & AttributePathIB::Builder::Attribute(const AttributeId aAttribute)
318 : {
319 : // skip if error has already been set
320 12300 : if (mError == CHIP_NO_ERROR)
321 : {
322 12144 : mError = mpWriter->Put(TLV::ContextTag(Tag::kAttribute), aAttribute);
323 : }
324 12300 : return *this;
325 : }
326 :
327 5866 : AttributePathIB::Builder & AttributePathIB::Builder::ListIndex(const DataModel::Nullable<chip::ListIndex> & aListIndex)
328 : {
329 : // skip if error has already been set
330 5866 : if (mError == CHIP_NO_ERROR)
331 : {
332 5710 : mError = DataModel::Encode(*mpWriter, TLV::ContextTag(Tag::kListIndex), aListIndex);
333 : }
334 5866 : 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 12996 : CHIP_ERROR AttributePathIB::Builder::EndOfAttributePathIB()
348 : {
349 12996 : EndOfContainer();
350 12996 : return GetError();
351 : }
352 :
353 1923 : CHIP_ERROR AttributePathIB::Builder::Encode(const AttributePathParams & aAttributePathParams)
354 : {
355 1923 : if (!(aAttributePathParams.HasWildcardEndpointId()))
356 : {
357 1503 : Endpoint(aAttributePathParams.mEndpointId);
358 : }
359 :
360 1923 : if (!(aAttributePathParams.HasWildcardClusterId()))
361 : {
362 1440 : Cluster(aAttributePathParams.mClusterId);
363 : }
364 :
365 1923 : if (!(aAttributePathParams.HasWildcardAttributeId()))
366 : {
367 1231 : Attribute(aAttributePathParams.mAttributeId);
368 : }
369 :
370 1923 : if (!(aAttributePathParams.HasWildcardListIndex()))
371 : {
372 14 : ListIndex(aAttributePathParams.mListIndex);
373 : }
374 :
375 1923 : return EndOfAttributePathIB();
376 : }
377 :
378 2490 : CHIP_ERROR AttributePathIB::Builder::Encode(const ConcreteDataAttributePath & aAttributePath)
379 : {
380 2490 : Endpoint(aAttributePath.mEndpointId);
381 2490 : Cluster(aAttributePath.mClusterId);
382 2490 : Attribute(aAttributePath.mAttributeId);
383 :
384 2490 : 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 2490 : return EndOfAttributePathIB();
399 : }
400 :
401 : } // namespace app
402 : } // namespace chip
|