SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
ByteOrder.cpp
Go to the documentation of this file.
1 /**
2  * \file ByteOrder.cpp
3  * \date January 2021
4  * \authors Marino von Wattenwyl
5  * \copyright http://opensource.org/licenses/GPL-3.0
6  * \remarks Please use clangformat to format the code. See more code style on
7  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
8 */
9 
10 #include <ByteOrder.h>
11 #include <cstring>
12 
13 //-----------------------------------------------------------------------------
14 namespace ByteOrder
15 {
16 //-----------------------------------------------------------------------------
17 /*! Converts a 16-bit number from little-endian to big-endian regardless of the host byte order.
18  * See toBigEndian32() for an explanation of the algorithm.
19  * \param src the 16-bit number that should be converted
20  * \param dest the pointer where the big-endian result will be written to
21  */
22 void toBigEndian16(uint16_t src, char* dest)
23 {
24  char* arr = (char*)&src;
25  uint16_t res = (uint16_t)arr[0] << 8 |
26  (uint16_t)arr[1];
27  memcpy(dest, &res, 2);
28 }
29 //-----------------------------------------------------------------------------
30 /*! Converts a 32-bit number from little-endian to big-endian regardless of the host byte order.
31  * Here is an example that shows how the algorithm works:
32  *
33  * Let's say we want to convert the number 8, which has the following memory layouts:
34  *
35  * Little-endian: [8 0 0 0]
36  * Big-Endian: [0 0 0 8]
37  *
38  * Now we take the address of the number and convert it to a char pointer to
39  * get access to the individual bytes of the number:
40  *
41  * char* arr = (char*)&src;
42  *
43  * This results in the following values for the array indices:
44  *
45  * Little-endian: [0] => 8, [1] => 0, [2] => 0, [3] => 0
46  * Big-endian: [0] => 0, [1] => 0, [2] => 0, [3] => 8
47  *
48  * Next, we take all the array elements and shift them by (24 - index) bytes to the left:
49  *
50  * uint32_t res =
51  * (uint32_t)arr[0] << 24 |
52  * (uint32_t)arr[1] << 16 |
53  * (uint32_t)arr[2] << 8 |
54  * (uint32_t)arr[3] << 0;
55  *
56  * On a little-endian system, the 8 will be shifted 24 bits to the left and be the most significant
57  * byte, which is stored last in little-endian:
58  *
59  * [0 0 0 8]
60  *
61  * On a big-endian system, the 8 will not be shifted and remain the least significant byte,
62  * which is also stored last in big-endian:
63  *
64  * [0 0 0 8]
65  *
66  * We have thus achieved a host independent conversion to big-endian
67  * Finally, we copy the 4 bytes to the destination:
68  *
69  * std::memcpy(dest, &res, 4);
70  *
71  * \param src the 32-bit number that should be converted
72  * \param dest the pointer where the big-endian result will be written to
73  */
74 void toBigEndian32(uint32_t src, char* dest)
75 {
76  char* arr = (char*)&src;
77  uint32_t res = (uint32_t)arr[0] << 24 |
78  (uint32_t)arr[1] << 16 |
79  (uint32_t)arr[2] << 8 |
80  (uint32_t)arr[3];
81  memcpy(dest, &res, 4);
82 }
83 //-----------------------------------------------------------------------------
84 /*! Converts a 64-bit number from little-endian to big-endian regardless of the host byte order.
85  * See toBigEndian32() for an explanation of the algorithm.
86  * \param src the 64-bit number that should be converted
87  * \param dest the pointer where the big-endian result will be written to
88  */
89 void toBigEndian64(uint64_t src, char* dest)
90 {
91  char* arr = (char*)&src;
92  uint64_t res = (uint64_t)arr[0] << 56 |
93  (uint64_t)arr[1] << 48 |
94  (uint64_t)arr[2] << 40 |
95  (uint64_t)arr[3] << 32 |
96  (uint64_t)arr[4] << 24 |
97  (uint64_t)arr[5] << 16 |
98  (uint64_t)arr[6] << 8 |
99  (uint64_t)arr[7];
100  memcpy(dest, &res, 8);
101 }
102 //-----------------------------------------------------------------------------
103 /*! Converts a 16-bit number to big-endian and writes it to a stream
104  * \param number the number to be converted and written
105  * \param stream the destination stream
106  */
107 void writeBigEndian16(uint16_t number, std::ostream& stream)
108 {
109  char buffer[2];
110  toBigEndian16(number, buffer);
111  stream.write(buffer, 2);
112 }
113 //-----------------------------------------------------------------------------
114 /*! Converts a 32-bit number to big-endian and writes it to a stream
115  * \param number the number to be converted and written
116  * \param stream the destination stream
117  */
118 void writeBigEndian32(uint32_t number, std::ostream& stream)
119 {
120  char buffer[4];
121  toBigEndian32(number, buffer);
122  stream.write(buffer, 4);
123 }
124 //-----------------------------------------------------------------------------
125 /*! Converts a 64-bit number to big-endian and writes it to a stream
126  * \param number the number to be converted and written
127  * \param stream the destination stream
128  */
129 void writeBigEndian64(uint64_t number, std::ostream& stream)
130 {
131  char buffer[8];
132  toBigEndian64(number, buffer);
133  stream.write(buffer, 8);
134 }
135 //-----------------------------------------------------------------------------
136 } // namespace ByteOrder
137  //-----------------------------------------------------------------------------
Abort compilation if a char has not 8 bits, as functions for this case aren't implemented yet.
Definition: ByteOrder.cpp:15
void toBigEndian32(uint32_t src, char *dest)
Definition: ByteOrder.cpp:74
void toBigEndian16(uint16_t src, char *dest)
Definition: ByteOrder.cpp:22
void writeBigEndian32(uint32_t number, std::ostream &stream)
Definition: ByteOrder.cpp:118
void writeBigEndian16(uint16_t number, std::ostream &stream)
Definition: ByteOrder.cpp:107
void writeBigEndian64(uint64_t number, std::ostream &stream)
Definition: ByteOrder.cpp:129
void toBigEndian64(uint64_t src, char *dest)
Definition: ByteOrder.cpp:89