mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 10:22:48 +00:00
kdecore: new KCompressor and KDecompressor classes replacing KFilterDev
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
efd9978abf
commit
860b2d098d
28 changed files with 776 additions and 2251 deletions
|
@ -55,12 +55,12 @@ if(ENABLE_TESTING)
|
|||
endif()
|
||||
|
||||
# required features
|
||||
find_package(ZLIB)
|
||||
find_package(LibDeflate)
|
||||
set_package_properties(ZLIB PROPERTIES
|
||||
DESCRIPTION "Support for gzip compressed files and data streams"
|
||||
URL "http://www.zlib.net"
|
||||
DESCRIPTION "Heavily optimized library for DEFLATE/zlib/gzip compression and decompression"
|
||||
URL "https://github.com/ebiggers/libdeflate"
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Required by the core KDE libraries and some critical kioslaves"
|
||||
PURPOSE "Compression and decompression of DEFLATE/zlib/gzip format"
|
||||
)
|
||||
|
||||
find_package(SharedMimeInfo 0.91)
|
||||
|
|
31
cmake/modules/FindLibDeflate.cmake
Normal file
31
cmake/modules/FindLibDeflate.cmake
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Try to find libdeflate, once done this will define:
|
||||
#
|
||||
# LIBDEFLATE_FOUND - system has libdeflate
|
||||
# LIBDEFLATE_INCLUDES - the libdeflate include directory
|
||||
# LIBDEFLATE_LIBRARIES - the libraries needed to use libdeflate
|
||||
#
|
||||
# Copyright (c) 2022 Ivailo Monev <xakepa10@gmail.com>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
# libdeflate does not provide pkg-config files
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_path(LIBDEFLATE_INCLUDES
|
||||
NAMES libdeflate.h
|
||||
HINTS $ENV{LIBDEFLATEDIR}/include
|
||||
)
|
||||
|
||||
find_library(LIBDEFLATE_LIBRARIES
|
||||
NAMES deflate
|
||||
HINTS $ENV{LIBDEFLATEDIR}/lib
|
||||
)
|
||||
|
||||
find_package_handle_standard_args(LibDeflate
|
||||
REQUIRED_VARS LIBDEFLATE_LIBRARIES LIBDEFLATE_INCLUDES
|
||||
)
|
||||
|
||||
mark_as_advanced(LIBDEFLATE_INCLUDES LIBDEFLATE_LIBRARIES)
|
|
@ -132,8 +132,8 @@ install(
|
|||
KFileMetaInfoItem
|
||||
KFilePlacesModel
|
||||
KFileTreeView
|
||||
KFilterBase
|
||||
KFilterDev
|
||||
KCompressor
|
||||
KDecompressor
|
||||
KFind
|
||||
KFindDialog
|
||||
KFloatValidator
|
||||
|
|
1
includes/KCompressor
Normal file
1
includes/KCompressor
Normal file
|
@ -0,0 +1 @@
|
|||
#include "../kcompressor.h"
|
1
includes/KDecompressor
Normal file
1
includes/KDecompressor
Normal file
|
@ -0,0 +1 @@
|
|||
#include "../kdecompressor.h"
|
|
@ -1 +0,0 @@
|
|||
#include "../kfilterbase.h"
|
|
@ -1 +0,0 @@
|
|||
#include "../kfilterdev.h"
|
|
@ -31,7 +31,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}/compression)
|
|||
include_directories(
|
||||
${KDE4_KDECORE_INCLUDES}
|
||||
${KDE4_KDEUI_INCLUDES}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
${LIBDEFLATE_INCLUDES}
|
||||
${QT_INCLUDES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/auth
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/sonnet
|
||||
|
@ -49,14 +49,12 @@ add_definitions(-DQT_NO_CAST_FROM_ASCII)
|
|||
# compile bzip2 support if available
|
||||
if(BZIP2_FOUND)
|
||||
include_directories(${BZIP2_INCLUDE_DIR})
|
||||
set(kdecore_OPTIONAL_SRCS ${kdecore_OPTIONAL_SRCS} compression/kbzip2filter.cpp)
|
||||
set(kdecore_OPTIONAL_LIBS ${kdecore_OPTIONAL_LIBS} ${BZIP2_LIBRARIES})
|
||||
endif(BZIP2_FOUND)
|
||||
|
||||
# compile lzma support if available
|
||||
if(LIBLZMA_FOUND)
|
||||
include_directories(${LIBLZMA_INCLUDE_DIRS})
|
||||
set(kdecore_OPTIONAL_SRCS ${kdecore_OPTIONAL_SRCS} compression/kxzfilter.cpp)
|
||||
set(kdecore_OPTIONAL_LIBS ${kdecore_OPTIONAL_LIBS} ${LIBLZMA_LIBRARIES})
|
||||
endif(LIBLZMA_FOUND)
|
||||
|
||||
|
@ -89,9 +87,8 @@ endif()
|
|||
########### next target ###############
|
||||
|
||||
set(kdecore_LIB_SRCS
|
||||
compression/kgzipfilter.cpp
|
||||
compression/kfilterbase.cpp
|
||||
compression/kfilterdev.cpp
|
||||
compression/kcompressor.cpp
|
||||
compression/kdecompressor.cpp
|
||||
config/kconfig.cpp
|
||||
config/kconfigbase.cpp
|
||||
config/kconfigdata.cpp
|
||||
|
@ -219,7 +216,7 @@ endif()
|
|||
add_library(kdecore ${LIBRARY_TYPE} ${kdecore_LIB_SRCS})
|
||||
|
||||
target_link_libraries(kdecore PRIVATE
|
||||
${ZLIB_LIBRARY}
|
||||
${LIBDEFLATE_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${kdecore_OPTIONAL_LIBS}
|
||||
)
|
||||
|
@ -277,8 +274,8 @@ install(
|
|||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/kdecore_export.h
|
||||
compression/kfilterbase.h
|
||||
compression/kfilterdev.h
|
||||
compression/kcompressor.h
|
||||
compression/kdecompressor.h
|
||||
config/kconfig.h
|
||||
config/kconfigbase.h
|
||||
config/kconfiggroup.h
|
||||
|
|
|
@ -1,6 +1,2 @@
|
|||
kde4_bool_to_01(BZIP2_FOUND HAVE_BZIP2_SUPPORT)
|
||||
if(BZIP2_FOUND AND BZIP2_NEED_PREFIX)
|
||||
set(NEED_BZ2_PREFIX 1)
|
||||
endif()
|
||||
|
||||
kde4_bool_to_01(LIBLZMA_FOUND HAVE_XZ_SUPPORT)
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#cmakedefine01 HAVE_BZIP2_SUPPORT
|
||||
|
||||
/* Set to 1 if the libbz2 functions need the BZ2_ prefix */
|
||||
#cmakedefine01 NEED_BZ2_PREFIX
|
||||
|
||||
/* Set to 1 if you have xz */
|
||||
#cmakedefine01 HAVE_XZ_SUPPORT
|
||||
|
||||
|
|
|
@ -1,205 +0,0 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2000-2005 David Faure <faure@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "kbzip2filter.h"
|
||||
|
||||
#include <config-compression.h>
|
||||
|
||||
#if HAVE_BZIP2_SUPPORT
|
||||
|
||||
// we don't need that
|
||||
#define BZ_NO_STDIO
|
||||
extern "C" {
|
||||
#include <bzlib.h>
|
||||
}
|
||||
|
||||
#if NEED_BZ2_PREFIX
|
||||
#define bzDecompressInit(x,y,z) BZ2_bzDecompressInit(x,y,z)
|
||||
#define bzDecompressEnd(x) BZ2_bzDecompressEnd(x)
|
||||
#define bzCompressEnd(x) BZ2_bzCompressEnd(x)
|
||||
#define bzDecompress(x) BZ2_bzDecompress(x)
|
||||
#define bzCompress(x,y) BZ2_bzCompress(x, y)
|
||||
#define bzCompressInit(x,y,z,a) BZ2_bzCompressInit(x, y, z, a);
|
||||
#endif
|
||||
|
||||
#include <kdebug.h>
|
||||
|
||||
#include <qiodevice.h>
|
||||
|
||||
|
||||
|
||||
// For docu on this, see /usr/doc/bzip2-0.9.5d/bzip2-0.9.5d/manual_3.html
|
||||
|
||||
class KBzip2Filter::Private
|
||||
{
|
||||
public:
|
||||
Private()
|
||||
: isInitialized(false)
|
||||
{
|
||||
memset(&zStream, 0, sizeof(zStream));
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
bz_stream zStream;
|
||||
int mode;
|
||||
bool isInitialized;
|
||||
};
|
||||
|
||||
KBzip2Filter::KBzip2Filter()
|
||||
:d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KBzip2Filter::~KBzip2Filter()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool KBzip2Filter::init( int mode )
|
||||
{
|
||||
if (d->isInitialized) {
|
||||
terminate();
|
||||
}
|
||||
|
||||
d->zStream.next_in = 0;
|
||||
d->zStream.avail_in = 0;
|
||||
if ( mode == QIODevice::ReadOnly )
|
||||
{
|
||||
const int result = bzDecompressInit(&d->zStream, 0, 0);
|
||||
if (result != BZ_OK) {
|
||||
kDebug(7118) << "bzDecompressInit returned " << result;
|
||||
return false;
|
||||
}
|
||||
} else if ( mode == QIODevice::WriteOnly ) {
|
||||
const int result = bzCompressInit(&d->zStream, 5, 0, 0);
|
||||
if (result != BZ_OK) {
|
||||
kDebug(7118) << "bzDecompressInit returned " << result;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
kWarning(7118) << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
|
||||
return false;
|
||||
}
|
||||
d->mode = mode;
|
||||
d->isInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
int KBzip2Filter::mode() const
|
||||
{
|
||||
return d->mode;
|
||||
}
|
||||
|
||||
bool KBzip2Filter::terminate()
|
||||
{
|
||||
if (d->mode == QIODevice::ReadOnly) {
|
||||
const int result = bzDecompressEnd(&d->zStream);
|
||||
if (result != BZ_OK) {
|
||||
kDebug(7118) << "bzDecompressEnd returned " << result;
|
||||
return false;
|
||||
}
|
||||
} else if (d->mode == QIODevice::WriteOnly) {
|
||||
const int result = bzCompressEnd(&d->zStream);
|
||||
if (result != BZ_OK) {
|
||||
kDebug(7118) << "bzDecompressEnd returned " << result;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
kWarning(7118) << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
|
||||
return false;
|
||||
}
|
||||
d->isInitialized = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool KBzip2Filter::reset()
|
||||
{
|
||||
// bzip2 doesn't seem to have a reset call...
|
||||
if (!terminate()) {
|
||||
return false;
|
||||
}
|
||||
if (!init( d->mode )) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void KBzip2Filter::setOutBuffer( char * data, uint maxlen )
|
||||
{
|
||||
d->zStream.avail_out = maxlen;
|
||||
d->zStream.next_out = data;
|
||||
}
|
||||
|
||||
void KBzip2Filter::setInBuffer( const char *data, unsigned int size )
|
||||
{
|
||||
d->zStream.avail_in = size;
|
||||
d->zStream.next_in = const_cast<char *>(data);
|
||||
}
|
||||
|
||||
int KBzip2Filter::inBufferAvailable() const
|
||||
{
|
||||
return d->zStream.avail_in;
|
||||
}
|
||||
|
||||
int KBzip2Filter::outBufferAvailable() const
|
||||
{
|
||||
return d->zStream.avail_out;
|
||||
}
|
||||
|
||||
KBzip2Filter::Result KBzip2Filter::uncompress()
|
||||
{
|
||||
//qDebug() << "Calling bzDecompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
|
||||
int result = bzDecompress(&d->zStream);
|
||||
if ( result < BZ_OK ) {
|
||||
kWarning(7118) << "bzDecompress returned" << result;
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case BZ_OK:
|
||||
return KFilterBase::Ok;
|
||||
case BZ_STREAM_END:
|
||||
return KFilterBase::End;
|
||||
default:
|
||||
return KFilterBase::Error;
|
||||
}
|
||||
}
|
||||
|
||||
KBzip2Filter::Result KBzip2Filter::compress( bool finish )
|
||||
{
|
||||
//qDebug() << "Calling bzCompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
|
||||
int result = bzCompress(&d->zStream, finish ? BZ_FINISH : BZ_RUN );
|
||||
|
||||
switch (result) {
|
||||
case BZ_OK:
|
||||
case BZ_FLUSH_OK:
|
||||
case BZ_RUN_OK:
|
||||
case BZ_FINISH_OK:
|
||||
return KFilterBase::Ok;
|
||||
case BZ_STREAM_END:
|
||||
//qDebug() << " bzCompress returned " << result;
|
||||
return KFilterBase::End;
|
||||
default:
|
||||
//qDebug() << " bzCompress returned " << result;
|
||||
return KFilterBase::Error;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_BZIP2_SUPPORT */
|
|
@ -1,58 +0,0 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2000 David Faure <faure@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KBZIP2FILTER_H
|
||||
#define KBZIP2FILTER_H
|
||||
|
||||
#include <config-compression.h>
|
||||
|
||||
#if HAVE_BZIP2_SUPPORT
|
||||
|
||||
#include "kfilterbase.h"
|
||||
|
||||
/**
|
||||
* Internal class used by KFilterDev
|
||||
* @internal
|
||||
*/
|
||||
class KBzip2Filter : public KFilterBase
|
||||
{
|
||||
public:
|
||||
KBzip2Filter();
|
||||
virtual ~KBzip2Filter();
|
||||
|
||||
virtual bool init( int );
|
||||
virtual int mode() const;
|
||||
virtual bool terminate();
|
||||
virtual bool reset();
|
||||
virtual bool readHeader() { return true; } // bzip2 handles it by itself ! Cool !
|
||||
virtual bool writeHeader( const QByteArray & ) { return true; }
|
||||
virtual void setOutBuffer( char * data, uint maxlen );
|
||||
virtual void setInBuffer( const char * data, uint size );
|
||||
virtual int inBufferAvailable() const;
|
||||
virtual int outBufferAvailable() const;
|
||||
virtual Result uncompress();
|
||||
virtual Result compress( bool finish );
|
||||
private:
|
||||
class Private;
|
||||
Private* const d;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
290
kdecore/compression/kcompressor.cpp
Normal file
290
kdecore/compression/kcompressor.cpp
Normal file
|
@ -0,0 +1,290 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2, as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "config-compression.h"
|
||||
#include "kcompressor.h"
|
||||
#include "klocale.h"
|
||||
#include "kmimetype.h"
|
||||
#include "kdebug.h"
|
||||
#include <qplatformdefs.h>
|
||||
|
||||
#include <libdeflate.h>
|
||||
|
||||
#if defined(HAVE_BZIP2_SUPPORT)
|
||||
# include <bzlib.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_XZ_SUPPORT)
|
||||
# include <lzma.h>
|
||||
#endif
|
||||
|
||||
// for reference:
|
||||
// http://linux.math.tifr.res.in/manuals/html/manual_3.html
|
||||
|
||||
class KCompressorPrivate
|
||||
{
|
||||
public:
|
||||
KCompressorPrivate();
|
||||
|
||||
KCompressor::KCompressorType m_type;
|
||||
int m_level;
|
||||
QByteArray m_result;
|
||||
QString m_errorstring;
|
||||
};
|
||||
|
||||
KCompressorPrivate::KCompressorPrivate()
|
||||
: m_type(KCompressor::TypeUnknown),
|
||||
m_level(1)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KCompressor::KCompressor()
|
||||
: d(new KCompressorPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
KCompressor::~KCompressor()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
KCompressor::KCompressorType KCompressor::type() const
|
||||
{
|
||||
return d->m_type;
|
||||
}
|
||||
|
||||
bool KCompressor::setType(const KCompressorType type)
|
||||
{
|
||||
if (type == KCompressor::TypeUnknown) {
|
||||
return false;
|
||||
}
|
||||
d->m_type = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
int KCompressor::level() const
|
||||
{
|
||||
return d->m_level;
|
||||
}
|
||||
|
||||
bool KCompressor::setLevel(const int level)
|
||||
{
|
||||
d->m_errorstring.clear();
|
||||
if (level < 0 || level > 9) {
|
||||
d->m_errorstring = i18n("Compression level not in the 0-9 range: %1", level);
|
||||
return false;
|
||||
}
|
||||
d->m_level = level;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KCompressor::process(const QByteArray &data)
|
||||
{
|
||||
d->m_errorstring.clear();
|
||||
d->m_result.clear();
|
||||
|
||||
switch (d->m_type) {
|
||||
case KCompressor::TypeUnknown: {
|
||||
return false;
|
||||
}
|
||||
case KCompressor::TypeDeflate: {
|
||||
struct libdeflate_compressor* comp = libdeflate_alloc_compressor(d->m_level);
|
||||
if (Q_UNLIKELY(!comp)) {
|
||||
d->m_errorstring = i18n("Could not allocate compressor");
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t boundresult = libdeflate_deflate_compress_bound(comp, data.size());
|
||||
if (Q_UNLIKELY(boundresult <= 0)) {
|
||||
d->m_errorstring = i18n("Compression boundary is negative or zero");
|
||||
libdeflate_free_compressor(comp);
|
||||
return false;
|
||||
}
|
||||
|
||||
d->m_result.resize(boundresult);
|
||||
const size_t compresult = libdeflate_deflate_compress(
|
||||
comp,
|
||||
data.constData(), data.size(),
|
||||
d->m_result.data(), d->m_result.size()
|
||||
);
|
||||
libdeflate_free_compressor(comp);
|
||||
|
||||
if (Q_UNLIKELY(compresult <= 0)) {
|
||||
d->m_errorstring = i18n("Could not compress data");
|
||||
d->m_result.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
d->m_result.resize(compresult);
|
||||
return true;
|
||||
}
|
||||
case KCompressor::TypeZlib: {
|
||||
struct libdeflate_compressor* comp = libdeflate_alloc_compressor(d->m_level);
|
||||
if (Q_UNLIKELY(!comp)) {
|
||||
d->m_errorstring = i18n("Could not allocate compressor");
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t boundresult = libdeflate_zlib_compress_bound(comp, data.size());
|
||||
if (Q_UNLIKELY(boundresult <= 0)) {
|
||||
d->m_errorstring = i18n("Compression boundary is negative or zero");
|
||||
libdeflate_free_compressor(comp);
|
||||
return false;
|
||||
}
|
||||
|
||||
d->m_result.resize(boundresult);
|
||||
const size_t compresult = libdeflate_zlib_compress(
|
||||
comp,
|
||||
data.constData(), data.size(),
|
||||
d->m_result.data(), d->m_result.size()
|
||||
);
|
||||
libdeflate_free_compressor(comp);
|
||||
|
||||
if (Q_UNLIKELY(compresult <= 0)) {
|
||||
d->m_errorstring = i18n("Could not compress data");
|
||||
d->m_result.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
d->m_result.resize(compresult);
|
||||
return true;
|
||||
}
|
||||
case KCompressor::TypeGZip: {
|
||||
struct libdeflate_compressor* comp = libdeflate_alloc_compressor(d->m_level);
|
||||
if (Q_UNLIKELY(!comp)) {
|
||||
d->m_errorstring = i18n("Could not allocate compressor");
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t boundresult = libdeflate_gzip_compress_bound(comp, data.size());
|
||||
if (Q_UNLIKELY(boundresult <= 0)) {
|
||||
d->m_errorstring = i18n("Compression boundary is negative or zero");
|
||||
libdeflate_free_compressor(comp);
|
||||
return false;
|
||||
}
|
||||
|
||||
d->m_result.resize(boundresult);
|
||||
const size_t compresult = libdeflate_gzip_compress(
|
||||
comp,
|
||||
data.constData(), data.size(),
|
||||
d->m_result.data(), d->m_result.size()
|
||||
);
|
||||
libdeflate_free_compressor(comp);
|
||||
|
||||
if (Q_UNLIKELY(compresult <= 0)) {
|
||||
d->m_errorstring = i18n("Could not compress data");
|
||||
d->m_result.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
d->m_result.resize(compresult);
|
||||
return true;
|
||||
}
|
||||
#if defined(HAVE_BZIP2_SUPPORT)
|
||||
case KCompressor::TypeBZip2: {
|
||||
d->m_result.resize(data.size() + QT_BUFFSIZE);
|
||||
uint compsize = d->m_result.size();
|
||||
|
||||
int compresult = compresult = BZ2_bzBuffToBuffCompress(
|
||||
d->m_result.data(), &compsize,
|
||||
(char*)data.constData(), data.size(),
|
||||
d->m_level, 0, 0
|
||||
);
|
||||
|
||||
if (Q_UNLIKELY(compresult < BZ_OK || compresult > BZ_STREAM_END)) {
|
||||
d->m_errorstring = i18n("Could not compress data");
|
||||
return false;
|
||||
}
|
||||
|
||||
d->m_result.resize(compsize);
|
||||
return true;
|
||||
}
|
||||
#endif // HAVE_BZIP2_SUPPORT
|
||||
#if defined(HAVE_XZ_SUPPORT)
|
||||
case KCompressor::TypeXZ: {
|
||||
d->m_result.resize(data.size() + QT_BUFFSIZE);
|
||||
size_t compsize = d->m_result.size();
|
||||
|
||||
lzma_stream comp = LZMA_STREAM_INIT;
|
||||
comp.next_in = (const uint8_t*)data.constData();
|
||||
comp.avail_in = data.size();
|
||||
comp.next_out = (uint8_t*)d->m_result.data();
|
||||
comp.avail_out = compsize;
|
||||
|
||||
lzma_ret compresult = lzma_easy_encoder(&comp, d->m_level, LZMA_CHECK_CRC32);
|
||||
if (Q_UNLIKELY(compresult != LZMA_OK)) {
|
||||
d->m_errorstring = i18n("Could not initialize compressor");
|
||||
d->m_result.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
compresult = lzma_code(&comp, LZMA_FINISH);
|
||||
if (Q_UNLIKELY(compresult != LZMA_OK && compresult != LZMA_STREAM_END)) {
|
||||
d->m_errorstring = i18n("Could not compress data");
|
||||
d->m_result.clear();
|
||||
return false;
|
||||
}
|
||||
compsize = comp.total_out;
|
||||
lzma_end(&comp);
|
||||
|
||||
d->m_result.resize(compsize);
|
||||
return true;
|
||||
}
|
||||
#endif // HAVE_XZ_SUPPORT
|
||||
default: {
|
||||
kWarning() << "Unsupported type" << d->m_type;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
QByteArray KCompressor::result() const
|
||||
{
|
||||
return d->m_result;
|
||||
}
|
||||
|
||||
QString KCompressor::errorString() const
|
||||
{
|
||||
return d->m_errorstring;
|
||||
}
|
||||
|
||||
KCompressor::KCompressorType KCompressor::typeForMime(const QString &mime)
|
||||
{
|
||||
const KMimeType::Ptr kmimetype = KMimeType::mimeType(mime);
|
||||
if (kmimetype) {
|
||||
if (kmimetype->is(QString::fromLatin1("application/x-gzip"))) {
|
||||
return KCompressor::TypeGZip;
|
||||
} else if (kmimetype->is(QString::fromLatin1("application/x-bzip"))) {
|
||||
return KCompressor::TypeBZip2;
|
||||
} else if (kmimetype->is(QString::fromLatin1("application/x-xz"))) {
|
||||
return KCompressor::TypeXZ;
|
||||
}
|
||||
}
|
||||
return KCompressor::TypeUnknown;
|
||||
}
|
||||
|
||||
KCompressor::KCompressorType KCompressor::typeForFile(const QString &filepath)
|
||||
{
|
||||
const KMimeType::Ptr kmimetype = KMimeType::findByPath(filepath);
|
||||
if (kmimetype) {
|
||||
return KCompressor::typeForMime(kmimetype->name());
|
||||
}
|
||||
return KCompressor::TypeUnknown;
|
||||
}
|
60
kdecore/compression/kcompressor.h
Normal file
60
kdecore/compression/kcompressor.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2, as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KCOMPRESSOR_H
|
||||
#define KCOMPRESSOR_H
|
||||
|
||||
#include <kdecore_export.h>
|
||||
|
||||
#include <QString>
|
||||
|
||||
class KCompressorPrivate;
|
||||
|
||||
class KDECORE_EXPORT KCompressor
|
||||
{
|
||||
public:
|
||||
enum KCompressorType {
|
||||
TypeUnknown = 0,
|
||||
TypeDeflate = 1,
|
||||
TypeZlib = 2,
|
||||
TypeGZip = 3,
|
||||
TypeBZip2 = 4,
|
||||
TypeXZ = 5
|
||||
};
|
||||
|
||||
KCompressor();
|
||||
~KCompressor();
|
||||
|
||||
KCompressorType type() const;
|
||||
bool setType(const KCompressorType type);
|
||||
int level() const;
|
||||
bool setLevel(const int level);
|
||||
|
||||
bool process(const QByteArray &data);
|
||||
QByteArray result() const;
|
||||
|
||||
QString errorString() const;
|
||||
|
||||
static KCompressorType typeForMime(const QString &mime);
|
||||
static KCompressorType typeForFile(const QString &filepath);
|
||||
|
||||
private:
|
||||
KCompressorPrivate* d;
|
||||
};
|
||||
|
||||
#endif // KCOMPRESSOR_H
|
323
kdecore/compression/kdecompressor.cpp
Normal file
323
kdecore/compression/kdecompressor.cpp
Normal file
|
@ -0,0 +1,323 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2, as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "config-compression.h"
|
||||
#include "kdecompressor.h"
|
||||
#include "klocale.h"
|
||||
#include "kmimetype.h"
|
||||
#include "kdebug.h"
|
||||
#include <qplatformdefs.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <libdeflate.h>
|
||||
|
||||
#if defined(HAVE_BZIP2_SUPPORT)
|
||||
# include <bzlib.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_XZ_SUPPORT)
|
||||
# include <lzma.h>
|
||||
#endif
|
||||
|
||||
// for reference:
|
||||
// http://linux.math.tifr.res.in/manuals/html/manual_3.html
|
||||
|
||||
class KDecompressorPrivate
|
||||
{
|
||||
public:
|
||||
KDecompressorPrivate();
|
||||
|
||||
KDecompressor::KDecompressorType m_type;
|
||||
QByteArray m_result;
|
||||
QString m_errorstring;
|
||||
};
|
||||
|
||||
KDecompressorPrivate::KDecompressorPrivate()
|
||||
: m_type(KDecompressor::TypeUnknown)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KDecompressor::KDecompressor()
|
||||
: d(new KDecompressorPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
KDecompressor::~KDecompressor()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
KDecompressor::KDecompressorType KDecompressor::type() const
|
||||
{
|
||||
return d->m_type;
|
||||
}
|
||||
|
||||
bool KDecompressor::setType(const KDecompressorType type)
|
||||
{
|
||||
if (type == KDecompressor::TypeUnknown) {
|
||||
return false;
|
||||
}
|
||||
d->m_type = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KDecompressor::process(const QByteArray &data)
|
||||
{
|
||||
d->m_errorstring.clear();
|
||||
d->m_result.clear();
|
||||
|
||||
switch (d->m_type) {
|
||||
case KDecompressor::TypeUnknown: {
|
||||
return false;
|
||||
}
|
||||
case KDecompressor::TypeDeflate: {
|
||||
struct libdeflate_decompressor* decomp = libdeflate_alloc_decompressor();
|
||||
if (Q_UNLIKELY(!decomp)) {
|
||||
d->m_errorstring = i18n("Could not allocate decompressor");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t speculativesize = (data.size() * 2);
|
||||
d->m_result.resize(speculativesize);
|
||||
|
||||
libdeflate_result decompresult = LIBDEFLATE_INSUFFICIENT_SPACE;
|
||||
while (decompresult == LIBDEFLATE_INSUFFICIENT_SPACE) {
|
||||
decompresult = libdeflate_deflate_decompress(
|
||||
decomp,
|
||||
data.constData(), data.size(),
|
||||
d->m_result.data(), d->m_result.size(),
|
||||
&speculativesize
|
||||
);
|
||||
|
||||
if (decompresult == LIBDEFLATE_INSUFFICIENT_SPACE) {
|
||||
speculativesize = (speculativesize + QT_BUFFSIZE);
|
||||
d->m_result.resize(speculativesize);
|
||||
}
|
||||
|
||||
if (speculativesize >= INT_MAX) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
libdeflate_free_decompressor(decomp);
|
||||
|
||||
if (decompresult != LIBDEFLATE_SUCCESS) {
|
||||
d->m_errorstring = i18n("Could not decompress data");
|
||||
d->m_result.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
d->m_result.resize(speculativesize);
|
||||
return true;
|
||||
}
|
||||
case KDecompressor::TypeZlib: {
|
||||
struct libdeflate_decompressor* decomp = libdeflate_alloc_decompressor();
|
||||
if (Q_UNLIKELY(!decomp)) {
|
||||
d->m_errorstring = i18n("Could not allocate decompressor");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t speculativesize = (data.size() * 2);
|
||||
d->m_result.resize(speculativesize);
|
||||
|
||||
libdeflate_result decompresult = LIBDEFLATE_INSUFFICIENT_SPACE;
|
||||
while (decompresult == LIBDEFLATE_INSUFFICIENT_SPACE) {
|
||||
decompresult = libdeflate_zlib_decompress(
|
||||
decomp,
|
||||
data.constData(), data.size(),
|
||||
d->m_result.data(), d->m_result.size(),
|
||||
&speculativesize
|
||||
);
|
||||
|
||||
if (decompresult == LIBDEFLATE_INSUFFICIENT_SPACE) {
|
||||
speculativesize = (speculativesize + QT_BUFFSIZE);
|
||||
d->m_result.resize(speculativesize);
|
||||
}
|
||||
|
||||
if (speculativesize >= INT_MAX) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
libdeflate_free_decompressor(decomp);
|
||||
|
||||
if (decompresult != LIBDEFLATE_SUCCESS) {
|
||||
d->m_errorstring = i18n("Could not decompress data");
|
||||
d->m_result.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
d->m_result.resize(speculativesize);
|
||||
return true;
|
||||
}
|
||||
case KDecompressor::TypeGZip: {
|
||||
struct libdeflate_decompressor* decomp = libdeflate_alloc_decompressor();
|
||||
if (Q_UNLIKELY(!decomp)) {
|
||||
d->m_errorstring = i18n("Could not allocate decompressor");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t speculativesize = (data.size() * 2);
|
||||
d->m_result.resize(speculativesize);
|
||||
|
||||
libdeflate_result decompresult = LIBDEFLATE_INSUFFICIENT_SPACE;
|
||||
while (decompresult == LIBDEFLATE_INSUFFICIENT_SPACE) {
|
||||
decompresult = libdeflate_gzip_decompress(
|
||||
decomp,
|
||||
data.constData(), data.size(),
|
||||
d->m_result.data(), d->m_result.size(),
|
||||
&speculativesize
|
||||
);
|
||||
|
||||
if (decompresult == LIBDEFLATE_INSUFFICIENT_SPACE) {
|
||||
speculativesize = (speculativesize + QT_BUFFSIZE);
|
||||
d->m_result.resize(speculativesize);
|
||||
}
|
||||
|
||||
if (speculativesize >= INT_MAX) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
libdeflate_free_decompressor(decomp);
|
||||
|
||||
if (decompresult != LIBDEFLATE_SUCCESS) {
|
||||
d->m_errorstring = i18n("Could not decompress data");
|
||||
d->m_result.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
d->m_result.resize(speculativesize);
|
||||
return true;
|
||||
}
|
||||
#if defined(HAVE_BZIP2_SUPPORT)
|
||||
case KDecompressor::TypeBZip2: {
|
||||
uint speculativesize = (data.size() * 2);
|
||||
d->m_result.resize(speculativesize);
|
||||
int decompresult = BZ_OUTBUFF_FULL;
|
||||
while (decompresult == BZ_OUTBUFF_FULL) {
|
||||
decompresult = BZ2_bzBuffToBuffDecompress(
|
||||
d->m_result.data(), &speculativesize,
|
||||
(char*)data.constData(), data.size(),
|
||||
0, 0
|
||||
);
|
||||
|
||||
if (decompresult == BZ_OUTBUFF_FULL) {
|
||||
speculativesize = (speculativesize + QT_BUFFSIZE);
|
||||
d->m_result.resize(speculativesize);
|
||||
}
|
||||
|
||||
if (speculativesize >= INT_MAX) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Q_UNLIKELY(decompresult < BZ_OK || decompresult > BZ_STREAM_END)) {
|
||||
d->m_errorstring = i18n("Could not decompress data");
|
||||
d->m_result.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
d->m_result.resize(speculativesize);
|
||||
return true;
|
||||
}
|
||||
#endif // HAVE_BZIP2_SUPPORT
|
||||
#if defined(HAVE_XZ_SUPPORT)
|
||||
case KDecompressor::TypeXZ: {
|
||||
size_t speculativesize = (data.size() * 2);
|
||||
d->m_result.resize(speculativesize);
|
||||
|
||||
lzma_stream decomp = LZMA_STREAM_INIT;
|
||||
decomp.next_in = (const uint8_t*)data.constData();
|
||||
decomp.avail_in = data.size();
|
||||
decomp.next_out = (uint8_t*)d->m_result.data();
|
||||
decomp.avail_out = speculativesize;
|
||||
|
||||
lzma_ret decompresult = lzma_auto_decoder(&decomp, UINT64_MAX, 0);
|
||||
if (Q_UNLIKELY(decompresult != LZMA_OK)) {
|
||||
d->m_errorstring = i18n("Could not initialize decompressor");
|
||||
d->m_result.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
decompresult = LZMA_MEM_ERROR;
|
||||
while (decompresult == LZMA_MEM_ERROR) {
|
||||
decompresult = lzma_code(&decomp, LZMA_FINISH);
|
||||
|
||||
if (decompresult == LZMA_MEM_ERROR) {
|
||||
speculativesize = (speculativesize + QT_BUFFSIZE);
|
||||
d->m_result.resize(speculativesize);
|
||||
}
|
||||
|
||||
if (speculativesize >= INT_MAX) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Q_UNLIKELY(decompresult != LZMA_OK && decompresult != LZMA_STREAM_END)) {
|
||||
d->m_errorstring = i18n("Could not decompress data");
|
||||
d->m_result.clear();
|
||||
return false;
|
||||
}
|
||||
speculativesize = decomp.total_out;
|
||||
lzma_end(&decomp);
|
||||
|
||||
d->m_result.resize(speculativesize);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // HAVE_XZ_SUPPORT
|
||||
default: {
|
||||
kWarning() << "Unsupported type" << d->m_type;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
QByteArray KDecompressor::result() const
|
||||
{
|
||||
return d->m_result;
|
||||
}
|
||||
|
||||
QString KDecompressor::errorString() const
|
||||
{
|
||||
return d->m_errorstring;
|
||||
}
|
||||
|
||||
KDecompressor::KDecompressorType KDecompressor::typeForMime(const QString &mime)
|
||||
{
|
||||
const KMimeType::Ptr kmimetype = KMimeType::mimeType(mime);
|
||||
if (kmimetype) {
|
||||
if (kmimetype->is(QString::fromLatin1("application/x-gzip"))) {
|
||||
return KDecompressor::TypeGZip;
|
||||
} else if (kmimetype->is(QString::fromLatin1("application/x-bzip"))) {
|
||||
return KDecompressor::TypeBZip2;
|
||||
} else if (kmimetype->is(QString::fromLatin1("application/x-xz"))) {
|
||||
return KDecompressor::TypeXZ;
|
||||
}
|
||||
}
|
||||
return KDecompressor::TypeUnknown;
|
||||
}
|
||||
|
||||
KDecompressor::KDecompressorType KDecompressor::typeForFile(const QString &filepath)
|
||||
{
|
||||
const KMimeType::Ptr kmimetype = KMimeType::findByPath(filepath);
|
||||
if (kmimetype) {
|
||||
return KDecompressor::typeForMime(kmimetype->name());
|
||||
}
|
||||
return KDecompressor::TypeUnknown;
|
||||
}
|
58
kdecore/compression/kdecompressor.h
Normal file
58
kdecore/compression/kdecompressor.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2022 Ivailo Monev <xakepa10@gmail.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2, as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KDECOMPRESSOR_H
|
||||
#define KDECOMPRESSOR_H
|
||||
|
||||
#include <kdecore_export.h>
|
||||
|
||||
#include <QString>
|
||||
|
||||
class KDecompressorPrivate;
|
||||
|
||||
class KDECORE_EXPORT KDecompressor
|
||||
{
|
||||
public:
|
||||
enum KDecompressorType {
|
||||
TypeUnknown = 0,
|
||||
TypeDeflate = 1,
|
||||
TypeZlib = 2,
|
||||
TypeGZip = 3,
|
||||
TypeBZip2 = 4,
|
||||
TypeXZ = 5
|
||||
};
|
||||
|
||||
KDecompressor();
|
||||
~KDecompressor();
|
||||
|
||||
KDecompressorType type() const;
|
||||
bool setType(const KDecompressorType type);
|
||||
|
||||
bool process(const QByteArray &data);
|
||||
QByteArray result() const;
|
||||
|
||||
QString errorString() const;
|
||||
|
||||
static KDecompressorType typeForMime(const QString &mime);
|
||||
static KDecompressorType typeForFile(const QString &filepath);
|
||||
|
||||
private:
|
||||
KDecompressorPrivate* d;
|
||||
};
|
||||
|
||||
#endif // KDECOMPRESSOR_H
|
|
@ -1,176 +0,0 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2000-2005 David Faure <faure@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "kfilterbase.h"
|
||||
#include <config-compression.h>
|
||||
|
||||
#include <QtCore/QIODevice>
|
||||
#include <kmimetype.h>
|
||||
#include "kgzipfilter.h"
|
||||
#if HAVE_BZIP2_SUPPORT
|
||||
#include "kbzip2filter.h"
|
||||
#endif
|
||||
#if HAVE_XZ_SUPPORT
|
||||
#include "kxzfilter.h"
|
||||
#endif
|
||||
|
||||
class KFilterBasePrivate
|
||||
{
|
||||
public:
|
||||
KFilterBasePrivate();
|
||||
|
||||
QIODevice * m_dev;
|
||||
bool m_bAutoDel;
|
||||
KFilterBase::FilterFlags m_flags;
|
||||
};
|
||||
|
||||
KFilterBasePrivate::KFilterBasePrivate()
|
||||
: m_dev( 0L ),
|
||||
m_bAutoDel( false ),
|
||||
m_flags(KFilterBase::WithHeaders)
|
||||
{
|
||||
}
|
||||
|
||||
KFilterBase::KFilterBase()
|
||||
: d(new KFilterBasePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
KFilterBase::~KFilterBase()
|
||||
{
|
||||
if ( d->m_bAutoDel )
|
||||
delete d->m_dev;
|
||||
delete d;
|
||||
}
|
||||
|
||||
void KFilterBase::setDevice( QIODevice * dev, bool autodelete )
|
||||
{
|
||||
d->m_dev = dev;
|
||||
d->m_bAutoDel = autodelete;
|
||||
}
|
||||
|
||||
QIODevice * KFilterBase::device()
|
||||
{
|
||||
return d->m_dev;
|
||||
}
|
||||
|
||||
bool KFilterBase::inBufferEmpty() const
|
||||
{
|
||||
return inBufferAvailable() == 0;
|
||||
}
|
||||
|
||||
bool KFilterBase::outBufferFull() const
|
||||
{
|
||||
return outBufferAvailable() == 0;
|
||||
}
|
||||
|
||||
KFilterBase * KFilterBase::findFilterByFileName( const QString & fileName )
|
||||
{
|
||||
if ( fileName.endsWith( QLatin1String(".gz"), Qt::CaseInsensitive ) )
|
||||
{
|
||||
return new KGzipFilter;
|
||||
}
|
||||
#if HAVE_BZIP2_SUPPORT
|
||||
if ( fileName.endsWith( QLatin1String(".bz2"), Qt::CaseInsensitive ) )
|
||||
{
|
||||
return new KBzip2Filter;
|
||||
}
|
||||
#endif
|
||||
#if HAVE_XZ_SUPPORT
|
||||
if ( fileName.endsWith( QLatin1String(".lzma"), Qt::CaseInsensitive ) || fileName.endsWith( QLatin1String(".xz"), Qt::CaseInsensitive ) )
|
||||
{
|
||||
return new KXzFilter;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
// not a warning, since this is called often with other mimetypes (see #88574)...
|
||||
// maybe we can avoid that though?
|
||||
//qDebug() << "KFilterBase::findFilterByFileName : no filter found for " << fileName;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
KFilterBase * KFilterBase::findFilterByMimeType( const QString & mimeType )
|
||||
{
|
||||
if (mimeType == QLatin1String("application/x-gzip")) {
|
||||
return new KGzipFilter;
|
||||
}
|
||||
#if HAVE_BZIP2_SUPPORT
|
||||
if (mimeType == QLatin1String("application/x-bzip")
|
||||
|| mimeType == QLatin1String("application/x-bzip2") // old name, kept for compatibility
|
||||
) {
|
||||
return new KBzip2Filter;
|
||||
}
|
||||
#endif
|
||||
#if HAVE_XZ_SUPPORT
|
||||
if ( mimeType == QLatin1String( "application/x-lzma" ) // legacy name, still used
|
||||
|| mimeType == QLatin1String( "application/x-xz" ) // current naming
|
||||
) {
|
||||
return new KXzFilter;
|
||||
}
|
||||
#endif
|
||||
const KMimeType::Ptr mime = KMimeType::mimeType(mimeType);
|
||||
if (mime) {
|
||||
if (mime->is(QString::fromLatin1("application/x-gzip"))) {
|
||||
return new KGzipFilter;
|
||||
}
|
||||
#if HAVE_BZIP2_SUPPORT
|
||||
if (mime->is(QString::fromLatin1("application/x-bzip"))) {
|
||||
return new KBzip2Filter;
|
||||
}
|
||||
#endif
|
||||
#if HAVE_XZ_SUPPORT
|
||||
if (mime->is(QString::fromLatin1("application/x-lzma"))) {
|
||||
return new KXzFilter;
|
||||
}
|
||||
|
||||
if (mime->is(QString::fromLatin1("application/x-xz"))) {
|
||||
return new KXzFilter;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// not a warning, since this is called often with other mimetypes (see #88574)...
|
||||
// maybe we can avoid that though?
|
||||
//qDebug() << "no filter found for" << mimeType;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool KFilterBase::terminate()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KFilterBase::reset()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void KFilterBase::setFilterFlags(FilterFlags flags)
|
||||
{
|
||||
d->m_flags = flags;
|
||||
}
|
||||
|
||||
KFilterBase::FilterFlags KFilterBase::filterFlags() const
|
||||
{
|
||||
return d->m_flags;
|
||||
}
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2000 David Faure <faure@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KFILTERBASE_H
|
||||
#define KFILTERBASE_H
|
||||
|
||||
#include <kdecore_export.h>
|
||||
|
||||
#include <QtCore/qiodevice.h>
|
||||
|
||||
class KFilterBasePrivate;
|
||||
|
||||
/**
|
||||
* This is the base class for compression filters
|
||||
* such as gzip and bzip2. It's pretty much internal.
|
||||
* Don't use directly, use KFilterDev instead.
|
||||
* @internal
|
||||
*/
|
||||
class KDECORE_EXPORT KFilterBase
|
||||
{
|
||||
public:
|
||||
KFilterBase();
|
||||
virtual ~KFilterBase();
|
||||
|
||||
/**
|
||||
* Sets the device on which the filter will work
|
||||
* @param dev the device on which the filter will work
|
||||
* @param autodelete if true, @p dev is deleted when the filter is deleted
|
||||
*/
|
||||
void setDevice( QIODevice * dev, bool autodelete = false );
|
||||
// Note that this isn't in the constructor, because of KPluginFactory::create,
|
||||
// but it should be called before using the filterbase !
|
||||
|
||||
/**
|
||||
* Returns the device on which the filter will work.
|
||||
* @returns the device on which the filter will work
|
||||
*/
|
||||
QIODevice * device();
|
||||
/** \internal */
|
||||
virtual bool init( int mode ) = 0;
|
||||
/** \internal */
|
||||
virtual int mode() const = 0;
|
||||
/** \internal */
|
||||
virtual bool terminate();
|
||||
/** \internal */
|
||||
virtual bool reset();
|
||||
/** \internal */
|
||||
virtual bool readHeader() = 0;
|
||||
/** \internal */
|
||||
virtual bool writeHeader( const QByteArray & filename ) = 0;
|
||||
/** \internal */
|
||||
virtual void setOutBuffer( char * data, uint maxlen ) = 0;
|
||||
/** \internal */
|
||||
virtual void setInBuffer( const char * data, uint size ) = 0;
|
||||
/** \internal */
|
||||
virtual bool inBufferEmpty() const;
|
||||
/** \internal */
|
||||
virtual int inBufferAvailable() const = 0;
|
||||
/** \internal */
|
||||
virtual bool outBufferFull() const;
|
||||
/** \internal */
|
||||
virtual int outBufferAvailable() const = 0;
|
||||
|
||||
/** \internal */
|
||||
enum Result { Ok, End, Error };
|
||||
/** \internal */
|
||||
virtual Result uncompress() = 0;
|
||||
/** \internal */
|
||||
virtual Result compress( bool finish ) = 0;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* \since 4.3
|
||||
*/
|
||||
enum FilterFlags {
|
||||
NoHeaders = 0,
|
||||
WithHeaders = 1
|
||||
};
|
||||
/**
|
||||
* \internal
|
||||
* \since 4.3
|
||||
*/
|
||||
void setFilterFlags(FilterFlags flags);
|
||||
FilterFlags filterFlags() const;
|
||||
|
||||
/**
|
||||
* Call this to create the appropriate filter for the file
|
||||
* named @p fileName.
|
||||
* @param fileName the name of the file to filter
|
||||
* @return the filter for the @p fileName, or 0 if not found
|
||||
*/
|
||||
static KFilterBase * findFilterByFileName( const QString & fileName );
|
||||
|
||||
/**
|
||||
* Call this to create the appropriate filter for the mimetype
|
||||
* @p mimeType. For instance application/x-gzip.
|
||||
* @param mimeType the mime type of the file to filter
|
||||
* @return the filter for the @p mimeType, or 0 if not found
|
||||
*/
|
||||
static KFilterBase * findFilterByMimeType( const QString & mimeType );
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY( KFilterBase )
|
||||
KFilterBasePrivate * const d;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,368 +0,0 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2000, 2006 David Faure <faure@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "kfilterdev.h"
|
||||
#include "kfilterbase.h"
|
||||
|
||||
#include <stdio.h> // for EOF
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/qfile.h>
|
||||
|
||||
#define BUFFER_SIZE 8*1024
|
||||
|
||||
class KFilterDev::Private
|
||||
{
|
||||
public:
|
||||
Private() : bNeedHeader(true), bSkipHeaders(false),
|
||||
autoDeleteFilterBase(false), bOpenedUnderlyingDevice(false),
|
||||
bIgnoreData(false){}
|
||||
bool bNeedHeader;
|
||||
bool bSkipHeaders;
|
||||
bool autoDeleteFilterBase;
|
||||
bool bOpenedUnderlyingDevice;
|
||||
bool bIgnoreData;
|
||||
QByteArray buffer; // Used as 'input buffer' when reading, as 'output buffer' when writing
|
||||
QByteArray origFileName;
|
||||
KFilterBase::Result result;
|
||||
KFilterBase *filter;
|
||||
};
|
||||
|
||||
KFilterDev::KFilterDev( KFilterBase * _filter, bool autoDeleteFilterBase )
|
||||
: d(new Private)
|
||||
{
|
||||
assert(_filter);
|
||||
d->filter = _filter;
|
||||
d->autoDeleteFilterBase = autoDeleteFilterBase;
|
||||
}
|
||||
|
||||
KFilterDev::~KFilterDev()
|
||||
{
|
||||
if ( isOpen() )
|
||||
close();
|
||||
if ( d->autoDeleteFilterBase )
|
||||
delete d->filter;
|
||||
delete d;
|
||||
}
|
||||
|
||||
//static
|
||||
QIODevice * KFilterDev::deviceForFile( const QString & fileName, const QString & mimetype,
|
||||
bool forceFilter )
|
||||
{
|
||||
QFile * f = new QFile( fileName );
|
||||
KFilterBase * base = mimetype.isEmpty() ? KFilterBase::findFilterByFileName( fileName )
|
||||
: KFilterBase::findFilterByMimeType( mimetype );
|
||||
if ( base )
|
||||
{
|
||||
base->setDevice(f, true);
|
||||
return new KFilterDev(base, true);
|
||||
}
|
||||
if(!forceFilter)
|
||||
return f;
|
||||
else
|
||||
{
|
||||
delete f;
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
QIODevice * KFilterDev::device( QIODevice* inDevice, const QString & mimetype, bool autoDeleteInDevice )
|
||||
{
|
||||
if (inDevice==0)
|
||||
return 0;
|
||||
KFilterBase * base = KFilterBase::findFilterByMimeType(mimetype);
|
||||
if ( base )
|
||||
{
|
||||
base->setDevice(inDevice, autoDeleteInDevice);
|
||||
return new KFilterDev(base, true /* auto-delete "base" */);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool KFilterDev::open( QIODevice::OpenMode mode )
|
||||
{
|
||||
if (isOpen()) {
|
||||
qWarning() << "KFilterDev::open: device is already open";
|
||||
return true; // QFile returns false, but well, the device -is- open...
|
||||
}
|
||||
//kDebug(7005) << mode;
|
||||
if ( mode == QIODevice::ReadOnly )
|
||||
{
|
||||
d->buffer.resize(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
d->buffer.resize( BUFFER_SIZE );
|
||||
d->filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
|
||||
}
|
||||
d->bNeedHeader = !d->bSkipHeaders;
|
||||
d->filter->setFilterFlags(d->bSkipHeaders ? KFilterBase::NoHeaders : KFilterBase::WithHeaders);
|
||||
d->filter->init( mode );
|
||||
d->bOpenedUnderlyingDevice = !d->filter->device()->isOpen();
|
||||
bool ret = d->bOpenedUnderlyingDevice ? d->filter->device()->open( mode ) : true;
|
||||
d->result = KFilterBase::Ok;
|
||||
|
||||
if ( !ret )
|
||||
qWarning() << "KFilterDev::open: Couldn't open underlying device";
|
||||
else
|
||||
setOpenMode( mode );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void KFilterDev::close()
|
||||
{
|
||||
if ( !isOpen() )
|
||||
return;
|
||||
if ( d->filter->mode() == QIODevice::WriteOnly )
|
||||
write( 0L, 0 ); // finish writing
|
||||
//kDebug(7005) << "Calling terminate().";
|
||||
|
||||
d->filter->terminate();
|
||||
if ( d->bOpenedUnderlyingDevice )
|
||||
d->filter->device()->close();
|
||||
setOpenMode( QIODevice::NotOpen );
|
||||
}
|
||||
|
||||
bool KFilterDev::seek( qint64 pos )
|
||||
{
|
||||
qint64 ioIndex = this->pos(); // current position
|
||||
if ( ioIndex == pos )
|
||||
return true;
|
||||
|
||||
//kDebug(7005) << "seek(" << pos << ") called";
|
||||
|
||||
Q_ASSERT ( d->filter->mode() == QIODevice::ReadOnly );
|
||||
|
||||
if ( pos == 0 )
|
||||
{
|
||||
// We can forget about the cached data
|
||||
d->bNeedHeader = !d->bSkipHeaders;
|
||||
d->result = KFilterBase::Ok;
|
||||
d->filter->setInBuffer(0L,0);
|
||||
d->filter->reset();
|
||||
QIODevice::seek(pos);
|
||||
return d->filter->device()->reset();
|
||||
}
|
||||
|
||||
if ( ioIndex > pos ) // we can start from here
|
||||
pos = pos - ioIndex;
|
||||
else
|
||||
{
|
||||
// we have to start from 0 ! Ugly and slow, but better than the previous
|
||||
// solution (KTarGz was allocating everything into memory)
|
||||
if (!seek(0)) // recursive
|
||||
return false;
|
||||
}
|
||||
|
||||
//kDebug(7005) << "reading " << pos << " dummy bytes";
|
||||
QByteArray dummy( qMin( pos, (qint64)3*BUFFER_SIZE ), 0 );
|
||||
d->bIgnoreData = true;
|
||||
bool result = ( read( dummy.data(), pos ) == pos );
|
||||
d->bIgnoreData = false;
|
||||
QIODevice::seek(pos);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool KFilterDev::atEnd() const
|
||||
{
|
||||
return (d->result == KFilterBase::End)
|
||||
&& QIODevice::atEnd() // take QIODevice's internal buffer into account
|
||||
&& d->filter->device()->atEnd();
|
||||
}
|
||||
|
||||
qint64 KFilterDev::readData( char *data, qint64 maxlen )
|
||||
{
|
||||
Q_ASSERT ( d->filter->mode() == QIODevice::ReadOnly );
|
||||
//kDebug(7005) << "maxlen=" << maxlen;
|
||||
KFilterBase* filter = d->filter;
|
||||
|
||||
uint dataReceived = 0;
|
||||
|
||||
// We came to the end of the stream
|
||||
if ( d->result == KFilterBase::End )
|
||||
return dataReceived;
|
||||
|
||||
// If we had an error, return -1.
|
||||
if ( d->result != KFilterBase::Ok )
|
||||
return -1;
|
||||
|
||||
|
||||
qint64 outBufferSize;
|
||||
if ( d->bIgnoreData )
|
||||
{
|
||||
outBufferSize = qMin( maxlen, (qint64)3*BUFFER_SIZE );
|
||||
}
|
||||
else
|
||||
{
|
||||
outBufferSize = maxlen;
|
||||
}
|
||||
outBufferSize -= dataReceived;
|
||||
qint64 availOut = outBufferSize;
|
||||
filter->setOutBuffer( data, outBufferSize );
|
||||
|
||||
while ( dataReceived < maxlen )
|
||||
{
|
||||
if (filter->inBufferEmpty())
|
||||
{
|
||||
// Not sure about the best size to set there.
|
||||
// For sure, it should be bigger than the header size (see comment in readHeader)
|
||||
d->buffer.resize( BUFFER_SIZE );
|
||||
// Request data from underlying device
|
||||
int size = filter->device()->read( d->buffer.data(),
|
||||
d->buffer.size() );
|
||||
//kDebug(7005) << "got" << size << "bytes from device";
|
||||
if (size) {
|
||||
filter->setInBuffer( d->buffer.data(), size );
|
||||
} else {
|
||||
// Not enough data available in underlying device for now
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (d->bNeedHeader)
|
||||
{
|
||||
(void) filter->readHeader();
|
||||
d->bNeedHeader = false;
|
||||
}
|
||||
|
||||
d->result = filter->uncompress();
|
||||
|
||||
if (d->result == KFilterBase::Error)
|
||||
{
|
||||
qWarning() << "KFilterDev: Error when uncompressing data";
|
||||
break;
|
||||
}
|
||||
|
||||
// We got that much data since the last time we went here
|
||||
uint outReceived = availOut - filter->outBufferAvailable();
|
||||
//kDebug(7005) << "avail_out = " << filter->outBufferAvailable() << " result=" << d->result << " outReceived=" << outReceived;
|
||||
if( availOut < (uint)filter->outBufferAvailable() )
|
||||
qWarning() << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !";
|
||||
|
||||
dataReceived += outReceived;
|
||||
if ( !d->bIgnoreData ) // Move on in the output buffer
|
||||
{
|
||||
data += outReceived;
|
||||
availOut = maxlen - dataReceived;
|
||||
}
|
||||
else if ( maxlen - dataReceived < outBufferSize )
|
||||
{
|
||||
availOut = maxlen - dataReceived;
|
||||
}
|
||||
if (d->result == KFilterBase::End)
|
||||
{
|
||||
//kDebug(7005) << "got END. dataReceived=" << dataReceived;
|
||||
break; // Finished.
|
||||
}
|
||||
filter->setOutBuffer( data, availOut );
|
||||
}
|
||||
|
||||
return dataReceived;
|
||||
}
|
||||
|
||||
qint64 KFilterDev::writeData( const char *data /*0 to finish*/, qint64 len )
|
||||
{
|
||||
KFilterBase* filter = d->filter;
|
||||
Q_ASSERT ( filter->mode() == QIODevice::WriteOnly );
|
||||
// If we had an error, return 0.
|
||||
if ( d->result != KFilterBase::Ok )
|
||||
return 0;
|
||||
|
||||
bool finish = (data == 0L);
|
||||
if (!finish)
|
||||
{
|
||||
filter->setInBuffer( data, len );
|
||||
if (d->bNeedHeader)
|
||||
{
|
||||
(void)filter->writeHeader( d->origFileName );
|
||||
d->bNeedHeader = false;
|
||||
}
|
||||
}
|
||||
|
||||
uint dataWritten = 0;
|
||||
uint availIn = len;
|
||||
while ( dataWritten < len || finish )
|
||||
{
|
||||
|
||||
d->result = filter->compress( finish );
|
||||
|
||||
if (d->result == KFilterBase::Error)
|
||||
{
|
||||
qWarning() << "KFilterDev: Error when compressing data";
|
||||
// What to do ?
|
||||
break;
|
||||
}
|
||||
|
||||
// Wrote everything ?
|
||||
if (filter->inBufferEmpty() || (d->result == KFilterBase::End))
|
||||
{
|
||||
// We got that much data since the last time we went here
|
||||
uint wrote = availIn - filter->inBufferAvailable();
|
||||
|
||||
//kDebug(7005) << " Wrote everything for now. avail_in=" << filter->inBufferAvailable() << "result=" << d->result << "wrote=" << wrote;
|
||||
|
||||
// Move on in the input buffer
|
||||
data += wrote;
|
||||
dataWritten += wrote;
|
||||
|
||||
availIn = len - dataWritten;
|
||||
//kDebug(7005) << " availIn=" << availIn << "dataWritten=" << dataWritten << "pos=" << pos();
|
||||
if ( availIn > 0 )
|
||||
filter->setInBuffer( data, availIn );
|
||||
}
|
||||
|
||||
if (filter->outBufferFull() || (d->result == KFilterBase::End) || finish)
|
||||
{
|
||||
//kDebug(7005) << " writing to underlying. avail_out=" << filter->outBufferAvailable();
|
||||
int towrite = d->buffer.size() - filter->outBufferAvailable();
|
||||
if ( towrite > 0 )
|
||||
{
|
||||
// Write compressed data to underlying device
|
||||
int size = filter->device()->write( d->buffer.data(), towrite );
|
||||
if ( size != towrite ) {
|
||||
qWarning() << "KFilterDev::write. Could only write " << size << " out of " << towrite << " bytes";
|
||||
return 0; // indicate an error (happens on disk full)
|
||||
}
|
||||
//else
|
||||
//kDebug(7005) << " wrote " << size << " bytes";
|
||||
}
|
||||
if (d->result == KFilterBase::End)
|
||||
{
|
||||
//kDebug(7005) << " END";
|
||||
Q_ASSERT(finish); // hopefully we don't get end before finishing
|
||||
break;
|
||||
}
|
||||
d->buffer.resize(BUFFER_SIZE);
|
||||
filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
|
||||
}
|
||||
}
|
||||
|
||||
return dataWritten;
|
||||
}
|
||||
|
||||
void KFilterDev::setOrigFileName( const QByteArray & fileName )
|
||||
{
|
||||
d->origFileName = fileName;
|
||||
}
|
||||
|
||||
void KFilterDev::setSkipHeaders()
|
||||
{
|
||||
d->bSkipHeaders = true;
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2000 David Faure <faure@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef KFILTERDEV_H
|
||||
#define KFILTERDEV_H
|
||||
|
||||
#include <kdecore_export.h>
|
||||
#include <QtCore/qfile.h>
|
||||
|
||||
class KFilterBase;
|
||||
|
||||
/**
|
||||
* A class for reading and writing compressed data onto a device
|
||||
* (e.g. file, but other usages are possible, like a buffer or a socket).
|
||||
*
|
||||
* To simply read/write compressed files, see deviceForFile.
|
||||
*
|
||||
* @author David Faure <faure@kde.org>
|
||||
*/
|
||||
class KDECORE_EXPORT KFilterDev : public QIODevice
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Destructs the KFilterDev.
|
||||
* Calls close() if the filter device is still open.
|
||||
*/
|
||||
virtual ~KFilterDev();
|
||||
|
||||
/**
|
||||
* Open for reading or writing.
|
||||
* If the KFilterBase's device is not opened, it will be opened.
|
||||
*/
|
||||
virtual bool open( QIODevice::OpenMode mode );
|
||||
/**
|
||||
* Close after reading or writing.
|
||||
* If the KFilterBase's device was opened by open(), it will be closed.
|
||||
*/
|
||||
virtual void close();
|
||||
|
||||
/**
|
||||
* For writing gzip compressed files only:
|
||||
* set the name of the original file, to be used in the gzip header.
|
||||
* @param fileName the name of the original file
|
||||
*/
|
||||
void setOrigFileName( const QByteArray & fileName );
|
||||
|
||||
/**
|
||||
* Call this let this device skip the gzip headers when reading/writing.
|
||||
* This way KFilterDev (with gzip filter) can be used as a direct wrapper
|
||||
* around zlib - this is used by KZip.
|
||||
*/
|
||||
void setSkipHeaders();
|
||||
|
||||
/**
|
||||
* That one can be quite slow, when going back. Use with care.
|
||||
*/
|
||||
virtual bool seek( qint64 );
|
||||
|
||||
virtual bool atEnd() const;
|
||||
|
||||
/// Reimplemented to return true. KFilterDev is a sequential QIODevice.
|
||||
/// Well, not really, since it supports seeking and KZip uses that.
|
||||
//virtual bool isSequential() const { return true; }
|
||||
|
||||
public:
|
||||
|
||||
|
||||
// KDE4 TODO: turn those static methods into constructors
|
||||
|
||||
/**
|
||||
* Creates an i/o device that is able to read from @p fileName,
|
||||
* whether it's compressed or not. Available compression filters
|
||||
* (gzip/bzip2 etc.) will automatically be used.
|
||||
*
|
||||
* The compression filter to be used is determined from the @p fileName
|
||||
* if @p mimetype is empty. Pass "application/x-gzip" or "application/x-bzip"
|
||||
* to force the corresponding decompression filter, if available.
|
||||
*
|
||||
* Warning: application/x-bzip may not be available.
|
||||
* In that case a QFile opened on the compressed data will be returned !
|
||||
* Use KFilterBase::findFilterByMimeType and code similar to what
|
||||
* deviceForFile is doing, to better control what's happening.
|
||||
*
|
||||
* The returned QIODevice has to be deleted after using.
|
||||
*
|
||||
* @param fileName the name of the file to filter
|
||||
* @param mimetype the mime type of the file to filter, or QString() if unknown
|
||||
* @param forceFilter if true, the function will either find a compression filter, or return 0.
|
||||
* If false, it will always return a QIODevice. If no
|
||||
* filter is available it will return a simple QFile.
|
||||
* This can be useful if the file is usable without a filter.
|
||||
* @return if a filter has been found, the QIODevice for the filter. If the
|
||||
* filter does not exist, the return value depends on @p forceFilter.
|
||||
* The returned QIODevice has to be deleted after using.
|
||||
*/
|
||||
static QIODevice * deviceForFile( const QString & fileName, const QString & mimetype = QString(),
|
||||
bool forceFilter = false );
|
||||
|
||||
/**
|
||||
* Creates an i/o device that is able to read from the QIODevice @p inDevice,
|
||||
* whether the data is compressed or not. Available compression filters
|
||||
* (gzip/bzip2 etc.) will automatically be used.
|
||||
*
|
||||
* The compression filter to be used is determined @p mimetype .
|
||||
* Pass "application/x-gzip" or "application/x-bzip"
|
||||
* to use the corresponding decompression filter.
|
||||
*
|
||||
* Warning: application/x-bzip may not be available.
|
||||
* In that case 0 will be returned !
|
||||
*
|
||||
* The returned QIODevice has to be deleted after using.
|
||||
* @param inDevice input device. Won't be deleted if @p autoDeleteInDevice = false
|
||||
* @param mimetype the mime type for the filter
|
||||
* @param autoDeleteInDevice if true, @p inDevice will be deleted automatically
|
||||
* @return a KFilterDev that filters the original stream. Must be deleted after using
|
||||
*/
|
||||
static QIODevice * device( QIODevice* inDevice, const QString & mimetype, bool autoDeleteInDevice = true );
|
||||
|
||||
protected:
|
||||
virtual qint64 readData( char *data, qint64 maxlen );
|
||||
virtual qint64 writeData( const char *data, qint64 len );
|
||||
|
||||
private:
|
||||
/**
|
||||
* Constructs a KFilterDev for a given filter (e.g. gzip, bzip2 etc.).
|
||||
* @param filter the KFilterBase to use
|
||||
* @param autoDeleteFilterBase when true this object will become the
|
||||
* owner of @p filter.
|
||||
*/
|
||||
explicit KFilterDev( KFilterBase * filter, bool autoDeleteFilterBase = false );
|
||||
private:
|
||||
class Private;
|
||||
Private* const d;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -1,390 +0,0 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2000-2005 David Faure <faure@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "kgzipfilter.h"
|
||||
|
||||
#include <kdebug.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <zlib.h>
|
||||
#include <QtCore/qiodevice.h>
|
||||
|
||||
|
||||
/* gzip flag byte */
|
||||
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
|
||||
#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
|
||||
#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
|
||||
#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
|
||||
#define COMMENT 0x10 /* bit 4 set: file comment present */
|
||||
#define RESERVED 0xE0 /* bits 5..7: reserved */
|
||||
|
||||
// #define DEBUG_GZIP
|
||||
|
||||
class KGzipFilter::Private
|
||||
{
|
||||
public:
|
||||
Private()
|
||||
: headerWritten(false), footerWritten(false), compressed(false), mode(0), crc(0), isInitialized(false)
|
||||
{
|
||||
zStream.zalloc = (alloc_func)0;
|
||||
zStream.zfree = (free_func)0;
|
||||
zStream.opaque = (voidpf)0;
|
||||
}
|
||||
|
||||
z_stream zStream;
|
||||
bool headerWritten;
|
||||
bool footerWritten;
|
||||
bool compressed;
|
||||
int mode;
|
||||
ulong crc;
|
||||
bool isInitialized;
|
||||
};
|
||||
|
||||
KGzipFilter::KGzipFilter()
|
||||
: d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KGzipFilter::~KGzipFilter()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool KGzipFilter::init(int mode)
|
||||
{
|
||||
return init(mode, filterFlags() == WithHeaders ? GZipHeader : RawDeflate);
|
||||
}
|
||||
|
||||
bool KGzipFilter::init(int mode, Flag flag)
|
||||
{
|
||||
if (d->isInitialized) {
|
||||
terminate();
|
||||
}
|
||||
d->zStream.next_in = Z_NULL;
|
||||
d->zStream.avail_in = 0;
|
||||
if ( mode == QIODevice::ReadOnly )
|
||||
{
|
||||
const int windowBits = (flag == RawDeflate)
|
||||
? -MAX_WBITS /*no zlib header*/
|
||||
: (flag == GZipHeader) ?
|
||||
MAX_WBITS + 32 /* auto-detect and eat gzip header */
|
||||
: MAX_WBITS /*zlib header*/;
|
||||
const int result = inflateInit2(&d->zStream, windowBits);
|
||||
if ( result != Z_OK ) {
|
||||
kDebug(7110) << "inflateInit2 returned " << result;
|
||||
return false;
|
||||
}
|
||||
} else if ( mode == QIODevice::WriteOnly )
|
||||
{
|
||||
int result = deflateInit2(&d->zStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY); // same here
|
||||
if ( result != Z_OK ) {
|
||||
kDebug(7110) << "deflateInit returned " << result;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
kWarning(7110) << "KGzipFilter: Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
|
||||
return false;
|
||||
}
|
||||
d->mode = mode;
|
||||
d->compressed = true;
|
||||
d->headerWritten = false;
|
||||
d->footerWritten = false;
|
||||
d->isInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
int KGzipFilter::mode() const
|
||||
{
|
||||
return d->mode;
|
||||
}
|
||||
|
||||
bool KGzipFilter::terminate()
|
||||
{
|
||||
if ( d->mode == QIODevice::ReadOnly )
|
||||
{
|
||||
int result = inflateEnd(&d->zStream);
|
||||
if ( result != Z_OK ) {
|
||||
kDebug(7110) << "inflateEnd returned " << result;
|
||||
return false;
|
||||
}
|
||||
} else if ( d->mode == QIODevice::WriteOnly )
|
||||
{
|
||||
int result = deflateEnd(&d->zStream);
|
||||
if ( result != Z_OK ) {
|
||||
kDebug(7110) << "deflateEnd returned " << result;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
d->isInitialized = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool KGzipFilter::reset()
|
||||
{
|
||||
if ( d->mode == QIODevice::ReadOnly )
|
||||
{
|
||||
int result = inflateReset(&d->zStream);
|
||||
if ( result != Z_OK ) {
|
||||
kDebug(7110) << "inflateReset returned " << result;
|
||||
return false;
|
||||
}
|
||||
} else if ( d->mode == QIODevice::WriteOnly ) {
|
||||
int result = deflateReset(&d->zStream);
|
||||
if ( result != Z_OK ) {
|
||||
kDebug(7110) << "deflateReset returned " << result;
|
||||
return false;
|
||||
}
|
||||
d->headerWritten = false;
|
||||
d->footerWritten = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KGzipFilter::readHeader()
|
||||
{
|
||||
// We now rely on zlib to read the full header (see the MAX_WBITS + 32 in init).
|
||||
// We just use this method to check if the data is actually compressed.
|
||||
|
||||
#ifdef DEBUG_GZIP
|
||||
kDebug(7110) << "avail=" << d->zStream.avail_in;
|
||||
#endif
|
||||
// Assume not compressed until we see a gzip header
|
||||
d->compressed = false;
|
||||
Bytef *p = d->zStream.next_in;
|
||||
int i = d->zStream.avail_in;
|
||||
if ((i -= 10) < 0) return false; // Need at least 10 bytes
|
||||
#ifdef DEBUG_GZIP
|
||||
kDebug(7110) << "first byte is " << QString::number(*p,16);
|
||||
#endif
|
||||
if (*p++ != 0x1f) return false; // GZip magic
|
||||
#ifdef DEBUG_GZIP
|
||||
kDebug(7110) << "second byte is " << QString::number(*p,16);
|
||||
#endif
|
||||
if (*p++ != 0x8b) return false;
|
||||
|
||||
#if 0
|
||||
int method = *p++;
|
||||
int flags = *p++;
|
||||
if ((method != Z_DEFLATED) || (flags & RESERVED) != 0) return false;
|
||||
p += 6;
|
||||
if ((flags & EXTRA_FIELD) != 0) // skip extra field
|
||||
{
|
||||
if ((i -= 2) < 0) return false; // Need at least 2 bytes
|
||||
int len = *p++;
|
||||
len += (*p++) << 8;
|
||||
if ((i -= len) < 0) return false; // Need at least len bytes
|
||||
p += len;
|
||||
}
|
||||
if ((flags & ORIG_NAME) != 0) // skip original file name
|
||||
{
|
||||
#ifdef DEBUG_GZIP
|
||||
kDebug(7110) << "ORIG_NAME=" << (char*)p;
|
||||
#endif
|
||||
while( (i > 0) && (*p))
|
||||
{
|
||||
i--; p++;
|
||||
}
|
||||
if (--i <= 0) return false;
|
||||
p++;
|
||||
}
|
||||
if ((flags & COMMENT) != 0) // skip comment
|
||||
{
|
||||
while( (i > 0) && (*p))
|
||||
{
|
||||
i--; p++;
|
||||
}
|
||||
if (--i <= 0) return false;
|
||||
p++;
|
||||
}
|
||||
if ((flags & HEAD_CRC) != 0) // skip the header crc
|
||||
{
|
||||
if ((i-=2) < 0) return false;
|
||||
p += 2;
|
||||
}
|
||||
|
||||
d->zStream.avail_in = i;
|
||||
d->zStream.next_in = p;
|
||||
#endif
|
||||
|
||||
d->compressed = true;
|
||||
#ifdef DEBUG_GZIP
|
||||
kDebug(7110) << "header OK";
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Output a 16 bit value, lsb first */
|
||||
#define put_short(w) \
|
||||
*p++ = (uchar) ((w) & 0xff); \
|
||||
*p++ = (uchar) ((ushort)(w) >> 8);
|
||||
|
||||
/* Output a 32 bit value to the bit stream, lsb first */
|
||||
#define put_long(n) \
|
||||
put_short((n) & 0xffff); \
|
||||
put_short(((ulong)(n)) >> 16);
|
||||
|
||||
bool KGzipFilter::writeHeader( const QByteArray & fileName )
|
||||
{
|
||||
Bytef *p = d->zStream.next_out;
|
||||
int i = d->zStream.avail_out;
|
||||
*p++ = 0x1f;
|
||||
*p++ = 0x8b;
|
||||
*p++ = Z_DEFLATED;
|
||||
*p++ = ORIG_NAME;
|
||||
put_long( time( 0L ) ); // Modification time (in unix format)
|
||||
*p++ = 0; // Extra flags (2=max compress, 4=fastest compress)
|
||||
*p++ = 3; // Unix
|
||||
|
||||
uint len = fileName.length();
|
||||
for ( uint j = 0 ; j < len ; ++j )
|
||||
*p++ = fileName[j];
|
||||
*p++ = 0;
|
||||
int headerSize = p - d->zStream.next_out;
|
||||
i -= headerSize;
|
||||
Q_ASSERT(i>0);
|
||||
d->crc = crc32(0L, Z_NULL, 0);
|
||||
d->zStream.next_out = p;
|
||||
d->zStream.avail_out = i;
|
||||
d->headerWritten = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void KGzipFilter::writeFooter()
|
||||
{
|
||||
Q_ASSERT( d->headerWritten );
|
||||
Q_ASSERT(!d->footerWritten);
|
||||
Bytef *p = d->zStream.next_out;
|
||||
int i = d->zStream.avail_out;
|
||||
//kDebug(7110) << "avail_out=" << i << "writing CRC=" << QString::number(d->crc, 16) << "at p=" << p;
|
||||
put_long( d->crc );
|
||||
//kDebug(7110) << "writing totalin=" << d->zStream.total_in << "at p=" << p;
|
||||
put_long( d->zStream.total_in );
|
||||
i -= p - d->zStream.next_out;
|
||||
d->zStream.next_out = p;
|
||||
d->zStream.avail_out = i;
|
||||
d->footerWritten = true;
|
||||
}
|
||||
|
||||
void KGzipFilter::setOutBuffer( char * data, uint maxlen )
|
||||
{
|
||||
d->zStream.avail_out = maxlen;
|
||||
d->zStream.next_out = (Bytef *) data;
|
||||
}
|
||||
void KGzipFilter::setInBuffer( const char * data, uint size )
|
||||
{
|
||||
#ifdef DEBUG_GZIP
|
||||
kDebug(7110) << "avail_in=" << size;
|
||||
#endif
|
||||
d->zStream.avail_in = size;
|
||||
d->zStream.next_in = (Bytef*) data;
|
||||
}
|
||||
int KGzipFilter::inBufferAvailable() const
|
||||
{
|
||||
return d->zStream.avail_in;
|
||||
}
|
||||
int KGzipFilter::outBufferAvailable() const
|
||||
{
|
||||
return d->zStream.avail_out;
|
||||
}
|
||||
|
||||
KGzipFilter::Result KGzipFilter::uncompress_noop()
|
||||
{
|
||||
// I'm not sure we really need support for that (uncompressed streams),
|
||||
// but why not, it can't hurt to have it. One case I can think of is someone
|
||||
// naming a tar file "blah.tar.gz" :-)
|
||||
if ( d->zStream.avail_in > 0 )
|
||||
{
|
||||
int n = (d->zStream.avail_in < d->zStream.avail_out) ? d->zStream.avail_in : d->zStream.avail_out;
|
||||
memcpy( d->zStream.next_out, d->zStream.next_in, n );
|
||||
d->zStream.avail_out -= n;
|
||||
d->zStream.next_in += n;
|
||||
d->zStream.avail_in -= n;
|
||||
return KFilterBase::Ok;
|
||||
} else
|
||||
return KFilterBase::End;
|
||||
}
|
||||
|
||||
KGzipFilter::Result KGzipFilter::uncompress()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (d->mode == 0) {
|
||||
qWarning() << "mode==0; KGzipFilter::init was not called!";
|
||||
return KFilterBase::Error;
|
||||
} else if (d->mode == QIODevice::WriteOnly) {
|
||||
qWarning() << "uncompress called but the filter was opened for writing!";
|
||||
return KFilterBase::Error;
|
||||
}
|
||||
Q_ASSERT ( d->mode == QIODevice::ReadOnly );
|
||||
#endif
|
||||
|
||||
if ( d->compressed )
|
||||
{
|
||||
#ifdef DEBUG_GZIP
|
||||
kDebug(7110) << "Calling inflate with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
|
||||
kDebug(7110) << " next_in=" << d->zStream.next_in;
|
||||
#endif
|
||||
int result = inflate(&d->zStream, Z_SYNC_FLUSH);
|
||||
#ifdef DEBUG_GZIP
|
||||
kDebug(7110) << " -> inflate returned " << result;
|
||||
kDebug(7110) << " now avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
|
||||
kDebug(7110) << " next_in=" << d->zStream.next_in;
|
||||
#else
|
||||
if ( result != Z_OK && result != Z_STREAM_END )
|
||||
kDebug(7110) << "Warning: inflate() returned " << result;
|
||||
#endif
|
||||
return ( result == Z_OK ? KFilterBase::Ok : ( result == Z_STREAM_END ? KFilterBase::End : KFilterBase::Error ) );
|
||||
} else
|
||||
return uncompress_noop();
|
||||
}
|
||||
|
||||
KGzipFilter::Result KGzipFilter::compress( bool finish )
|
||||
{
|
||||
Q_ASSERT ( d->compressed );
|
||||
Q_ASSERT ( d->mode == QIODevice::WriteOnly );
|
||||
|
||||
Bytef* p = d->zStream.next_in;
|
||||
ulong len = d->zStream.avail_in;
|
||||
#ifdef DEBUG_GZIP
|
||||
kDebug(7110) << " calling deflate with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
|
||||
#endif
|
||||
const int result = deflate(&d->zStream, finish ? Z_FINISH : Z_NO_FLUSH);
|
||||
if ( result != Z_OK && result != Z_STREAM_END ) {
|
||||
kDebug(7110) << " deflate returned " << result;
|
||||
}
|
||||
if ( d->headerWritten )
|
||||
{
|
||||
//kDebug(7110) << "Computing CRC for the next " << len - d->zStream.avail_in << " bytes";
|
||||
d->crc = crc32(d->crc, p, len - d->zStream.avail_in);
|
||||
}
|
||||
KGzipFilter::Result callerResult = result == Z_OK ? KFilterBase::Ok : (Z_STREAM_END ? KFilterBase::End : KFilterBase::Error);
|
||||
|
||||
if (result == Z_STREAM_END && d->headerWritten && !d->footerWritten) {
|
||||
if (d->zStream.avail_out >= 8 /*footer size*/) {
|
||||
//kDebug(7110) << "finished, write footer";
|
||||
writeFooter();
|
||||
} else {
|
||||
// No room to write the footer (#157706/#188415), we'll have to do it on the next pass.
|
||||
//kDebug(7110) << "finished, but no room for footer yet";
|
||||
callerResult = KFilterBase::Ok;
|
||||
}
|
||||
}
|
||||
return callerResult;
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2000, 2009 David Faure <faure@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KGZIPFILTER_H
|
||||
#define KGZIPFILTER_H
|
||||
|
||||
#include "kfilterbase.h"
|
||||
|
||||
/**
|
||||
* Internal class used by KFilterDev
|
||||
*
|
||||
* This header is not installed.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class KDECORE_EXPORT KGzipFilter : public KFilterBase
|
||||
{
|
||||
public:
|
||||
KGzipFilter();
|
||||
virtual ~KGzipFilter();
|
||||
|
||||
|
||||
virtual bool init(int mode);
|
||||
|
||||
// The top of zlib.h explains it: there are three cases.
|
||||
// - Raw deflate, no header (e.g. inside a ZIP file)
|
||||
// - Thin zlib header (1) (which is normally what HTTP calls "deflate" (2))
|
||||
// - Gzip header, implemented here by readHeader
|
||||
//
|
||||
// (1) as written out by compress()/compress2()
|
||||
// (2) see http://www.zlib.net/zlib_faq.html#faq39
|
||||
enum Flag {
|
||||
RawDeflate = 0, // raw deflate data
|
||||
ZlibHeader = 1, // zlib headers (HTTP deflate)
|
||||
GZipHeader = 2
|
||||
};
|
||||
bool init(int mode, Flag flag); // for direct users of KGzipFilter
|
||||
virtual int mode() const;
|
||||
virtual bool terminate();
|
||||
virtual bool reset();
|
||||
virtual bool readHeader(); // this is about the GZIP header
|
||||
virtual bool writeHeader( const QByteArray & fileName );
|
||||
void writeFooter();
|
||||
virtual void setOutBuffer( char * data, uint maxlen );
|
||||
virtual void setInBuffer( const char * data, uint size );
|
||||
virtual int inBufferAvailable() const;
|
||||
virtual int outBufferAvailable() const;
|
||||
virtual Result uncompress();
|
||||
virtual Result compress( bool finish );
|
||||
|
||||
private:
|
||||
Result uncompress_noop();
|
||||
class Private;
|
||||
Private* const d;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,184 +0,0 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2007-2008 Per Øyvind Karlsen <peroyvind@mandriva.org>
|
||||
|
||||
Based on kbzip2filter:
|
||||
Copyright (C) 2000-2005 David Faure <faure@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "kxzfilter.h"
|
||||
|
||||
#include <config-compression.h>
|
||||
|
||||
#if HAVE_XZ_SUPPORT
|
||||
extern "C" {
|
||||
#include <lzma.h>
|
||||
}
|
||||
|
||||
#include <kdebug.h>
|
||||
|
||||
#include <qiodevice.h>
|
||||
|
||||
|
||||
class KXzFilter::Private
|
||||
{
|
||||
public:
|
||||
Private()
|
||||
: isInitialized(false)
|
||||
{
|
||||
memset(&zStream, 0, sizeof(zStream));
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
lzma_stream zStream;
|
||||
int mode;
|
||||
bool isInitialized;
|
||||
};
|
||||
|
||||
KXzFilter::KXzFilter()
|
||||
:d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
KXzFilter::~KXzFilter()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool KXzFilter::init( int mode )
|
||||
{
|
||||
if (d->isInitialized) {
|
||||
terminate();
|
||||
}
|
||||
|
||||
d->zStream.next_in = 0;
|
||||
d->zStream.avail_in = 0;
|
||||
if ( mode == QIODevice::ReadOnly ) {
|
||||
/* We set the memlimit for decompression to 100MiB which should be
|
||||
* more than enough to be sufficient for level 9 which requires 65 MiB.
|
||||
*/
|
||||
const lzma_ret result = lzma_auto_decoder(&d->zStream, 100<<20, 0);
|
||||
if (result != LZMA_OK) {
|
||||
kDebug(7131) << "lzma_auto_decoder returned " << result;
|
||||
return false;
|
||||
}
|
||||
} else if ( mode == QIODevice::WriteOnly ) {
|
||||
const lzma_ret result = lzma_easy_encoder(&d->zStream, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC32);
|
||||
if (result != LZMA_OK) {
|
||||
kDebug(7131) << "lzma_easy_encoder returned " << result;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
kWarning(7131) << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
|
||||
return false;
|
||||
}
|
||||
d->mode = mode;
|
||||
d->isInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
int KXzFilter::mode() const
|
||||
{
|
||||
return d->mode;
|
||||
}
|
||||
|
||||
bool KXzFilter::terminate()
|
||||
{
|
||||
if (d->mode == QIODevice::ReadOnly || d->mode == QIODevice::WriteOnly) {
|
||||
lzma_end(&d->zStream);
|
||||
} else {
|
||||
kWarning(7131) << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
|
||||
return false;
|
||||
}
|
||||
d->isInitialized = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool KXzFilter::reset()
|
||||
{
|
||||
kDebug(7131) << "KXzFilter::reset";
|
||||
// liblzma doesn't have a reset call...
|
||||
if (!terminate()) {
|
||||
return false;
|
||||
}
|
||||
if (!init( d->mode )) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void KXzFilter::setOutBuffer( char * data, uint maxlen )
|
||||
{
|
||||
d->zStream.avail_out = maxlen;
|
||||
d->zStream.next_out = (uint8_t *)data;
|
||||
}
|
||||
|
||||
void KXzFilter::setInBuffer( const char *data, unsigned int size )
|
||||
{
|
||||
d->zStream.avail_in = size;
|
||||
d->zStream.next_in = (uint8_t *)const_cast<char *>(data);
|
||||
}
|
||||
|
||||
int KXzFilter::inBufferAvailable() const
|
||||
{
|
||||
return d->zStream.avail_in;
|
||||
}
|
||||
|
||||
int KXzFilter::outBufferAvailable() const
|
||||
{
|
||||
return d->zStream.avail_out;
|
||||
}
|
||||
|
||||
KXzFilter::Result KXzFilter::uncompress()
|
||||
{
|
||||
//kDebug(7131) << "Calling lzma_code with avail_in=" << inBufferAvailable() << " avail_out =" << outBufferAvailable();
|
||||
lzma_ret result = lzma_code(&d->zStream, LZMA_RUN);
|
||||
if ( result != LZMA_OK ) {
|
||||
kDebug(7131) << "lzma_code returned " << result;
|
||||
kDebug(7131) << "KXzFilter::uncompress " << ( result == LZMA_STREAM_END ? KFilterBase::End : KFilterBase::Error );
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case LZMA_OK:
|
||||
return KFilterBase::Ok;
|
||||
case LZMA_STREAM_END:
|
||||
return KFilterBase::End;
|
||||
default:
|
||||
return KFilterBase::Error;
|
||||
}
|
||||
}
|
||||
|
||||
KXzFilter::Result KXzFilter::compress( bool finish )
|
||||
{
|
||||
//kDebug(7131) << "Calling lzma_code with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
|
||||
lzma_ret result = lzma_code(&d->zStream, finish ? LZMA_FINISH : LZMA_RUN );
|
||||
|
||||
switch (result) {
|
||||
case LZMA_OK:
|
||||
return KFilterBase::Ok;
|
||||
case LZMA_STREAM_END:
|
||||
kDebug(7131) << " lzma_code returned " << result;
|
||||
return KFilterBase::End;
|
||||
default:
|
||||
kDebug(7131) << " lzma_code returned " << result;
|
||||
return KFilterBase::Error;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_XZ_SUPPORT */
|
|
@ -1,61 +0,0 @@
|
|||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2007-2008 Per Øyvind Karlsen <peroyvind@mandriva.org>
|
||||
|
||||
Based on kbzip2filter:
|
||||
Copyright (C) 2000 David Faure <faure@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KXZFILTER_H
|
||||
#define KXZFILTER_H
|
||||
|
||||
#include <config-compression.h>
|
||||
|
||||
#if HAVE_XZ_SUPPORT
|
||||
|
||||
#include "kfilterbase.h"
|
||||
|
||||
/**
|
||||
* Internal class used by KFilterDev
|
||||
* @internal
|
||||
*/
|
||||
class KXzFilter : public KFilterBase
|
||||
{
|
||||
public:
|
||||
KXzFilter();
|
||||
virtual ~KXzFilter();
|
||||
|
||||
virtual bool init( int );
|
||||
virtual int mode() const;
|
||||
virtual bool terminate();
|
||||
virtual bool reset();
|
||||
virtual bool readHeader() { return true; } // lzma handles it by itself ! Cool !
|
||||
virtual bool writeHeader( const QByteArray & ) { return true; }
|
||||
virtual void setOutBuffer( char * data, uint maxlen );
|
||||
virtual void setInBuffer( const char * data, uint size );
|
||||
virtual int inBufferAvailable() const;
|
||||
virtual int outBufferAvailable() const;
|
||||
virtual Result uncompress();
|
||||
virtual Result compress( bool finish );
|
||||
private:
|
||||
class Private;
|
||||
Private* const d;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // KXZFILTER_H
|
|
@ -19,8 +19,6 @@
|
|||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "kcharsets.h"
|
||||
|
||||
#include "kfilterdev.h"
|
||||
#include "kentities.cpp"
|
||||
|
||||
#include "kconfig.h"
|
||||
|
|
|
@ -104,12 +104,6 @@ set(kmimeglobsfileparsertest_SRCS kmimeglobsfileparsertest.cpp ../services/kmime
|
|||
kde4_add_test(kdecore-kmimeglobsfileparsertest ${kmimeglobsfileparsertest_SRCS})
|
||||
target_link_libraries(kdecore-kmimeglobsfileparsertest ${KDE4_KDECORE_LIBS} ${QT_QTTEST_LIBRARY})
|
||||
|
||||
########### kfiltertest ###############
|
||||
|
||||
set(kfiltertest_SRCS kfiltertest.cpp)
|
||||
kde4_add_test(kdecore-kfiltertest ${kfiltertest_SRCS})
|
||||
target_link_libraries(kdecore-kfiltertest ${KDE4_KDECORE_LIBS} ${QT_QTTEST_LIBRARY} ${ZLIB_LIBRARIES})
|
||||
|
||||
########### module for klibloadertest4 ###############
|
||||
|
||||
set(klibloadertestmodule4_PART_SRCS klibloadertest4_module.cpp )
|
||||
|
|
|
@ -1,369 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2002-2005 David Faure <faure@kde.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License version 2 as published by the Free Software Foundation;
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public License
|
||||
* along with this library; see the file COPYING.LIB. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "kfiltertest.h"
|
||||
|
||||
#include "qtest_kde.h"
|
||||
|
||||
#include <config-compression.h>
|
||||
#include "kfilterdev.h"
|
||||
#include "kfilterbase.h"
|
||||
#include <kdebug.h>
|
||||
#include <kgzipfilter.h>
|
||||
#include <krandom.h>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QTextStream>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QBuffer>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <zlib.h>
|
||||
|
||||
QTEST_KDEMAIN_CORE(KFilterTest)
|
||||
|
||||
void KFilterTest::initTestCase()
|
||||
{
|
||||
const QString currentdir = QDir::currentPath();
|
||||
pathgz = currentdir + "/test.gz";
|
||||
pathbz2 = currentdir + "/test.bz2";
|
||||
pathxz = currentdir + "/test.xz";
|
||||
|
||||
// warning, update the COMPAREs in test_block_write() if changing the test data...
|
||||
testData = "hello world\n";
|
||||
}
|
||||
|
||||
void KFilterTest::test_block_write(const QString & fileName, const QByteArray& data)
|
||||
{
|
||||
QIODevice * dev = KFilterDev::deviceForFile( fileName );
|
||||
QVERIFY( dev != 0 );
|
||||
bool ok = dev->open( QIODevice::WriteOnly );
|
||||
QVERIFY( ok );
|
||||
|
||||
const int ret = dev->write(data);
|
||||
QCOMPARE(ret, data.size());
|
||||
|
||||
dev->close();
|
||||
delete dev;
|
||||
|
||||
QVERIFY( QFile::exists( fileName ) );
|
||||
}
|
||||
|
||||
void KFilterTest::test_block_write()
|
||||
{
|
||||
kDebug() << " -- test_block_write gzip -- ";
|
||||
test_block_write(pathgz, testData);
|
||||
QCOMPARE( QFileInfo( pathgz ).size(), 33LL ); // size of test.gz
|
||||
|
||||
#if HAVE_BZIP2_SUPPORT
|
||||
kDebug() << " -- test_block_write bzip2 -- ";
|
||||
test_block_write(pathbz2, testData);
|
||||
QCOMPARE( QFileInfo( pathbz2 ).size(), 52LL ); // size of test.bz2
|
||||
#endif
|
||||
|
||||
#if HAVE_XZ_SUPPORT
|
||||
kDebug() << " -- test_block_write xz -- ";
|
||||
test_block_write(pathxz, testData);
|
||||
QCOMPARE( QFileInfo( pathxz ).size(), 64LL ); // size of test.lzma
|
||||
#endif
|
||||
}
|
||||
|
||||
void KFilterTest::test_biggerWrites()
|
||||
{
|
||||
const QString currentdir = QDir::currentPath();
|
||||
const QString outFile = currentdir + "/test_big.gz";
|
||||
// Find the out-of-bounds from #157706/#188415
|
||||
QByteArray data;
|
||||
data.reserve(10000);
|
||||
// Prepare test data
|
||||
for (int i = 0; i < 8170; ++i)
|
||||
data.append(static_cast<char>(KRandom::randomMax(256)));
|
||||
QCOMPARE(data.size(), 8170);
|
||||
// 8170 random bytes compress to 8194 bytes due to the gzip header/footer.
|
||||
// Now we can go one by one until we pass 8192.
|
||||
// On 32 bit systems it crashed with data.size()=8173, before the "no room for footer yet" fix.
|
||||
int compressedSize = 0;
|
||||
while (compressedSize < 8200) {
|
||||
test_block_write(outFile, data);
|
||||
compressedSize = QFileInfo(outFile).size();
|
||||
kDebug() << data.size() << "compressed into" << compressedSize;
|
||||
// Test data is valid
|
||||
test_readall(outFile, QString::fromLatin1("application/x-gzip"), data);
|
||||
|
||||
|
||||
data.append(static_cast<char>(KRandom::randomMax(256)));
|
||||
}
|
||||
}
|
||||
|
||||
void KFilterTest::test_block_read( const QString & fileName )
|
||||
{
|
||||
QIODevice * dev = KFilterDev::deviceForFile( fileName );
|
||||
QVERIFY( dev != 0 );
|
||||
bool ok = dev->open( QIODevice::ReadOnly );
|
||||
QVERIFY( ok );
|
||||
|
||||
QByteArray array(1024,'\0');
|
||||
QByteArray read;
|
||||
int n;
|
||||
while ( ( n = dev->read( array.data(), array.size() ) ) )
|
||||
{
|
||||
QVERIFY( n > 0 );
|
||||
read += QByteArray( array, n );
|
||||
//kDebug() << "read returned " << n;
|
||||
//kDebug() << "read='" << read << "'";
|
||||
|
||||
// pos() has no real meaning on sequential devices
|
||||
// Ah, but kzip uses kfilterdev as a non-sequential device...
|
||||
|
||||
QCOMPARE( (int)dev->pos(), (int)read.size() );
|
||||
//kDebug() << "dev.at = " << dev->at();
|
||||
}
|
||||
QCOMPARE( read, testData );
|
||||
|
||||
// Test seeking back
|
||||
ok = dev->seek(0);
|
||||
// test readAll
|
||||
read = dev->readAll();
|
||||
QCOMPARE( read.size(), testData.size() );
|
||||
QCOMPARE( read, testData );
|
||||
|
||||
dev->close();
|
||||
delete dev;
|
||||
}
|
||||
|
||||
void KFilterTest::test_block_read()
|
||||
{
|
||||
kDebug() << " -- test_block_read gzip -- ";
|
||||
test_block_read(pathgz);
|
||||
#if HAVE_BZIP2_SUPPORT
|
||||
kDebug() << " -- test_block_read bzip2 -- ";
|
||||
test_block_read(pathbz2);
|
||||
#endif
|
||||
#if HAVE_XZ_SUPPORT
|
||||
kDebug() << " -- test_block_read lzma -- ";
|
||||
test_block_read(pathxz);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KFilterTest::test_getch( const QString & fileName )
|
||||
{
|
||||
QIODevice * dev = KFilterDev::deviceForFile( fileName );
|
||||
QVERIFY( dev != 0 );
|
||||
bool ok = dev->open( QIODevice::ReadOnly );
|
||||
QVERIFY( ok );
|
||||
QByteArray read;
|
||||
char ch;
|
||||
while ( dev->getChar(&ch) ) {
|
||||
//printf("%c",ch);
|
||||
read += ch;
|
||||
}
|
||||
dev->close();
|
||||
delete dev;
|
||||
QCOMPARE( read, testData );
|
||||
}
|
||||
|
||||
void KFilterTest::test_getch()
|
||||
{
|
||||
kDebug() << " -- test_getch gzip -- ";
|
||||
test_getch(pathgz);
|
||||
#if HAVE_BZIP2_SUPPORT
|
||||
kDebug() << " -- test_getch bzip2 -- ";
|
||||
test_getch(pathbz2);
|
||||
#endif
|
||||
#if HAVE_XZ_SUPPORT
|
||||
kDebug() << " -- test_getch lzma -- ";
|
||||
test_getch(pathxz);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KFilterTest::test_textstream( const QString & fileName )
|
||||
{
|
||||
QIODevice * dev = KFilterDev::deviceForFile( fileName );
|
||||
QVERIFY( dev != 0 );
|
||||
bool ok = dev->open( QIODevice::ReadOnly );
|
||||
QVERIFY( ok );
|
||||
QTextStream ts( dev );
|
||||
QString readStr = ts.readAll();
|
||||
dev->close();
|
||||
delete dev;
|
||||
|
||||
QByteArray read = readStr.toLatin1();
|
||||
QCOMPARE( read, testData );
|
||||
}
|
||||
|
||||
void KFilterTest::test_textstream()
|
||||
{
|
||||
kDebug() << " -- test_textstream gzip -- ";
|
||||
test_textstream(pathgz);
|
||||
#if HAVE_BZIP2_SUPPORT
|
||||
kDebug() << " -- test_textstream bzip2 -- ";
|
||||
test_textstream(pathbz2);
|
||||
#endif
|
||||
#if HAVE_XZ_SUPPORT
|
||||
kDebug() << " -- test_textstream lzma -- ";
|
||||
test_textstream(pathxz);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KFilterTest::test_readall(const QString & fileName, const QString& mimeType, const QByteArray& expectedData)
|
||||
{
|
||||
QFile file(fileName);
|
||||
QIODevice *flt = KFilterDev::device(&file, mimeType, false);
|
||||
QVERIFY(flt);
|
||||
bool ok = flt->open( QIODevice::ReadOnly );
|
||||
QVERIFY(ok);
|
||||
const QByteArray read = flt->readAll();
|
||||
QCOMPARE(read.size(), expectedData.size());
|
||||
QCOMPARE(read, expectedData);
|
||||
delete flt;
|
||||
}
|
||||
|
||||
void KFilterTest::test_readall()
|
||||
{
|
||||
kDebug() << " -- test_readall gzip -- ";
|
||||
test_readall(pathgz, QString::fromLatin1("application/x-gzip"), testData);
|
||||
#if HAVE_BZIP2_SUPPORT
|
||||
kDebug() << " -- test_readall bzip2 -- ";
|
||||
test_readall(pathbz2, QString::fromLatin1("application/x-bzip"), testData);
|
||||
#endif
|
||||
#if HAVE_XZ_SUPPORT
|
||||
kDebug() << " -- test_readall lzma -- ";
|
||||
test_readall(pathxz, QString::fromLatin1("application/x-xz"), testData);
|
||||
#endif
|
||||
kDebug() << " -- test_readall gzip-derived -- ";
|
||||
test_readall(pathgz, QString::fromLatin1("image/svg+xml-compressed"), testData);
|
||||
}
|
||||
|
||||
void KFilterTest::test_uncompressed()
|
||||
{
|
||||
// Can KFilterDev handle uncompressed data even when using gzip decompression?
|
||||
kDebug() << " -- test_uncompressed -- ";
|
||||
QBuffer buffer(&testData);
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
QIODevice *flt = KFilterDev::device(&buffer, QString::fromLatin1("application/x-gzip"), false);
|
||||
bool ok = flt->open( QIODevice::ReadOnly );
|
||||
QVERIFY(ok);
|
||||
QByteArray read = flt->readAll();
|
||||
QCOMPARE( read.size(), testData.size() );
|
||||
QCOMPARE( read, testData );
|
||||
delete flt;
|
||||
}
|
||||
|
||||
void KFilterTest::test_findFilterByMimeType_data()
|
||||
{
|
||||
QTest::addColumn<QString>("mimeType");
|
||||
QTest::addColumn<bool>("valid");
|
||||
|
||||
// direct mimetype name
|
||||
QTest::newRow("application/x-gzip") << QString::fromLatin1("application/x-gzip") << true;
|
||||
#if HAVE_BZIP2_SUPPORT
|
||||
QTest::newRow("application/x-bzip") << QString::fromLatin1("application/x-bzip") << true;
|
||||
QTest::newRow("application/x-bzip2") << QString::fromLatin1("application/x-bzip2") << true;
|
||||
#else
|
||||
QTest::newRow("application/x-bzip") << QString::fromLatin1("application/x-bzip") << false;
|
||||
QTest::newRow("application/x-bzip2") << QString::fromLatin1("application/x-bzip2") << false;
|
||||
#endif
|
||||
// indirect compressed mimetypes
|
||||
QTest::newRow("application/x-gzdvi") << QString::fromLatin1("application/x-gzdvi") << true;
|
||||
|
||||
// non-compressed mimetypes
|
||||
QTest::newRow("text/plain") << QString::fromLatin1("text/plain") << false;
|
||||
QTest::newRow("application/x-tar") << QString::fromLatin1("application/x-tar") << false;
|
||||
}
|
||||
|
||||
void KFilterTest::test_findFilterByMimeType()
|
||||
{
|
||||
QFETCH(QString, mimeType);
|
||||
QFETCH(bool, valid);
|
||||
|
||||
KFilterBase *filter = KFilterBase::findFilterByMimeType(mimeType);
|
||||
QCOMPARE(filter != 0, valid);
|
||||
|
||||
delete filter;
|
||||
}
|
||||
|
||||
static void getCompressedData(QByteArray& data, QByteArray& compressedData)
|
||||
{
|
||||
data = "Hello world, this is a test for deflate, from bug 114830 / 117683";
|
||||
compressedData.resize(long(data.size()*1.1f) + 12L); // requirements of zlib::compress2
|
||||
unsigned long out_bufferlen = compressedData.size();
|
||||
const int ret = compress2((Bytef*)compressedData.data(), &out_bufferlen, (const Bytef*)data.constData(), data.size(), 1);
|
||||
QCOMPARE(ret, Z_OK);
|
||||
compressedData.resize(out_bufferlen);
|
||||
}
|
||||
|
||||
void KFilterTest::test_deflateWithZlibHeader()
|
||||
{
|
||||
QByteArray data, deflatedData;
|
||||
getCompressedData(data, deflatedData);
|
||||
|
||||
#if 0 // Can't use KFilterDev for this, we need to call KGzipFilter::init(QIODevice::ReadOnly, KGzipFilter::ZlibHeader);
|
||||
QBuffer buffer(&deflatedData);
|
||||
QIODevice *flt = KFilterDev::device(&buffer, "application/x-gzip", false);
|
||||
static_cast<KFilterDev *>(flt)->setSkipHeaders();
|
||||
bool ok = flt->open( QIODevice::ReadOnly );
|
||||
QVERIFY(ok);
|
||||
const QByteArray read = flt->readAll();
|
||||
#else
|
||||
KGzipFilter* mFilterDevice = new KGzipFilter;
|
||||
mFilterDevice->init(QIODevice::ReadOnly, KGzipFilter::ZlibHeader);
|
||||
|
||||
mFilterDevice->setInBuffer(deflatedData.constData(), deflatedData.size());
|
||||
char buf[8192];
|
||||
mFilterDevice->setOutBuffer(buf, sizeof(buf));
|
||||
KFilterBase::Result result = mFilterDevice->uncompress();
|
||||
QCOMPARE(result, KFilterBase::End);
|
||||
const int bytesOut = sizeof(buf) - mFilterDevice->outBufferAvailable();
|
||||
QVERIFY(bytesOut);
|
||||
QByteArray read(buf, bytesOut);
|
||||
mFilterDevice->terminate();
|
||||
delete mFilterDevice;
|
||||
#endif
|
||||
QCOMPARE(QString::fromLatin1(read), QString::fromLatin1(data)); // more readable output than the line below
|
||||
QCOMPARE(read, data);
|
||||
}
|
||||
|
||||
void KFilterTest::test_pushData() // ### UNFINISHED
|
||||
{
|
||||
QFile file(pathgz);
|
||||
QVERIFY(file.open(QIODevice::ReadOnly));
|
||||
const QByteArray compressed = file.readAll();
|
||||
const int firstChunkSize = compressed.size() / 2;
|
||||
QByteArray firstData(compressed, firstChunkSize);
|
||||
QBuffer inBuffer(&firstData);
|
||||
QVERIFY(inBuffer.open(QIODevice::ReadWrite));
|
||||
QIODevice *flt = KFilterDev::device(&inBuffer, "application/x-gzip", false);
|
||||
QVERIFY(flt->open(QIODevice::ReadOnly));
|
||||
QByteArray read = flt->readAll();
|
||||
qDebug() << QString::fromLatin1(read);
|
||||
|
||||
// And later...
|
||||
inBuffer.write(QByteArray(compressed.data() + firstChunkSize, compressed.size() - firstChunkSize));
|
||||
QCOMPARE(inBuffer.data().size(), compressed.size());
|
||||
read += flt->readAll();
|
||||
qDebug() << QString::fromLatin1(read);
|
||||
delete flt;
|
||||
}
|
||||
|
||||
void KFilterTest::slotFilterOutput(const QByteArray& data)
|
||||
{
|
||||
m_filterOutput += data;
|
||||
}
|
||||
|
||||
#include "moc_kfiltertest.cpp"
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2002-2005 David Faure <faure@kde.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License version 2 as published by the Free Software Foundation;
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public License
|
||||
* along with this library; see the file COPYING.LIB. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef KFILTERTEST_H
|
||||
#define KFILTERTEST_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
|
||||
class KFilterTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void test_block_write();
|
||||
void test_block_read();
|
||||
void test_biggerWrites();
|
||||
void test_getch();
|
||||
void test_textstream();
|
||||
void test_readall();
|
||||
void test_uncompressed();
|
||||
void test_findFilterByMimeType_data();
|
||||
void test_findFilterByMimeType();
|
||||
void test_deflateWithZlibHeader();
|
||||
void test_pushData();
|
||||
|
||||
private:
|
||||
void test_block_write(const QString & fileName, const QByteArray& data);
|
||||
void test_block_read( const QString & fileName );
|
||||
void test_getch( const QString & fileName );
|
||||
void test_textstream( const QString & fileName );
|
||||
void test_readall(const QString & fileName, const QString& mimeType, const QByteArray& expectedData);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void slotFilterOutput(const QByteArray& data);
|
||||
|
||||
private:
|
||||
QString pathgz;
|
||||
QString pathbz2;
|
||||
QString pathxz;
|
||||
QByteArray testData;
|
||||
QByteArray m_filterOutput;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue