qendian.h

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
00004 ** All rights reserved.
00005 ** Contact: Nokia Corporation (qt-info@nokia.com)
00006 **
00007 ** This file is part of the QtCore module of the Qt Toolkit.
00008 **
00009 ** $QT_BEGIN_LICENSE:LGPL$
00010 ** Commercial Usage
00011 ** Licensees holding valid Qt Commercial licenses may use this file in
00012 ** accordance with the Qt Commercial License Agreement provided with the
00013 ** Software or, alternatively, in accordance with the terms contained in
00014 ** a written agreement between you and Nokia.
00015 **
00016 ** GNU Lesser General Public License Usage
00017 ** Alternatively, this file may be used under the terms of the GNU Lesser
00018 ** General Public License version 2.1 as published by the Free Software
00019 ** Foundation and appearing in the file LICENSE.LGPL included in the
00020 ** packaging of this file.  Please review the following information to
00021 ** ensure the GNU Lesser General Public License version 2.1 requirements
00022 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
00023 **
00024 ** In addition, as a special exception, Nokia gives you certain additional
00025 ** rights.  These rights are described in the Nokia Qt LGPL Exception
00026 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this module.
00027 **
00028 ** GNU General Public License Usage
00029 ** Alternatively, this file may be used under the terms of the GNU
00030 ** General Public License version 3.0 as published by the Free Software
00031 ** Foundation and appearing in the file LICENSE.GPL included in the
00032 ** packaging of this file.  Please review the following information to
00033 ** ensure the GNU General Public License version 3.0 requirements will be
00034 ** met: http://www.gnu.org/copyleft/gpl.html.
00035 **
00036 ** If you have questions regarding the use of this file, please contact
00037 ** Nokia at qt-info@nokia.com.
00038 ** $QT_END_LICENSE$
00039 **
00040 ****************************************************************************/
00041 
00042 #ifndef QENDIAN_H
00043 #define QENDIAN_H
00044 
00045 #include <QtCore/qglobal.h>
00046 
00047 #ifdef Q_OS_LINUX
00048 # include <features.h>
00049 #endif
00050 
00051 #ifdef __GLIBC__
00052 #include <byteswap.h>
00053 #endif
00054 
00055 QT_BEGIN_HEADER
00056 
00057 QT_BEGIN_NAMESPACE
00058 
00059 QT_MODULE(Core)
00060 
00061 /*
00062  * ENDIAN FUNCTIONS
00063 */
00064 inline void qbswap_helper(const uchar *src, uchar *dest, int size)
00065 {
00066     for (int i = 0; i < size ; ++i) dest[i] = src[size - 1 - i];
00067 }
00068 
00069 /*
00070  * qbswap(const T src, const uchar *dest);
00071  * Changes the byte order of \a src from big endian to little endian or vice versa
00072  * and stores the result in \a dest.
00073  * There is no alignment requirements for \a dest.
00074 */
00075 template <typename T> inline void qbswap(const T src, uchar *dest)
00076 {
00077     qbswap_helper(reinterpret_cast<const uchar *>(&src), dest, sizeof(T));
00078 }
00079 
00080 // Used to implement a type-safe and alignment-safe copy operation
00081 // If you want to avoid the memcopy, you must write specializations for this function
00082 template <typename T> inline void qToUnaligned(const T src, uchar *dest)
00083 {
00084     qMemCopy(dest, &src, sizeof(T));
00085 }
00086 
00087 /* T qFromLittleEndian(const uchar *src)
00088  * This function will read a little-endian encoded value from \a src
00089  * and return the value in host-endian encoding.
00090  * There is no requirement that \a src must be aligned.
00091 */
00092 #if defined Q_CC_MSVC && _MSC_VER < 1300 || defined Q_CC_SUN
00093 inline quint64 qFromLittleEndian_helper(const uchar *src, quint64 *dest)
00094 {
00095     return 0
00096         | src[0]
00097         | src[1] * Q_UINT64_C(0x0000000000000100)
00098         | src[2] * Q_UINT64_C(0x0000000000010000)
00099         | src[3] * Q_UINT64_C(0x0000000001000000)
00100         | src[4] * Q_UINT64_C(0x0000000100000000)
00101         | src[5] * Q_UINT64_C(0x0000010000000000)
00102         | src[6] * Q_UINT64_C(0x0001000000000000)
00103         | src[7] * Q_UINT64_C(0x0100000000000000);
00104 }
00105 
00106 inline quint32 qFromLittleEndian_helper(const uchar *src, quint32 *dest)
00107 {
00108     return 0
00109         | src[0]
00110         | src[1] * quint32(0x00000100)
00111         | src[2] * quint32(0x00010000)
00112         | src[3] * quint32(0x01000000);
00113 }
00114 
00115 inline quint16 qFromLittleEndian_helper(const uchar *src, quint16 *dest)
00116 {
00117     return 0
00118         | src[0]
00119         | src[1] * 0x0100;
00120 }
00121 
00122 inline qint64 qFromLittleEndian_helper(const uchar *src, qint64 * dest)
00123 { return static_cast<qint64>(qFromLittleEndian_helper(src, reinterpret_cast<quint64*>(0))); }
00124 inline qint32 qFromLittleEndian_helper(const uchar *src, qint32 * dest)
00125 { return static_cast<qint32>(qFromLittleEndian_helper(src, reinterpret_cast<quint32*>(0))); }
00126 inline qint16 qFromLittleEndian_helper(const uchar *src, qint16 * dest)
00127 { return static_cast<qint16>(qFromLittleEndian_helper(src, reinterpret_cast<quint16*>(0))); }
00128 
00129 template <class T> inline T qFromLittleEndian(const uchar *src)
00130 {
00131     return qFromLittleEndian_helper(src, reinterpret_cast<T*>(0));
00132 }
00133 
00134 #else
00135 template <typename T> inline T qFromLittleEndian(const uchar *src);
00136 template <> inline quint64 qFromLittleEndian<quint64>(const uchar *src)
00137 {
00138     return 0
00139         | src[0]
00140         | src[1] * Q_UINT64_C(0x0000000000000100)
00141         | src[2] * Q_UINT64_C(0x0000000000010000)
00142         | src[3] * Q_UINT64_C(0x0000000001000000)
00143         | src[4] * Q_UINT64_C(0x0000000100000000)
00144         | src[5] * Q_UINT64_C(0x0000010000000000)
00145         | src[6] * Q_UINT64_C(0x0001000000000000)
00146         | src[7] * Q_UINT64_C(0x0100000000000000);
00147 }
00148 
00149 template <> inline quint32 qFromLittleEndian<quint32>(const uchar *src)
00150 {
00151     return 0
00152         | src[0]
00153         | src[1] * quint32(0x00000100)
00154         | src[2] * quint32(0x00010000)
00155         | src[3] * quint32(0x01000000);
00156 }
00157 
00158 template <> inline quint16 qFromLittleEndian<quint16>(const uchar *src)
00159 {
00160     return quint16(0
00161                    | src[0]
00162                    | src[1] * 0x0100);
00163 }
00164 
00165 // signed specializations
00166 template <> inline qint64 qFromLittleEndian<qint64>(const uchar *src)
00167 { return static_cast<qint64>(qFromLittleEndian<quint64>(src)); }
00168 
00169 template <> inline qint32 qFromLittleEndian<qint32>(const uchar *src)
00170 { return static_cast<qint32>(qFromLittleEndian<quint32>(src)); }
00171 
00172 template <> inline qint16 qFromLittleEndian<qint16>(const uchar *src)
00173 { return static_cast<qint16>(qFromLittleEndian<quint16>(src)); }
00174 #endif
00175 
00176 /* This function will read a big-endian (also known as network order) encoded value from \a src
00177  * and return the value in host-endian encoding.
00178  * There is no requirement that \a src must be aligned.
00179 */
00180 #if defined Q_CC_MSVC && _MSC_VER < 1300 || defined Q_CC_SUN
00181 inline quint64 qFromBigEndian_helper(const uchar *src, quint64 *dest)
00182 {
00183     return 0
00184         | src[7]
00185         | src[6] * Q_UINT64_C(0x0000000000000100)
00186         | src[5] * Q_UINT64_C(0x0000000000010000)
00187         | src[4] * Q_UINT64_C(0x0000000001000000)
00188         | src[3] * Q_UINT64_C(0x0000000100000000)
00189         | src[2] * Q_UINT64_C(0x0000010000000000)
00190         | src[1] * Q_UINT64_C(0x0001000000000000)
00191         | src[0] * Q_UINT64_C(0x0100000000000000);
00192 }
00193 
00194 inline quint32 qFromBigEndian_helper(const uchar *src, quint32 * dest)
00195 {
00196     return 0
00197         | src[3]
00198         | src[2] * quint32(0x00000100)
00199         | src[1] * quint32(0x00010000)
00200         | src[0] * quint32(0x01000000);
00201 }
00202 
00203 inline quint16 qFromBigEndian_helper(const uchar *src, quint16 * des)
00204 {
00205     return 0
00206         | src[1]
00207         | src[0] * 0x0100;
00208 }
00209 
00210 
00211 inline qint64 qFromBigEndian_helper(const uchar *src, qint64 * dest)
00212 { return static_cast<qint64>(qFromBigEndian_helper(src, reinterpret_cast<quint64*>(0))); }
00213 inline qint32 qFromBigEndian_helper(const uchar *src, qint32 * dest)
00214 { return static_cast<qint32>(qFromBigEndian_helper(src, reinterpret_cast<quint32*>(0))); }
00215 inline qint16 qFromBigEndian_helper(const uchar *src, qint16 * dest)
00216 { return static_cast<qint16>(qFromBigEndian_helper(src, reinterpret_cast<quint16*>(0))); }
00217 
00218 template <class T> inline T qFromBigEndian(const uchar *src)
00219 {
00220     return qFromBigEndian_helper(src, reinterpret_cast<T*>(0));
00221 }
00222 
00223 #else
00224 template <class T> inline T qFromBigEndian(const uchar *src);
00225 template<>
00226 inline quint64 qFromBigEndian<quint64>(const uchar *src)
00227 {
00228     return 0
00229         | src[7]
00230         | src[6] * Q_UINT64_C(0x0000000000000100)
00231         | src[5] * Q_UINT64_C(0x0000000000010000)
00232         | src[4] * Q_UINT64_C(0x0000000001000000)
00233         | src[3] * Q_UINT64_C(0x0000000100000000)
00234         | src[2] * Q_UINT64_C(0x0000010000000000)
00235         | src[1] * Q_UINT64_C(0x0001000000000000)
00236         | src[0] * Q_UINT64_C(0x0100000000000000);
00237 }
00238 
00239 template<>
00240 inline quint32 qFromBigEndian<quint32>(const uchar *src)
00241 {
00242     return 0
00243         | src[3]
00244         | src[2] * quint32(0x00000100)
00245         | src[1] * quint32(0x00010000)
00246         | src[0] * quint32(0x01000000);
00247 }
00248 
00249 template<>
00250 inline quint16 qFromBigEndian<quint16>(const uchar *src)
00251 {
00252     return quint16( 0
00253                     | src[1]
00254                     | src[0] * quint16(0x0100));
00255 }
00256 
00257 
00258 // signed specializations
00259 template <> inline qint64 qFromBigEndian<qint64>(const uchar *src)
00260 { return static_cast<qint64>(qFromBigEndian<quint64>(src)); }
00261 
00262 template <> inline qint32 qFromBigEndian<qint32>(const uchar *src)
00263 { return static_cast<qint32>(qFromBigEndian<quint32>(src)); }
00264 
00265 template <> inline qint16 qFromBigEndian<qint16>(const uchar *src)
00266 { return static_cast<qint16>(qFromBigEndian<quint16>(src)); }
00267 #endif
00268 /*
00269  * T qbswap(T source).
00270  * Changes the byte order of a value from big endian to little endian or vice versa.
00271  * This function can be used if you are not concerned about alignment issues,
00272  * and it is therefore a bit more convenient and in most cases more efficient.
00273 */
00274 template <typename T> T qbswap(T source);
00275 
00276 #ifdef __GLIBC__
00277 template <> inline quint64 qbswap<quint64>(quint64 source)
00278 {
00279     return bswap_64(source);
00280 }
00281 template <> inline quint32 qbswap<quint32>(quint32 source)
00282 {
00283     return bswap_32(source);
00284 }
00285 template <> inline quint16 qbswap<quint16>(quint16 source)
00286 {
00287     return bswap_16(source);
00288 }
00289 #else
00290 template <> inline quint64 qbswap<quint64>(quint64 source)
00291 {
00292     return 0
00293         | ((source & Q_UINT64_C(0x00000000000000ff)) << 56)
00294         | ((source & Q_UINT64_C(0x000000000000ff00)) << 40)
00295         | ((source & Q_UINT64_C(0x0000000000ff0000)) << 24)
00296         | ((source & Q_UINT64_C(0x00000000ff000000)) << 8)
00297         | ((source & Q_UINT64_C(0x000000ff00000000)) >> 8)
00298         | ((source & Q_UINT64_C(0x0000ff0000000000)) >> 24)
00299         | ((source & Q_UINT64_C(0x00ff000000000000)) >> 40)
00300         | ((source & Q_UINT64_C(0xff00000000000000)) >> 56);
00301 }
00302 
00303 template <> inline quint32 qbswap<quint32>(quint32 source)
00304 {
00305     return 0
00306         | ((source & 0x000000ff) << 24)
00307         | ((source & 0x0000ff00) << 8)
00308         | ((source & 0x00ff0000) >> 8)
00309         | ((source & 0xff000000) >> 24);
00310 }
00311 
00312 template <> inline quint16 qbswap<quint16>(quint16 source)
00313 {
00314     return quint16( 0
00315                     | ((source & 0x00ff) << 8)
00316                     | ((source & 0xff00) >> 8) );
00317 }
00318 #endif // __GLIBC__
00319 
00320 // signed specializations
00321 template <> inline qint64 qbswap<qint64>(qint64 source)
00322 {
00323     return qbswap<quint64>(quint64(source));
00324 }
00325 
00326 template <> inline qint32 qbswap<qint32>(qint32 source)
00327 {
00328     return qbswap<quint32>(quint32(source));
00329 }
00330 
00331 template <> inline qint16 qbswap<qint16>(qint16 source)
00332 {
00333     return qbswap<quint16>(quint16(source));
00334 }
00335 
00336 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
00337 
00338 template <typename T> inline T qToBigEndian(T source)
00339 { return source; }
00340 template <typename T> inline T qFromBigEndian(T source)
00341 { return source; }
00342 template <typename T> inline T qToLittleEndian(T source)
00343 { return qbswap<T>(source); }
00344 template <typename T> inline T qFromLittleEndian(T source)
00345 { return qbswap<T>(source); }
00346 template <typename T> inline void qToBigEndian(T src, uchar *dest)
00347 { qToUnaligned<T>(src, dest); }
00348 template <typename T> inline void qToLittleEndian(T src, uchar *dest)
00349 { qbswap<T>(src, dest); }
00350 #else // Q_LITTLE_ENDIAN
00351 
00352 template <typename T> inline T qToBigEndian(T source)
00353 { return qbswap<T>(source); }
00354 template <typename T> inline T qFromBigEndian(T source)
00355 { return qbswap<T>(source); }
00356 template <typename T> inline T qToLittleEndian(T source)
00357 { return source; }
00358 template <typename T> inline T qFromLittleEndian(T source)
00359 { return source; }
00360 template <typename T> inline void qToBigEndian(T src, uchar *dest)
00361 { qbswap<T>(src, dest); }
00362 template <typename T> inline void qToLittleEndian(T src, uchar *dest)
00363 { qToUnaligned<T>(src, dest); }
00364 
00365 #endif // Q_BYTE_ORDER == Q_BIG_ENDIAN
00366 
00367 QT_END_NAMESPACE
00368 
00369 QT_END_HEADER
00370 
00371 #endif // QENDIAN_H