• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeio/tdeio
 

tdeio/tdeio

  • tdeio
  • tdeio
kfilterdev.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 2000 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 <kdebug.h>
22 #include <stdio.h> // for EOF
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <tqfile.h>
26 
27 #define BUFFER_SIZE 8*1024
28 
29 class KFilterDev::KFilterDevPrivate
30 {
31 public:
32  KFilterDevPrivate() : 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  TQByteArray buffer; // Used as 'input buffer' when reading, as 'output buffer' when writing
41  TQCString ungetchBuffer;
42  TQCString origFileName;
43  KFilterBase::Result result;
44 };
45 
46 KFilterDev::KFilterDev( KFilterBase * _filter, bool autoDeleteFilterBase )
47  : filter(_filter)
48 {
49  assert(filter);
50  d = new KFilterDevPrivate;
51  d->autoDeleteFilterBase = autoDeleteFilterBase;
52 }
53 
54 KFilterDev::~KFilterDev()
55 {
56  if ( isOpen() )
57  close();
58  if ( d->autoDeleteFilterBase )
59  delete filter;
60  delete d;
61 }
62 
63 #ifndef KDE_NO_COMPAT
64 //this one is static
65 // Cumbersome API. To be removed in KDE 3.0.
66 TQIODevice* KFilterDev::createFilterDevice(KFilterBase* base, TQFile* file)
67 {
68  if (file==0)
69  return 0;
70 
71  //we don't need a filter
72  if (base==0)
73  return TQT_TQIODEVICE(new TQFile(file->name())); // A bit strange IMHO. We ask for a TQFile but we create another one !?! (DF)
74 
75  base->setDevice(TQT_TQIODEVICE(file));
76  return new KFilterDev(base);
77 }
78 #endif
79 
80 //static
81 TQIODevice * KFilterDev::deviceForFile( const TQString & fileName, const TQString & mimetype,
82  bool forceFilter )
83 {
84  TQFile * f = new TQFile( fileName );
85  KFilterBase * base = mimetype.isEmpty() ? KFilterBase::findFilterByFileName( fileName )
86  : KFilterBase::findFilterByMimeType( mimetype );
87  if ( base )
88  {
89  base->setDevice(TQT_TQIODEVICE(f), true);
90  return new KFilterDev(base, true);
91  }
92  if(!forceFilter)
93  return TQT_TQIODEVICE(f);
94  else
95  {
96  delete f;
97  return 0L;
98  }
99 }
100 
101 TQIODevice * KFilterDev::device( TQIODevice* inDevice, const TQString & mimetype)
102 {
103  return device( inDevice, mimetype, true );
104 }
105 
106 TQIODevice * KFilterDev::device( TQIODevice* inDevice, const TQString & mimetype, bool autoDeleteInDevice )
107 {
108  if (inDevice==0)
109  return 0;
110  KFilterBase * base = KFilterBase::findFilterByMimeType(mimetype);
111  if ( base )
112  {
113  base->setDevice(inDevice, autoDeleteInDevice);
114  return new KFilterDev(base, true /* auto-delete "base" */);
115  }
116  return 0;
117 }
118 
119 bool KFilterDev::open( TQ_OpenMode mode )
120 {
121  //kdDebug(7005) << "KFilterDev::open " << mode << endl;
122  if ( mode == IO_ReadOnly )
123  {
124  d->buffer.resize(0);
125  d->ungetchBuffer.resize(0);
126  }
127  else
128  {
129  d->buffer.resize( BUFFER_SIZE );
130  filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
131  }
132  d->bNeedHeader = !d->bSkipHeaders;
133  filter->init( mode );
134  d->bOpenedUnderlyingDevice = !filter->device()->isOpen();
135  bool ret = d->bOpenedUnderlyingDevice ? filter->device()->open( (TQ_OpenMode)mode ) : true;
136  d->result = KFilterBase::OK;
137 
138  if ( !ret )
139  kdWarning(7005) << "KFilterDev::open: Couldn't open underlying device" << endl;
140  else
141  {
142  setState( IO_Open );
143  setMode( mode );
144  }
145  TQIODevice::at(0);
146  return ret;
147 }
148 
149 void KFilterDev::close()
150 {
151  if ( !isOpen() )
152  return;
153  //kdDebug(7005) << "KFilterDev::close" << endl;
154  if ( filter->mode() == IO_WriteOnly )
155  writeBlock( 0L, 0 ); // finish writing
156  //kdDebug(7005) << "KFilterDev::close. Calling terminate()." << endl;
157 
158  filter->terminate();
159  if ( d->bOpenedUnderlyingDevice )
160  filter->device()->close();
161 
162  setState( 0 ); // not IO_Open
163 }
164 
165 void KFilterDev::flush()
166 {
167  //kdDebug(7005) << "KFilterDev::flush" << endl;
168  filter->device()->flush();
169  // Hmm, might not be enough...
170 }
171 
172 #ifdef USE_QT4
173 qint64 KFilterDev::size() const
174 #else // USE_QT4
175 TQIODevice::Offset KFilterDev::size() const
176 #endif // USE_QT4
177 {
178  // Well, hmm, Houston, we have a problem.
179  // We can't know the size of the uncompressed data
180  // before uncompressing it.......
181 
182  // But readAll, which is not virtual, needs the size.........
183 
184  kdDebug(7005) << "KFilterDev::size - can't be implemented, returning -1" << endl;
185  //abort();
186  return (uint)-1;
187 }
188 
189 TQIODevice::Offset KFilterDev::at() const
190 {
191  return TQIODevice::at();
192 }
193 
194 bool KFilterDev::at( TQIODevice::Offset pos )
195 {
196  //kdDebug(7005) << "KFilterDev::at " << pos << " currently at " << TQIODevice::at() << endl;
197 
198  if ( TQIODevice::at() == pos )
199  return true;
200 
201  Q_ASSERT ( filter->mode() == IO_ReadOnly );
202 
203  if ( pos == 0 )
204  {
205  TQIODevice::at(0);
206  // We can forget about the cached data
207  d->ungetchBuffer.resize(0);
208  d->bNeedHeader = !d->bSkipHeaders;
209  d->result = KFilterBase::OK;
210  filter->setInBuffer(0L,0);
211  filter->reset();
212  return filter->device()->reset();
213  }
214 
215  if ( TQIODevice::at() < pos ) // we can start from here
216  pos = pos - TQIODevice::at();
217  else
218  {
219  // we have to start from 0 ! Ugly and slow, but better than the previous
220  // solution (KTarGz was allocating everything into memory)
221  if (!at(0)) // sets ioIndex to 0
222  return false;
223  }
224 
225  //kdDebug(7005) << "KFilterDev::at : reading " << pos << " dummy bytes" << endl;
226  TQByteArray dummy( TQMIN( pos, 3*BUFFER_SIZE ) );
227  d->bIgnoreData = true;
228  bool result = ( (TQIODevice::Offset)readBlock( dummy.data(), pos ) == pos );
229  d->bIgnoreData = false;
230  return result;
231 }
232 
233 bool KFilterDev::atEnd() const
234 {
235  return filter->device()->atEnd() && (d->result == KFilterBase::END)
236  && d->ungetchBuffer.isEmpty();
237 }
238 
239 TQT_TQIO_LONG KFilterDev::tqreadBlock( char *data, TQT_TQIO_ULONG maxlen )
240 {
241  Q_ASSERT ( filter->mode() == IO_ReadOnly );
242  //kdDebug(7005) << "KFilterDev::readBlock maxlen=" << maxlen << endl;
243 
244  uint dataReceived = 0;
245  if ( !d->ungetchBuffer.isEmpty() )
246  {
247  uint len = d->ungetchBuffer.length();
248  if ( !d->bIgnoreData )
249  {
250  while ( ( dataReceived < len ) && ( dataReceived < maxlen ) )
251  {
252  *data = d->ungetchBuffer[ len - dataReceived - 1 ];
253  data++;
254  dataReceived++;
255  }
256  }
257  else
258  {
259  dataReceived = TQMIN( len, maxlen );
260  }
261  d->ungetchBuffer.truncate( len - dataReceived );
262  TQIODevice::at(TQIODevice::at() + dataReceived);
263  }
264 
265  // If we came to the end of the stream
266  // return what we got from the ungetchBuffer.
267  if ( d->result == KFilterBase::END )
268  return dataReceived;
269 
270  // If we had an error, return -1.
271  if ( d->result != KFilterBase::OK )
272  return -1;
273 
274 
275  TQ_ULONG outBufferSize;
276  if ( d->bIgnoreData )
277  {
278  outBufferSize = TQMIN( maxlen, 3*BUFFER_SIZE );
279  }
280  else
281  {
282  outBufferSize = maxlen;
283  }
284  outBufferSize -= dataReceived;
285  TQ_ULONG availOut = outBufferSize;
286  filter->setOutBuffer( data, outBufferSize );
287 
288  bool decompressedAll = false;
289  while ( dataReceived < maxlen )
290  {
291  if (filter->inBufferEmpty())
292  {
293  // Not sure about the best size to set there.
294  // For sure, it should be bigger than the header size (see comment in readHeader)
295  d->buffer.resize( BUFFER_SIZE );
296  // Request data from underlying device
297  int size = filter->device()->readBlock( d->buffer.data(),
298  d->buffer.size() );
299  if ( size )
300  filter->setInBuffer( d->buffer.data(), size );
301  else {
302  if ( decompressedAll )
303  {
304  // We decoded everything there was to decode. So -> done.
305  //kdDebug(7005) << "Seems we're done. dataReceived=" << dataReceived << endl;
306  d->result = KFilterBase::END;
307  break;
308  }
309  }
310  //kdDebug(7005) << "KFilterDev::readBlock got " << size << " bytes from device" << endl;
311  }
312  if (d->bNeedHeader)
313  {
314  (void) filter->readHeader();
315  d->bNeedHeader = false;
316  }
317 
318  d->result = filter->uncompress();
319 
320  if (d->result == KFilterBase::ERROR)
321  {
322  kdWarning(7005) << "KFilterDev: Error when uncompressing data" << endl;
323  break;
324  }
325 
326  // We got that much data since the last time we went here
327  uint outReceived = availOut - filter->outBufferAvailable();
328  //kdDebug(7005) << "avail_out = " << filter->outBufferAvailable() << " result=" << d->result << " outReceived=" << outReceived << endl;
329  if( availOut < (uint)filter->outBufferAvailable() )
330  kdWarning(7005) << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !" << endl;
331 
332  dataReceived += outReceived;
333  if ( !d->bIgnoreData ) // Move on in the output buffer
334  {
335  data += outReceived;
336  availOut = maxlen - dataReceived;
337  }
338  else if ( maxlen - dataReceived < outBufferSize )
339  {
340  availOut = maxlen - dataReceived;
341  }
342  TQIODevice::at(TQIODevice::at() + outReceived);
343  if (d->result == KFilterBase::END)
344  {
345  //kdDebug(7005) << "KFilterDev::readBlock got END. dataReceived=" << dataReceived << endl;
346  break; // Finished.
347  }
348  if (filter->inBufferEmpty() && filter->outBufferAvailable() != 0 )
349  {
350  decompressedAll = true;
351  }
352  filter->setOutBuffer( data, availOut );
353  }
354 
355  return dataReceived;
356 }
357 
358 TQT_TQIO_LONG KFilterDev::tqwriteBlock( const char *data /*0 to finish*/, TQT_TQIO_ULONG len )
359 {
360  Q_ASSERT ( filter->mode() == IO_WriteOnly );
361  // If we had an error, return 0.
362  if ( d->result != KFilterBase::OK )
363  return 0;
364 
365  bool finish = (data == 0L);
366  if (!finish)
367  {
368  filter->setInBuffer( data, len );
369  if (d->bNeedHeader)
370  {
371  (void)filter->writeHeader( d->origFileName );
372  d->bNeedHeader = false;
373  }
374  }
375 
376  uint dataWritten = 0;
377  uint availIn = len;
378  while ( dataWritten < len || finish )
379  {
380 
381  d->result = filter->compress( finish );
382 
383  if (d->result == KFilterBase::ERROR)
384  {
385  kdWarning(7005) << "KFilterDev: Error when compressing data" << endl;
386  // What to do ?
387  break;
388  }
389 
390  // Wrote everything ?
391  if (filter->inBufferEmpty() || (d->result == KFilterBase::END))
392  {
393  // We got that much data since the last time we went here
394  uint wrote = availIn - filter->inBufferAvailable();
395 
396  //kdDebug(7005) << " Wrote everything for now. avail_in = " << filter->inBufferAvailable() << " result=" << d->result << " wrote=" << wrote << endl;
397 
398  // Move on in the input buffer
399  data += wrote;
400  dataWritten += wrote;
401  TQIODevice::at(TQIODevice::at() + wrote);
402 
403  availIn = len - dataWritten;
404  //kdDebug(7005) << " KFilterDev::writeBlock availIn=" << availIn << " dataWritten=" << dataWritten << " ioIndex=" << ioIndex << endl;
405  if ( availIn > 0 ) // Not sure this will ever happen
406  filter->setInBuffer( data, availIn );
407  }
408 
409  if (filter->outBufferFull() || (d->result == KFilterBase::END))
410  {
411  //kdDebug(7005) << " KFilterDev::writeBlock writing to underlying. avail_out=" << filter->outBufferAvailable() << endl;
412  int towrite = d->buffer.size() - filter->outBufferAvailable();
413  if ( towrite > 0 )
414  {
415  // Write compressed data to underlying device
416  int size = filter->device()->writeBlock( d->buffer.data(), towrite );
417  if ( size != towrite ) {
418  kdWarning(7005) << "KFilterDev::writeBlock. Could only write " << size << " out of " << towrite << " bytes" << endl;
419  return 0; // indicate an error (happens on disk full)
420  }
421  //else
422  //kdDebug(7005) << " KFilterDev::writeBlock wrote " << size << " bytes" << endl;
423  }
424  d->buffer.resize( 8*1024 );
425  filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
426  if (d->result == KFilterBase::END)
427  {
428  //kdDebug(7005) << " KFilterDev::writeBlock END" << endl;
429  Q_ASSERT(finish); // hopefully we don't get end before finishing
430  break;
431  }
432  }
433  }
434 
435  return dataWritten;
436 }
437 
438 int KFilterDev::getch()
439 {
440  Q_ASSERT ( filter->mode() == IO_ReadOnly );
441  //kdDebug(7005) << "KFilterDev::getch" << endl;
442  if ( !d->ungetchBuffer.isEmpty() ) {
443  int len = d->ungetchBuffer.length();
444  int ch = d->ungetchBuffer[ len-1 ];
445  d->ungetchBuffer.truncate( len - 1 );
446  TQIODevice::at(TQIODevice::at() + 1);
447  //kdDebug(7005) << "KFilterDev::getch from ungetch: " << TQString(TQChar(ch)) << endl;
448  return ch;
449  }
450  char buf[1];
451  int ret = readBlock( buf, 1 ) == 1 ? buf[0] : EOF;
452  //kdDebug(7005) << "KFilterDev::getch ret=" << TQString(TQChar(ret)) << endl;
453  return ret;
454 }
455 
456 int KFilterDev::putch( int c )
457 {
458  //kdDebug(7005) << "KFilterDev::putch" << endl;
459  char buf[1];
460  buf[0] = c;
461  return writeBlock( buf, 1 ) == 1 ? c : -1;
462 }
463 
464 int KFilterDev::ungetch( int ch )
465 {
466  //kdDebug(7005) << "KFilterDev::ungetch " << TQString(TQChar(ch)) << endl;
467  if ( ch == EOF ) // cannot unget EOF
468  return ch;
469 
470  // pipe or similar => we cannot ungetch, so do it manually
471  d->ungetchBuffer +=ch;
472  TQIODevice::at(TQIODevice::at() - 1);
473  return ch;
474 }
475 
476 void KFilterDev::setOrigFileName( const TQCString & fileName )
477 {
478  d->origFileName = fileName;
479 }
480 
481 void KFilterDev::setSkipHeaders()
482 {
483  d->bSkipHeaders = true;
484 }
KFilterBase::findFilterByFileName
static KFilterBase * findFilterByFileName(const TQString &fileName)
Call this to create the appropriate filter for the file named fileName.
Definition: kfilterbase.cpp:42
KFilterDev::createFilterDevice
static TQIODevice * createFilterDevice(KFilterBase *base, TQFile *file) KDE_DEPRECATED
Call this to create the appropriate filter device for base working on file .
Definition: kfilterdev.cpp:66
KFilterBase::findFilterByMimeType
static KFilterBase * findFilterByMimeType(const TQString &mimeType)
Call this to create the appropriate filter for the mimetype mimeType.
Definition: kfilterbase.cpp:49
KFilterBase::setDevice
void setDevice(TQIODevice *dev, bool autodelete=false)
Sets the device on which the filter will work.
Definition: kfilterbase.cpp:36
KFilterBase::device
TQIODevice * device()
Returns the device on which the filter will work.
Definition: kfilterbase.h:58
KFilterBase
This is the base class for compression filters such as gzip and bzip2.
Definition: kfilterbase.h:38
KFilterDev::KFilterDev
KFilterDev(KFilterBase *filter, bool autoDeleteFilterBase=false)
Constructs a KFilterDev for a given filter (e.g.
Definition: kfilterdev.cpp:46
KFilterDev::device
static TQIODevice * device(TQIODevice *inDevice, const TQString &mimetype)
Creates an i/o device that is able to read from the TQIODevice inDevice, whether the data is compress...
Definition: kfilterdev.cpp:101
KFilterDev::setSkipHeaders
void setSkipHeaders()
Call this let this device skip the gzip headers when reading/writing.
Definition: kfilterdev.cpp:481
KFilterDev::setOrigFileName
void setOrigFileName(const TQCString &fileName)
For writing gzip compressed files only: set the name of the original file, to be used in the gzip hea...
Definition: kfilterdev.cpp:476
KFilterDev::deviceForFile
static TQIODevice * deviceForFile(const TQString &fileName, const TQString &mimetype=TQString::null, bool forceFilter=false)
Creates an i/o device that is able to read from fileName, whether it's compressed or not...
Definition: kfilterdev.cpp:81
KFilterDev::~KFilterDev
virtual ~KFilterDev()
Destructs the KFilterDev.
Definition: kfilterdev.cpp:54
KFilterDev::open
virtual bool open(TQ_OpenMode mode)
Open for reading or writing.
Definition: kfilterdev.cpp:119
KFilterDev::close
virtual void close()
Close after reading or writing.
Definition: kfilterdev.cpp:149

tdeio/tdeio

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

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/tdeio by doxygen 1.8.8
This website is maintained by Timothy Pearson.