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
25namespace Poco {
26
27
28class 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{
33public:
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
99private:
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//
134inline 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
144inline Int16 ByteOrder::flipBytes(Int16 value)
145{
146 return Int16(flipBytes(UInt16(value)));
147}
148
149
150inline 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
163inline Int32 ByteOrder::flipBytes(Int32 value)
164{
165 return Int32(flipBytes(UInt32(value)));
166}
167
168
169inline float ByteOrder::flipBytes(float value)
170{
171 return flip(value);
172}
173
174
175inline double ByteOrder::flipBytes(double value)
176{
177 return flip(value);
178}
179
180
181#if defined(POCO_HAVE_INT64)
182inline 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
196inline 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
256POCO_IMPLEMENT_BYTEORDER_BIG(toBigEndian)
257POCO_IMPLEMENT_BYTEORDER_BIG(fromBigEndian)
258POCO_IMPLEMENT_BYTEORDER_BIG(toNetwork)
259POCO_IMPLEMENT_BYTEORDER_BIG(fromNetwork)
260POCO_IMPLEMENT_BYTEORDER_LIT(toLittleEndian)
261POCO_IMPLEMENT_BYTEORDER_LIT(fromLittleEndian)
262
263
264} // namespace Poco
265
266
267#endif // Foundation_ByteOrder_INCLUDED
268