1 | // |
2 | // ByteOrder.h |
3 | // |
4 | // Library: Foundation |
5 | // Package: Core |
6 | // Module: ByteOrder |
7 | // |
8 | // Copyright (c) 2004-2014, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #ifndef Foundation_ByteOrder_INCLUDED |
16 | #define Foundation_ByteOrder_INCLUDED |
17 | |
18 | |
19 | #include "Poco/Foundation.h" |
20 | #include "Poco/Types.h" |
21 | #if defined(_MSC_VER) |
22 | #include <stdlib.h> // builtins |
23 | #endif |
24 | |
25 | namespace Poco { |
26 | |
27 | |
28 | class Foundation_API ByteOrder |
29 | /// This class contains a number of static methods |
30 | /// to convert between big-endian and little-endian |
31 | /// integers of various sizes. |
32 | { |
33 | public: |
34 | static Int16 flipBytes(Int16 value); |
35 | static UInt16 flipBytes(UInt16 value); |
36 | static Int32 flipBytes(Int32 value); |
37 | static UInt32 flipBytes(UInt32 value); |
38 | static float flipBytes(float value); |
39 | static double flipBytes(double value); |
40 | #if defined(POCO_HAVE_INT64) |
41 | static Int64 flipBytes(Int64 value); |
42 | static UInt64 flipBytes(UInt64 value); |
43 | #endif |
44 | |
45 | static Int16 toBigEndian(Int16 value); |
46 | static UInt16 toBigEndian (UInt16 value); |
47 | static Int32 toBigEndian(Int32 value); |
48 | static UInt32 toBigEndian (UInt32 value); |
49 | #if defined(POCO_HAVE_INT64) |
50 | static Int64 toBigEndian(Int64 value); |
51 | static UInt64 toBigEndian (UInt64 value); |
52 | #endif |
53 | |
54 | static Int16 fromBigEndian(Int16 value); |
55 | static UInt16 fromBigEndian (UInt16 value); |
56 | static Int32 fromBigEndian(Int32 value); |
57 | static UInt32 fromBigEndian (UInt32 value); |
58 | #if defined(POCO_HAVE_INT64) |
59 | static Int64 fromBigEndian(Int64 value); |
60 | static UInt64 fromBigEndian (UInt64 value); |
61 | #endif |
62 | |
63 | static Int16 toLittleEndian(Int16 value); |
64 | static UInt16 toLittleEndian (UInt16 value); |
65 | static Int32 toLittleEndian(Int32 value); |
66 | static UInt32 toLittleEndian (UInt32 value); |
67 | #if defined(POCO_HAVE_INT64) |
68 | static Int64 toLittleEndian(Int64 value); |
69 | static UInt64 toLittleEndian (UInt64 value); |
70 | #endif |
71 | |
72 | static Int16 fromLittleEndian(Int16 value); |
73 | static UInt16 fromLittleEndian (UInt16 value); |
74 | static Int32 fromLittleEndian(Int32 value); |
75 | static UInt32 fromLittleEndian (UInt32 value); |
76 | #if defined(POCO_HAVE_INT64) |
77 | static Int64 fromLittleEndian(Int64 value); |
78 | static UInt64 fromLittleEndian (UInt64 value); |
79 | #endif |
80 | |
81 | static Int16 toNetwork(Int16 value); |
82 | static UInt16 toNetwork (UInt16 value); |
83 | static Int32 toNetwork(Int32 value); |
84 | static UInt32 toNetwork (UInt32 value); |
85 | #if defined(POCO_HAVE_INT64) |
86 | static Int64 toNetwork(Int64 value); |
87 | static UInt64 toNetwork (UInt64 value); |
88 | #endif |
89 | |
90 | static Int16 fromNetwork(Int16 value); |
91 | static UInt16 fromNetwork (UInt16 value); |
92 | static Int32 fromNetwork(Int32 value); |
93 | static UInt32 fromNetwork (UInt32 value); |
94 | #if defined(POCO_HAVE_INT64) |
95 | static Int64 fromNetwork(Int64 value); |
96 | static UInt64 fromNetwork (UInt64 value); |
97 | #endif |
98 | |
99 | private: |
100 | template<typename T> |
101 | static T flip(T value) |
102 | { |
103 | T flip = value; |
104 | std::size_t halfSize = sizeof(T) / 2; |
105 | char* flipP = reinterpret_cast<char*>(&flip); |
106 | |
107 | for (std::size_t i = 0; i < halfSize; i++) |
108 | { |
109 | std::swap(flipP[i], flipP[sizeof(T) - i - 1]); |
110 | } |
111 | return flip; |
112 | } |
113 | }; |
114 | |
115 | |
116 | #if !defined(POCO_NO_BYTESWAP_BUILTINS) |
117 | #if defined(_MSC_VER) |
118 | #if (POCO_MSVC_VERSION > 71) |
119 | #define POCO_HAVE_MSC_BYTESWAP 1 |
120 | #endif |
121 | #elif defined(__clang__) |
122 | #if __has_builtin(__builtin_bswap32) |
123 | #define POCO_HAVE_GCC_BYTESWAP 1 |
124 | #endif |
125 | #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) |
126 | #define POCO_HAVE_GCC_BYTESWAP 1 |
127 | #endif |
128 | #endif |
129 | |
130 | |
131 | // |
132 | // inlines |
133 | // |
134 | inline UInt16 ByteOrder::flipBytes(UInt16 value) |
135 | { |
136 | #if defined(POCO_HAVE_MSC_BYTESWAP) |
137 | return _byteswap_ushort(value); |
138 | #else |
139 | return ((value >> 8) & 0x00FF) | ((value << 8) & 0xFF00); |
140 | #endif |
141 | } |
142 | |
143 | |
144 | inline Int16 ByteOrder::flipBytes(Int16 value) |
145 | { |
146 | return Int16(flipBytes(UInt16(value))); |
147 | } |
148 | |
149 | |
150 | inline UInt32 ByteOrder::flipBytes(UInt32 value) |
151 | { |
152 | #if defined(POCO_HAVE_MSC_BYTESWAP) |
153 | return _byteswap_ulong(value); |
154 | #elif defined(POCO_HAVE_GCC_BYTESWAP) |
155 | return __builtin_bswap32(value); |
156 | #else |
157 | return ((value >> 24) & 0x000000FF) | ((value >> 8) & 0x0000FF00) |
158 | | ((value << 8) & 0x00FF0000) | ((value << 24) & 0xFF000000); |
159 | #endif |
160 | } |
161 | |
162 | |
163 | inline Int32 ByteOrder::flipBytes(Int32 value) |
164 | { |
165 | return Int32(flipBytes(UInt32(value))); |
166 | } |
167 | |
168 | |
169 | inline float ByteOrder::flipBytes(float value) |
170 | { |
171 | return flip(value); |
172 | } |
173 | |
174 | |
175 | inline double ByteOrder::flipBytes(double value) |
176 | { |
177 | return flip(value); |
178 | } |
179 | |
180 | |
181 | #if defined(POCO_HAVE_INT64) |
182 | inline UInt64 ByteOrder::flipBytes(UInt64 value) |
183 | { |
184 | #if defined(POCO_HAVE_MSC_BYTESWAP) |
185 | return _byteswap_uint64(value); |
186 | #elif defined(POCO_HAVE_GCC_BYTESWAP) |
187 | return __builtin_bswap64(value); |
188 | #else |
189 | UInt32 hi = UInt32(value >> 32); |
190 | UInt32 lo = UInt32(value & 0xFFFFFFFF); |
191 | return UInt64(flipBytes(hi)) | (UInt64(flipBytes(lo)) << 32); |
192 | #endif |
193 | } |
194 | |
195 | |
196 | inline Int64 ByteOrder::flipBytes(Int64 value) |
197 | { |
198 | return Int64(flipBytes(UInt64(value))); |
199 | } |
200 | #endif // POCO_HAVE_INT64 |
201 | |
202 | |
203 | // |
204 | // some macro trickery to automate the method implementation |
205 | // |
206 | #define POCO_IMPLEMENT_BYTEORDER_NOOP_(op, type) \ |
207 | inline type ByteOrder::op(type value) \ |
208 | { \ |
209 | return value; \ |
210 | } |
211 | #define POCO_IMPLEMENT_BYTEORDER_FLIP_(op, type) \ |
212 | inline type ByteOrder::op(type value) \ |
213 | { \ |
214 | return flipBytes(value); \ |
215 | } |
216 | |
217 | |
218 | #if defined(POCO_HAVE_INT64) |
219 | #define POCO_IMPLEMENT_BYTEORDER_NOOP(op) \ |
220 | POCO_IMPLEMENT_BYTEORDER_NOOP_(op, Int16) \ |
221 | POCO_IMPLEMENT_BYTEORDER_NOOP_(op, UInt16) \ |
222 | POCO_IMPLEMENT_BYTEORDER_NOOP_(op, Int32) \ |
223 | POCO_IMPLEMENT_BYTEORDER_NOOP_(op, UInt32) \ |
224 | POCO_IMPLEMENT_BYTEORDER_NOOP_(op, Int64) \ |
225 | POCO_IMPLEMENT_BYTEORDER_NOOP_(op, UInt64) |
226 | #define POCO_IMPLEMENT_BYTEORDER_FLIP(op) \ |
227 | POCO_IMPLEMENT_BYTEORDER_FLIP_(op, Int16) \ |
228 | POCO_IMPLEMENT_BYTEORDER_FLIP_(op, UInt16) \ |
229 | POCO_IMPLEMENT_BYTEORDER_FLIP_(op, Int32) \ |
230 | POCO_IMPLEMENT_BYTEORDER_FLIP_(op, UInt32) \ |
231 | POCO_IMPLEMENT_BYTEORDER_FLIP_(op, Int64) \ |
232 | POCO_IMPLEMENT_BYTEORDER_FLIP_(op, UInt64) |
233 | #else |
234 | #define POCO_IMPLEMENT_BYTEORDER_NOOP(op) \ |
235 | POCO_IMPLEMENT_BYTEORDER_NOOP_(op, Int16) \ |
236 | POCO_IMPLEMENT_BYTEORDER_NOOP_(op, UInt16) \ |
237 | POCO_IMPLEMENT_BYTEORDER_NOOP_(op, Int32) \ |
238 | POCO_IMPLEMENT_BYTEORDER_NOOP_(op, UInt32) |
239 | #define POCO_IMPLEMENT_BYTEORDER_FLIP(op) \ |
240 | POCO_IMPLEMENT_BYTEORDER_FLIP_(op, Int16) \ |
241 | POCO_IMPLEMENT_BYTEORDER_FLIP_(op, UInt16) \ |
242 | POCO_IMPLEMENT_BYTEORDER_FLIP_(op, Int32) \ |
243 | POCO_IMPLEMENT_BYTEORDER_FLIP_(op, UInt32) |
244 | #endif |
245 | |
246 | |
247 | #if defined(POCO_ARCH_BIG_ENDIAN) |
248 | #define POCO_IMPLEMENT_BYTEORDER_BIG POCO_IMPLEMENT_BYTEORDER_NOOP |
249 | #define POCO_IMPLEMENT_BYTEORDER_LIT POCO_IMPLEMENT_BYTEORDER_FLIP |
250 | #else |
251 | #define POCO_IMPLEMENT_BYTEORDER_BIG POCO_IMPLEMENT_BYTEORDER_FLIP |
252 | #define POCO_IMPLEMENT_BYTEORDER_LIT POCO_IMPLEMENT_BYTEORDER_NOOP |
253 | #endif |
254 | |
255 | |
256 | POCO_IMPLEMENT_BYTEORDER_BIG(toBigEndian) |
257 | POCO_IMPLEMENT_BYTEORDER_BIG(fromBigEndian) |
258 | POCO_IMPLEMENT_BYTEORDER_BIG(toNetwork) |
259 | POCO_IMPLEMENT_BYTEORDER_BIG(fromNetwork) |
260 | POCO_IMPLEMENT_BYTEORDER_LIT(toLittleEndian) |
261 | POCO_IMPLEMENT_BYTEORDER_LIT(fromLittleEndian) |
262 | |
263 | |
264 | } // namespace Poco |
265 | |
266 | |
267 | #endif // Foundation_ByteOrder_INCLUDED |
268 | |