Commit 23fb924b authored by David Faure's avatar David Faure
Browse files

New ioslave that uses a KFilterBase, i.e. gzip and bzip2.

Meant to replace kio_gzip.
Couldn't test it, because file:/blah.gz#gzip: makes KURL return true
in isLocalFile. I wonder where kio_gzip was used at all, since the URL
was never created this way automatically.

This directory also provides the actual filters for gzip and bzip2.
The latter comes with a configure test now.

svn path=/trunk/kdebase/kioslave/; revision=68491
parent dcff8619
SUBDIRS = gzip $(BZIP2DIR)
AM_CPPFLAGS = -DQT_NO_CAST_ASCII
INCLUDES = $(all_includes)
lib_LTLIBRARIES = kio_filter.la
kio_filter_la_SOURCES = filter.cc
kio_filter_la_LIBADD = $(LIB_KSYCOCA)
kio_filter_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
noinst_HEADERS = filter.h
METASOURCES = AUTO
protocoldir = $(kde_servicesdir)
protocol_DATA = gzip.protocol
INCLUDES = $(all_includes)
LDFLAGS = $(all_libraries) $(KDE_RPATH)
METASOURCES = AUTO
lib_LTLIBRARIES = kbzip2filter.la
kbzip2filter_la_SOURCES = kbzip2filter.cpp
kbzip2filter_la_LIBADD = $(LIB_KSYCOCA) $(LIBBZ2)
kbzip2filter_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
kde_services_DATA = kbzip2filter.desktop
protocoldir = $(kde_servicesdir)
protocol_DATA = bzip.protocol bzip2.protocol
[Protocol]
exec=kio_filter
protocol=bzip
mimetype=application/x-bzip
input=stream
output=stream
reading=true
source=false
[Protocol]
exec=kio_filter
protocol=bzip2
mimetype=application/x-bzip2
input=stream
output=stream
reading=true
source=false
/* 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include "kbzip2filter.h"
#define BZ_NO_STDIO // we don't need that
#include <bzlib.h>
#include <kdebug.h>
#include <klibloader.h>
// For docu on this, see /usr/doc/bzip2-0.9.5d/bzip2-0.9.5d/manual_3.html
class KBzip2FilterFactory : public KLibFactory
{
public:
KBzip2FilterFactory() : KLibFactory() {}
~KBzip2FilterFactory(){}
QObject *createObject( QObject *, const char *, const char*, const QStringList & )
{
return new KBzip2Filter;
}
};
extern "C" {
void *init_kbzip2filter()
{
return new KBzip2FilterFactory;
}
}
class KBzip2Filter::KBzip2FilterPrivate
{
public:
// The reason for this stuff here is to avoid including zlib.h in kbzip2dev.h
bz_stream zStream;
};
KBzip2Filter::KBzip2Filter()
{
d = new KBzip2FilterPrivate;
d->zStream.bzalloc = 0;
d->zStream.bzfree = 0;
d->zStream.opaque = 0;
}
KBzip2Filter::~KBzip2Filter()
{
delete d;
}
void KBzip2Filter::init()
{
// warning this may be read-only specific
d->zStream.next_in = 0;
d->zStream.avail_in = 0;
/*outputBuffer.resize( 8*1024 );// Start with a modest buffer
zStream.avail_out = outputBuffer.size();
zStream.next_out = outputBuffer.data();*/
int result = bzDecompressInit(&d->zStream, 0, 0);
kdDebug() << "bzDecompressInit returned " << result << endl;
// Not idea what to do with result :)
}
void KBzip2Filter::terminate()
{
// readonly specific !
int result = bzDecompressEnd(&d->zStream);
kdDebug() << "bzDecompressEnd returned " << result << endl;
}
void KBzip2Filter::reset()
{
// bzip2 doesn't seem to have a reset call...
terminate();
init();
}
bool KBzip2Filter::readHeader()
{
return true;
}
void KBzip2Filter::setOutBuffer( char * data, uint maxlen )
{
d->zStream.avail_out = maxlen;
d->zStream.next_out = data;
}
void KBzip2Filter::setInBuffer( char * data, uint size )
{
d->zStream.avail_in = size;
d->zStream.next_in = data;
}
int KBzip2Filter::inBufferAvailable() const
{
return d->zStream.avail_in;
}
int KBzip2Filter::outBufferAvailable() const
{
return d->zStream.avail_out;
}
KBzip2Filter::Result KBzip2Filter::uncompress()
{
//kdDebug() << "Calling bzDecompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable() << endl;
int result = bzDecompress(&d->zStream);
if ( result != BZ_OK )
{
kdDebug() << "bzDecompress returned " << result << endl;
kdDebug() << "KBzip2Filter::uncompress" << ( result == BZ_OK ? OK : ( result == BZ_STREAM_END ? END : ERROR ) ) << endl;
}
return ( result == BZ_OK ? OK : ( result == BZ_STREAM_END ? END : ERROR ) );
}
[Desktop Entry]
Type=Service
Name=BZip2 Filter
X-KDE-Library=kbzip2filter
ServiceTypes=KDECompressionFilter,application/x-bzip2,application/x-tbz
/* 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#ifndef __kbzip2filter__h
#define __kbzip2filter__h
#include "kfilterbase.h"
class KBzip2Filter : public KFilterBase
{
public:
KBzip2Filter();
virtual ~KBzip2Filter();
virtual void init();
virtual void terminate();
virtual void reset();
virtual bool readHeader();
virtual void setOutBuffer( char * data, uint maxlen );
virtual void setInBuffer( char * data, uint size );
virtual int inBufferAvailable() const;
virtual int outBufferAvailable() const;
virtual Result uncompress();
private:
class KBzip2FilterPrivate;
KBzip2FilterPrivate *d;
};
#endif
/*
This file is part of KDE
Copyright (C) 1999-2000 Waldo Bastian (bastian@kde.org)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// $Id$
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <kinstance.h>
#include <kdebug.h>
#include <kmimemagic.h>
#include <kfilterbase.h>
#include <kcomprmanager.h>
#include "filter.h"
extern "C" { int kdemain(int argc, char **argv); }
int kdemain( int argc, char ** argv)
{
KInstance instance( "kio_gzip" );
kdDebug(7110) << "Starting " << getpid() << endl;
if (argc != 4)
{
fprintf(stderr, "Usage: kio_filter protocol domain-socket1 domain-socket2\n");
exit(-1);
}
FilterProtocol slave(argv[1], argv[2], argv[3]);
slave.dispatchLoop();
kdDebug(7110) << "Done" << endl;
return 0;
}
FilterProtocol::FilterProtocol( const QCString & protocol, const QCString &pool, const QCString &app )
: KIO::SlaveBase( protocol, pool, app )
{
QString mimetype = QString::fromLatin1("application/x-") + protocol;
filter = KComprManager::self()->findFilterByMimeType( mimetype );
ASSERT(filter);
}
void FilterProtocol::get( const KURL & )
{
if (subURL.isEmpty())
{
error( KIO::ERR_NO_SOURCE_PROTOCOL, mProtocol );
return;
}
if (!filter)
{
error( KIO::ERR_INTERNAL, mProtocol );
return;
}
needSubURLData();
filter->init();
bool bNeedHeader = true;
bool bNeedMimetype = true;
bool bError = true;
int result;
QByteArray inputBuffer;
QByteArray outputBuffer(8*1024); // Start with a modest buffer
filter->setOutBuffer( outputBuffer.data(), outputBuffer.size() );
while(true)
{
if (filter->inBufferEmpty())
{
dataReq(); // Request data
result = readData( inputBuffer);
kdDebug(7110) << "requestData: got " << result << endl;
if (result <= 0)
{
bError = true;
break; // Unexpected EOF.
}
filter->setInBuffer( inputBuffer.data(), inputBuffer.size() );
}
if (bNeedHeader)
{
bError = !filter->readHeader();
if (bError)
break;
bNeedHeader = false;
}
result = filter->uncompress();
if ((filter->outBufferAvailable() == 0) || (result == KFilterBase::END))
{
kdDebug(7110) << "avail_out = " << filter->outBufferAvailable() << endl;
if (filter->outBufferAvailable() != 0)
{
// Discard unused space :-)
outputBuffer.resize(outputBuffer.size() - filter->outBufferAvailable());
}
if (bNeedMimetype)
{
KMimeMagicResult * result = KMimeMagic::self()->findBufferFileType( outputBuffer, subURL.fileName() );
kdDebug(7110) << "Emitting mimetype " << result->mimeType() << endl;
mimeType( result->mimeType() );
bNeedMimetype = false;
}
data( outputBuffer ); // Send data
filter->setOutBuffer( outputBuffer.data(), outputBuffer.size() );
if (result == KFilterBase::END)
break; // Finished.
}
if (result != KFilterBase::OK)
{
bError = true;
break; // Error
}
}
if (!bError)
{
dataReq(); // Request data
result = readData( inputBuffer);
kdDebug(7110) << "requestData: got " << result << "(expecting 0)" << endl;
data( QByteArray() ); // Send EOF
}
filter->terminate();
if (bError)
{
error(KIO::ERR_COULD_NOT_READ, subURL.url());
subURL = KURL(); // Clear subURL
return;
}
subURL = KURL(); // Clear subURL
finished();
}
void FilterProtocol::put( const KURL &/*url*/, int, bool /*_overwrite*/, bool /*_resume*/ )
{
error( KIO::ERR_UNSUPPORTED_ACTION, QString::fromLatin1("put"));
}
void FilterProtocol::setSubURL(const KURL &url)
{
subURL = url;
}
/*
This file is part of KDE
Copyright (C) 2000 Waldo Bastian (bastian@kde.org)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __filter_h__
#define __filter_h__
#include <qobject.h>
#include <kio/global.h>
#include <kio/slavebase.h>
class FilterProtocol : public QObject, public KIO::SlaveBase
{
public:
FilterProtocol( const QCString & protocol, const QCString &pool, const QCString &app );
virtual void get( const KURL &url );
virtual void put( const KURL &url, int _mode, bool _overwrite,
bool _resume );
virtual void setSubURL(const KURL &url);
private:
KURL subURL;
KFilterBase * filter;
};
#endif
[Protocol]
exec=kio_filter
protocol=gzip
mimetype=application/gzip
input=stream
output=stream
reading=true
source=false
INCLUDES = $(all_includes)
LDFLAGS = $(all_libraries) $(KDE_RPATH)
METASOURCES = AUTO
lib_LTLIBRARIES = kgzipfilter.la
kgzipfilter_la_SOURCES = kgzipfilter.cpp
kgzipfilter_la_LIBADD = $(LIB_KSYCOCA) $(LIBZ)
kgzipfilter_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
kde_services_DATA = kgzipfilter.desktop
/* 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include "kgzipfilter.h"
#include <zlib.h>
#include <kdebug.h>
#include <klibloader.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 */
class KGzipFilterFactory : public KLibFactory
{
public:
KGzipFilterFactory() : KLibFactory() {}
~KGzipFilterFactory(){}
QObject *createObject( QObject *, const char *, const char*, const QStringList & )
{
return new KGzipFilter;
}
};
extern "C" {
void *init_kgzipfilter()
{
return new KGzipFilterFactory;
}
}
class KGzipFilter::KGzipFilterPrivate
{
public:
// The reason for this stuff here is to avoid including zlib.h in kgzipdev.h
z_stream zStream;
bool bCompressed;
};
KGzipFilter::KGzipFilter()
{
d = new KGzipFilterPrivate;
d->zStream.zalloc = (alloc_func)0;
d->zStream.zfree = (free_func)0;
d->zStream.opaque = (voidpf)0;
}
KGzipFilter::~KGzipFilter()
{
delete d;
}
void KGzipFilter::init()
{
// warning this may be read-only specific
d->zStream.next_in = Z_NULL;
d->zStream.avail_in = 0;
/*outputBuffer.resize( 8*1024 );// Start with a modest buffer
zStream.avail_out = outputBuffer.size();
zStream.next_out = (Bytef *) outputBuffer.data();*/
int result = inflateInit2(&d->zStream, -MAX_WBITS);
kdDebug() << "inflateInit returned " << result << endl;
// Not idea what to do with result :)
d->bCompressed = true;
}
void KGzipFilter::terminate()
{
// readonly specific !
int result = inflateEnd(&d->zStream);
kdDebug() << "inflateEnd returned " << result << endl;
}
void KGzipFilter::reset()
{
int result = inflateReset(&d->zStream);
kdDebug() << "inflateReset returned " << result << endl;
}
bool KGzipFilter::readHeader()
{
kdDebug() << "KGzipFilter::readHeader" << endl;
// Assume not compressed until we successfully decode the header
d->bCompressed = false;
// Assume the first block of data contains the whole header.
// The right way is to build this as a big state machine which
// is a pain in the ass.
// With 8K-blocks, we don't risk much anyway.
Bytef *p = d->zStream.next_in;
int i = d->zStream.avail_in;
if ((i -= 10) < 0) return false; // Need at least 10 bytes
if (*p++ != 0x1f) return false; // GZip magic
if (*p++ != 0x8b) return false;
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
{
while( (i > 0) && (*p))
{
i--; p++;
}
if (--i <= 0) return false;
p++;
}
if ((flags & COMMENT) != 0) // skip comment
{
while( (i > 0) && (*p))
{
i--; p++;