• 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
29class KFilterDev::KFilterDevPrivate
30{
31public:
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
46KFilterDev::KFilterDev( KFilterBase * _filter, bool autoDeleteFilterBase )
47 : filter(_filter)
48{
49 assert(filter);
50 d = new KFilterDevPrivate;
51 d->autoDeleteFilterBase = autoDeleteFilterBase;
52}
53
54KFilterDev::~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.
66TQIODevice* 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
81TQIODevice * 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
101TQIODevice * KFilterDev::device( TQIODevice* inDevice, const TQString & mimetype)
102{
103 return device( inDevice, mimetype, true );
104}
105
106TQIODevice * 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
119bool 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
149void 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
165void KFilterDev::flush()
166{
167 //kdDebug(7005) << "KFilterDev::flush" << endl;
168 filter->device()->flush();
169 // Hmm, might not be enough...
170}
171
172TQIODevice::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
185TQIODevice::Offset KFilterDev::at() const
186{
187 return TQIODevice::at();
188}
189
190bool 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
229bool KFilterDev::atEnd() const
230{
231 return filter->device()->atEnd() && (d->result == KFilterBase::END)
232 && d->ungetchBuffer.isEmpty();
233}
234
235TQ_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
354TQ_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
434int 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
452int 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
460int 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
472void KFilterDev::setOrigFileName( const TQCString & fileName )
473{
474 d->origFileName = fileName;
475}
476
477void 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::device
TQIODevice * device()
Returns the device on which the filter will work.
Definition kfilterbase.h:58
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::setDevice
void setDevice(TQIODevice *dev, bool autodelete=false)
Sets the device on which the filter will work.
Definition kfilterbase.cpp:36
KFilterDev
A class for reading and writing compressed data onto a device (e.g.
Definition kfilterdev.h:37
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
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
  • 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.8
This website is maintained by Timothy Pearson.