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