Hello community, here is the log from the commit of package kimageformats for openSUSE:Factory checked in at 2019-02-14 14:26:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kimageformats (Old) and /work/SRC/openSUSE:Factory/.kimageformats.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kimageformats" Thu Feb 14 14:26:02 2019 rev:64 rq:674245 version:5.55.0 Changes: -------- --- /work/SRC/openSUSE:Factory/kimageformats/kimageformats.changes 2019-02-04 21:10:44.239883591 +0100 +++ /work/SRC/openSUSE:Factory/.kimageformats.new.28833/kimageformats.changes 2019-02-14 14:26:11.839851031 +0100 @@ -1,0 +2,12 @@ +Sun Feb 10 22:03:10 UTC 2019 - [email protected] + +- Update to 5.55.0 + * New feature release + * For more details please see: + * https://www.kde.org/announcements/kde-frameworks-5.55.0.php +- Changes since 5.54.0: + * Too many changes to list here +- Dropped patches, now upstream: + * 0001-Fix-various-OOB-reads-and-writes-in-kimg_tga-and-kim.patch + +------------------------------------------------------------------- Old: ---- 0001-Fix-various-OOB-reads-and-writes-in-kimg_tga-and-kim.patch kimageformats-5.54.0.tar.xz New: ---- kimageformats-5.55.0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kimageformats.spec ++++++ --- /var/tmp/diff_new_pack.K7fFwj/_old 2019-02-14 14:26:13.207850390 +0100 +++ /var/tmp/diff_new_pack.K7fFwj/_new 2019-02-14 14:26:13.211850389 +0100 @@ -16,13 +16,13 @@ # -%define _tar_path 5.54 +%define _tar_path 5.55 # Full KF5 version (e.g. 5.33.0) %{!?_kf5_version: %global _kf5_version %{version}} # Last major and minor KF5 version (e.g. 5.33) %{!?_kf5_bugfix_version: %define _kf5_bugfix_version %(echo %{_kf5_version} | awk -F. '{print $1"."$2}')} Name: kimageformats -Version: 5.54.0 +Version: 5.55.0 Release: 0 Summary: Image format plugins for Qt License: LGPL-2.1-or-later @@ -30,8 +30,6 @@ URL: https://www.kde.org Source: http://download.kde.org/stable/frameworks/%{_tar_path}/%{name}-%{version}.tar.xz Source1: baselibs.conf -# PATCH-FIX-UPSTREAM -Patch001: 0001-Fix-various-OOB-reads-and-writes-in-kimg_tga-and-kim.patch BuildRequires: cmake >= 3.0 BuildRequires: extra-cmake-modules >= %{_kf5_bugfix_version} BuildRequires: fdupes @@ -65,7 +63,7 @@ environments. %prep -%autosetup -p1 +%setup -q %build %cmake_kf5 -d build ++++++ kimageformats-5.54.0.tar.xz -> kimageformats-5.55.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/CMakeLists.txt new/kimageformats-5.55.0/CMakeLists.txt --- old/kimageformats-5.54.0/CMakeLists.txt 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/CMakeLists.txt 2019-02-02 18:22:00.000000000 +0100 @@ -3,7 +3,7 @@ project(KImageFormats) include(FeatureSummary) -find_package(ECM 5.54.0 NO_MODULE) +find_package(ECM 5.55.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) @@ -17,7 +17,7 @@ include(CheckIncludeFiles) -set(REQUIRED_QT_VERSION 5.9.0) +set(REQUIRED_QT_VERSION 5.10.0) find_package(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) find_package(KF5Archive) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/autotests/CMakeLists.txt new/kimageformats-5.55.0/autotests/CMakeLists.txt --- old/kimageformats-5.54.0/autotests/CMakeLists.txt 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/autotests/CMakeLists.txt 2019-02-02 18:22:00.000000000 +0100 @@ -3,7 +3,7 @@ include(ECMMarkAsTest) include(CMakeParseArguments) -add_definitions(-DPLUGIN_DIR="${CMAKE_CURRENT_BINARY_DIR}/../src") +add_definitions(-DPLUGIN_DIR="${CMAKE_CURRENT_BINARY_DIR}/../bin") remove_definitions(-DQT_NO_CAST_FROM_ASCII) macro(kimageformats_read_tests) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/autotests/readtest.cpp new/kimageformats-5.55.0/autotests/readtest.cpp --- old/kimageformats-5.54.0/autotests/readtest.cpp 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/autotests/readtest.cpp 2019-02-02 18:22:00.000000000 +0100 @@ -75,6 +75,7 @@ int main(int argc, char ** argv) { QCoreApplication app(argc, argv); + QCoreApplication::removeLibraryPath(QStringLiteral(PLUGIN_DIR)); QCoreApplication::addLibraryPath(QStringLiteral(PLUGIN_DIR)); QCoreApplication::setApplicationName(QStringLiteral("readtest")); QCoreApplication::setApplicationVersion(QStringLiteral("1.0.0")); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/autotests/writetest.cpp new/kimageformats-5.55.0/autotests/writetest.cpp --- old/kimageformats-5.54.0/autotests/writetest.cpp 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/autotests/writetest.cpp 2019-02-02 18:22:00.000000000 +0100 @@ -34,6 +34,7 @@ int main(int argc, char ** argv) { QCoreApplication app(argc, argv); + QCoreApplication::removeLibraryPath(QStringLiteral(PLUGIN_DIR)); QCoreApplication::addLibraryPath(QStringLiteral(PLUGIN_DIR)); QCoreApplication::setApplicationName(QStringLiteral("readtest")); QCoreApplication::setApplicationVersion(QStringLiteral("1.0.0")); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/src/imageformats/exr.cpp new/kimageformats-5.55.0/src/imageformats/exr.cpp --- old/kimageformats-5.54.0/src/imageformats/exr.cpp 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/src/imageformats/exr.cpp 2019-02-02 18:22:00.000000000 +0100 @@ -30,7 +30,7 @@ #include <QImage> #include <QDataStream> -// #include <QDebug> +#include <QDebug> #include <QImageIOPlugin> class K_IStream: public Imf::IStream diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/src/imageformats/gimp_p.h new/kimageformats-5.55.0/src/imageformats/gimp_p.h --- old/kimageformats-5.54.0/src/imageformats/gimp_p.h 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/src/imageformats/gimp_p.h 2019-02-02 18:22:00.000000000 +0100 @@ -125,7 +125,8 @@ PROP_PARASITES = 21, PROP_UNIT = 22, PROP_PATHS = 23, - PROP_USER_UNIT = 24 + PROP_USER_UNIT = 24, + MAX_SUPPORTED_PROPTYPE // should always be at the end so its value is last + 1 } PropType; // From GIMP "xcf.c" v1.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/src/imageformats/pcx.cpp new/kimageformats-5.55.0/src/imageformats/pcx.cpp --- old/kimageformats-5.54.0/src/imageformats/pcx.cpp 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/src/imageformats/pcx.cpp 2019-02-02 18:22:00.000000000 +0100 @@ -11,7 +11,7 @@ #include <QColor> #include <QDataStream> -// #include <QDebug> +#include <QDebug> #include <QImage> @@ -253,6 +253,9 @@ img = QImage(header.width(), header.height(), QImage::Format_Mono); img.setColorCount(2); + if (img.isNull()) + return; + for (int y = 0; y < header.height(); ++y) { if (s.atEnd()) { img = QImage(); @@ -325,6 +328,10 @@ readLine(s, buf, header); uchar *p = img.scanLine(y); + + if (!p) + return; + unsigned int bpl = qMin(header.BytesPerLine, (quint16)header.width()); for (unsigned int x = 0; x < bpl; ++x) { p[ x ] = buf[ x ]; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/src/imageformats/pic.cpp new/kimageformats-5.55.0/src/imageformats/pic.cpp --- old/kimageformats-5.54.0/src/imageformats/pic.cpp 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/src/imageformats/pic.cpp 2019-02-02 18:22:00.000000000 +0100 @@ -59,7 +59,10 @@ header.comment = QByteArray(comment); header.id.resize(4); - s.readRawData(header.id.data(), 4); + const int bytesRead = s.readRawData(header.id.data(), 4); + if (bytesRead != 4) { + header.id.resize(bytesRead); + } s >> header.width; s >> header.height; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/src/imageformats/psd.cpp new/kimageformats-5.55.0/src/imageformats/psd.cpp --- old/kimageformats-5.54.0/src/imageformats/psd.cpp 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/src/imageformats/psd.cpp 2019-02-02 18:22:00.000000000 +0100 @@ -177,6 +177,10 @@ QRgb *image_data = reinterpret_cast<QRgb*>(img.bits()); + if (!image_data) { + return false; + } + static const channelUpdater updaters[4] = { updateRed, updateGreen, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/src/imageformats/ras.cpp new/kimageformats-5.55.0/src/imageformats/ras.cpp --- old/kimageformats-5.54.0/src/imageformats/ras.cpp 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/src/imageformats/ras.cpp 2019-02-02 18:22:00.000000000 +0100 @@ -13,7 +13,7 @@ #include <QImage> #include <QDataStream> -// #include <QDebug> +#include <QDebug> namespace // Private. { @@ -131,6 +131,9 @@ // Allocate image img = QImage(ras.Width, ras.Height, QImage::Format_ARGB32); + if (img.isNull()) + return false; + // Reconstruct image from RGB palette if we have a palette // TODO: make generic so it works with 24bit or 32bit palettes if (ras.ColorMapType == 1 && ras.Depth == 8) { @@ -248,6 +251,10 @@ // Read image header. RasHeader ras; s >> ras; + + if (ras.ColorMapLength > std::numeric_limits<int>::max()) + return false; + // TODO: add support for old versions of RAS where Length may be zero in header s.device()->seek(RasHeader::SIZE + ras.Length + ras.ColorMapLength); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/src/imageformats/rgb.cpp new/kimageformats-5.55.0/src/imageformats/rgb.cpp --- old/kimageformats-5.54.0/src/imageformats/rgb.cpp 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/src/imageformats/rgb.cpp 2019-02-02 18:22:00.000000000 +0100 @@ -27,7 +27,7 @@ #include <QVector> #include <QImage> -// #include <QDebug> +#include <QDebug> class RLEData : public QVector<uchar> { @@ -144,13 +144,16 @@ if (_bpc == 2) { _pos++; } + if (_pos >= _data.end()) { + return false; + } n = *_pos & 0x7f; if (!n) { break; } if (*_pos++ & 0x80) { - for (; i < _xsize && n--; i++) { + for (; i < _xsize && _pos < _data.end() && n--; i++) { *dest++ = *_pos; _pos += _bpc; } @@ -309,16 +312,23 @@ return false; } - _numrows = _ysize * _zsize; - img = QImage(_xsize, _ysize, QImage::Format_RGB32); + if (_zsize == 0 ) + return false; + if (_zsize == 2 || _zsize == 4) { img = img.convertToFormat(QImage::Format_ARGB32); } else if (_zsize > 4) { // qDebug() << "using first 4 of " << _zsize << " channels"; + // Only let this continue if it won't cause a int overflow later + // this is most likely a broken file anyway + if (_ysize > std::numeric_limits<int>::max() / _zsize) + return false; } + _numrows = _ysize * _zsize; + if (_rle) { uint l; _starttab = new quint32[_numrows]; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/src/imageformats/tga.cpp new/kimageformats-5.55.0/src/imageformats/tga.cpp --- old/kimageformats-5.54.0/src/imageformats/tga.cpp 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/src/imageformats/tga.cpp 2019-02-02 18:22:00.000000000 +0100 @@ -24,7 +24,7 @@ #include <QImage> #include <QDataStream> -// #include <QDebug> +#include <QDebug> typedef quint32 uint; typedef quint16 ushort; @@ -186,10 +186,14 @@ // However alpha exists only in the 32 bit format. if ((tga.pixel_size == 32) && (tga.flags & 0xf)) { img = QImage(tga.width, tga.height, QImage::Format_ARGB32); + + if (numAlphaBits > 8) { + return false; + } } uint pixel_size = (tga.pixel_size / 8); - uint size = tga.width * tga.height * pixel_size; + qint64 size = qint64(tga.width) * qint64(tga.height) * pixel_size; if (size < 1) { // qDebug() << "This TGA file is broken with size " << size; @@ -200,24 +204,42 @@ char palette[768]; if (info.pal) { // @todo Support palettes in other formats! - s.readRawData(palette, 3 * tga.colormap_length); + const int size = 3 * tga.colormap_length; + const int dataRead = s.readRawData(palette, size); + if (dataRead < size) { + memset(&palette[dataRead], 0, size - dataRead); + } } // Allocate image. - uchar *const image = new uchar[size]; + uchar *const image = reinterpret_cast<uchar*>(malloc(size)); + if (!image) { + return false; + } + + bool valid = true; if (info.rle) { // Decode image. char *dst = (char *)image; - int num = size; + qint64 num = size; while (num > 0) { + if (s.atEnd()) { + valid = false; + break; + } + // Get packet header. uchar c; s >> c; uint count = (c & 0x7f) + 1; num -= count * pixel_size; + if (num < 0) { + valid = false; + break; + } if (c & 0x80) { // RLE pixels. @@ -237,7 +259,15 @@ } } else { // Read raw image. - s.readRawData((char *)image, size); + const int dataRead = s.readRawData((char *)image, size); + if (dataRead < size) { + memset(&image[dataRead], 0, size - dataRead); + } + } + + if (!valid) { + free(image); + return false; } // Convert image to internal format. @@ -294,7 +324,7 @@ } // Free image. - delete [] image; + free(image); return true; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kimageformats-5.54.0/src/imageformats/xcf.cpp new/kimageformats-5.55.0/src/imageformats/xcf.cpp --- old/kimageformats-5.54.0/src/imageformats/xcf.cpp 2019-01-04 22:42:58.000000000 +0100 +++ new/kimageformats-5.55.0/src/imageformats/xcf.cpp 2019-02-02 18:22:00.000000000 +0100 @@ -27,7 +27,9 @@ #include <QIODevice> #include <QStack> #include <QVector> -// #include <QDebug> +#include <QDebug> + +#include <string.h> #include "gimp_p.h" @@ -86,16 +88,17 @@ } mask_channel; bool active; //!< Is this layer the active layer? - quint32 opacity; //!< The opacity of the layer - quint32 visible; //!< Is the layer visible? + quint32 opacity = 255; //!< The opacity of the layer + quint32 visible = 1; //!< Is the layer visible? quint32 linked; //!< Is this layer linked (geometrically) quint32 preserve_transparency; //!< Preserve alpha when drawing on layer? - quint32 apply_mask; //!< Apply the layer mask? + quint32 apply_mask = 9; //!< Apply the layer mask? Use 9 as "uninitilized". Spec says "If the property does not appear for a layer which has a layer mask, it defaults to true (1). + // Robust readers should force this to false if the layer has no layer mask. quint32 edit_mask; //!< Is the layer mask the being edited? quint32 show_mask; //!< Show the layer mask rather than the image? - qint32 x_offset; //!< x offset of the layer relative to the image - qint32 y_offset; //!< y offset of the layer relative to the image - quint32 mode; //!< Combining mode of layer (LayerModeEffects) + qint32 x_offset = 0; //!< x offset of the layer relative to the image + qint32 y_offset = 0; //!< y offset of the layer relative to the image + quint32 mode = 0; //!< Combining mode of layer (LayerModeEffects) quint32 tattoo; //!< (unique identifier?) //! As each tile is read from the file, it is buffered here. @@ -112,6 +115,9 @@ { delete[] name; } + + Layer(const Layer &) = delete; + Layer &operator=(const Layer &) = delete; }; /*! @@ -126,11 +132,11 @@ qint32 type; //!< type of the XCF image (GimpImageBaseType) quint8 compression; //!< tile compression method (CompressionType) - float x_resolution; //!< x resolution in dots per inch - float y_resolution; //!< y resolution in dots per inch + float x_resolution = -1;//!< x resolution in dots per inch + float y_resolution = -1;//!< y resolution in dots per inch qint32 tattoo; //!< (unique identifier?) quint32 unit; //!< Units of The GIMP (inch, mm, pica, etc...) - qint32 num_colors; //!< number of colors in an indexed image + qint32 num_colors = 0; //!< number of colors in an indexed image QVector<QRgb> palette; //!< indexed image color palette int num_layers; //!< number of layers @@ -178,7 +184,7 @@ static const LayerModes layer_modes[]; bool loadImageProperties(QDataStream &xcf_io, XCFImage &image); - bool loadProperty(QDataStream &xcf_io, PropType &type, QByteArray &bytes); + bool loadProperty(QDataStream &xcf_io, PropType &type, QByteArray &bytes, quint32 &rawType); bool loadLayer(QDataStream &xcf_io, XCFImage &xcf_image); bool loadLayerProperties(QDataStream &xcf_io, Layer &layer); bool composeTiles(XCFImage &xcf_image); @@ -384,8 +390,9 @@ while (true) { PropType type; QByteArray bytes; + quint32 rawType; - if (!loadProperty(xcf_io, type, bytes)) { + if (!loadProperty(xcf_io, type, bytes, rawType)) { // qDebug() << "XCF: error loading global image properties"; return false; } @@ -444,6 +451,7 @@ return false; } + xcf_image.palette = QVector<QRgb>(); xcf_image.palette.reserve(xcf_image.num_colors); for (int i = 0; i < xcf_image.num_colors; i++) { @@ -454,7 +462,7 @@ break; default: -// qDebug() << "XCF: unimplemented image property" << type +// qDebug() << "XCF: unimplemented image property" << rawType // << ", size " << bytes.size() << endl; break; } @@ -468,11 +476,16 @@ * \param type returns with the property type. * \param bytes returns with the property data. * \return true if there were no IO errors. */ -bool XCFImageFormat::loadProperty(QDataStream &xcf_io, PropType &type, QByteArray &bytes) +bool XCFImageFormat::loadProperty(QDataStream &xcf_io, PropType &type, QByteArray &bytes, quint32 &rawType) { - quint32 foo; - xcf_io >> foo; - type = PropType(foo); // TODO urks + xcf_io >> rawType; + if (rawType >= MAX_SUPPORTED_PROPTYPE) { + type = MAX_SUPPORTED_PROPTYPE; + // return true because we don't really want to totally fail on an unsupported property since it may not be fatal + return true; + } + + type = PropType(rawType); char *data = nullptr; quint32 size; @@ -486,11 +499,12 @@ quint32 ncolors; xcf_io >> ncolors; + size = 3 * ncolors + 4; + if (size > 65535 || size < 4) { return false; } - size = 3 * ncolors + 4; data = new char[size]; // since we already read "ncolors" from the stream, we put that data back @@ -528,7 +542,11 @@ return false; } data = new char[size]; - xcf_io.readRawData(data, size); + const quint32 dataRead = xcf_io.readRawData(data, size); + if (dataRead < size) { +// qDebug() << "XCF: loadProperty read less data than expected" << data_length << dataRead; + memset(&data[dataRead], 0, size - dataRead); + } } if (size != 0 && data) { @@ -595,11 +613,19 @@ } if (layer.mask_offset != 0) { + // 9 means its not on the file. Spec says "If the property does not appear for a layer which has a layer mask, it defaults to true (1). + if (layer.apply_mask == 9) { + layer.apply_mask = 1; + } + xcf_io.device()->seek(layer.mask_offset); if (!loadMask(xcf_io, layer)) { return false; } + } else { + // Spec says "Robust readers should force this to false if the layer has no layer mask." + layer.apply_mask = 0; } // Now we should have enough information to initialize the final @@ -631,8 +657,9 @@ while (true) { PropType type; QByteArray bytes; + quint32 rawType; - if (!loadProperty(xcf_io, type, bytes)) { + if (!loadProperty(xcf_io, type, bytes, rawType)) { // qDebug() << "XCF: error loading layer properties"; return false; } @@ -649,6 +676,7 @@ case PROP_OPACITY: property >> layer.opacity; + layer.opacity = std::min(layer.opacity, 255u); break; case PROP_VISIBLE: @@ -688,7 +716,7 @@ break; default: -// qDebug() << "XCF: unimplemented layer property " << type +// qDebug() << "XCF: unimplemented layer property " << rawType // << ", size " << bytes.size() << endl; break; } @@ -953,6 +981,46 @@ xcf_io >> width >> height >> bpp >> offset; + // make sure bpp is correct and complain if it is not + switch (layer.type) { + case RGB_GIMAGE: + if (bpp != 3) { + qWarning() << "Found layer of type RGB but with bpp != 3" << bpp; + bpp = 3; + } + break; + case RGBA_GIMAGE: + if (bpp != 4) { + qWarning() << "Found layer of type RGBA but with bpp != 4" << bpp; + bpp = 4; + } + break; + case GRAY_GIMAGE: + if (bpp != 1) { + qWarning() << "Found layer of type Gray but with bpp != 1" << bpp; + bpp = 1; + } + break; + case GRAYA_GIMAGE: + if (bpp != 2) { + qWarning() << "Found layer of type Gray+Alpha but with bpp != 2" << bpp; + bpp = 2; + } + break; + case INDEXED_GIMAGE: + if (bpp != 1) { + qWarning() << "Found layer of type Indexed but with bpp != 1" << bpp; + bpp = 1; + } + break; + case INDEXEDA_GIMAGE: + if (bpp != 2) { + qWarning() << "Found layer of type Indexed+Alpha but with bpp != 2" << bpp; + bpp = 2; + } + break; + } + // GIMP stores images in a "mipmap"-like format (multiple levels of // increasingly lower resolution). Only the top level is used here, // however. @@ -1109,7 +1177,11 @@ xcfdata = xcfodata = new uchar[data_length]; - xcf_io.readRawData((char *)xcfdata, data_length); + const int dataRead = xcf_io.readRawData((char *)xcfdata, data_length); + if (dataRead < data_length) { +// qDebug() << "XCF: read less data than expected" << data_length << dataRead; + memset(&xcfdata[dataRead], 0, data_length - dataRead); + } if (!xcf_io.device()->isOpen()) { delete[] xcfodata; @@ -1215,8 +1287,9 @@ while (true) { PropType type; QByteArray bytes; + quint32 rawType; - if (!loadProperty(xcf_io, type, bytes)) { + if (!loadProperty(xcf_io, type, bytes, rawType)) { // qDebug() << "XCF: error loading channel properties"; return false; } @@ -1229,6 +1302,7 @@ case PROP_OPACITY: property >> layer.mask_channel.opacity; + layer.mask_channel.opacity = std::min(layer.mask_channel.opacity, 255u); break; case PROP_VISIBLE: @@ -1249,7 +1323,7 @@ break; default: -// qDebug() << "XCF: unimplemented channel property " << type +// qDebug() << "XCF: unimplemented channel property " << rawType // << ", size " << bytes.size() << endl; break; } @@ -1429,8 +1503,16 @@ break; } - image.setDotsPerMeterX((int)(xcf_image.x_resolution * INCHESPERMETER)); - image.setDotsPerMeterY((int)(xcf_image.y_resolution * INCHESPERMETER)); + if (xcf_image.x_resolution > 0 && xcf_image.y_resolution > 0) { + const float dpmx = xcf_image.x_resolution * INCHESPERMETER; + if (dpmx > std::numeric_limits<int>::max()) + return false; + const float dpmy = xcf_image.y_resolution * INCHESPERMETER; + if (dpmy > std::numeric_limits<int>::max()) + return false; + image.setDotsPerMeterX((int)dpmx); + image.setDotsPerMeterY((int)dpmy); + } return true; }
