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
54QT_BEGIN_HEADER
55
56QT_BEGIN_NAMESPACE
57
58QT_MODULE(Core)
59
60/*
61 * ENDIAN FUNCTIONS
62*/
63inline 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*/
74template <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
81template <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
92inline 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
105inline 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
114inline quint16 qFromLittleEndian_helper(const uchar *src, quint16 *dest)
115{
116 return 0
117 | src[0]
118 | src[1] * 0x0100;
119}
120
121inline qint64 qFromLittleEndian_helper(const uchar *src, qint64 * dest)
122{ return static_cast<qint64>(qFromLittleEndian_helper(src, reinterpret_cast<quint64*>(0))); }
123inline qint32 qFromLittleEndian_helper(const uchar *src, qint32 * dest)
124{ return static_cast<qint32>(qFromLittleEndian_helper(src, reinterpret_cast<quint32*>(0))); }
125inline qint16 qFromLittleEndian_helper(const uchar *src, qint16 * dest)
126{ return static_cast<qint16>(qFromLittleEndian_helper(src, reinterpret_cast<quint16*>(0))); }
127
128template <class T> inline T qFromLittleEndian(const uchar *src)
129{
130 return qFromLittleEndian_helper(src, reinterpret_cast<T*>(0));
131}
132
133#else
134template <typename T> inline T qFromLittleEndian(const uchar *src);
135template <> 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
148template <> 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
157template <> inline quint16 qFromLittleEndian<quint16>(const uchar *src)
158{
159 return quint16(0
160 | src[0]
161 | src[1] * 0x0100);
162}
163
164// signed specializations
165template <> inline qint64 qFromLittleEndian<qint64>(const uchar *src)
166{ return static_cast<qint64>(qFromLittleEndian<quint64>(src)); }
167
168template <> inline qint32 qFromLittleEndian<qint32>(const uchar *src)
169{ return static_cast<qint32>(qFromLittleEndian<quint32>(src)); }
170
171template <> 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
180inline 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
193inline 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
202inline quint16 qFromBigEndian_helper(const uchar *src, quint16 * des)
203{
204 return 0
205 | src[1]
206 | src[0] * 0x0100;
207}
208
209
210inline qint64 qFromBigEndian_helper(const uchar *src, qint64 * dest)
211{ return static_cast<qint64>(qFromBigEndian_helper(src, reinterpret_cast<quint64*>(0))); }
212inline qint32 qFromBigEndian_helper(const uchar *src, qint32 * dest)
213{ return static_cast<qint32>(qFromBigEndian_helper(src, reinterpret_cast<quint32*>(0))); }
214inline qint16 qFromBigEndian_helper(const uchar *src, qint16 * dest)
215{ return static_cast<qint16>(qFromBigEndian_helper(src, reinterpret_cast<quint16*>(0))); }
216
217template <class T> inline T qFromBigEndian(const uchar *src)
218{
219 return qFromBigEndian_helper(src, reinterpret_cast<T*>(0));
220}
221
222#else
223template <class T> inline T qFromBigEndian(const uchar *src);
224template<>
225inline 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
238template<>
239inline 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
248template<>
249inline 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
258template <> inline qint64 qFromBigEndian<qint64>(const uchar *src)
259{ return static_cast<qint64>(qFromBigEndian<quint64>(src)); }
260
261template <> inline qint32 qFromBigEndian<qint32>(const uchar *src)
262{ return static_cast<qint32>(qFromBigEndian<quint32>(src)); }
263
264template <> 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*/
273template <typename T> T qbswap(T source);
274
275#ifdef __GLIBC__
276template <> inline quint64 qbswap<quint64>(quint64 source)
277{
278 return bswap_64(source);
279}
280template <> inline quint32 qbswap<quint32>(quint32 source)
281{
282 return bswap_32(source);
283}
284template <> inline quint16 qbswap<quint16>(quint16 source)
285{
286 return bswap_16(source);
287}
288#else
289template <> 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
302template <> 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
311template <> 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
320template <> inline qint64 qbswap<qint64>(qint64 source)
321{
322 return qbswap<quint64>(quint64(source));
323}
324
325template <> inline qint32 qbswap<qint32>(qint32 source)
326{
327 return qbswap<quint32>(quint32(source));
328}
329
330template <> inline qint16 qbswap<qint16>(qint16 source)
331{
332 return qbswap<quint16>(quint16(source));
333}
334
335#if Q_BYTE_ORDER == Q_BIG_ENDIAN
336
337template <typename T> inline T qToBigEndian(T source)
338{ return source; }
339template <typename T> inline T qFromBigEndian(T source)
340{ return source; }
341template <typename T> inline T qToLittleEndian(T source)
342{ return qbswap<T>(source); }
343template <typename T> inline T qFromLittleEndian(T source)
344{ return qbswap<T>(source); }
345template <typename T> inline void qToBigEndian(T src, uchar *dest)
346{ qToUnaligned<T>(src, dest); }
347template <typename T> inline void qToLittleEndian(T src, uchar *dest)
348{ qbswap<T>(src, dest); }
349#else // Q_LITTLE_ENDIAN
350
351template <typename T> inline T qToBigEndian(T source)
352{ return qbswap<T>(source); }
353template <typename T> inline T qFromBigEndian(T source)
354{ return qbswap<T>(source); }
355template <typename T> inline T qToLittleEndian(T source)
356{ return source; }
357template <typename T> inline T qFromLittleEndian(T source)
358{ return source; }
359template <typename T> inline void qToBigEndian(T src, uchar *dest)
360{ qbswap<T>(src, dest); }
361template <typename T> inline void qToLittleEndian(T src, uchar *dest)
362{ qToUnaligned<T>(src, dest); }
363
364#endif // Q_BYTE_ORDER == Q_BIG_ENDIAN
365
366template <> inline quint8 qbswap<quint8>(quint8 source)
367{
368 return source;
369}
370
371QT_END_NAMESPACE
372
373QT_END_HEADER
374
375#endif // QENDIAN_H
376