1
/****************************************************************************
2
**
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
**
7
** This file is part of the QtCore module of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
33
**
34
**
35
**
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