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 */
112 template <typename UintType> UintType HostSwap(UintType aValue);
113
HostSwap(uint8_t aValue)114 template <> inline uint8_t HostSwap(uint8_t aValue) { return aValue; }
HostSwap(uint16_t aValue)115 template <> inline uint16_t HostSwap(uint16_t aValue) { return HostSwap16(aValue); }
HostSwap(uint32_t aValue)116 template <> inline uint32_t HostSwap(uint32_t aValue) { return HostSwap32(aValue); }
HostSwap(uint64_t aValue)117 template <> inline uint64_t HostSwap(uint64_t aValue) { return HostSwap64(aValue); }
118
119 /**
120 * Reads a `uint16_t` value from a given buffer assuming big-endian encoding.
121 *
122 * @param[in] aBuffer Pointer to buffer to read from.
123 *
124 * @returns The `uint16_t` value read from buffer.
125 *
126 */
ReadUint16(const uint8_t * aBuffer)127 inline uint16_t ReadUint16(const uint8_t *aBuffer) { return static_cast<uint16_t>((aBuffer[0] << 8) | aBuffer[1]); }
128
129 /**
130 * Reads a `uint32_t` value from a given buffer assuming big-endian encoding.
131 *
132 * @param[in] aBuffer Pointer to buffer to read from.
133 *
134 * @returns The `uint32_t` value read from buffer.
135 *
136 */
ReadUint32(const uint8_t * aBuffer)137 inline uint32_t ReadUint32(const uint8_t *aBuffer)
138 {
139 return ((static_cast<uint32_t>(aBuffer[0]) << 24) | (static_cast<uint32_t>(aBuffer[1]) << 16) |
140 (static_cast<uint32_t>(aBuffer[2]) << 8) | (static_cast<uint32_t>(aBuffer[3]) << 0));
141 }
142
143 /**
144 * Reads a 24-bit integer value from a given buffer assuming big-endian encoding.
145 *
146 * @param[in] aBuffer Pointer to buffer to read from.
147 *
148 * @returns The value read from buffer.
149 *
150 */
ReadUint24(const uint8_t * aBuffer)151 inline uint32_t ReadUint24(const uint8_t *aBuffer)
152 {
153 return ((static_cast<uint32_t>(aBuffer[0]) << 16) | (static_cast<uint32_t>(aBuffer[1]) << 8) |
154 (static_cast<uint32_t>(aBuffer[2]) << 0));
155 }
156
157 /**
158 * Reads a `uint64_t` value from a given buffer assuming big-endian encoding.
159 *
160 * @param[in] aBuffer Pointer to buffer to read from.
161 *
162 * @returns The `uint64_t` value read from buffer.
163 *
164 */
ReadUint64(const uint8_t * aBuffer)165 inline uint64_t ReadUint64(const uint8_t *aBuffer)
166 {
167 return ((static_cast<uint64_t>(aBuffer[0]) << 56) | (static_cast<uint64_t>(aBuffer[1]) << 48) |
168 (static_cast<uint64_t>(aBuffer[2]) << 40) | (static_cast<uint64_t>(aBuffer[3]) << 32) |
169 (static_cast<uint64_t>(aBuffer[4]) << 24) | (static_cast<uint64_t>(aBuffer[5]) << 16) |
170 (static_cast<uint64_t>(aBuffer[6]) << 8) | (static_cast<uint64_t>(aBuffer[7]) << 0));
171 }
172
173 /**
174 * Reads a `UintType` integer value from a given buffer assuming big-endian encoding.
175 *
176 * @tparam UintType The unsigned int type.
177 *
178 * @param[in] aBuffer Pointer to the buffer to read from.
179 *
180 * @returns The `UintType` value read from the buffer.
181 *
182 */
183 template <typename UintType> UintType Read(const uint8_t *aBuffer);
184
Read(const uint8_t * aBuffer)185 template <> inline uint8_t Read(const uint8_t *aBuffer) { return *aBuffer; }
Read(const uint8_t * aBuffer)186 template <> inline uint16_t Read(const uint8_t *aBuffer) { return ReadUint16(aBuffer); }
Read(const uint8_t * aBuffer)187 template <> inline uint32_t Read(const uint8_t *aBuffer) { return ReadUint32(aBuffer); }
Read(const uint8_t * aBuffer)188 template <> inline uint64_t Read(const uint8_t *aBuffer) { return ReadUint64(aBuffer); }
189
190 /**
191 * Writes a `uint16_t` value to a given buffer using big-endian encoding.
192 *
193 * @param[in] aValue The value to write to buffer.
194 * @param[out] aBuffer Pointer to buffer where the value will be written.
195 *
196 */
WriteUint16(uint16_t aValue,uint8_t * aBuffer)197 inline void WriteUint16(uint16_t aValue, uint8_t *aBuffer)
198 {
199 aBuffer[0] = (aValue >> 8) & 0xff;
200 aBuffer[1] = (aValue >> 0) & 0xff;
201 }
202
203 /**
204 * Writes a 24-bit integer value to a given buffer using big-endian encoding.
205 *
206 * @param[in] aValue The value to write to buffer.
207 * @param[out] aBuffer Pointer to buffer where the value will be written.
208 *
209 */
WriteUint24(uint32_t aValue,uint8_t * aBuffer)210 inline void WriteUint24(uint32_t aValue, uint8_t *aBuffer)
211 {
212 aBuffer[0] = (aValue >> 16) & 0xff;
213 aBuffer[1] = (aValue >> 8) & 0xff;
214 aBuffer[2] = (aValue >> 0) & 0xff;
215 }
216
217 /**
218 * Writes a `uint32_t` value to a given buffer using big-endian encoding.
219 *
220 * @param[in] aValue The value to write to buffer.
221 * @param[out] aBuffer Pointer to buffer where the value will be written.
222 *
223 */
WriteUint32(uint32_t aValue,uint8_t * aBuffer)224 inline void WriteUint32(uint32_t aValue, uint8_t *aBuffer)
225 {
226 aBuffer[0] = (aValue >> 24) & 0xff;
227 aBuffer[1] = (aValue >> 16) & 0xff;
228 aBuffer[2] = (aValue >> 8) & 0xff;
229 aBuffer[3] = (aValue >> 0) & 0xff;
230 }
231
232 /**
233 * Writes a `uint64_t` value to a given buffer using big-endian encoding.
234 *
235 * @param[in] aValue The value to write to buffer.
236 * @param[out] aBuffer Pointer to buffer where the value will be written.
237 *
238 */
WriteUint64(uint64_t aValue,uint8_t * aBuffer)239 inline void WriteUint64(uint64_t aValue, uint8_t *aBuffer)
240 {
241 aBuffer[0] = (aValue >> 56) & 0xff;
242 aBuffer[1] = (aValue >> 48) & 0xff;
243 aBuffer[2] = (aValue >> 40) & 0xff;
244 aBuffer[3] = (aValue >> 32) & 0xff;
245 aBuffer[4] = (aValue >> 24) & 0xff;
246 aBuffer[5] = (aValue >> 16) & 0xff;
247 aBuffer[6] = (aValue >> 8) & 0xff;
248 aBuffer[7] = (aValue >> 0) & 0xff;
249 }
250
251 /**
252 * Writes a `UintType` integer value to a given buffer assuming big-endian encoding.
253 *
254 * @tparam UintType The unsigned int type.
255 *
256 * @param[in] aValue The value to write to buffer.
257 * @param[in] aBuffer Pointer to the buffer to write to.
258 *
259 */
260 template <typename UintType> void Write(UintType aValue, uint8_t *aBuffer);
261
Write(uint8_t aValue,uint8_t * aBuffer)262 template <> inline void Write(uint8_t aValue, uint8_t *aBuffer) { *aBuffer = aValue; }
Write(uint16_t aValue,uint8_t * aBuffer)263 template <> inline void Write(uint16_t aValue, uint8_t *aBuffer) { WriteUint16(aValue, aBuffer); }
Write(uint32_t aValue,uint8_t * aBuffer)264 template <> inline void Write(uint32_t aValue, uint8_t *aBuffer) { WriteUint32(aValue, aBuffer); }
Write(uint64_t aValue,uint8_t * aBuffer)265 template <> inline void Write(uint64_t aValue, uint8_t *aBuffer) { WriteUint64(aValue, aBuffer); }
266
267 } // namespace BigEndian
268
269 namespace LittleEndian {
270
271 #if BYTE_ORDER_BIG_ENDIAN
272
HostSwap16(uint16_t v)273 inline constexpr uint16_t HostSwap16(uint16_t v) { return Swap16(v); }
HostSwap32(uint32_t v)274 inline constexpr uint32_t HostSwap32(uint32_t v) { return Swap32(v); }
HostSwap64(uint64_t v)275 inline constexpr uint64_t HostSwap64(uint64_t v) { return Swap64(v); }
276
277 #else /* BYTE_ORDER_LITTLE_ENDIAN */
278
279 inline constexpr uint16_t HostSwap16(uint16_t v) { return v; }
280 inline constexpr uint32_t HostSwap32(uint32_t v) { return v; }
281 inline constexpr uint64_t HostSwap64(uint64_t v) { return v; }
282
283 #endif
284
285 /**
286 * This template function performs host swap on a given unsigned integer value assuming little-endian encoding.
287 *
288 * @tparam UintType The unsigned int type.
289 *
290 * @param aValue The value to host swap.
291 *
292 * @returns The host swapped value.
293 *
294 */
295 template <typename UintType> UintType HostSwap(UintType aValue);
296
HostSwap(uint8_t aValue)297 template <> inline uint8_t HostSwap(uint8_t aValue) { return aValue; }
HostSwap(uint16_t aValue)298 template <> inline uint16_t HostSwap(uint16_t aValue) { return HostSwap16(aValue); }
HostSwap(uint32_t aValue)299 template <> inline uint32_t HostSwap(uint32_t aValue) { return HostSwap32(aValue); }
HostSwap(uint64_t aValue)300 template <> inline uint64_t HostSwap(uint64_t aValue) { return HostSwap64(aValue); }
301
302 /**
303 * Reads a `uint16_t` value from a given buffer assuming little-endian encoding.
304 *
305 * @param[in] aBuffer Pointer to buffer to read from.
306 *
307 * @returns The `uint16_t` value read from buffer.
308 *
309 */
ReadUint16(const uint8_t * aBuffer)310 inline uint16_t ReadUint16(const uint8_t *aBuffer) { return static_cast<uint16_t>(aBuffer[0] | (aBuffer[1] << 8)); }
311
312 /**
313 * Reads a 24-bit integer value from a given buffer assuming little-endian encoding.
314 *
315 * @param[in] aBuffer Pointer to buffer to read from.
316 *
317 * @returns The value read from buffer.
318 *
319 */
ReadUint24(const uint8_t * aBuffer)320 inline uint32_t ReadUint24(const uint8_t *aBuffer)
321 {
322 return ((static_cast<uint32_t>(aBuffer[0]) << 0) | (static_cast<uint32_t>(aBuffer[1]) << 8) |
323 (static_cast<uint32_t>(aBuffer[2]) << 16));
324 }
325
326 /**
327 * Reads a `uint32_t` value from a given buffer assuming little-endian encoding.
328 *
329 * @param[in] aBuffer Pointer to buffer to read from.
330 *
331 * @returns The `uint32_t` value read from buffer.
332 *
333 */
ReadUint32(const uint8_t * aBuffer)334 inline uint32_t ReadUint32(const uint8_t *aBuffer)
335 {
336 return ((static_cast<uint32_t>(aBuffer[0]) << 0) | (static_cast<uint32_t>(aBuffer[1]) << 8) |
337 (static_cast<uint32_t>(aBuffer[2]) << 16) | (static_cast<uint32_t>(aBuffer[3]) << 24));
338 }
339
340 /**
341 * Reads a `uint64_t` value from a given buffer assuming little-endian encoding.
342 *
343 * @param[in] aBuffer Pointer to buffer to read from.
344 *
345 * @returns The `uint64_t` value read from buffer.
346 *
347 */
ReadUint64(const uint8_t * aBuffer)348 inline uint64_t ReadUint64(const uint8_t *aBuffer)
349 {
350 return ((static_cast<uint64_t>(aBuffer[0]) << 0) | (static_cast<uint64_t>(aBuffer[1]) << 8) |
351 (static_cast<uint64_t>(aBuffer[2]) << 16) | (static_cast<uint64_t>(aBuffer[3]) << 24) |
352 (static_cast<uint64_t>(aBuffer[4]) << 32) | (static_cast<uint64_t>(aBuffer[5]) << 40) |
353 (static_cast<uint64_t>(aBuffer[6]) << 48) | (static_cast<uint64_t>(aBuffer[7]) << 56));
354 }
355
356 /**
357 * Reads a `UintType` integer value from a given buffer assuming little-endian encoding.
358 *
359 * @tparam UintType The unsigned int type.
360 *
361 * @param[in] aBuffer Pointer to the buffer to read from.
362 *
363 * @returns The `UintType` value read from the buffer.
364 *
365 */
366 template <typename UintType> UintType Read(const uint8_t *aBuffer);
367
Read(const uint8_t * aBuffer)368 template <> inline uint8_t Read(const uint8_t *aBuffer) { return *aBuffer; }
Read(const uint8_t * aBuffer)369 template <> inline uint16_t Read(const uint8_t *aBuffer) { return ReadUint16(aBuffer); }
Read(const uint8_t * aBuffer)370 template <> inline uint32_t Read(const uint8_t *aBuffer) { return ReadUint32(aBuffer); }
Read(const uint8_t * aBuffer)371 template <> inline uint64_t Read(const uint8_t *aBuffer) { return ReadUint64(aBuffer); }
372
373 /**
374 * Writes a `uint16_t` value to a given buffer using little-endian encoding.
375 *
376 * @param[in] aValue The value to write to buffer.
377 * @param[out] aBuffer Pointer to buffer where the value will be written.
378 *
379 */
WriteUint16(uint16_t aValue,uint8_t * aBuffer)380 inline void WriteUint16(uint16_t aValue, uint8_t *aBuffer)
381 {
382 aBuffer[0] = (aValue >> 0) & 0xff;
383 aBuffer[1] = (aValue >> 8) & 0xff;
384 }
385
386 /**
387 * Writes a 24-bit integer value to a given buffer using little-endian encoding.
388 *
389 * @param[in] aValue The value to write to buffer.
390 * @param[out] aBuffer Pointer to buffer where the value will be written.
391 *
392 */
WriteUint24(uint32_t aValue,uint8_t * aBuffer)393 inline void WriteUint24(uint32_t aValue, uint8_t *aBuffer)
394 {
395 aBuffer[0] = (aValue >> 0) & 0xff;
396 aBuffer[1] = (aValue >> 8) & 0xff;
397 aBuffer[2] = (aValue >> 16) & 0xff;
398 }
399
400 /**
401 * Writes a `uint32_t` value to a given buffer using little-endian encoding.
402 *
403 * @param[in] aValue The value to write to buffer.
404 * @param[out] aBuffer Pointer to buffer where the value will be written.
405 *
406 */
WriteUint32(uint32_t aValue,uint8_t * aBuffer)407 inline void WriteUint32(uint32_t aValue, uint8_t *aBuffer)
408 {
409 aBuffer[0] = (aValue >> 0) & 0xff;
410 aBuffer[1] = (aValue >> 8) & 0xff;
411 aBuffer[2] = (aValue >> 16) & 0xff;
412 aBuffer[3] = (aValue >> 24) & 0xff;
413 }
414
415 /**
416 * Writes a `uint64_t` value to a given buffer using little-endian encoding.
417 *
418 * @param[in] aValue The value to write to buffer.
419 * @param[out] aBuffer Pointer to buffer where the value will be written.
420 *
421 */
WriteUint64(uint64_t aValue,uint8_t * aBuffer)422 inline void WriteUint64(uint64_t aValue, uint8_t *aBuffer)
423 {
424 aBuffer[0] = (aValue >> 0) & 0xff;
425 aBuffer[1] = (aValue >> 8) & 0xff;
426 aBuffer[2] = (aValue >> 16) & 0xff;
427 aBuffer[3] = (aValue >> 24) & 0xff;
428 aBuffer[4] = (aValue >> 32) & 0xff;
429 aBuffer[5] = (aValue >> 40) & 0xff;
430 aBuffer[6] = (aValue >> 48) & 0xff;
431 aBuffer[7] = (aValue >> 56) & 0xff;
432 }
433
434 /**
435 * Writes a `UintType` integer value to a given buffer assuming little-endian encoding.
436 *
437 * @tparam UintType The unsigned int type.
438 *
439 * @param[in] aValue The value to write to buffer.
440 * @param[in] aBuffer Pointer to the buffer to write to.
441 *
442 */
443 template <typename UintType> void Write(UintType aValue, uint8_t *aBuffer);
444
Write(uint8_t aValue,uint8_t * aBuffer)445 template <> inline void Write(uint8_t aValue, uint8_t *aBuffer) { *aBuffer = aValue; }
Write(uint16_t aValue,uint8_t * aBuffer)446 template <> inline void Write(uint16_t aValue, uint8_t *aBuffer) { WriteUint16(aValue, aBuffer); }
Write(uint32_t aValue,uint8_t * aBuffer)447 template <> inline void Write(uint32_t aValue, uint8_t *aBuffer) { WriteUint32(aValue, aBuffer); }
Write(uint64_t aValue,uint8_t * aBuffer)448 template <> inline void Write(uint64_t aValue, uint8_t *aBuffer) { WriteUint64(aValue, aBuffer); }
449
450 } // namespace LittleEndian
451
452 } // namespace ot
453
454 #endif // ENCODING_HPP_
455