• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • kdecore
  • compression
kfilterdev.cpp
Go to the documentation of this file.
1/* This file is part of the KDE libraries
2 Copyright (C) 2000, 2006 David Faure <faure@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
12
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
17*/
18
19#include "kfilterdev.h"
20#include "kfilterbase.h"
21#include <QDebug>
22#include <stdio.h> // for EOF
23#include <stdlib.h>
24#include <assert.h>
25#include <QtCore/QFile>
26
27#define BUFFER_SIZE 8*1024
28
29class KFilterDev::Private
30{
31public:
32 Private() : bNeedHeader(true), bSkipHeaders(false),
33 autoDeleteFilterBase(false), bOpenedUnderlyingDevice(false),
34 bIgnoreData(false){}
35 bool bNeedHeader;
36 bool bSkipHeaders;
37 bool autoDeleteFilterBase;
38 bool bOpenedUnderlyingDevice;
39 bool bIgnoreData;
40 QByteArray buffer; // Used as 'input buffer' when reading, as 'output buffer' when writing
41 QByteArray origFileName;
42 KFilterBase::Result result;
43 KFilterBase *filter;
44};
45
46KFilterDev::KFilterDev( KFilterBase * _filter, bool autoDeleteFilterBase )
47 : d(new Private)
48{
49 assert(_filter);
50 d->filter = _filter;
51 d->autoDeleteFilterBase = autoDeleteFilterBase;
52}
53
54KFilterDev::~KFilterDev()
55{
56 if ( isOpen() )
57 close();
58 if ( d->autoDeleteFilterBase )
59 delete d->filter;
60 delete d;
61}
62
63//static
64QIODevice * KFilterDev::deviceForFile( const QString & fileName, const QString & mimetype,
65 bool forceFilter )
66{
67 QFile * f = new QFile( fileName );
68 KFilterBase * base = mimetype.isEmpty() ? KFilterBase::findFilterByFileName( fileName )
69 : KFilterBase::findFilterByMimeType( mimetype );
70 if ( base )
71 {
72 base->setDevice(f, true);
73 return new KFilterDev(base, true);
74 }
75 if(!forceFilter)
76 return f;
77 else
78 {
79 delete f;
80 return 0L;
81 }
82}
83
84QIODevice * KFilterDev::device( QIODevice* inDevice, const QString & mimetype, bool autoDeleteInDevice )
85{
86 if (inDevice==0)
87 return 0;
88 KFilterBase * base = KFilterBase::findFilterByMimeType(mimetype);
89 if ( base )
90 {
91 base->setDevice(inDevice, autoDeleteInDevice);
92 return new KFilterDev(base, true /* auto-delete "base" */);
93 }
94 return 0;
95}
96
97bool KFilterDev::open( QIODevice::OpenMode mode )
98{
99 if (isOpen()) {
100 qWarning() << "KFilterDev::open: device is already open";
101 return true; // QFile returns false, but well, the device -is- open...
102 }
103 //kDebug(7005) << mode;
104 if ( mode == QIODevice::ReadOnly )
105 {
106 d->buffer.resize(0);
107 }
108 else
109 {
110 d->buffer.resize( BUFFER_SIZE );
111 d->filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
112 }
113 d->bNeedHeader = !d->bSkipHeaders;
114 d->filter->setFilterFlags(d->bSkipHeaders ? KFilterBase::NoHeaders : KFilterBase::WithHeaders);
115 d->filter->init( mode );
116 d->bOpenedUnderlyingDevice = !d->filter->device()->isOpen();
117 bool ret = d->bOpenedUnderlyingDevice ? d->filter->device()->open( mode ) : true;
118 d->result = KFilterBase::Ok;
119
120 if ( !ret )
121 qWarning() << "KFilterDev::open: Couldn't open underlying device";
122 else
123 setOpenMode( mode );
124
125 return ret;
126}
127
128void KFilterDev::close()
129{
130 if ( !isOpen() )
131 return;
132 if ( d->filter->mode() == QIODevice::WriteOnly )
133 write( 0L, 0 ); // finish writing
134 //kDebug(7005) << "Calling terminate().";
135
136 d->filter->terminate();
137 if ( d->bOpenedUnderlyingDevice )
138 d->filter->device()->close();
139 setOpenMode( QIODevice::NotOpen );
140}
141
142bool KFilterDev::seek( qint64 pos )
143{
144 qint64 ioIndex = this->pos(); // current position
145 if ( ioIndex == pos )
146 return true;
147
148 //kDebug(7005) << "seek(" << pos << ") called";
149
150 Q_ASSERT ( d->filter->mode() == QIODevice::ReadOnly );
151
152 if ( pos == 0 )
153 {
154 // We can forget about the cached data
155 d->bNeedHeader = !d->bSkipHeaders;
156 d->result = KFilterBase::Ok;
157 d->filter->setInBuffer(0L,0);
158 d->filter->reset();
159 QIODevice::seek(pos);
160 return d->filter->device()->reset();
161 }
162
163 if ( ioIndex > pos ) // we can start from here
164 pos = pos - ioIndex;
165 else
166 {
167 // we have to start from 0 ! Ugly and slow, but better than the previous
168 // solution (KTarGz was allocating everything into memory)
169 if (!seek(0)) // recursive
170 return false;
171 }
172
173 //kDebug(7005) << "reading " << pos << " dummy bytes";
174 QByteArray dummy( qMin( pos, (qint64)3*BUFFER_SIZE ), 0 );
175 d->bIgnoreData = true;
176 bool result = ( read( dummy.data(), pos ) == pos );
177 d->bIgnoreData = false;
178 QIODevice::seek(pos);
179 return result;
180}
181
182bool KFilterDev::atEnd() const
183{
184 return (d->result == KFilterBase::End)
185 && QIODevice::atEnd() // take QIODevice's internal buffer into account
186 && d->filter->device()->atEnd();
187}
188
189qint64 KFilterDev::readData( char *data, qint64 maxlen )
190{
191 Q_ASSERT ( d->filter->mode() == QIODevice::ReadOnly );
192 //kDebug(7005) << "maxlen=" << maxlen;
193 KFilterBase* filter = d->filter;
194
195 uint dataReceived = 0;
196
197 // We came to the end of the stream
198 if ( d->result == KFilterBase::End )
199 return dataReceived;
200
201 // If we had an error, return -1.
202 if ( d->result != KFilterBase::Ok )
203 return -1;
204
205
206 qint64 outBufferSize;
207 if ( d->bIgnoreData )
208 {
209 outBufferSize = qMin( maxlen, (qint64)3*BUFFER_SIZE );
210 }
211 else
212 {
213 outBufferSize = maxlen;
214 }
215 outBufferSize -= dataReceived;
216 qint64 availOut = outBufferSize;
217 filter->setOutBuffer( data, outBufferSize );
218
219 while ( dataReceived < maxlen )
220 {
221 if (filter->inBufferEmpty())
222 {
223 // Not sure about the best size to set there.
224 // For sure, it should be bigger than the header size (see comment in readHeader)
225 d->buffer.resize( BUFFER_SIZE );
226 // Request data from underlying device
227 int size = filter->device()->read( d->buffer.data(),
228 d->buffer.size() );
229 //kDebug(7005) << "got" << size << "bytes from device";
230 if (size) {
231 filter->setInBuffer( d->buffer.data(), size );
232 } else {
233 // Not enough data available in underlying device for now
234 break;
235 }
236 }
237 if (d->bNeedHeader)
238 {
239 (void) filter->readHeader();
240 d->bNeedHeader = false;
241 }
242
243 d->result = filter->uncompress();
244
245 if (d->result == KFilterBase::Error)
246 {
247 qWarning() << "KFilterDev: Error when uncompressing data";
248 break;
249 }
250
251 // We got that much data since the last time we went here
252 uint outReceived = availOut - filter->outBufferAvailable();
253 //kDebug(7005) << "avail_out = " << filter->outBufferAvailable() << " result=" << d->result << " outReceived=" << outReceived;
254 if( availOut < (uint)filter->outBufferAvailable() )
255 qWarning() << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !";
256
257 dataReceived += outReceived;
258 if ( !d->bIgnoreData ) // Move on in the output buffer
259 {
260 data += outReceived;
261 availOut = maxlen - dataReceived;
262 }
263 else if ( maxlen - dataReceived < outBufferSize )
264 {
265 availOut = maxlen - dataReceived;
266 }
267 if (d->result == KFilterBase::End)
268 {
269 //kDebug(7005) << "got END. dataReceived=" << dataReceived;
270 break; // Finished.
271 }
272 filter->setOutBuffer( data, availOut );
273 }
274
275 return dataReceived;
276}
277
278qint64 KFilterDev::writeData( const char *data /*0 to finish*/, qint64 len )
279{
280 KFilterBase* filter = d->filter;
281 Q_ASSERT ( filter->mode() == QIODevice::WriteOnly );
282 // If we had an error, return 0.
283 if ( d->result != KFilterBase::Ok )
284 return 0;
285
286 bool finish = (data == 0L);
287 if (!finish)
288 {
289 filter->setInBuffer( data, len );
290 if (d->bNeedHeader)
291 {
292 (void)filter->writeHeader( d->origFileName );
293 d->bNeedHeader = false;
294 }
295 }
296
297 uint dataWritten = 0;
298 uint availIn = len;
299 while ( dataWritten < len || finish )
300 {
301
302 d->result = filter->compress( finish );
303
304 if (d->result == KFilterBase::Error)
305 {
306 qWarning() << "KFilterDev: Error when compressing data";
307 // What to do ?
308 break;
309 }
310
311 // Wrote everything ?
312 if (filter->inBufferEmpty() || (d->result == KFilterBase::End))
313 {
314 // We got that much data since the last time we went here
315 uint wrote = availIn - filter->inBufferAvailable();
316
317 //kDebug(7005) << " Wrote everything for now. avail_in=" << filter->inBufferAvailable() << "result=" << d->result << "wrote=" << wrote;
318
319 // Move on in the input buffer
320 data += wrote;
321 dataWritten += wrote;
322
323 availIn = len - dataWritten;
324 //kDebug(7005) << " availIn=" << availIn << "dataWritten=" << dataWritten << "pos=" << pos();
325 if ( availIn > 0 )
326 filter->setInBuffer( data, availIn );
327 }
328
329 if (filter->outBufferFull() || (d->result == KFilterBase::End) || finish)
330 {
331 //kDebug(7005) << " writing to underlying. avail_out=" << filter->outBufferAvailable();
332 int towrite = d->buffer.size() - filter->outBufferAvailable();
333 if ( towrite > 0 )
334 {
335 // Write compressed data to underlying device
336 int size = filter->device()->write( d->buffer.data(), towrite );
337 if ( size != towrite ) {
338 qWarning() << "KFilterDev::write. Could only write " << size << " out of " << towrite << " bytes";
339 return 0; // indicate an error (happens on disk full)
340 }
341 //else
342 //kDebug(7005) << " wrote " << size << " bytes";
343 }
344 if (d->result == KFilterBase::End)
345 {
346 //kDebug(7005) << " END";
347 Q_ASSERT(finish); // hopefully we don't get end before finishing
348 break;
349 }
350 d->buffer.resize(BUFFER_SIZE);
351 filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
352 }
353 }
354
355 return dataWritten;
356}
357
358void KFilterDev::setOrigFileName( const QByteArray & fileName )
359{
360 d->origFileName = fileName;
361}
362
363void KFilterDev::setSkipHeaders()
364{
365 d->bSkipHeaders = true;
366}
KFilterBase
This is the base class for compression filters such as gzip and bzip2.
Definition: kfilterbase.h:37
KFilterBase::outBufferAvailable
virtual int outBufferAvailable() const =0
KFilterBase::Result
Result
Definition: kfilterbase.h:82
KFilterBase::Error
@ Error
Definition: kfilterbase.h:82
KFilterBase::End
@ End
Definition: kfilterbase.h:82
KFilterBase::Ok
@ Ok
Definition: kfilterbase.h:82
KFilterBase::setInBuffer
virtual void setInBuffer(const char *data, uint size)=0
KFilterBase::setOutBuffer
virtual void setOutBuffer(char *data, uint maxlen)=0
KFilterBase::WithHeaders
@ WithHeaders
Definition: kfilterbase.h:94
KFilterBase::NoHeaders
@ NoHeaders
Definition: kfilterbase.h:93
KFilterBase::uncompress
virtual Result uncompress()=0
KFilterBase::findFilterByMimeType
static KFilterBase * findFilterByMimeType(const QString &mimeType)
Call this to create the appropriate filter for the mimetype mimeType.
Definition: kfilterbase.cpp:103
KFilterBase::writeHeader
virtual bool writeHeader(const QByteArray &filename)=0
KFilterBase::findFilterByFileName
static KFilterBase * findFilterByFileName(const QString &fileName)
Call this to create the appropriate filter for the file named fileName.
Definition: kfilterbase.cpp:75
KFilterBase::compress
virtual Result compress(bool finish)=0
KFilterBase::inBufferEmpty
virtual bool inBufferEmpty() const
Definition: kfilterbase.cpp:65
KFilterBase::device
QIODevice * device()
Returns the device on which the filter will work.
Definition: kfilterbase.cpp:60
KFilterBase::inBufferAvailable
virtual int inBufferAvailable() const =0
KFilterBase::readHeader
virtual bool readHeader()=0
KFilterBase::setDevice
void setDevice(QIODevice *dev, bool autodelete=false)
Sets the device on which the filter will work.
Definition: kfilterbase.cpp:54
KFilterBase::mode
virtual int mode() const =0
KFilterBase::outBufferFull
virtual bool outBufferFull() const
Definition: kfilterbase.cpp:70
KFilterDev
A class for reading and writing compressed data onto a device (e.g.
Definition: kfilterdev.h:37
KFilterDev::seek
virtual bool seek(qint64)
That one can be quite slow, when going back.
Definition: kfilterdev.cpp:142
KFilterDev::deviceForFile
static QIODevice * deviceForFile(const QString &fileName, const QString &mimetype=QString(), bool forceFilter=false)
Reimplemented to return true.
Definition: kfilterdev.cpp:64
KFilterDev::open
virtual bool open(QIODevice::OpenMode mode)
Open for reading or writing.
Definition: kfilterdev.cpp:97
KFilterDev::device
static QIODevice * device(QIODevice *inDevice, const QString &mimetype, bool autoDeleteInDevice=true)
Creates an i/o device that is able to read from the QIODevice inDevice, whether the data is compresse...
Definition: kfilterdev.cpp:84
KFilterDev::writeData
virtual qint64 writeData(const char *data, qint64 len)
Definition: kfilterdev.cpp:278
KFilterDev::close
virtual void close()
Close after reading or writing.
Definition: kfilterdev.cpp:128
KFilterDev::readData
virtual qint64 readData(char *data, qint64 maxlen)
Definition: kfilterdev.cpp:189
KFilterDev::setOrigFileName
void setOrigFileName(const QByteArray &fileName)
For writing gzip compressed files only: set the name of the original file, to be used in the gzip hea...
Definition: kfilterdev.cpp:358
KFilterDev::setSkipHeaders
void setSkipHeaders()
Call this let this device skip the gzip headers when reading/writing.
Definition: kfilterdev.cpp:363
KFilterDev::~KFilterDev
virtual ~KFilterDev()
Destructs the KFilterDev.
Definition: kfilterdev.cpp:54
KFilterDev::atEnd
virtual bool atEnd() const
Definition: kfilterdev.cpp:182
QIODevice
QString
qint64
kfilterbase.h
BUFFER_SIZE
#define BUFFER_SIZE
Definition: kfilterdev.cpp:27
kfilterdev.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal