Move endian integers to qendian_p.h

The endian integers have more use than just in QJson, and is already
used separately by QtDeclarative. This patch moves q_littleendian out
of qjson_p.h and matches it with a corresponding q_bigendian, and puts
it to use in simplifying endian handling in the ico image handler.

Change-Id: I975bb701a089256db8ced3cb53b4bd62cdfb02dd
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Allan Sandfeld Jensen 2017-06-15 13:04:36 +02:00
parent 4d70e03002
commit e5e1fac136
7 changed files with 185 additions and 146 deletions

View File

@ -9,6 +9,7 @@ HEADERS += \
global/qprocessordetection.h \
global/qnamespace.h \
global/qendian.h \
global/qendian_p.h \
global/qnumeric_p.h \
global/qnumeric.h \
global/qfloat16_p.h \

View File

@ -0,0 +1,141 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QENDIAN_P_H
#define QENDIAN_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qendian.h"
QT_BEGIN_NAMESPACE
template<class S>
class QSpecialInteger
{
typedef typename S::StorageType T;
T val;
public:
QSpecialInteger() = default;
explicit Q_DECL_CONSTEXPR QSpecialInteger(T i) : val(S::toSpecial(i)) {}
QSpecialInteger &operator =(T i) { val = S::toSpecial(i); return *this; }
operator T() const { return S::fromSpecial(val); }
bool operator ==(QSpecialInteger<S> i) const { return val == i.val; }
bool operator !=(QSpecialInteger<S> i) const { return val != i.val; }
QSpecialInteger &operator +=(T i)
{ return (*this = S::fromSpecial(val) + i); }
QSpecialInteger &operator -=(T i)
{ return (*this = S::fromSpecial(val) - i); }
QSpecialInteger &operator *=(T i)
{ return (*this = S::fromSpecial(val) * i); }
QSpecialInteger &operator >>=(T i)
{ return (*this = S::fromSpecial(val) >> i); }
QSpecialInteger &operator <<=(T i)
{ return (*this = S::fromSpecial(val) << i); }
QSpecialInteger &operator /=(T i)
{ return (*this = S::fromSpecial(val) / i); }
QSpecialInteger &operator %=(T i)
{ return (*this = S::fromSpecial(val) % i); }
QSpecialInteger &operator |=(T i)
{ return (*this = S::fromSpecial(val) | i); }
QSpecialInteger &operator &=(T i)
{ return (*this = S::fromSpecial(val) & i); }
QSpecialInteger &operator ^=(T i)
{ return (*this = S::fromSpecial(val) ^ i); }
};
template<typename T>
class QLittleEndianStorageType {
public:
typedef T StorageType;
static Q_DECL_CONSTEXPR T toSpecial(T source) { return qToLittleEndian(source); }
static Q_DECL_CONSTEXPR T fromSpecial(T source) { return qFromLittleEndian(source); }
};
template<typename T>
class QBigEndianStorageType {
public:
typedef T StorageType;
static Q_DECL_CONSTEXPR T toSpecial(T source) { return qToBigEndian(source); }
static Q_DECL_CONSTEXPR T fromSpecial(T source) { return qFromBigEndian(source); }
};
template<typename T>
using QLEInteger = QSpecialInteger<QLittleEndianStorageType<T>>;
template<typename T>
using QBEInteger = QSpecialInteger<QBigEndianStorageType<T>>;
template <typename T>
class QTypeInfo<QLEInteger<T> >
: public QTypeInfoMerger<QLEInteger<T>, T> {};
template <typename T>
class QTypeInfo<QBEInteger<T> >
: public QTypeInfoMerger<QBEInteger<T>, T> {};
typedef QLEInteger<qint16> qint16_le;
typedef QLEInteger<qint32> qint32_le;
typedef QLEInteger<qint64> qint64_le;
typedef QLEInteger<quint16> quint16_le;
typedef QLEInteger<quint32> quint32_le;
typedef QLEInteger<quint64> quint64_le;
typedef QBEInteger<qint16> qint16_be;
typedef QBEInteger<qint32> qint32_be;
typedef QBEInteger<qint64> qint64_be;
typedef QBEInteger<quint16> quint16_be;
typedef QBEInteger<quint32> quint32_be;
typedef QBEInteger<quint64> quint64_be;
QT_END_NAMESPACE
#endif // QENDIAN_P_H

View File

