1 /*
2 * Copyright (c) 2016, 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 byte-ordering encoding.
32 */
33
34 #ifndef ENCODING_HPP_
35 #define ENCODING_HPP_
36
37 #include "openthread-core-config.h"
38
39 #ifndef BYTE_ORDER_BIG_ENDIAN
40 #if defined(WORDS_BIGENDIAN) || \
41 defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
42 #define BYTE_ORDER_BIG_ENDIAN 1
43 #else
44 #define BYTE_ORDER_BIG_ENDIAN 0
45 #endif
46 #endif
47
48 #include <stdint.h>
49
50 namespace ot {
51
Swap16(uint16_t v)52 inline constexpr uint16_t Swap16(uint16_t v)
53 {
54 return (((v & 0x00ffU) << 8) & 0xff00) | (((v & 0xff00U) >> 8) & 0x00ff);
55 }
56
Swap32(uint32_t v)57 inline constexpr uint32_t Swap32(uint32_t v)
58 {
59 return ((v & static_cast<uint32_t>(0x000000ffUL)) << 24) | ((v & static_cast<uint32_t>(0x0000ff00UL)) << 8) |
60 ((v & static_cast<uint32_t>(0x00ff0000UL)) >> 8) | ((v & static_cast<uint32_t>(0xff000000UL)) >> 24);
61 }
62
Swap64(uint64_t v)63 inline uint64_t constexpr Swap64(uint64_t v)
64 {
65 return ((v & static_cast<uint64_t>(0x00000000000000ffULL)) << 56) |
66 ((v & static_cast<uint64_t>(0x000000000000ff00ULL)) << 40) |
67 ((v & static_cast<uint64_t>(0x0000000000ff0000ULL)) << 24) |
68 ((v & static_cast<uint64_t>(0x00000000ff000000ULL)) << 8) |
69 ((v & static_cast<uint64_t>(0x000000ff00000000ULL)) >> 8) |
70 ((v & static_cast<uint64_t>(0x0000ff0000000000ULL)) >> 24) |
71 ((v & static_cast<uint64_t>(0x00ff000000000000ULL)) >> 40) |
72 ((v & static_cast<uint64_t>(0xff00000000000000ULL)) >> 56);
73 }
74
Reverse32(uint32_t v)75 inline uint32_t Reverse32(uint32_t v)
76 {
77 v = ((v & 0x55555555) << 1) | ((v & 0xaaaaaaaa) >> 1);
78 v = ((v & 0x33333333) << 2) | ((v & 0xcccccccc) >> 2);
79 v = ((v & 0x0f0f0f0f) << 4) | ((v & 0xf0f0f0f0) >> 4);
80 v = ((v & 0x00ff00ff) << 8) | ((v & 0xff00ff00) >> 8);
81 v = ((v & 0x0000ffff) << 16) | ((v & 0xffff0000) >> 16);
82
83 return v;
84 }
85
86 namespace BigEndian {
87
88 #if BYTE_ORDER_BIG_ENDIAN
89
HostSwap16(uint16_t v)90 inline constexpr uint16_t HostSwap16(uint16_t v) { return v; }
HostSwap32(uint32_t v)91 inline constexpr uint32_t HostSwap32(uint32_t v) { return v; }
HostSwap64(uint64_t v)92 inline constexpr uint64_t HostSwap64(uint64_t v) { return v; }
93
94 #else /* BYTE_ORDER_LITTLE_ENDIAN */
95
96 inline constexpr uint16_t HostSwap16(uint16_t v) { return Swap16(v); }
97 inline constexpr uint32_t HostSwap32(uint32_t v) { return Swap32(v); }
98 inline constexpr uint64_t HostSwap64(uint64_t v) { return Swap64(v); }
99
100 #endif // LITTLE_ENDIAN
101
102 /**
103 * This template function performs host swap on a given unsigned integer value assuming big-endian encoding.
104 *
105 * @tparam UintType The unsigned int type.
106 *
107 * @param aValue The value to host swap.
108 *
109 * @returns The host swapped value.
110 */
111 template <typename UintType> UintType HostSwap(UintType aValue);
112
HostSwap(uint8_t aValue)113 template <> inline uint8_t HostSwap(uint8_t aValue) { return aValue; }
HostSwap(uint16_t aValue)114 template <> inline uint16_t HostSwap(uint16_t aValue) { return HostSwap16(aValue); }
HostSwap(uint32_t aValue)115 template <> inline uint32_t HostSwap(uint32_t aValue) { return HostSwap32(aValue); }
HostSwap(uint64_t aValue)116 template <> inline uint64_t HostSwap(uint64_t aValue) { return HostSwap64(aValue); }
117
118 /**
119 * Reads a `uint16_t` value from a given buffer assuming big-endian encoding.
120 *
121 * @param[in] aBuffer Pointer to buffer to read from.
122 *
123 * @returns The `uint16_t` value read from buffer.
124 */
ReadUint16(const uint8_t * aBuffer)125 inline uint16_t ReadUint16(const uint8_t *aBuffer) { return static_cast<uint16_t>((aBuffer[0] << 8) | aBuffer[1]); }
126
127 /**
128 * Reads a `uint32_t` value from a given buffer assuming big-endian encoding.
129 *
130 * @param[in] aBuffer Pointer to buffer to read from.
131 *
132 * @returns The `uint32_t` value read from buffer.
133 */
ReadUint32(const uint8_t * aBuffer)134 inline uint32_t ReadUint32(const uint8_t *aBuffer)
135 {
136 return ((static_cast<uint32_t>(aBuffer[0]) << 24) | (static_cast<uint32_t>(aBuffer[1]) << 16) |
137 (static_cast<uint32_t>(aBuffer[2]) << 8) | (static_cast<uint32_t>(aBuffer[3]) << 0));
138 }
139
140 /**
141 * Reads a 24-bit integer value from a given buffer assuming big-endian encoding.
142 *
143 * @param[in] aBuffer Pointer to buffer to read from.
144 *
145 * @returns The value read from buffer.
146 */
ReadUint24(const uint8_t * aBuffer)147 inline uint32_t ReadUint24(const uint8_t *aBuffer)
148 {
149 return ((static_cast<uint32_t>(aBuffer[0]) << 16) | (static_cast<uint32_t>(aBuffer[1]) << 8) |
150 (static_cast<uint32_t>(aBuffer[2]) << 0));
151 }
152
153 /**
154 * Reads a `uint64_t` value from a given buffer assuming big-endian encoding.
155 *
156 * @param[in] aBuffer Pointer to buffer to read from.
157 *
158 * @returns The `uint64_t` value read from buffer.
159 */
ReadUint64(const uint8_t * aBuffer)160 inline uint64_t ReadUint64(const uint8_t *aBuffer)
161 {
162 return ((static_cast<uint64_t>(aBuffer[0]) << 56) | (static_cast<uint64_t>(aBuffer[1]) << 48) |
163 (static_cast<uint64_t>(aBuffer[2]) << 40) | (static_cast<uint64_t>(aBuffer[3]) << 32) |
164 (static_cast<uint64_t>(aBuffer[4]) << 24) | (static_cast<uint64_t>(aBuffer[5]) << 16) |
165 (static_cast<uint64_t>(aBuffer[6]) << 8) | (static_cast<uint64_t>(aBuffer[7]) << 0));
166 }
167
168 /**
169 * Reads a `UintType` integer value from a given buffer assuming big-endian encoding.
170 *
171 * @tparam UintType The unsigned int type.
172 *
173 * @param[in] aBuffer Pointer to the buffer to read from.
174 *
175 * @returns The `UintType` value read from the buffer.
176 */
177 template <typename UintType> UintType Read(const uint8_t *aBuffer);
178
Read(const uint8_t * aBuffer)179 template <> inline uint8_t Read(const uint8_t *aBuffer) { return *aBuffer; }
Read(const uint8_t * aBuffer)180 template <> inline uint16_t Read(const uint8_t *aBuffer) { return ReadUint16(aBuffer); }
Read(const uint8_t * aBuffer)181 template <> inline uint32_t Read(const uint8_t *aBuffer) { return ReadUint32(aBuffer); }
Read(const uint8_t * aBuffer)182 template <> inline uint64_t Read(const uint8_t *aBuffer) { return ReadUint64(aBuffer); }
183
184 /**
185 * Writes a `uint16_t` value to a given buffer using big-endian encoding.
186 *
187 * @param[in] aValue The value to write to buffer.
188 * @param[out] aBuffer Pointer to buffer where the value will be written.
189 */
WriteUint16(uint16_t aValue,uint8_t * aBuffer)190 inline void WriteUint16(uint16_t aValue, uint8_t *aBuffer)
191 {
192 aBuffer[0] = (aValue >> 8) & 0xff;
193 aBuffer[1] = (aValue >> 0) & 0xff;
194 }
195
196 /**
197 * Writes a 24-bit integer value to a given buffer using big-endian encoding.
198 *
199 * @param[in] aValue The value to write to buffer.
200 * @param[out] aBuffer Pointer to buffer where the value will be written.
201 */
WriteUint24(uint32_t aValue,uint8_t * aBuffer)202 inline void WriteUint24(uint32_t aValue, uint8_t *aBuffer)
203 {
204 aBuffer[0] = (aValue >> 16) & 0xff;
205 aBuffer[1] = (aValue >> 8) & 0xff;
206 aBuffer[2] = (aValue >> 0) & 0xff;
207 }
208
209 /**
210 * Writes a `uint32_t` value to a given buffer using big-endian encoding.
211 *
212 * @param[in] aValue The value to write to buffer.
213 * @param[out] aBuffer Pointer to buffer where the value will be written.
214 */
WriteUint32(uint32_t aValue,uint8_t * aBuffer)215 inline void WriteUint32(uint32_t aValue, uint8_t *aBuffer)
216 {
217 aBuffer[0] = (aValue >> 24) & 0xff;
218 aBuffer[1] = (aValue >> 16) & 0xff;
219 aBuffer[2] = (aValue >> 8) & 0xff;
220 aBuffer[3] = (aValue >> 0) & 0xff;
221 }
222
223 /**
224 * Writes a `uint64_t` value to a given buffer using big-endian encoding.
225 *
226 * @param[in] aValue The value to write to buffer.
227 * @param[out] aBuffer Pointer to buffer where the value will be written.
228 */
WriteUint64(uint64_t aValue,uint8_t * aBuffer)229 inline void WriteUint64(uint64_t aValue, uint8_t *aBuffer)
230 {
231 aBuffer[0] = (aValue >> 56) & 0xff;
232 aBuffer[1] = (aValue >> 48) & 0xff;
233 aBuffer[2] = (aValue >> 40) & 0xff;
234 aBuffer[3] = (aValue >> 32) & 0xff;
235 aBuffer[4] = (aValue >> 24) & 0xff;
236 aBuffer[5] = (aValue >> 16) & 0xff;
237 aBuffer[6] = (aValue >> 8) & 0xff;
238 aBuffer[7] = (aValue >> 0) & 0xff;
239 }
240
241 /**
242 * Writes a `UintType` integer value to a given buffer assuming big-endian encoding.
243 *
244 * @tparam UintType The unsigned int type.
245 *
246 * @param[in] aValue The value to write to buffer.
247 * @param[in] aBuffer Pointer to the buffer to write to.
248 */
249 template <typename UintType> void Write(UintType aValue, uint8_t *aBuffer);
250
Write(uint8_t aValue,uint8_t * aBuffer)251 template <> inline void Write(uint8_t aValue, uint8_t *aBuffer) { *aBuffer = aValue; }
Write(uint16_t aValue,uint8_t * aBuffer)252 template <> inline void Write(uint16_t aValue, uint8_t *aBuffer) { WriteUint16(aValue, aBuffer); }
Write(uint32_t aValue,uint8_t * aBuffer)253 template <> inline void Write(uint32_t aValue, uint8_t *aBuffer) { WriteUint32(aValue, aBuffer); }
Write(uint64_t aValue,uint8_t * aBuffer)254 template <> inline void Write(uint64_t aValue, uint8_t *aBuffer) { WriteUint64(aValue, aBuffer); }
255
256 } // namespace BigEndian
257
258 namespace LittleEndian {
259
260 #if BYTE_ORDER_BIG_ENDIAN
261
HostSwap16(uint16_t v)262 inline constexpr uint16_t HostSwap16(uint16_t v) { return Swap16(v); }
HostSwap32(uint32_t v)263 inline constexpr uint32_t HostSwap32(uint32_t v) { return Swap32(v); }
HostSwap64(uint64_t v)264 inline constexpr uint64_t HostSwap64(uint64_t v) { return Swap64(v); }
265
266 #else /* BYTE_ORDER_LITTLE_ENDIAN */
267
268 inline constexpr uint16_t HostSwap16(uint16_t v) { return v; }
269 inline constexpr uint32_t HostSwap32(uint32_t v) { return v; }
270 inline constexpr uint64_t HostSwap64(uint64_t v) { return v; }
271
272 #endif
273
274 /**
275 * This template function performs host swap on a given unsigned integer value assuming little-endian encoding.
276 *
277 * @tparam UintType The unsigned int type.
278 *
279 * @param aValue The value to host swap.
280 *
281 * @returns The host swapped value.
282 */
283 template <typename UintType> UintType HostSwap(UintType aValue);
284
HostSwap(uint8_t aValue)285 template <> inline uint8_t HostSwap(uint8_t aValue) { return aValue; }
HostSwap(uint16_t aValue)286 template <> inline uint16_t HostSwap(uint16_t aValue) { return HostSwap16(aValue); }
HostSwap(uint32_t aValue)287 template <> inline uint32_t HostSwap(uint32_t aValue) { return HostSwap32(aValue); }
HostSwap(uint64_t aValue)288 template <> inline uint64_t HostSwap(uint64_t aValue) { return HostSwap64(aValue); }
289
290 /**
291 * Reads a `uint16_t` value from a given buffer assuming little-endian encoding.
292 *
293 * @param[in] aBuffer Pointer to buffer to read from.
294 *
295 * @returns The `uint16_t` value read from buffer.
296 */
ReadUint16(const uint8_t * aBuffer)297 inline uint16_t ReadUint16(const uint8_t *aBuffer) { return static_cast<uint16_t>(aBuffer[0] | (aBuffer[1] << 8)); }
298
299 /**
300 * Reads a 24-bit integer value from a given buffer assuming little-endian encoding.
301 *
302 * @param[in] aBuffer Pointer to buffer to read from.
303 *
304 * @returns The value read from buffer.
305 */
ReadUint24(const uint8_t * aBuffer)306 inline uint32_t ReadUint24(const uint8_t *aBuffer)
307 {
308 return ((static_cast<uint32_t>(aBuffer[0]) << 0) | (static_cast<uint32_t>(aBuffer[1]) << 8) |
309 (static_cast<uint32_t>(aBuffer[2]) << 16));
310 }
311
312 /**
313 * Reads a `uint32_t` value from a given buffer assuming little-endian encoding.
314 *
315 * @param[in] aBuffer Pointer to buffer to read from.
316 *
317 * @returns The `uint32_t` value read from buffer.
318 */
ReadUint32(const uint8_t * aBuffer)319 inline uint32_t ReadUint32(const uint8_t *aBuffer)
320 {
321 return ((static_cast<uint32_t>(aBuffer[0]) << 0) | (static_cast<uint32_t>(aBuffer[1]) << 8) |
322 (static_cast<uint32_t>(aBuffer[2]) << 16) | (static_cast<uint32_t>(aBuffer[3]) << 24));
323 }
324
325 /**
326 * Reads a `uint64_t` value from a given buffer assuming little-endian encoding.
327 *
328 * @param[in] aBuffer Pointer to buffer to read from.
329 *
330 * @returns The `uint64_t` value read from buffer.
331 */
ReadUint64(const uint8_t * aBuffer)332 inline uint64_t ReadUint64(const uint8_t *aBuffer)
333 {
334 return ((static_cast<uint64_t>(aBuffer[0]) << 0) | (static_cast<uint64_t>(aBuffer[1]) << 8) |
335 (static_cast<uint64_t>(aBuffer[2]) << 16) | (static_cast<uint64_t>(aBuffer[3]) << 24) |
336 (static_cast<uint64_t>(aBuffer[4]) << 32) | (static_cast<uint64_t>(aBuffer[5]) << 40) |
337 (static_cast<uint64_t>(aBuffer[6]) << 48) | (static_cast<uint64_t>(aBuffer[7]) << 56));
338 }
339
340 /**
341 * Reads a `UintType` integer value from a given buffer assuming little-endian encoding.
342 *
343 * @tparam UintType The unsigned int type.
344 *
345 * @param[in] aBuffer Pointer to the buffer to read from.
346 *
347 * @returns The `UintType` value read from the buffer.
348 */
349 template <typename UintType> UintType Read(const uint8_t *aBuffer);
350
Read(const uint8_t * aBuffer)351 template <> inline uint8_t Read(const uint8_t *aBuffer) { return *aBuffer; }
Read(const uint8_t * aBuffer)352 template <> inline uint16_t Read(const uint8_t *aBuffer) { return ReadUint16(aBuffer); }
Read(const uint8_t * aBuffer)353 template <> inline uint32_t Read(const uint8_t *aBuffer) { return ReadUint32(aBuffer); }
Read(const uint8_t * aBuffer)354 template <> inline uint64_t Read(const uint8_t *aBuffer) { return ReadUint64(aBuffer); }
355
356 /**
357 * Writes a `uint16_t` value to a given buffer using little-endian encoding.
358 *
359 * @param[in] aValue The value to write to buffer.
360 * @param[out] aBuffer Pointer to buffer where the value will be written.
361 */
WriteUint16(uint16_t aValue,uint8_t * aBuffer)362 inline void WriteUint16(uint16_t aValue, uint8_t *aBuffer)
363 {
364 aBuffer[0] = (aValue >> 0) & 0xff;
365 aBuffer[1] = (aValue >> 8) & 0xff;
366 }
367
368 /**
369 * Writes a 24-bit integer value to a given buffer using little-endian encoding.
370 *
371 * @param[in] aValue The value to write to buffer.
372 * @param[out] aBuffer Pointer to buffer where the value will be written.
373 */
WriteUint24(uint32_t aValue,uint8_t * aBuffer)374 inline void WriteUint24(uint32_t aValue, uint8_t *aBuffer)
375 {
376 aBuffer[0] = (aValue >> 0) & 0xff;
377 aBuffer[1] = (aValue >> 8) & 0xff;
378 aBuffer[2] = (aValue >> 16) & 0xff;
379 }
380
381 /**
382 * Writes a `uint32_t` value to a given buffer using little-endian encoding.
383 *
384 * @param[in] aValue The value to write to buffer.
385 * @param[out] aBuffer Pointer to buffer where the value will be written.
386 */
WriteUint32(uint32_t aValue,uint8_t * aBuffer)387 inline void WriteUint32(uint32_t aValue, uint8_t *aBuffer)
388 {
389 aBuffer[0] = (aValue >> 0) & 0xff;
390 aBuffer[1] = (aValue >> 8) & 0xff;
391 aBuffer[2] = (aValue >> 16) & 0xff;
392 aBuffer[3] = (aValue >> 24) & 0xff;
393 }
394
395 /**
396 * Writes a `uint64_t` value to a given buffer using little-endian encoding.
397 *
398 * @param[in] aValue The value to write to buffer.
399 * @param[out] aBuffer Pointer to buffer where the value will be written.
400 */
WriteUint64(uint64_t aValue,uint8_t * aBuffer)401 inline void WriteUint64(uint64_t aValue, uint8_t *aBuffer)
402 {
403 aBuffer[0] = (aValue >> 0) & 0xff;
404 aBuffer[1] = (aValue >> 8) & 0xff;
405 aBuffer[2] = (aValue >> 16) & 0xff;
406 aBuffer[3] = (aValue >> 24) & 0xff;
407 aBuffer[4] = (aValue >> 32) & 0xff;
408 aBuffer[5] = (aValue >> 40) & 0xff;
409 aBuffer[6] = (aValue >> 48) & 0xff;
410 aBuffer[7] = (aValue >> 56) & 0xff;
411 }
412
413 /**
414 * Writes a `UintType` integer value to a given buffer assuming little-endian encoding.
415 *
416 * @tparam UintType The unsigned int type.
417 *
418 * @param[in] aValue The value to write to buffer.
419 * @param[in] aBuffer Pointer to the buffer to write to.
420 */
421 template <typename UintType> void Write(UintType aValue, uint8_t *aBuffer);
422
Write(uint8_t aValue,uint8_t * aBuffer)423 template <> inline void Write(uint8_t aValue, uint8_t *aBuffer) { *aBuffer = aValue; }
Write(uint16_t aValue,uint8_t * aBuffer)424 template <> inline void Write(uint16_t aValue, uint8_t *aBuffer) { WriteUint16(aValue, aBuffer); }
Write(uint32_t aValue,uint8_t * aBuffer)425 template <> inline void Write(uint32_t aValue, uint8_t *aBuffer) { WriteUint32(aValue, aBuffer); }
Write(uint64_t aValue,uint8_t * aBuffer)426 template <> inline void Write(uint64_t aValue, uint8_t *aBuffer) { WriteUint64(aValue, aBuffer); }
427
428 } // namespace LittleEndian
429
430 } // namespace ot
431
432 #endif // ENCODING_HPP_
433