1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtCore module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #ifndef QENDIAN_H |
43 | #define QENDIAN_H |
44 | |
45 | #include <QtCore/qglobal.h> |
46 | |
47 | // include stdlib.h and hope that it defines __GLIBC__ for glibc-based systems |
48 | #include <stdlib.h> |
49 | |
50 | #ifdef __GLIBC__ |
51 | #include <byteswap.h> |
52 | #endif |
53 | |
54 | QT_BEGIN_HEADER |
55 | |
56 | QT_BEGIN_NAMESPACE |
57 | |
58 | QT_MODULE(Core) |
59 | |
60 | /* |
61 | * ENDIAN FUNCTIONS |
62 | */ |
63 | inline void qbswap_helper(const uchar *src, uchar *dest, int size) |
64 | { |
65 | for (int i = 0; i < size ; ++i) dest[i] = src[size - 1 - i]; |
66 | } |
67 | |
68 | /* |
69 | * qbswap(const T src, const uchar *dest); |
70 | * Changes the byte order of \a src from big endian to little endian or vice versa |
71 | * and stores the result in \a dest. |
72 | * There is no alignment requirements for \a dest. |
73 | */ |
74 | template <typename T> inline void qbswap(const T src, uchar *dest) |
75 | { |
76 | qbswap_helper(reinterpret_cast<const uchar *>(&src), dest, sizeof(T)); |
77 | } |
78 | |
79 | // Used to implement a type-safe and alignment-safe copy operation |
80 | // If you want to avoid the memcopy, you must write specializations for this function |
81 | template <typename T> inline void qToUnaligned(const T src, uchar *dest) |
82 | { |
83 | qMemCopy(dest, &src, sizeof(T)); |
84 | } |
85 | |
86 | /* T qFromLittleEndian(const uchar *src) |
87 | * This function will read a little-endian encoded value from \a src |
88 | * and return the value in host-endian encoding. |
89 | * There is no requirement that \a src must be aligned. |
90 | */ |
91 | #if defined Q_CC_SUN |
92 | inline quint64 qFromLittleEndian_helper(const uchar *src, quint64 *dest) |
93 | { |
94 | return 0 |
95 | | src[0] |
96 | | src[1] * Q_UINT64_C(0x0000000000000100) |
97 | | src[2] * Q_UINT64_C(0x0000000000010000) |
98 | | src[3] * Q_UINT64_C(0x0000000001000000) |
99 | | src[4] * Q_UINT64_C(0x0000000100000000) |
100 | | src[5] * Q_UINT64_C(0x0000010000000000) |
101 | | src[6] * Q_UINT64_C(0x0001000000000000) |
102 | | src[7] * Q_UINT64_C(0x0100000000000000); |
103 | } |
104 | |
105 | inline quint32 qFromLittleEndian_helper(const uchar *src, quint32 *dest) |
106 | { |
107 | return 0 |
108 | | src[0] |
109 | | src[1] * quint32(0x00000100) |
110 | | src[2] * quint32(0x00010000) |
111 | | src[3] * quint32(0x01000000); |
112 | } |
113 | |
114 | inline quint16 qFromLittleEndian_helper(const uchar *src, quint16 *dest) |
115 | { |
116 | return 0 |
117 | | src[0] |
118 | | src[1] * 0x0100; |
119 | } |
120 | |
121 | inline qint64 qFromLittleEndian_helper(const uchar *src, qint64 * dest) |
122 | { return static_cast<qint64>(qFromLittleEndian_helper(src, reinterpret_cast<quint64*>(0))); } |
123 | inline qint32 qFromLittleEndian_helper(const uchar *src, qint32 * dest) |
124 | { return static_cast<qint32>(qFromLittleEndian_helper(src, reinterpret_cast<quint32*>(0))); } |
125 | inline qint16 qFromLittleEndian_helper(const uchar *src, qint16 * dest) |
126 | { return static_cast<qint16>(qFromLittleEndian_helper(src, reinterpret_cast<quint16*>(0))); } |
127 | |
128 | template <class T> inline T qFromLittleEndian(const uchar *src) |
129 | { |
130 | return qFromLittleEndian_helper(src, reinterpret_cast<T*>(0)); |
131 | } |
132 | |
133 | #else |
134 | template <typename T> inline T qFromLittleEndian(const uchar *src); |
135 | template <> inline quint64 qFromLittleEndian<quint64>(const uchar *src) |
136 | { |
137 | return 0 |
138 | | src[0] |
139 | | src[1] * Q_UINT64_C(0x0000000000000100) |
140 | | src[2] * Q_UINT64_C(0x0000000000010000) |
141 | | src[3] * Q_UINT64_C(0x0000000001000000) |
142 | | src[4] * Q_UINT64_C(0x0000000100000000) |
143 | | src[5] * Q_UINT64_C(0x0000010000000000) |
144 | | src[6] * Q_UINT64_C(0x0001000000000000) |
145 | | src[7] * Q_UINT64_C(0x0100000000000000); |
146 | } |
147 | |
148 | template <> inline quint32 qFromLittleEndian<quint32>(const uchar *src) |
149 | { |
150 | return 0 |
151 | | src[0] |
152 | | src[1] * quint32(0x00000100) |
153 | | src[2] * quint32(0x00010000) |
154 | | src[3] * quint32(0x01000000); |
155 | } |
156 | |
157 | template <> inline quint16 qFromLittleEndian<quint16>(const uchar *src) |
158 | { |
159 | return quint16(0 |
160 | | src[0] |
161 | | src[1] * 0x0100); |
162 | } |
163 | |
164 | // signed specializations |
165 | template <> inline qint64 qFromLittleEndian<qint64>(const uchar *src) |
166 | { return static_cast<qint64>(qFromLittleEndian<quint64>(src)); } |
167 | |
168 | template <> inline qint32 qFromLittleEndian<qint32>(const uchar *src) |
169 | { return static_cast<qint32>(qFromLittleEndian<quint32>(src)); } |
170 | |
171 | template <> inline qint16 qFromLittleEndian<qint16>(const uchar *src) |
172 | { return static_cast<qint16>(qFromLittleEndian<quint16>(src)); } |
173 | #endif |
174 | |
175 | /* This function will read a big-endian (also known as network order) encoded value from \a src |
176 | * and return the value in host-endian encoding. |
177 | * There is no requirement that \a src must be aligned. |
178 | */ |
179 | #if defined Q_CC_SUN |
180 | inline quint64 qFromBigEndian_helper(const uchar *src, quint64 *dest) |
181 | { |
182 | return 0 |
183 | | src[7] |
184 | | src[6] * Q_UINT64_C(0x0000000000000100) |
185 | | src[5] * Q_UINT64_C(0x0000000000010000) |
186 | | src[4] * Q_UINT64_C(0x0000000001000000) |
187 | | src[3] * Q_UINT64_C(0x0000000100000000) |
188 | | src[2] * Q_UINT64_C(0x0000010000000000) |
189 | | src[1] * Q_UINT64_C(0x0001000000000000) |
190 | | src[0] * Q_UINT64_C(0x0100000000000000); |
191 | } |
192 | |
193 | inline quint32 qFromBigEndian_helper(const uchar *src, quint32 * dest) |
194 | { |
195 | return 0 |
196 | | src[3] |
197 | | src[2] * quint32(0x00000100) |
198 | | src[1] * quint32(0x00010000) |
199 | | src[0] * quint32(0x01000000); |
200 | } |
201 | |
202 | inline quint16 qFromBigEndian_helper(const uchar *src, quint16 * des) |
203 | { |
204 | return 0 |
205 | | src[1] |
206 | | src[0] * 0x0100; |
207 | } |
208 | |
209 | |
210 | inline qint64 qFromBigEndian_helper(const uchar *src, qint64 * dest) |
211 | { return static_cast<qint64>(qFromBigEndian_helper(src, reinterpret_cast<quint64*>(0))); } |
212 | inline qint32 qFromBigEndian_helper(const uchar *src, qint32 * dest) |
213 | { return static_cast<qint32>(qFromBigEndian_helper(src, reinterpret_cast<quint32*>(0))); } |
214 | inline qint16 qFromBigEndian_helper(const uchar *src, qint16 * dest) |
215 | { return static_cast<qint16>(qFromBigEndian_helper(src, reinterpret_cast<quint16*>(0))); } |
216 | |
217 | template <class T> inline T qFromBigEndian(const uchar *src) |
218 | { |
219 | return qFromBigEndian_helper(src, reinterpret_cast<T*>(0)); |
220 | } |
221 | |
222 | #else |
223 | template <class T> inline T qFromBigEndian(const uchar *src); |
224 | template<> |
225 | inline quint64 qFromBigEndian<quint64>(const uchar *src) |
226 | { |
227 | return 0 |
228 | | src[7] |
229 | | src[6] * Q_UINT64_C(0x0000000000000100) |
230 | | src[5] * Q_UINT64_C(0x0000000000010000) |
231 | | src[4] * Q_UINT64_C(0x0000000001000000) |
232 | | src[3] * Q_UINT64_C(0x0000000100000000) |
233 | | src[2] * Q_UINT64_C(0x0000010000000000) |
234 | | src[1] * Q_UINT64_C(0x0001000000000000) |
235 | | src[0] * Q_UINT64_C(0x0100000000000000); |
236 | } |
237 | |
238 | template<> |
239 | inline quint32 qFromBigEndian<quint32>(const uchar *src) |
240 | { |
241 | return 0 |
242 | | src[3] |
243 | | src[2] * quint32(0x00000100) |
244 | | src[1] * quint32(0x00010000) |
245 | | src[0] * quint32(0x01000000); |
246 | } |
247 | |
248 | template<> |
249 | inline quint16 qFromBigEndian<quint16>(const uchar *src) |
250 | { |
251 | return quint16( 0 |
252 | | src[1] |
253 | | src[0] * quint16(0x0100)); |
254 | } |
255 | |
256 | |
257 | // signed specializations |
258 | template <> inline qint64 qFromBigEndian<qint64>(const uchar *src) |
259 | { return static_cast<qint64>(qFromBigEndian<quint64>(src)); } |
260 | |
261 | template <> inline qint32 qFromBigEndian<qint32>(const uchar *src) |
262 | { return static_cast<qint32>(qFromBigEndian<quint32>(src)); } |
263 | |
264 | template <> inline qint16 qFromBigEndian<qint16>(const uchar *src) |
265 | { return static_cast<qint16>(qFromBigEndian<quint16>(src)); } |
266 | #endif |
267 | /* |
268 | * T qbswap(T source). |
269 | * Changes the byte order of a value from big endian to little endian or vice versa. |
270 | * This function can be used if you are not concerned about alignment issues, |
271 | * and it is therefore a bit more convenient and in most cases more efficient. |
272 | */ |
273 | template <typename T> T qbswap(T source); |
274 | |
275 | #ifdef __GLIBC__ |
276 | template <> inline quint64 qbswap<quint64>(quint64 source) |
277 | { |
278 | return bswap_64(source); |
279 | } |
280 | template <> inline quint32 qbswap<quint32>(quint32 source) |
281 | { |
282 | return bswap_32(source); |
283 | } |
284 | template <> inline quint16 qbswap<quint16>(quint16 source) |
285 | { |
286 | return bswap_16(source); |
287 | } |
288 | #else |
289 | template <> inline quint64 qbswap<quint64>(quint64 source) |
290 | { |
291 | return 0 |
292 | | ((source & Q_UINT64_C(0x00000000000000ff)) << 56) |
293 | | ((source & Q_UINT64_C(0x000000000000ff00)) << 40) |
294 | | ((source & Q_UINT64_C(0x0000000000ff0000)) << 24) |
295 | | ((source & Q_UINT64_C(0x00000000ff000000)) << 8) |
296 | | ((source & Q_UINT64_C(0x000000ff00000000)) >> 8) |
297 | | ((source & Q_UINT64_C(0x0000ff0000000000)) >> 24) |
298 | | ((source & Q_UINT64_C(0x00ff000000000000)) >> 40) |
299 | | ((source & Q_UINT64_C(0xff00000000000000)) >> 56); |
300 | } |
301 | |
302 | template <> inline quint32 qbswap<quint32>(quint32 source) |
303 | { |
304 | return 0 |
305 | | ((source & 0x000000ff) << 24) |
306 | | ((source & 0x0000ff00) << 8) |
307 | | ((source & 0x00ff0000) >> 8) |
308 | | ((source & 0xff000000) >> 24); |
309 | } |
310 | |
311 | template <> inline quint16 qbswap<quint16>(quint16 source) |
312 | { |
313 | return quint16( 0 |
314 | | ((source & 0x00ff) << 8) |
315 | | ((source & 0xff00) >> 8) ); |
316 | } |
317 | #endif // __GLIBC__ |
318 | |
319 | // signed specializations |
320 | template <> inline qint64 qbswap<qint64>(qint64 source) |
321 | { |
322 | return qbswap<quint64>(quint64(source)); |
323 | } |
324 | |
325 | template <> inline qint32 qbswap<qint32>(qint32 source) |
326 | { |
327 | return qbswap<quint32>(quint32(source)); |
328 | } |
329 | |
330 | template <> inline qint16 qbswap<qint16>(qint16 source) |
331 | { |
332 | return qbswap<quint16>(quint16(source)); |
333 | } |
334 | |
335 | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
336 | |
337 | template <typename T> inline T qToBigEndian(T source) |
338 | { return source; } |
339 | template <typename T> inline T qFromBigEndian(T source) |
340 | { return source; } |
341 | template <typename T> inline T qToLittleEndian(T source) |
342 | { return qbswap<T>(source); } |
343 | template <typename T> inline T qFromLittleEndian(T source) |
344 | { return qbswap<T>(source); } |
345 | template <typename T> inline void qToBigEndian(T src, uchar *dest) |
346 | { qToUnaligned<T>(src, dest); } |
347 | template <typename T> inline void qToLittleEndian(T src, uchar *dest) |
348 | { qbswap<T>(src, dest); } |
349 | #else // Q_LITTLE_ENDIAN |
350 | |
351 | template <typename T> inline T qToBigEndian(T source) |
352 | { return qbswap<T>(source); } |
353 | template <typename T> inline T qFromBigEndian(T source) |
354 | { return qbswap<T>(source); } |
355 | template <typename T> inline T qToLittleEndian(T source) |
356 | { return source; } |
357 | template <typename T> inline T qFromLittleEndian(T source) |
358 | { return source; } |
359 | template <typename T> inline void qToBigEndian(T src, uchar *dest) |
360 | { qbswap<T>(src, dest); } |
361 | template <typename T> inline void qToLittleEndian(T src, uchar *dest) |
362 | { qToUnaligned<T>(src, dest); } |
363 | |
364 | #endif // Q_BYTE_ORDER == Q_BIG_ENDIAN |
365 | |
366 | template <> inline quint8 qbswap<quint8>(quint8 source) |
367 | { |
368 | return source; |
369 | } |
370 | |
371 | QT_END_NAMESPACE |
372 | |
373 | QT_END_HEADER |
374 | |
375 | #endif // QENDIAN_H |
376 | |