• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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