• 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 // If no data has been produced in this call, propagate the error
320 // immediately. Otherwise return the already produced data and
321 // report the error on the next readBlock() call.
322 if ( dataReceived == 0 )
323 return -1;
324 break;
325 }
326
327 // We got that much data since the last time we went here
328 uint outReceived = availOut - filter->outBufferAvailable();
329 //kdDebug(7005) << "avail_out = " << filter->outBufferAvailable() << " result=" << d->result << " outReceived=" << outReceived << endl;
330 if( availOut < (uint)filter->outBufferAvailable() )
331 kdWarning(7005) << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !" << endl;
332
333 dataReceived += outReceived;
334 if ( !d->bIgnoreData ) // Move on in the output buffer
335 {
336 data += outReceived;
337 availOut = maxlen - dataReceived;
338 }
339 else if ( maxlen - dataReceived < outBufferSize )
340 {
341 availOut = maxlen - dataReceived;
342 }
343 TQIODevice::at(TQIODevice::at() + outReceived);
344 if (d->result == KFilterBase::END)
345 {
346 //kdDebug(7005) << "KFilterDev::readBlock got END. dataReceived=" << dataReceived << endl;
347 break; // Finished.
348 }
349 if (filter->inBufferEmpty() && filter->outBufferAvailable() != 0 )
350 {
351 decompressedAll = true;
352 }
353 filter->setOutBuffer( data, availOut );
354 }
355
356 return dataReceived;
357}
358
359TQ_LONG KFilterDev::writeBlock( const char *data /*0 to finish*/, TQ_ULONG len )
360{
361 Q_ASSERT ( filter->mode() == IO_WriteOnly );
362 // If we had an error, return 0.
363 if ( d->result != KFilterBase::OK )
364 return 0;
365
366 bool finish = (data == 0L);
367 if (!finish)
368 {
369 filter->setInBuffer( data, len );
370 if (d->bNeedHeader)
371 {
372 (void)filter->writeHeader( d->origFileName );
373 d->bNeedHeader = false;
374 }
375 }
376
377 uint dataWritten = 0;
378 uint availIn = len;
379 while ( dataWritten < len || finish )
380 {
381
382 d->result = filter->compress( finish );
383
384 if (d->result == KFilterBase::ERROR)
385 {
386 kdWarning(7005) << "KFilterDev: Error when compressing data" << endl;
387 // What to do ?
388 break;
389 }
390
391 // Wrote everything ?
392 if (filter->inBufferEmpty() || (d->result == KFilterBase::END))
393 {
394 // We got that much data since the last time we went here
395 uint wrote = availIn - filter->inBufferAvailable();
396
397 //kdDebug(7005) << " Wrote everything for now. avail_in = " << filter->inBufferAvailable() << " result=" << d->result << " wrote=" << wrote << endl;
398
399 // Move on in the input buffer
400 data += wrote;
401 dataWritten += wrote;
402 TQIODevice::at(TQIODevice::at() + wrote);
403
404 availIn = len - dataWritten;
405 //kdDebug(7005) << " KFilterDev::writeBlock availIn=" << availIn << " dataWritten=" << dataWritten << " ioIndex=" << ioIndex << endl;
406 if ( availIn > 0 ) // Not sure this will ever happen
407 filter->setInBuffer( data, availIn );
408 }
409
410 if (filter->outBufferFull() || (d->result == KFilterBase::END))
411 {
412 //kdDebug(7005) << " KFilterDev::writeBlock writing to underlying. avail_out=" << filter->outBufferAvailable() << endl;
413 int towrite = d->buffer.size() - filter->outBufferAvailable();
414 if ( towrite > 0 )
415 {
416 // Write compressed data to underlying device
417 int size = filter->device()->writeBlock( d->buffer.data(), towrite );
418 if ( size != towrite ) {
419 kdWarning(7005) << "KFilterDev::writeBlock. Could only write " << size << " out of " << towrite << " bytes" << endl;
420 return 0; // indicate an error (happens on disk full)
421 }
422 //else
423 //kdDebug(7005) << " KFilterDev::writeBlock wrote " << size << " bytes" << endl;
424 }
425 d->buffer.resize( 8*1024 );
426 filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
427 if (d->result == KFilterBase::END)
428 {
429 //kdDebug(7005) << " KFilterDev::writeBlock END" << endl;
430 Q_ASSERT(finish); // hopefully we don't get end before finishing
431 break;
432 }
433 }
434 }
435
436 return dataWritten;
437}
438
439int KFilterDev::getch()
440{
441 Q_ASSERT ( filter->mode() == IO_ReadOnly );
442 //kdDebug(7005) << "KFilterDev::getch" << endl;
443 if ( !d->ungetchBuffer.isEmpty() ) {
444 int len = d->ungetchBuffer.length();
445 int ch = d->ungetchBuffer[ len-1 ];
446 d->ungetchBuffer.truncate( len - 1 );
447 TQIODevice::at(TQIODevice::at() + 1);
448 //kdDebug(7005) << "KFilterDev::getch from ungetch: " << TQString(TQChar(ch)) << endl;
449 return ch;
450 }
451 char buf[1];
452 int ret = readBlock( buf, 1 ) == 1 ? buf[0] : EOF;
453 //kdDebug(7005) << "KFilterDev::getch ret=" << TQString(TQChar(ret)) << endl;
454 return ret;
455}
456
457int KFilterDev::putch( int c )
458{
459 //kdDebug(7005) << "KFilterDev::putch" << endl;
460 char buf[1];
461 buf[0] = c;
462 return writeBlock( buf, 1 ) == 1 ? c : -1;
463}
464
465int KFilterDev::ungetch( int ch )
466{
467 //kdDebug(7005) << "KFilterDev::ungetch " << TQString(TQChar(ch)) << endl;
468 if ( ch == EOF ) // cannot unget EOF
469 return ch;
470
471 // pipe or similar => we cannot ungetch, so do it manually
472 d->ungetchBuffer +=ch;
473 TQIODevice::at(TQIODevice::at() - 1);
474 return ch;
475}
476
477void KFilterDev::setOrigFileName( const TQCString & fileName )
478{
479 d->origFileName = fileName;
480}
481
482void KFilterDev::setSkipHeaders()
483{
484 d->bSkipHeaders = true;
485}
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::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:477
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:482
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.4
This website is maintained by Timothy Pearson.