1 /*
2  *  Copyright (c) 2021, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for a `Data` and `MutableData`.
32  */
33 
34 #ifndef DATA_HPP_
35 #define DATA_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <stdint.h>
40 #include <string.h>
41 
42 #include "common/clearable.hpp"
43 #include "common/code_utils.hpp"
44 #include "common/const_cast.hpp"
45 #include "common/equatable.hpp"
46 #include "common/error.hpp"
47 #include "common/num_utils.hpp"
48 #include "common/type_traits.hpp"
49 
50 namespace ot {
51 
52 /**
53  * Type is used as the template parameter in `Data` and `MutableData` to indicate the `uint` type to
54  * use for the data length.
55  *
56  */
57 enum DataLengthType : uint8_t
58 {
59     kWithUint8Length,  ///< Use `uint8_t` for data length.
60     kWithUint16Length, ///< Use `uint16_t` for data length
61 };
62 
63 /**
64  * Specifies a function pointer which matches two given bytes.
65  *
66  * Such a function is used as a parameter in `Data::MatchesByteIn()` method. This can be used to relax the definition
67  * of a match when comparing data bytes, e.g., can be used for case-insensitive string comparison.
68  *
69  * @param[in] aFirst   A first byte.
70  * @param[in] aSecond  A second byte.
71  *
72  * @retval TRUE  if @p aFirst matches @p aSecond.
73  * @retval FALSE if @p aFirst does not match @p aSecond.
74  *
75  */
76 typedef bool (*ByteMatcher)(uint8_t aFirst, uint8_t aSecond);
77 
78 /**
79  * Implements common utility methods used by `Data` and `MutableData`.
80  *
81  */
82 class DataUtils
83 {
84 protected:
85     DataUtils(void) = default;
86     static bool MatchBytes(const uint8_t *aFirstBuffer,
87                            const uint8_t *aSecondBuffer,
88                            uint16_t       aLength,
89                            ByteMatcher    aMatcher);
90 };
91 
92 template <DataLengthType kDataLengthType> class MutableData;
93 
94 /**
95  * Represents a generic `Data` which is simply a wrapper over a pointer to a buffer with a given data length.
96  *
97  * The data length can be either `uint8_t` or `uint16_t` (determined by the template parameter `kDataLengthType`).
98  *
99  * While a `Data` instance itself can change (for example, it can be updated to point to another buffer), it always
100  * treats the content of the buffer as immutable.
101  *
102  * A `Data` instance MUST be initialized (using any of the `Init()` methods) before calling any other methods on the
103  * instance (e.g., `GetBytes()` or `GetLength()`), otherwise the behavior is undefined.
104  *
105  * @tparam kDataLengthType   Determines the data length type (`uint8_t` or `uint16_t`).
106  *
107  */
108 template <DataLengthType kDataLengthType>
109 class Data : public Clearable<Data<kDataLengthType>>, public Unequatable<Data<kDataLengthType>>, private DataUtils
110 {
111     friend class MutableData<kDataLengthType>;
112 
113 public:
114     /**
115      * Represents the data length type (`uint8_t` or `uint16_t`).
116      *
117      */
118     using LengthType = typename TypeTraits::Conditional<kDataLengthType == kWithUint8Length, uint8_t, uint16_t>::Type;
119 
120     /**
121      * Initializes the `Data` to point to a given buffer with a given length.
122      *
123      * @param[in] aBuffer   A pointer to a buffer containing the data.
124      * @param[in] aLength   The data length (number of bytes in @p aBuffer)
125      *
126      */
Init(const void * aBuffer,LengthType aLength)127     void Init(const void *aBuffer, LengthType aLength)
128     {
129         mBuffer = static_cast<const uint8_t *>(aBuffer);
130         mLength = aLength;
131     }
132 
133     /**
134      * Initializes the `Data` to point to a range of bytes in a given buffer.
135      *
136      * The range is specified by the pointers to its start @p aStart and its end @p aEnd. `Data` will point to the
137      * bytes in the buffer from @p aStart up to but excluding @p aEnd (i.e., `aStart <= bytes < aEnd`).
138      *
139      * @param[in] aStart  Pointer to the start of the range.
140      * @param[in] aEnd    Pointer to the end of the range.
141      *
142      */
InitFromRange(const uint8_t * aStart,const uint8_t * aEnd)143     void InitFromRange(const uint8_t *aStart, const uint8_t *aEnd)
144     {
145         Init(aStart, static_cast<LengthType>(aEnd - aStart));
146     }
147 
148     /**
149      * Initializes the `Data` to point to the content of an object.
150      *
151      * @tparm ObjectType   The object type (MUST not be a pointer type).
152      *
153      * @param[in] aObject   The object to initialize the `Data` with.
154      *
155      */
InitFrom(const ObjectType & aObject)156     template <typename ObjectType> void InitFrom(const ObjectType &aObject)
157     {
158         static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType MUST not be a pointer");
159         Init(&aObject, sizeof(aObject));
160     }
161 
162     /**
163      * Returns a pointer to the data bytes buffer.
164      *
165      * @returns A pointer to the data bytes buffer (can be `nullptr` if `Data` is cleared).
166      *
167      */
GetBytes(void) const168     const uint8_t *GetBytes(void) const { return mBuffer; }
169 
170     /**
171      * Returns the data length.
172      *
173      * @returns The data length (number of bytes).
174      *
175      */
GetLength(void) const176     LengthType GetLength(void) const { return mLength; }
177 
178     /**
179      * Sets the data length.
180      *
181      * @param[in] aLength   The data length (number of bytes).
182      *
183      */
SetLength(LengthType aLength)184     void SetLength(LengthType aLength) { mLength = aLength; }
185 
186     /**
187      * Copies the `Data` bytes to a given buffer.
188      *
189      * It is up to the caller to ensure that @p aBuffer has enough space for the current data length.
190      *
191      * @param[out] aBuffer  The buffer to copy the bytes into.
192      *
193      */
CopyBytesTo(void * aBuffer) const194     void CopyBytesTo(void *aBuffer) const { memcpy(aBuffer, mBuffer, mLength); }
195 
196     /**
197      * Compares the `Data` content with the bytes from a given buffer.
198      *
199      * It is up to the caller to ensure that @p aBuffer has enough bytes to compare with the current data length.
200      *
201      * @param[in] aBuffer   A pointer to a buffer to compare with the data.
202      *
203      * @retval TRUE   The `Data` content matches the bytes in @p aBuffer.
204      * @retval FALSE  The `Data` content does not match the byes in @p aBuffer.
205      *
206      */
MatchesBytesIn(const void * aBuffer) const207     bool MatchesBytesIn(const void *aBuffer) const { return memcmp(mBuffer, aBuffer, mLength) == 0; }
208 
209     /**
210      * Compares the `Data` content with the bytes from a given buffer using a given `Matcher` function.
211      *
212      * It is up to the caller to ensure that @p aBuffer has enough bytes to compare with the current data length.
213      *
214      * @param[in] aBuffer   A pointer to a buffer to compare with the data.
215      * @param[in] aMatcher  A `ByteMatcher` function to match the bytes. If `nullptr`, bytes are compared directly.
216      *
217      * @retval TRUE   The `Data` content matches the bytes in @p aBuffer.
218      * @retval FALSE  The `Data` content does not match the byes in @p aBuffer.
219      *
220      */
MatchesBytesIn(const void * aBuffer,ByteMatcher aMatcher)221     bool MatchesBytesIn(const void *aBuffer, ByteMatcher aMatcher)
222     {
223         return MatchBytes(mBuffer, static_cast<const uint8_t *>(aBuffer), mLength, aMatcher);
224     }
225 
226     /**
227      * Overloads operator `==` to compare the `Data` content with the content from another one.
228      *
229      * @param[in] aOtherData   The other `Data` to compare with.
230      *
231      * @retval TRUE   The two `Data` instances have matching content (same length and same bytes).
232      * @retval FALSE  The two `Data` instances do not have matching content.
233      *
234      */
operator ==(const Data & aOtherData) const235     bool operator==(const Data &aOtherData) const
236     {
237         return (mLength == aOtherData.mLength) && MatchesBytesIn(aOtherData.mBuffer);
238     }
239 
240     /**
241      * Checks whether the `Data` starts with the same byte content as from another `Data` instance.
242      *
243      * Checks that the `Data` instance contains the same bytes as @p aOtherData but allows it to have
244      * additional bytes at the end.
245      *
246      * @param[in] aOtherData  The other `Data` to compare with.
247      *
248      * @retval TRUE   This `Data` starts with the same byte content as in @p aOtherData.
249      * @retval FALSE  This `Data` does not start with the same byte content as in @p aOtherData.
250      *
251      */
StartsWith(const Data & aOtherData) const252     bool StartsWith(const Data &aOtherData) const
253     {
254         return (mLength >= aOtherData.mLength) && aOtherData.MatchesBytesIn(mBuffer);
255     }
256 
257 private:
258     const uint8_t *mBuffer;
259     LengthType     mLength;
260 };
261 
262 /**
263  * Represents a generic `MutableData` which is simply a wrapper over a pointer to a buffer with a given data
264  * length.
265  *
266  * It inherits from `Data` but unlike `Data` which treats its buffer content as immutable, `MutableData` allows its
267  * data buffer content to be changed.
268  *
269  * A `MutableData` instance MUST be initialized (using any of the `Init()` methods) before calling any other methods
270  * (e.g., `GetBytes()` or `GetLength()`), otherwise the behavior is undefined.
271 
272  *
273  */
274 template <DataLengthType kDataLengthType> class MutableData : public Data<kDataLengthType>
275 {
276     using Base = Data<kDataLengthType>;
277     using Base::mBuffer;
278     using Base::mLength;
279 
280 public:
281     /**
282      * Represents the data length type (`uint8_t` or `uint16_t`).
283      *
284      */
285     using LengthType = typename Base::LengthType;
286 
287     /**
288      * Initializes the `MutableData` to point to a given buffer with a given length.
289      *
290      * @param[in] aBuffer   A pointer to a buffer containing the data.
291      * @param[in] aLength   The data length (number of bytes in @p aBuffer)
292      *
293      */
Init(void * aBuffer,LengthType aLength)294     void Init(void *aBuffer, LengthType aLength) { Base::Init(aBuffer, aLength); }
295 
296     /**
297      * Initializes the `MutableData` to point to a range of bytes in a given buffer.
298      *
299      * The range is specified by the pointers to its start @p aStart and its end @p aEnd. `Data` will point to the
300      * bytes in the buffer from @p aStart up to but excluding @p aEnd (i.e., `aStart <= bytes < aEnd`).
301      *
302      * @param[in] aStart  Pointer to the start of the range.
303      * @param[in] aEnd    Pointer to the end of the range.
304      *
305      */
InitFormRange(uint8_t * aStart,uint8_t * aEnd)306     void InitFormRange(uint8_t *aStart, uint8_t *aEnd) { Base::InitFormRange(aStart, aEnd); }
307 
308     /**
309      * Initializes the `MutableData` to point to the content of an object.
310      *
311      * @tparm ObjectType   The object type (MUST not be a pointer type).
312      *
313      * @param[in] aObject   The object to initialize the `MutableData` with.
314      *
315      */
InitFrom(ObjectType & aObject)316     template <typename ObjectType> void InitFrom(ObjectType &aObject)
317     {
318         static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType MUST not be a pointer");
319         Init(&aObject, sizeof(aObject));
320     }
321 
322     /**
323      * Returns a pointer to the data bytes buffer.
324      *
325      * @returns A pointer to the data bytes buffer (can be `nullptr` if `Data` is empty or uninitialized).
326      *
327      */
GetBytes(void)328     uint8_t *GetBytes(void) { return AsNonConst(Base::GetBytes()); }
329 
330     /**
331      * Returns a pointer to the data bytes buffer.
332      *
333      * @returns A pointer to the data bytes buffer (can be `nullptr` if `Data` is empty or uninitialized).
334      *
335      */
GetBytes(void) const336     const uint8_t *GetBytes(void) const { return Base::GetBytes(); }
337 
338     /**
339      * Clears all the bytes (sets them to zero) in the buffer pointed by the `MutableData`.
340      *
341      */
ClearBytes(void)342     void ClearBytes(void) { memset(GetBytes(), 0, mLength); }
343 
344     /**
345      * Copies the bytes from a given buffer into the `MutableData` buffer.
346      *
347      * If the current `MutableData` length is larger than or equal to @p aLength, then all the bytes are copied
348      * from @p aBuffer into the buffer of `MutableData` and the `MutableData`'s length is changed to @p aLength.
349      *
350      * If the current `MutableData` length is smaller than @p aLength, then the method returns `kErrorNoBufs` but still
351      * copies as many bytes as can fit.
352      *
353      * @param[in] aBuffer  A pointer to a buffer to copy from.
354      * @param[in] aLength  The length of @p aBuffer (number of bytes).
355      *
356      * @retval kErrorNone    Successfully copied the bytes into `MutableData` buffer and adjusted its length.
357      * @retval kErrorNoBufs  `MutableData` buffer cannot fit the given @p aLength bytes.
358      *
359      */
CopyBytesFrom(const uint8_t * aBuffer,LengthType aLength)360     Error CopyBytesFrom(const uint8_t *aBuffer, LengthType aLength)
361     {
362         Error error = (mLength >= aLength) ? kErrorNone : kErrorNoBufs;
363 
364         mLength = Min(mLength, aLength);
365         memcpy(AsNonConst(mBuffer), aBuffer, mLength);
366 
367         return error;
368     }
369 
370     /**
371      * Copies the bytes from an given `Data` instance into the `MutableData` buffer.
372      *
373      * If the current `MutableData` length is larger than or equal to the @p aData length, then all the bytes are copied
374      * from @p aData into the buffer of `MutableData` and the `MutableData`'s length is adjusted accordingly.
375      *
376      * If the current `MutableData` length is smaller than @p aData length, then as many bytes as can fit are copied
377      * and the method returns `kErrorNoBufs`.
378      *
379      * @param[in] aData      A `Data` instance to copy the content from.
380      *
381      * @retval kErrorNone    Successfully copied the bytes into `MutableData` buffer and adjusted its length.
382      * @retval kErrorNoBufs  `MutableData` buffer cannot fit the given @p aData bytes.
383      *
384      */
CopyBytesFrom(const Data<kDataLengthType> & aData)385     Error CopyBytesFrom(const Data<kDataLengthType> &aData)
386     {
387         return CopyBytesFrom(aData.GetBytes(), aData.GetLength());
388     }
389 };
390 
391 } // namespace ot
392 
393 #endif // DATA_HPP_
394