@ -45,15 +45,8 @@ QT_BEGIN_NAMESPACE
namespace QJsonPrivate
{
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
#define Q_TO_LITTLE_ENDIAN(x) (x)
#else
#define Q_TO_LITTLE_ENDIAN(x) ( ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24) )
#endif
static const Base emptyArray = { { Q_TO_LITTLE_ENDIAN(sizeof(Base)) }, { 0 }, { 0 } };
static const Base emptyObject = { { Q_TO_LITTLE_ENDIAN(sizeof(Base)) }, { 0 }, { 0 } };
static Q_CONSTEXPR Base emptyArray = { { qle_uint(sizeof(Base)) }, { 0 }, { qle_uint(0) } };
static Q_CONSTEXPR Base emptyObject = { { qle_uint(sizeof(Base)) }, { 0 }, { qle_uint(0) } };
void Data::compact()
{
@ -394,7 +387,7 @@ int Value::requiredStorage(QJsonValue &v, bool *compressed)
v.d->compact();
v.base = static_cast<QJsonPrivate::Base *>(v.d->header->root());
}
return v.base ? v.base->size : sizeof(QJsonPrivate::Base);
return v.base ? uint(v.base->size) : sizeof(QJsonPrivate::Base);
case QJsonValue::Undefined:
case QJsonValue::Null:
case QJsonValue::Bool:

View File

@ -61,6 +61,7 @@
#include <qendian.h>
#include <qnumeric.h>
#include "private/qendian_p.h"
#include "private/qsimd_p.h"
#include <limits.h>
@ -131,42 +132,7 @@ class Value;
class Entry;
template<typename T>
class q_littleendian
{
public:
T val;
q_littleendian &operator =(T i) { val = qToLittleEndian(i); return *this; }
operator T() const { return qFromLittleEndian(val); }
bool operator ==(T i) { return qFromLittleEndian(val) == i; }
bool operator !=(T i) { return qFromLittleEndian(val) != i; }
bool operator ==(q_littleendian<T> i) { return val == i.val; }
bool operator !=(q_littleendian<T> i) { return val != i.val; }
bool operator <(T i) { return qFromLittleEndian(val) < i; }
bool operator >(T i) { return qFromLittleEndian(val) > i; }
bool operator <=(T i) { return qFromLittleEndian(val) <= i; }
bool operator >=(T i) { return qFromLittleEndian(val) >= i; }
q_littleendian &operator +=(T i) {
val = qToLittleEndian(qFromLittleEndian(val) + i);
return *this;
}
q_littleendian &operator |=(T i) {
val = qToLittleEndian(qFromLittleEndian(val) | i);
return *this;
}
q_littleendian &operator &=(T i) {
val = qToLittleEndian(qFromLittleEndian(val) & i);
return *this;
}
};
} // namespace QJsonPrivate
template <typename T>
class QTypeInfo<QJsonPrivate::q_littleendian<T> >
: public QTypeInfoMerger<QJsonPrivate::q_littleendian<T>, T> {};
namespace QJsonPrivate {
using q_littleendian = QLEInteger<T>;
typedef q_littleendian<short> qle_short;
typedef q_littleendian<unsigned short> qle_ushort;

View File

@ -40,6 +40,7 @@
#include <private/qdrawhelper_p.h>
#include <private/qguiapplication_p.h>
#include <private/qcolorprofile_p.h>
#include <private/qendian_p.h>
#include <private/qsimd_p.h>
#include <private/qimage_p.h>
#include <qendian.h>
@ -341,10 +342,10 @@ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32(quint32 *dest_data, con
// Handle 4 pixels at a time 12 bytes input to 16 bytes output.
for (; pixel + 3 < len; pixel += 4) {
const quint32 *src_packed = (const quint32 *) src_data;
const quint32 src1 = qFromBigEndian(src_packed[0]);
const quint32 src2 = qFromBigEndian(src_packed[1]);
const quint32 src3 = qFromBigEndian(src_packed[2]);
const quint32_be *src_packed = reinterpret_cast<const quint32_be *>(src_data);
const quint32 src1 = src_packed[0];
const quint32 src2 = src_packed[1];
const quint32 src3 = src_packed[2];
dest_data[0] = 0xff000000 | (src1 >> 8);
dest_data[1] = 0xff000000 | (src1 << 16) | (src2 >> 16);

View File

@ -3,6 +3,7 @@ TARGET = qico
HEADERS += main.h qicohandler.h
SOURCES += main.cpp qicohandler.cpp
OTHER_FILES += ico.json
QT += core-private
PLUGIN_TYPE = imageformats
PLUGIN_CLASS_NAME = QICOPlugin

View File

@ -48,6 +48,7 @@
#include "qicohandler.h"
#include <QtCore/qendian.h>
#include <private/qendian_p.h>
#include <QtGui/QImage>
#include <QtCore/QFile>
#include <QtCore/QBuffer>
@ -63,34 +64,34 @@ typedef struct
quint8 bHeight; // Height of the image (actual height, not times 2)
quint8 bColorCount; // Number of colors in image (0 if >=8bpp) [ not ture ]
quint8 bReserved; // Reserved
quint16 wPlanes; // Color Planes
quint16 wBitCount; // Bits per pixel
quint32 dwBytesInRes; // how many bytes in this resource?
quint32 dwImageOffset; // where in the file is this image
quint16_le wPlanes; // Color Planes
quint16_le wBitCount; // Bits per pixel
quint32_le dwBytesInRes; // how many bytes in this resource?
quint32_le dwImageOffset; // where in the file is this image
} ICONDIRENTRY, *LPICONDIRENTRY;
#define ICONDIRENTRY_SIZE 16
typedef struct
{
quint16 idReserved; // Reserved
quint16 idType; // resource type (1 for icons, 2 for cursors)
quint16 idCount; // how many images?
quint16_le idReserved; // Reserved
quint16_le idType; // resource type (1 for icons, 2 for cursors)
quint16_le idCount; // how many images?
ICONDIRENTRY idEntries[1]; // the entries for each image
} ICONDIR, *LPICONDIR;
#define ICONDIR_SIZE 6 // Exclude the idEntries field
typedef struct { // BMP information header
quint32 biSize; // size of this struct
quint32 biWidth; // pixmap width
quint32 biHeight; // pixmap height (specifies the combined height of the XOR and AND masks)
quint16 biPlanes; // should be 1
quint16 biBitCount; // number of bits per pixel
quint32 biCompression; // compression method
quint32 biSizeImage; // size of image
quint32 biXPelsPerMeter; // horizontal resolution
quint32 biYPelsPerMeter; // vertical resolution
quint32 biClrUsed; // number of colors used
quint32 biClrImportant; // number of important colors
quint32_le biSize; // size of this struct
quint32_le biWidth; // pixmap width
quint32_le biHeight; // pixmap height (specifies the combined height of the XOR and AND masks)
quint16_le biPlanes; // should be 1
quint16_le biBitCount; // number of bits per pixel
quint32_le biCompression; // compression method
quint32_le biSizeImage; // size of image
quint32_le biXPelsPerMeter; // horizontal resolution
quint32_le biYPelsPerMeter; // vertical resolution
quint32_le biClrUsed; // number of colors used
quint32_le biClrImportant; // number of important colors
} BMP_INFOHDR ,*LPBMP_INFOHDR;
#define BMP_INFOHDR_SIZE 40
@ -140,108 +141,43 @@ private:
// Data readers and writers that takes care of alignment and endian stuff.
static bool readIconDirEntry(QIODevice *iodev, ICONDIRENTRY *iconDirEntry)
{
if (iodev) {
uchar tmp[ICONDIRENTRY_SIZE];
if (iodev->read((char*)tmp, ICONDIRENTRY_SIZE) == ICONDIRENTRY_SIZE) {
iconDirEntry->bWidth = tmp[0];
iconDirEntry->bHeight = tmp[1];
iconDirEntry->bColorCount = tmp[2];
iconDirEntry->bReserved = tmp[3];
iconDirEntry->wPlanes = qFromLittleEndian<quint16>(&tmp[4]);
iconDirEntry->wBitCount = qFromLittleEndian<quint16>(&tmp[6]);
iconDirEntry->dwBytesInRes = qFromLittleEndian<quint32>(&tmp[8]);
iconDirEntry->dwImageOffset = qFromLittleEndian<quint32>(&tmp[12]);
return true;
}
}
if (iodev)
return (iodev->read((char*)iconDirEntry, ICONDIRENTRY_SIZE) == ICONDIRENTRY_SIZE);
return false;
}
static bool writeIconDirEntry(QIODevice *iodev, const ICONDIRENTRY &iconEntry)
{
if (iodev) {
uchar tmp[ICONDIRENTRY_SIZE];
tmp[0] = iconEntry.bWidth;
tmp[1] = iconEntry.bHeight;
tmp[2] = iconEntry.bColorCount;
tmp[3] = iconEntry.bReserved;
qToLittleEndian<quint16>(iconEntry.wPlanes, &tmp[4]);
qToLittleEndian<quint16>(iconEntry.wBitCount, &tmp[6]);
qToLittleEndian<quint32>(iconEntry.dwBytesInRes, &tmp[8]);
qToLittleEndian<quint32>(iconEntry.dwImageOffset, &tmp[12]);
return iodev->write((char*)tmp, ICONDIRENTRY_SIZE) == ICONDIRENTRY_SIZE;
}
if (iodev)
return iodev->write((char*)&iconEntry, ICONDIRENTRY_SIZE) == ICONDIRENTRY_SIZE;
return false;
}
static bool readIconDir(QIODevice *iodev, ICONDIR *iconDir)
{
if (iodev) {
uchar tmp[ICONDIR_SIZE];
if (iodev->read((char*)tmp, ICONDIR_SIZE) == ICONDIR_SIZE) {
iconDir->idReserved = qFromLittleEndian<quint16>(&tmp[0]);
iconDir->idType = qFromLittleEndian<quint16>(&tmp[2]);
iconDir->idCount = qFromLittleEndian<quint16>(&tmp[4]);
return true;
}
}
if (iodev)
return (iodev->read((char*)iconDir, ICONDIR_SIZE) == ICONDIR_SIZE);
return false;
}
static bool writeIconDir(QIODevice *iodev, const ICONDIR &iconDir)
{
if (iodev) {
uchar tmp[6];
qToLittleEndian(iconDir.idReserved, tmp);
qToLittleEndian(iconDir.idType, &tmp[2]);
qToLittleEndian(iconDir.idCount, &tmp[4]);
return iodev->write((char*)tmp, 6) == 6;
}
if (iodev)
return iodev->write((char*)&iconDir, 6) == 6;
return false;
}
static bool readBMPInfoHeader(QIODevice *iodev, BMP_INFOHDR *pHeader)
{
if (iodev) {
uchar header[BMP_INFOHDR_SIZE];
if (iodev->read((char*)header, BMP_INFOHDR_SIZE) == BMP_INFOHDR_SIZE) {
pHeader->biSize = qFromLittleEndian<quint32>(&header[0]);
pHeader->biWidth = qFromLittleEndian<quint32>(&header[4]);
pHeader->biHeight = qFromLittleEndian<quint32>(&header[8]);
pHeader->biPlanes = qFromLittleEndian<quint16>(&header[12]);
pHeader->biBitCount = qFromLittleEndian<quint16>(&header[14]);
pHeader->biCompression = qFromLittleEndian<quint32>(&header[16]);
pHeader->biSizeImage = qFromLittleEndian<quint32>(&header[20]);
pHeader->biXPelsPerMeter = qFromLittleEndian<quint32>(&header[24]);
pHeader->biYPelsPerMeter = qFromLittleEndian<quint32>(&header[28]);
pHeader->biClrUsed = qFromLittleEndian<quint32>(&header[32]);
pHeader->biClrImportant = qFromLittleEndian<quint32>(&header[36]);
return true;
}
}
if (iodev)
return (iodev->read((char*)pHeader, BMP_INFOHDR_SIZE) == BMP_INFOHDR_SIZE);
return false;
}
static bool writeBMPInfoHeader(QIODevice *iodev, const BMP_INFOHDR &header)
{
if (iodev) {
uchar tmp[BMP_INFOHDR_SIZE];
qToLittleEndian<quint32>(header.biSize, &tmp[0]);
qToLittleEndian<quint32>(header.biWidth, &tmp[4]);
qToLittleEndian<quint32>(header.biHeight, &tmp[8]);
qToLittleEndian<quint16>(header.biPlanes, &tmp[12]);
qToLittleEndian<quint16>(header.biBitCount, &tmp[14]);
qToLittleEndian<quint32>(header.biCompression, &tmp[16]);
qToLittleEndian<quint32>(header.biSizeImage, &tmp[20]);
qToLittleEndian<quint32>(header.biXPelsPerMeter, &tmp[24]);
qToLittleEndian<quint32>(header.biYPelsPerMeter, &tmp[28]);
qToLittleEndian<quint32>(header.biClrUsed, &tmp[32]);
qToLittleEndian<quint32>(header.biClrImportant, &tmp[36]);
return iodev->write((char*)tmp, BMP_INFOHDR_SIZE) == BMP_INFOHDR_SIZE;
}
if (iodev)
return iodev->write((char*)&header, BMP_INFOHDR_SIZE) == BMP_INFOHDR_SIZE;
return false;
}
@ -561,7 +497,7 @@ QImage ICOReader::iconAt(int index)
if (icoAttrib.depth == 32) // there's no colormap
icoAttrib.ncolors = 0;
else // # colors used
icoAttrib.ncolors = header.biClrUsed ? header.biClrUsed : 1 << icoAttrib.nbits;
icoAttrib.ncolors = header.biClrUsed ? uint(header.biClrUsed) : 1 << icoAttrib.nbits;
if (icoAttrib.ncolors > 256) //color table can't be more than 256
return img;
icoAttrib.w = iconEntry.bWidth;