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