Line data Source code
1 : /*
2 : * Copyright (c) 2025 Project CHIP Authors
3 : *
4 : * Licensed under the Apache License, Version 2.0 (the "License");
5 : * you may not use this file except in compliance with the License.
6 : * You may obtain a copy of the License at
7 : *
8 : * http://www.apache.org/licenses/LICENSE-2.0
9 : *
10 : * Unless required by applicable law or agreed to in writing, software
11 : * distributed under the License is distributed on an "AS IS" BASIS,
12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : * See the License for the specific language governing permissions and
14 : * limitations under the License.
15 : */
16 : #include <app/persistence/AttributePersistence.h>
17 :
18 : #include <app/ConcreteAttributePath.h>
19 : #include <app/data-model/Nullable.h>
20 : #include <app/persistence/AttributePersistenceProvider.h>
21 : #include <app/persistence/String.h>
22 : #include <lib/core/CHIPError.h>
23 : #include <lib/support/Span.h>
24 :
25 : namespace chip::app {
26 :
27 : namespace {
28 :
29 343 : bool VerifySuccessLogOnFailure(const ConcreteAttributePath & path, CHIP_ERROR err)
30 : {
31 686 : VerifyOrReturnValue(err != CHIP_NO_ERROR, true);
32 :
33 : // Value not found is typical. Not an error worth logging.
34 564 : VerifyOrReturnValue(err != CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND, false);
35 :
36 3 : ChipLogError(Zcl, "Failed to load attribute %u/" ChipLogFormatMEI "/" ChipLogFormatMEI ": %" CHIP_ERROR_FORMAT,
37 : path.mEndpointId, ChipLogValueMEI(path.mClusterId), ChipLogValueMEI(path.mAttributeId), err.Format());
38 3 : return false;
39 : }
40 :
41 : } // namespace
42 :
43 303 : bool AttributePersistence::InternalRawLoadNativeEndianValue(const ConcreteAttributePath & path, void * data,
44 : const void * valueOnLoadFailure, size_t size)
45 : {
46 303 : MutableByteSpan rawBytes(reinterpret_cast<uint8_t *>(data), size);
47 303 : if (!VerifySuccessLogOnFailure(path, mProvider.ReadValue(path, rawBytes)))
48 : {
49 : // in case of failure, set the default value
50 252 : memcpy(data, valueOnLoadFailure, size);
51 252 : return false;
52 : }
53 :
54 51 : if (rawBytes.size() != size)
55 : {
56 : // short read: the value is not valid
57 1 : memcpy(data, valueOnLoadFailure, size);
58 1 : return false;
59 : }
60 :
61 50 : return true;
62 : }
63 :
64 40 : bool AttributePersistence::LoadString(const ConcreteAttributePath & path, Storage::Internal::ShortString & value)
65 : {
66 40 : Storage::Internal::ShortStringInputAdapter io(value);
67 40 : MutableByteSpan rawBytes = io.ReadBuffer();
68 :
69 40 : if (!VerifySuccessLogOnFailure(path, mProvider.ReadValue(path, rawBytes)))
70 : {
71 30 : value.SetContent(""_span);
72 30 : return false;
73 : }
74 10 : return io.FinalizeRead(rawBytes);
75 : }
76 :
77 36 : CHIP_ERROR AttributePersistence::StoreString(const ConcreteAttributePath & path, const Storage::Internal::ShortString & value)
78 : {
79 36 : Storage::Internal::ShortStringOutputAdapter io(value);
80 36 : return mProvider.WriteValue(path, io.ContentWithPrefix());
81 : }
82 :
83 10 : CHIP_ERROR AttributePersistence::InternalStoreTLV(const ConcreteAttributePath & path, MutableByteSpan buffer, const void * context,
84 : TLVEncoderCallback encoder)
85 : {
86 10 : TLV::TLVWriter writer;
87 10 : writer.Init(buffer);
88 :
89 : TLV::TLVType container;
90 : // We wrap the value in an Anonymous Structure to ensure a single valid top-level element.
91 10 : ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
92 10 : ReturnErrorOnFailure(encoder(context, writer));
93 9 : ReturnErrorOnFailure(writer.EndContainer(container));
94 9 : ReturnErrorOnFailure(writer.Finalize());
95 :
96 9 : return mProvider.WriteValue(path, ByteSpan(buffer.data(), writer.GetLengthWritten()));
97 : }
98 :
99 11 : CHIP_ERROR AttributePersistence::InternalLoadTLV(const ConcreteAttributePath & path, MutableByteSpan buffer, void * context,
100 : TLVDecoderCallback decoder)
101 : {
102 11 : ReturnErrorOnFailure(mProvider.ReadValue(path, buffer));
103 :
104 7 : TLV::TLVReader reader;
105 7 : reader.Init(buffer);
106 :
107 7 : ReturnErrorOnFailure(reader.Next());
108 7 : VerifyOrReturnError(reader.GetType() == TLV::kTLVType_Structure, CHIP_ERROR_WRONG_TLV_TYPE);
109 :
110 : {
111 : TLV::TLVType container;
112 6 : ReturnErrorOnFailure(reader.EnterContainer(container));
113 6 : ReturnErrorOnFailure(reader.Next()); // Move to the element inside structure (Context Tag 1)
114 5 : VerifyOrReturnError(reader.GetTag() == kTLVEncodingTag, CHIP_ERROR_INVALID_ARGUMENT);
115 4 : ReturnErrorOnFailure(decoder(context, reader));
116 4 : ReturnErrorOnFailure(reader.VerifyEndOfContainer());
117 3 : ReturnErrorOnFailure(reader.ExitContainer(container));
118 : }
119 3 : ReturnErrorOnFailure(reader.VerifyEndOfContainer());
120 :
121 2 : return CHIP_NO_ERROR;
122 : }
123 :
124 : } // namespace chip::app
|