• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/type_traits.hpp"
48 
49 namespace ot {
50 
51 /**
52  * This enumeration type is used as the template parameter in `Data` and `MutableData` to indicate the `uint` type to
53  * use for the data length.
54  *
55  */
56 enum DataLengthType : uint8_t
57 {
58     kWithUint8Length,  ///< Use `uint8_t` for data length.
59     kWithUint16Length, ///< Use `uint16_t` for data length
60 };
61 
62 /**
63  * This type specifies a function pointer which matches two given bytes.
64  *
65  * Such a function is used as a parameter in `Data::MatchesByteIn()` method. This can be used to relax the definition
66  * of a match when comparing data bytes, e.g., can be used for case-insensitive string comparison.
67  *
68  * @param[in] aFirst   A first byte.
69  * @param[in] aSecond  A second byte.
70  *
71  * @retval TRUE  if @p aFirst matches @p aSecond.
72  * @retval FALSE if @p aFirst does not match @p aSecond.
73  *
74  */
75 typedef bool (*ByteMatcher)(uint8_t aFirst, uint8_t aSecond);
76 
77 /**
78  * This class implements common utility methods used by `Data` and `MutableData`.
79  *
80  */
81 class DataUtils
82 {
83 protected:
84     DataUtils(void) = default;
85     static bool MatchBytes(const uint8_t *aFirstBuffer,
86                            const uint8_t *aSecondBuffer,
87                            uint16_t       aLength,
88                            ByteMatcher    aMatcher);
89 };
90 
91 template <DataLengthType kDataLengthType> class MutableData;
92 
93 /**
94  * This type represents a generic `Data` which is simply a wrapper over a pointer to a buffer with a given data length.
95  *
96  * The data length can be either `uint8_t` or `uint16_t` (determined by the template parameter `kDataLengthType`).
97  *
98  * While a `Data` instance itself can change (for example, it can be updated to point to another buffer), it always
99  * treats the content of the buffer as immutable.
100  *
101  * A `Data` instance MUST be initialized (using any of the `Init()` methods) before calling any other methods on the
102  * instance (e.g., `GetBytes()` or `GetLength()`), otherwise the behavior is undefined.
103  *
104  * @tparam kDataLengthType   Determines the data length type (`uint8_t` or `uint16_t`).
105  *
106  */
107 template <DataLengthType kDataLengthType>
108 class Data : public Clearable<Data<kDataLengthType>>, public Unequatable<Data<kDataLengthType>>, private DataUtils
109 {
110     friend class MutableData<kDataLengthType>;
111 
112 public:
113     /**
114      * This type represents the data length type (`uint8_t` or `uint16_t`).
115      *
116      */
117     using LengthType = typename TypeTraits::Conditional<kDataLengthType == kWithUint8Length, uint8_t, uint16_t>::Type;
118 
119     /**
120      * This method initializes the `Data` to point to a given buffer with a given length.
121      *
122      * @param[in] aBuffer   A pointer to a buffer containing the data.
123      * @param[in] aLength   The data length (number of bytes in @p aBuffer)
124      *
125      */
Init(const void * aBuffer,LengthType aLength)126     void Init(const void *aBuffer, LengthType aLength)
127     {
128         mBuffer = static_cast<const uint8_t *>(aBuffer);
129         mLength = aLength;
130     }
131 
132     /**
133      * This method initializes the `Data` to point to a range of bytes in a given buffer.
134      *
135      * The range is specified by the pointers to its start @p aStart and its end @p aEnd. `Data` will point to the
136      * bytes in the buffer from @p aStart up to but excluding @p aEnd (i.e., `aStart <= bytes < aEnd`).
137      *
138      * @param[in] aStart  Pointer to the start of the range.
139      * @param[in] aEnd    Pointer to the end of the range.
140      *
141      */
InitFromRange(const uint8_t * aStart,const uint8_t * aEnd)142     void InitFromRange(const uint8_t *aStart, const uint8_t *aEnd)
143     {
144         Init(aStart, static_cast<LengthType>(aEnd - aStart));
145     }
146 
147     /**
148      * This template method initializes the `Data` to point to the content of an object.
149      *
150      * @tparm ObjectType   The object type (MUST not be a pointer type).
151      *
152      * @param[in] aObject   The object to initialize the `Data` with.
153      *
154      */
InitFrom(const ObjectType & aObject)155     template <typename ObjectType> void InitFrom(const ObjectType &aObject)
156     {
157         static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType MUST not be a pointer");
158         Init(&aObject, sizeof(aObject));
159     }
160 
161     /**
162      * This method returns a pointer to the data bytes buffer.
163      *
164      * @returns A pointer to the data bytes buffer (can be `nullptr` if `Data` is cleared).
165      *
166      */
GetBytes(void) const167     const uint8_t *GetBytes(void) const { return mBuffer; }
168 
169     /**
170      * This method returns the data length.
171      *
172      * @returns The data length (number of bytes).
173      *
174      */
GetLength(void) const175     LengthType GetLength(void) const { return mLength; }
176 
177     /**
178      * This method sets the data length.
179      *
180      * @param[in] aLength   The data length (number of bytes).
181      *
182      */
SetLength(LengthType aLength)183     void SetLength(LengthType aLength) { mLength = aLength; }
184 
185     /**
186      * This method copies the `Data` bytes to a given buffer.
187      *
188      * It is up to the caller to ensure that @p aBuffer has enough space for the current data length.
189      *
190      * @param[out] aBuffer  The buffer to copy the bytes into.
191      *
192      */
CopyBytesTo(void * aBuffer) const193     void CopyBytesTo(void *aBuffer) const { memcpy(aBuffer, mBuffer, mLength); }
194 
195     /**
196      * This method compares the `Data` content with the bytes from a given buffer.
197      *
198      * It is up to the caller to ensure that @p aBuffer has enough bytes to compare with the current data length.
199      *
200      * @param[in] aBuffer   A pointer to a buffer to compare with the data.
201      *
202      * @retval TRUE   The `Data` content matches the bytes in @p aBuffer.
203      * @retval FALSE  The `Data` content does not match the byes in @p aBuffer.
204      *
205      */
MatchesBytesIn(const void * aBuffer) const206     bool MatchesBytesIn(const void *aBuffer) const { return memcmp(mBuffer, aBuffer, mLength) == 0; }
207 
208     /**
209      * This method compares the `Data` content with the bytes from a given buffer using a given `Matcher` function.
210      *
211      * It is up to the caller to ensure that @p aBuffer has enough bytes to compare with the current data length.
212      *
213      * @param[in] aBuffer   A pointer to a buffer to compare with the data.
214      * @param[in] aMatcher  A `ByteMatcher` function to match the bytes. If `nullptr`, bytes are compared directly.
215      *
216      * @retval TRUE   The `Data` content matches the bytes in @p aBuffer.
217      * @retval FALSE  The `Data` content does not match the byes in @p aBuffer.
218      *
219      */
MatchesBytesIn(const void * aBuffer,ByteMatcher aMatcher)220     bool MatchesBytesIn(const void *aBuffer, ByteMatcher aMatcher)
221     {
222         return MatchBytes(mBuffer, static_cast<const uint8_t *>(aBuffer), mLength, aMatcher);
223     }
224 
225     /**
226      * This method overloads operator `==` to compare the `Data` content with the content from another one.
227      *
228      * @param[in] aOtherData   The other `Data` to compare with.
229      *
230      * @retval TRUE   The two `Data` instances have matching content (same length and same bytes).
231      * @retval FALSE  The two `Data` instances do not have matching content.
232      *
233      */
operator ==(const Data & aOtherData) const234     bool operator==(const Data &aOtherData) const
235     {
236         return (mLength == aOtherData.mLength) && MatchesBytesIn(aOtherData.mBuffer);
237     }
238 
239     /**
240      * This method checks whether the `Data` starts with the same byte content as from another `Data` instance.
241      *
242      * This method checks that the `Data` instance contains the same bytes as @p aOtherData but allows it to have
243      * additional bytes at the end.
244      *
245      * @param[in] aOtherData  The other `Data` to compare with.
246      *
247      * @retval TRUE   This `Data` starts with the same byte content as in @p aOtherData.
248      * @retval FALSE  This `Data` does not start with the same byte content as in @p aOtherData.
249      *
250      */
StartsWith(const Data & aOtherData) const251     bool StartsWith(const Data &aOtherData) const
252     {
253         return (mLength >= aOtherData.mLength) && aOtherData.MatchesBytesIn(mBuffer);
254     }
255 
256 private:
257     const uint8_t *mBuffer;
258     LengthType     mLength;
259 };
260 
261 /**
262  * This type represents a generic `MutableData` which is simply a wrapper over a pointer to a buffer with a given data
263  * length.
264  *
265  * It inherits from `Data` but unlike `Data` which treats its buffer content as immutable, `MutableData` allows its
266  * data buffer content to be changed.
267  *
268  * A `MutableData` instance MUST be initialized (using any of the `Init()` methods) before calling any other methods
269  * (e.g., `GetBytes()` or `GetLength()`), otherwise the behavior is undefined.
270 
271  *
272  */
273 template <DataLengthType kDataLengthType> class MutableData : public Data<kDataLengthType>
274 {
275     using Base = Data<kDataLengthType>;
276     using Base::mBuffer;
277     using Base::mLength;
278 
279 public:
280     /**
281      * This type represents the data length type (`uint8_t` or `uint16_t`).
282      *
283      */
284     using LengthType = typename Base::LengthType;
285 
286     /**
287      * This method initializes the `MutableData` to point to a given buffer with a given length.
288      *
289      * @param[in] aBuffer   A pointer to a buffer containing the data.
290      * @param[in] aLength   The data length (number of bytes in @p aBuffer)
291      *
292      */
Init(void * aBuffer,LengthType aLength)293     void Init(void *aBuffer, LengthType aLength) { Base::Init(aBuffer, aLength); }
294 
295     /**
296      * This method initializes the `MutableData` to point to a range of bytes in a given buffer.
297      *
298      * The range is specified by the pointers to its start @p aStart and its end @p aEnd. `Data` will point to the
299      * bytes in the buffer from @p aStart up to but excluding @p aEnd (i.e., `aStart <= bytes < aEnd`).
300      *
301      * @param[in] aStart  Pointer to the start of the range.
302      * @param[in] aEnd    Pointer to the end of the range.
303      *
304      */
InitFormRange(uint8_t * aStart,uint8_t * aEnd)305     void InitFormRange(uint8_t *aStart, uint8_t *aEnd) { Base::InitFormRange(aStart, aEnd); }
306 
307     /**
308      * This template method initializes the `MutableData` to point to the content of an object.
309      *
310      * @tparm ObjectType   The object type (MUST not be a pointer type).
311      *
312      * @param[in] aObject   The object to initialize the `MutableData` with.
313      *
314      */
InitFrom(ObjectType & aObject)315     template <typename ObjectType> void InitFrom(ObjectType &aObject)
316     {
317         static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType MUST not be a pointer");
318         Init(&aObject, sizeof(aObject));
319     }
320 
321     /**
322      * This method returns a pointer to the data bytes buffer.
323      *
324      * @returns A pointer to the data bytes buffer (can be `nullptr` if `Data` is empty or uninitialized).
325      *
326      */
GetBytes(void)327     uint8_t *GetBytes(void) { return AsNonConst(Base::GetBytes()); }
328 
329     /**
330      * This method returns a pointer to the data bytes buffer.
331      *
332      * @returns A pointer to the data bytes buffer (can be `nullptr` if `Data` is empty or uninitialized).
333      *
334      */
GetBytes(void) const335     const uint8_t *GetBytes(void) const { return Base::GetBytes(); }
336 
337     /**
338      * This method clears all the bytes (sets them to zero) in the buffer pointed by the `MutableData`.
339      *
340      */
ClearBytes(void)341     void ClearBytes(void) { memset(GetBytes(), 0, mLength); }
342 
343     /**
344      * This method copies the bytes from a given buffer into the `MutableData` buffer.
345      *
346      * If the current `MutableData` length is larger than or equal to @p aLength, then all the bytes are copied
347      * from @p aBuffer into the buffer of `MutableData` and the `MutableData`'s length is changed to @p aLength.
348      *
349      * If the current `MutableData` length is smaller than @p aLength, then the method returns `kErrorNoBufs` but still
350      * copies as many bytes as can fit.
351      *
352      * @param[in] aBuffer  A pointer to a buffer to copy from.
353      * @param[in] aLength  The length of @p aBuffer (number of bytes).
354      *
355      * @retval kErrorNone    Successfully copied the bytes into `MutableData` buffer and adjusted its length.
356      * @retval kErrorNoBufs  `MutableData` buffer cannot fit the given @p aLength bytes.
357      *
358      */
CopyBytesFrom(const uint8_t * aBuffer,LengthType aLength)359     Error CopyBytesFrom(const uint8_t *aBuffer, LengthType aLength)
360     {
361         Error error = (mLength >= aLength) ? kErrorNone : kErrorNoBufs;
362 
363         mLength = OT_MIN(mLength, aLength);
364         memcpy(AsNonConst(mBuffer), aBuffer, mLength);
365 
366         return error;
367     }
368 
369     /**
370      * This method copies the bytes from an given `Data` instance into the `MutableData` buffer.
371      *
372      * If the current `MutableData` length is larger than or equal to the @p aData length, then all the bytes are copied
373      * from @p aData into the buffer of `MutableData` and the `MutableData`'s length is adjusted accordingly.
374      *
375      * If the current `MutableData` length is smaller than @p aData length, then as many bytes as can fit are copied
376      * and the method returns `kErrorNoBufs`.
377      *
378      * @param[in] aData      A `Data` instance to copy the content from.
379      *
380      * @retval kErrorNone    Successfully copied the bytes into `MutableData` buffer and adjusted its length.
381      * @retval kErrorNoBufs  `MutableData` buffer cannot fit the given @p aData bytes.
382      *
383      */
CopyBytesFrom(const Data<kDataLengthType> & aData)384     Error CopyBytesFrom(const Data<kDataLengthType> &aData)
385     {
386         return CopyBytesFrom(aData.GetBytes(), aData.GetLength());
387     }
388 };
389 
390 } // namespace ot
391 
392 #endif // DATA_HPP_
393