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