• 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 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