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