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