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 : #pragma once
17 :
18 : #include <app/persistence/AttributePersistenceProvider.h>
19 : #include <app/persistence/PascalString.h>
20 : #include <lib/support/Span.h>
21 :
22 : #include <cstddef>
23 : #include <cstdint>
24 :
25 : namespace chip::app::Storage {
26 :
27 : namespace Internal {
28 :
29 : /// Represents a string that can be read/written to storage.
30 : ///
31 : /// This is currently implemented for SHORT strings only (< 255 bytes)
32 : /// that are NOT nullable
33 : class ShortString
34 : {
35 : public:
36 : /// Use the input buffer as a short pascal string.
37 : ///
38 : /// The input buffer is assumed to have:
39 : /// - size for a PascalString (i.e. generally pascal string max length + prefix == max length + 1 given we use
40 : /// short pascal strings here)
41 : /// - an extra +1 bytes for a null terminator so that c_str works.
42 : ///
43 : /// This means that buffer_size should be `N+2` where N is the expected maximum string length.
44 : ///
45 : /// This class is considered Internal, use chip::app::Storage::String<MAX_LENGTH> in application code.
46 11 : ShortString(char * buffer, size_t buffer_size) : mBuffer(buffer), mPascalSize(static_cast<uint8_t>(buffer_size - 1))
47 : {
48 : // for a buffer to be usable we need 1 byte for size, 1 byte for content and 1 byte for null terminator.
49 : // Strings without any size make no sense.
50 11 : VerifyOrDie(buffer_size >= 3);
51 11 : VerifyOrDie(buffer_size <= 1 + 254 + 1); // prefix + 254 length string + null terminator
52 11 : }
53 :
54 : /// Returns the content as a character span
55 28 : CharSpan Content() const { return AsPascal().Content(); }
56 :
57 : /// Returns the content as a null terminated string
58 13 : const char * c_str() const { return Content().data(); /* ALWAYS null terminated*/ }
59 :
60 : /// sets the internal value of the string to the given value.
61 : /// If the set fails, the value is set to empty string and false is returned.
62 : bool SetContent(CharSpan value);
63 :
64 : friend class ShortStringOutputAdapter;
65 : friend class ShortStringInputAdapter;
66 :
67 : private:
68 : char * mBuffer;
69 : uint8_t mPascalSize;
70 :
71 68 : ShortPascalString AsPascal() { return Span{ mBuffer, mPascalSize }; }
72 30 : ShortConstPascalString AsPascal() const { return CharSpan{ mBuffer, mPascalSize }; }
73 :
74 : /// Places a null terminator after the pascal string content, so that c_str() works
75 32 : void NullTerminate() { mBuffer[AsPascal().ContentWithLenPrefix().size()] = 0; }
76 : };
77 :
78 : /// Provides internal access and processing to a ShortString class.
79 : ///
80 : /// The class is intended to read raw data into a short string: it provides
81 : /// access to the internal read buffer and allows a `FinalizeRead` call to
82 : /// perform final validation of the read.
83 : ///
84 : /// Meant for internal use only, this is NOT public API outside the SDK code itself.
85 : class ShortStringInputAdapter
86 : {
87 : public:
88 7 : ShortStringInputAdapter(ShortString & value) : mValue(value) {}
89 7 : MutableByteSpan ReadBuffer() { return mValue.AsPascal().RawFullBuffer(); }
90 :
91 : /// Method to be called once data has been read into ReadBuffer
92 : ///
93 : /// Validates that the read span is valid, sets the value to empty string on failure.
94 : /// ByteSpan MUST be a subset of the buffer inside of the mValue.AsPascal().
95 : bool FinalizeRead(ByteSpan actuallyRead);
96 :
97 : private:
98 : ShortString & mValue;
99 : };
100 :
101 : /// Provides internal access and processing to a ShortString class.
102 : ///
103 : /// The class is intended to provide access to a serializable view of the
104 : /// short string, specifically access to its content with length.
105 : ///
106 : /// Meant for internal use only, this is NOT public API outside the SDK code itself.
107 : class ShortStringOutputAdapter
108 : {
109 : public:
110 2 : ShortStringOutputAdapter(const ShortString & value) : mValue(value) {}
111 2 : ByteSpan ContentWithPrefix() const { return mValue.AsPascal().ContentWithLenPrefix(); }
112 :
113 : private:
114 : const ShortString & mValue;
115 : };
116 :
117 : } // namespace Internal
118 :
119 : /// Represents a string of maximum length of `N` characters
120 : ///
121 : /// The string storage will be formatted to support persistent storage I/O,
122 : /// specifically stored as a length-prefixed string and it also maintains a null terminator
123 : /// so that both char-span and null terminated views are usable. The storage
124 : /// overhead of this string is 2 bytes (one for length prefix, one for null terminator).
125 : template <size_t N, typename = std::enable_if_t<(N < 255) && (N > 0)>>
126 : class String : public Internal::ShortString
127 : {
128 : public:
129 11 : String() : Internal::ShortString(mBuffer, sizeof(mBuffer)) { SetContent(""_span); }
130 :
131 : // internal shortstring contains self-referencing pointers. That cannot be copied, so we assume no copy for now
132 : // These could be implemented, however for now we assume people should just use the underlying Span() to set
133 : // the values.
134 : String(String &&) = delete;
135 : String & operator=(String &&) = delete;
136 : String(const String &) = delete;
137 : String & operator=(const String &) = delete;
138 :
139 : private:
140 : // +1 byte to null-terminate to allow for a c_str() implementation
141 : // as that seems very convenient.
142 : char mBuffer[ShortPascalString::BufferSizeFor(N) + 1] = { 0 };
143 : };
144 :
145 : } // namespace chip::app::Storage
|