• 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 new TQFile(file->name()); // A bit strange IMHO. We ask for a TQFile but we create another one !?! (DF)
74 
75  base->setDevice(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(f, true);
90  return new KFilterDev(base, true);
91  }
92  if(!forceFilter)
93  return 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( int 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( (int)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 TQIODevice::Offset KFilterDev::size() const
173 {
174  // Well, hmm, Houston, we have a problem.
175  // We can't know the size of the uncompressed data
176  // before uncompressing it.......
177 
178  // But readAll, which is not virtual, needs the size.........
179 
180  kdDebug(7005) << "KFilterDev::size - can't be implemented, returning -1" << endl;
181  //abort();
182  return (uint)-1;
183 }
184 
185 TQIODevice::Offset KFilterDev::at() const
186 {
187  return TQIODevice::at();
188 }
189 
190 bool KFilterDev::at( TQIODevice::Offset pos )
191 {
192  //kdDebug(7005) << "KFilterDev::at " << pos << " currently at " << TQIODevice::at() << endl;
193 
194  if ( TQIODevice::at() == pos )
195  return true;
196 
197  Q_ASSERT ( filter->mode() == IO_ReadOnly );
198 
199  if ( pos == 0 )
200  {
201  TQIODevice::at(0);
202  // We can forget about the cached data
203  d->ungetchBuffer.resize(0);
204  d->bNeedHeader = !d->bSkipHeaders;
205  d->result = KFilterBase::OK;
206  filter->setInBuffer(0L,0);
207  filter->reset();
208  return filter->device()->reset();
209  }
210 
211  if ( TQIODevice::at() < pos ) // we can start from here
212  pos = pos - TQIODevice::at();
213  else
214  {
215  // we have to start from 0 ! Ugly and slow, but better than the previous
216  // solution (KTarGz was allocating everything into memory)
217  if (!at(0)) // sets ioIndex to 0
218  return false;
219  }
220 
221  //kdDebug(7005) << "KFilterDev::at : reading " << pos << " dummy bytes" << endl;
222  TQByteArray dummy( TQMIN( pos, 3*BUFFER_SIZE ) );
223  d->bIgnoreData = true;
224  bool result = ( (TQIODevice::Offset)readBlock( dummy.data(), pos ) == pos );
225  d->bIgnoreData = false;
226  return result;
227 }
228 
229 bool KFilterDev::atEnd() const
230 {
231  return filter->device()->atEnd() && (d->result == KFilterBase::END)
232  && d->ungetchBuffer.isEmpty();
233 }
234 
235 TQ_LONG KFilterDev::readBlock( char *data, TQ_ULONG maxlen )
236 {
237  Q_ASSERT ( filter->mode() == IO_ReadOnly );
238  //kdDebug(7005) << "KFilterDev::readBlock maxlen=" << maxlen << endl;
239 
240  uint dataReceived = 0;
241  if ( !d->ungetchBuffer.isEmpty() )
242  {
243  uint len = d->ungetchBuffer.length();
244  if ( !d->bIgnoreData )
245  {
246  while ( ( dataReceived < len ) && ( dataReceived < maxlen ) )
247  {
248  *data = d->ungetchBuffer[ len - dataReceived - 1 ];
249  data++;
250  dataReceived++;
251  }
252  }
253  else
254  {
255  dataReceived = TQMIN( len, maxlen );
256  }
257  d->ungetchBuffer.truncate( len - dataReceived );
258  TQIODevice::at(TQIODevice::at() + dataReceived);
259  }
260 
261  // If we came to the end of the stream
262  // return what we got from the ungetchBuffer.
263  if ( d->result == KFilterBase::END )
264  return dataReceived;
265 
266  // If we had an error, return -1.
267  if ( d->result != KFilterBase::OK )
268  return -1;
269 
270 
271  TQ_ULONG outBufferSize;
272  if ( d->bIgnoreData )
273  {
274  outBufferSize = TQMIN( maxlen, 3*BUFFER_SIZE );
275  }
276  else
277  {
278  outBufferSize = maxlen;
279  }
280  outBufferSize -= dataReceived;
281  TQ_ULONG availOut = outBufferSize;
282  filter->setOutBuffer( data, outBufferSize );
283 
284  bool decompressedAll = false;
285  while ( dataReceived < maxlen )
286  {
287  if (filter->inBufferEmpty())
288  {
289  // Not sure about the best size to set there.
290  // For sure, it should be bigger than the header size (see comment in readHeader)
291  d->buffer.resize( BUFFER_SIZE );
292  // Request data from underlying device
293  int size = filter->device()->readBlock( d->buffer.data(),
294  d->buffer.size() );
295  if ( size )
296  filter->setInBuffer( d->buffer.data(), size );
297  else {
298  if ( decompressedAll )
299  {
300  // We decoded everything there was to decode. So -> done.
301  //kdDebug(7005) << "Seems we're done. dataReceived=" << dataReceived << endl;
302  d->result = KFilterBase::END;
303  break;
304  }
305  }
306  //kdDebug(7005) << "KFilterDev::readBlock got " << size << " bytes from device" << endl;
307  }
308  if (d->bNeedHeader)
309  {
310  (void) filter->readHeader();
311  d->bNeedHeader = false;
312  }
313 
314  d->result = filter->uncompress();
315 
316  if (d->result == KFilterBase::ERROR)
317  {
318  kdWarning(7005) << "KFilterDev: Error when uncompressing data" << endl;
319  break;
320  }
321 
322  // We got that much data since the last time we went here
323  uint outReceived = availOut - filter->outBufferAvailable();
324  //kdDebug(7005) << "avail_out = " << filter->outBufferAvailable() << " result=" << d->result << " outReceived=" << outReceived << endl;
325  if( availOut < (uint)filter->outBufferAvailable() )
326  kdWarning(7005) << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !" << endl;
327 
328  dataReceived += outReceived;
329  if ( !d->bIgnoreData ) // Move on in the output buffer
330  {
331  data += outReceived;
332  availOut = maxlen - dataReceived;
333  }
334  else if ( maxlen - dataReceived < outBufferSize )
335  {
336  availOut = maxlen - dataReceived;
337  }
338  TQIODevice::at(TQIODevice::at() + outReceived);
339  if (d->result == KFilterBase::END)
340  {
341  //kdDebug(7005) << "KFilterDev::readBlock got END. dataReceived=" << dataReceived << endl;
342  break; // Finished.
343  }
344  if (filter->inBufferEmpty() && filter->outBufferAvailable() != 0 )
345  {
346  decompressedAll = true;
347  }
348  filter->setOutBuffer( data, availOut );
349  }
350 
351  return dataReceived;
352 }
353 
354 TQ_LONG KFilterDev::writeBlock( const char *data /*0 to finish*/, TQ_ULONG len )
355 {
356  Q_ASSERT ( filter->mode() == IO_WriteOnly );
357  // If we had an error, return 0.
358  if ( d->result != KFilterBase::OK )
359  return 0;
360 
361  bool finish = (data == 0L);
362  if (!finish)
363  {
364  filter->setInBuffer( data, len );
365  if (d->bNeedHeader)
366  {
367  (void)filter->writeHeader( d->origFileName );
368  d->bNeedHeader = false;
369  }
370  }
371 
372  uint dataWritten = 0;
373  uint availIn = len;
374  while ( dataWritten < len || finish )
375  {
376 
377  d->result = filter->compress( finish );
378 
379  if (d->result == KFilterBase::ERROR)
380  {
381  kdWarning(7005) << "KFilterDev: Error when compressing data" << endl;
382  // What to do ?
383  break;
384  }
385 
386  // Wrote everything ?
387  if (filter->inBufferEmpty() || (d->result == KFilterBase::END))
388  {
389  // We got that much data since the last time we went here
390  uint wrote = availIn - filter->inBufferAvailable();
391 
392  //kdDebug(7005) << " Wrote everything for now. avail_in = " << filter->inBufferAvailable() << " result=" << d->result << " wrote=" << wrote << endl;
393 
394  // Move on in the input buffer
395  data += wrote;
396  dataWritten += wrote;
397  TQIODevice::at(TQIODevice::at() + wrote);
398 
399  availIn = len - dataWritten;
400  //kdDebug(7005) << " KFilterDev::writeBlock availIn=" << availIn << " dataWritten=" << dataWritten << " ioIndex=" << ioIndex << endl;
401  if ( availIn > 0 ) // Not sure this will ever happen
402  filter->setInBuffer( data, availIn );
403  }
404 
405  if (filter->outBufferFull() || (d->result == KFilterBase::END))
406  {
407  //kdDebug(7005) << " KFilterDev::writeBlock writing to underlying. avail_out=" << filter->outBufferAvailable() << endl;
408  int towrite = d->buffer.size() - filter->outBufferAvailable();
409  if ( towrite > 0 )
410  {
411  // Write compressed data to underlying device
412  int size = filter->device()->writeBlock( d->buffer.data(), towrite );
413  if ( size != towrite ) {
414  kdWarning(7005) << "KFilterDev::writeBlock. Could only write " << size << " out of " << towrite << " bytes" << endl;
415  return 0; // indicate an error (happens on disk full)
416  }
417  //else
418  //kdDebug(7005) << " KFilterDev::writeBlock wrote " << size << " bytes" << endl;
419  }
420  d->buffer.resize( 8*1024 );
421  filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
422  if (d->result == KFilterBase::END)
423  {
424  //kdDebug(7005) << " KFilterDev::writeBlock END" << endl;
425  Q_ASSERT(finish); // hopefully we don't get end before finishing
426  break;
427  }
428  }
429  }
430 
431  return dataWritten;
432 }
433 
434 int KFilterDev::getch()
435 {
436  Q_ASSERT ( filter->mode() == IO_ReadOnly );
437  //kdDebug(7005) << "KFilterDev::getch" << endl;
438  if ( !d->ungetchBuffer.isEmpty() ) {
439  int len = d->ungetchBuffer.length();
440  int ch = d->ungetchBuffer[ len-1 ];
441  d->ungetchBuffer.truncate( len - 1 );
442  TQIODevice::at(TQIODevice::at() + 1);
443  //kdDebug(7005) << "KFilterDev::getch from ungetch: " << TQString(TQChar(ch)) << endl;
444  return ch;
445  }
446  char buf[1];
447  int ret = readBlock( buf, 1 ) == 1 ? buf[0] : EOF;
448  //kdDebug(7005) << "KFilterDev::getch ret=" << TQString(TQChar(ret)) << endl;
449  return ret;
450 }
451 
452 int KFilterDev::putch( int c )
453 {
454  //kdDebug(7005) << "KFilterDev::putch" << endl;
455  char buf[1];
456  buf[0] = c;
457  return writeBlock( buf, 1 ) == 1 ? c : -1;
458 }
459 
460 int KFilterDev::ungetch( int ch )
461 {
462  //kdDebug(7005) << "KFilterDev::ungetch " << TQString(TQChar(ch)) << endl;
463  if ( ch == EOF ) // cannot unget EOF
464  return ch;
465 
466  // pipe or similar => we cannot ungetch, so do it manually
467  d->ungetchBuffer +=ch;
468  TQIODevice::at(TQIODevice::at() - 1);
469  return ch;
470 }
471 
472 void KFilterDev::setOrigFileName( const TQCString & fileName )
473 {
474  d->origFileName = fileName;
475 }
476 
477 void KFilterDev::setSkipHeaders()
478 {
479  d->bSkipHeaders = true;
480 }
KFilterBase
This is the base class for compression filters such as gzip and bzip2.
Definition: kfilterbase.h:39
KFilterBase::findFilterByMimeType
static KFilterBase * findFilterByMimeType(const TQString &mimeType)
Call this to create the appropriate filter for the mimetype mimeType.
Definition: kfilterbase.cpp:49
KFilterBase::findFilterByFileName
static KFilterBase * findFilterByFileName(const TQString &fileName)
Call this to create the appropriate filter for the file named fileName.
Definition: kfilterbase.cpp:42
KFilterBase::device
TQIODevice * device()
Returns the device on which the filter will work.
Definition: kfilterbase.h:58
KFilterBase::setDevice
void setDevice(TQIODevice *dev, bool autodelete=false)
Sets the device on which the filter will work.
Definition: kfilterbase.cpp:36
KFilterDev::createFilterDevice
static TQIODevice * createFilterDevice(KFilterBase *base, TQFile *file) TDE_DEPRECATED
Call this to create the appropriate filter device for base working on file .
Definition: kfilterdev.cpp:66
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:472
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::open
virtual bool open(int mode)
Open for reading or writing.
Definition: kfilterdev.cpp:119
KFilterDev::close
virtual void close()
Close after reading or writing.
Definition: kfilterdev.cpp:149
KFilterDev::KFilterDev
KFilterDev(KFilterBase *filter, bool autoDeleteFilterBase=false)
Constructs a KFilterDev for a given filter (e.g.
Definition: kfilterdev.cpp:46
KFilterDev::setSkipHeaders
void setSkipHeaders()
Call this let this device skip the gzip headers when reading/writing.
Definition: kfilterdev.cpp:477
KFilterDev::~KFilterDev
virtual ~KFilterDev()
Destructs the KFilterDev.
Definition: kfilterdev.cpp:54
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

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
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/tdeio by doxygen 1.9.1
This website is maintained by Timothy Pearson.