• 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 
29 class KFilterDev::Private
30 {
31 public:
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 
46 KFilterDev::KFilterDev( KFilterBase * _filter, bool autoDeleteFilterBase )
47  : d(new Private)
48 {
49  assert(_filter);
50  d->filter = _filter;
51  d->autoDeleteFilterBase = autoDeleteFilterBase;
52 }
53 
54 KFilterDev::~KFilterDev()
55 {
56  if ( isOpen() )
57  close();
58  if ( d->autoDeleteFilterBase )
59  delete d->filter;
60  delete d;
61 }
62 
63 //static
64 QIODevice * 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 
84 QIODevice * 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 
97 bool 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 
128 void 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 
142 bool 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 
182 bool 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 
189 qint64 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 
278 qint64 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 
358 void KFilterDev::setOrigFileName( const QByteArray & fileName )
359 {
360  d->origFileName = fileName;
361 }
362 
363 void KFilterDev::setSkipHeaders()
364 {
365  d->bSkipHeaders = true;
366 }
KFilterDev::deviceForFile
static QIODevice * deviceForFile(const QString &fileName, const QString &mimetype=QString(), bool forceFilter=false)
Reimplemented to return true.
Definition: kfilterdev.cpp:64
qint64
kfilterdev.h
KFilterBase::setInBuffer
virtual void setInBuffer(const char *data, uint size)=0
QString
KFilterBase::device
QIODevice * device()
Returns the device on which the filter will work.
Definition: kfilterbase.cpp:60
kfilterbase.h
KFilterBase::compress
virtual Result compress(bool finish)=0
KFilterDev
A class for reading and writing compressed data onto a device (e.g.
Definition: kfilterdev.h:36
KFilterBase::setOutBuffer
virtual void setOutBuffer(char *data, uint maxlen)=0
KFilterBase::End
Definition: kfilterbase.h:82
KFilterBase::inBufferAvailable
virtual int inBufferAvailable() const =0
KFilterBase::NoHeaders
Definition: kfilterbase.h:93
KFilterDev::writeData
virtual qint64 writeData(const char *data, qint64 len)
Definition: kfilterdev.cpp:278
KFilterDev::open
virtual bool open(QIODevice::OpenMode mode)
Open for reading or writing.
Definition: kfilterdev.cpp:97
KFilterBase
This is the base class for compression filters such as gzip and bzip2.
Definition: kfilterbase.h:36
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::setDevice
void setDevice(QIODevice *dev, bool autodelete=false)
Sets the device on which the filter will work.
Definition: kfilterbase.cpp:54
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::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
BUFFER_SIZE
#define BUFFER_SIZE
Definition: kfilterdev.cpp:27
KFilterDev::seek
virtual bool seek(qint64)
That one can be quite slow, when going back.
Definition: kfilterdev.cpp:142
KFilterDev::setSkipHeaders
void setSkipHeaders()
Call this let this device skip the gzip headers when reading/writing.
Definition: kfilterdev.cpp:363
KFilterBase::Result
Result
Definition: kfilterbase.h:82
KFilterDev::atEnd
virtual bool atEnd() const
Definition: kfilterdev.cpp:182
KFilterBase::mode
virtual int mode() const =0
KFilterBase::outBufferFull
virtual bool outBufferFull() const
Definition: kfilterbase.cpp:70
KFilterBase::inBufferEmpty
virtual bool inBufferEmpty() const
Definition: kfilterbase.cpp:65
KFilterDev::readData
virtual qint64 readData(char *data, qint64 maxlen)
Definition: kfilterdev.cpp:189
KFilterBase::Ok
Definition: kfilterbase.h:82
KFilterBase::WithHeaders
Definition: kfilterbase.h:94
KFilterBase::outBufferAvailable
virtual int outBufferAvailable() const =0
QIODevice
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
KFilterDev::~KFilterDev
virtual ~KFilterDev()
Destructs the KFilterDev.
Definition: kfilterdev.cpp:54
KFilterBase::Error
Definition: kfilterbase.h:82
KFilterDev::close
virtual void close()
Close after reading or writing.
Definition: kfilterdev.cpp:128
This file is part of the KDE documentation.
Documentation copyright © 1996-2018 The KDE developers.
Generated on Wed Aug 22 2018 19:24:37 by doxygen 1.8.14 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