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