source: box/trunk/lib/compress/CompressStream.cpp @ 2415

Revision 2415, 10.0 KB checked in by chris, 3 years ago (diff)

Rename NDEBUG flag to BOX_RELEASE_BUILD, as other projects use NDEBUG as
well (e.g. wxWidgets) and it causes conflicts which are difficult to
resolve.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    CompressStream.h
5//              Purpose: Compressing stream
6//              Created: 27/5/04
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <stdlib.h>
13#include <memory>
14
15#include "CompressStream.h"
16#include "Compress.h"
17#include "autogen_CompressException.h"
18
19#include "MemLeakFindOn.h"
20
21// How big a buffer to use
22#ifndef BOX_RELEASE_BUILD
23        // debug!
24        #define BUFFER_SIZE     256
25#else
26        #define BUFFER_SIZE     (32*1024)
27#endif
28
29#define USE_READ_COMPRESSOR             \
30        CheckRead();                            \
31        Compress<false> *pDecompress = (Compress<false> *)mpReadCompressor;
32
33#define USE_WRITE_COMPRESSOR    \
34        CheckWrite();                           \
35        Compress<true> *pCompress = (Compress<true> *)mpWriteCompressor;
36
37
38// --------------------------------------------------------------------------
39//
40// Function
41//              Name:    CompressStream::CompressStream(IOStream *, bool, bool, bool, bool)
42//              Purpose: Constructor
43//              Created: 27/5/04
44//
45// --------------------------------------------------------------------------
46CompressStream::CompressStream(IOStream *pStream, bool TakeOwnership,
47                bool DecompressRead, bool CompressWrite, bool PassThroughWhenNotCompressed)
48        : mpStream(pStream),
49          mHaveOwnership(TakeOwnership),
50          mDecompressRead(DecompressRead),
51          mCompressWrite(CompressWrite),
52          mPassThroughWhenNotCompressed(PassThroughWhenNotCompressed),
53          mpReadCompressor(0),
54          mpWriteCompressor(0),
55          mpBuffer(0),
56          mIsClosed(false)
57{
58        if(mpStream == 0)
59        {
60                THROW_EXCEPTION(CompressException, NullPointerPassedToCompressStream)
61        }
62}
63
64
65// --------------------------------------------------------------------------
66//
67// Function
68//              Name:    CompressStream::~CompressStream()
69//              Purpose: Destructor
70//              Created: 27/5/04
71//
72// --------------------------------------------------------------------------
73CompressStream::~CompressStream()
74{
75        // Clean up compressors
76        if(mpReadCompressor)
77        {
78                delete ((Compress<false>*)mpReadCompressor);
79                mpReadCompressor = 0;
80        }
81        if(mpWriteCompressor)
82        {
83                delete ((Compress<true>*)mpWriteCompressor);
84                mpWriteCompressor = 0;
85        }
86
87        // Delete the stream, if we have ownership
88        if(mHaveOwnership)
89        {
90                delete mpStream;
91                mpStream = 0;
92        }
93       
94        // Free any buffer
95        if(mpBuffer != 0)
96        {
97                ::free(mpBuffer);
98                mpBuffer = 0;
99        }
100}
101
102
103// --------------------------------------------------------------------------
104//
105// Function
106//              Name:    CompressStream::CompressStream(const CompressStream &)
107//              Purpose: Copy constructor, will exception
108//              Created: 27/5/04
109//
110// --------------------------------------------------------------------------
111CompressStream::CompressStream(const CompressStream &)
112{
113        THROW_EXCEPTION(CompressException, CopyCompressStreamNotAllowed)
114}
115
116
117// --------------------------------------------------------------------------
118//
119// Function
120//              Name:    CompressStream::operator=(const CompressStream &)
121//              Purpose: Assignment operator, will exception
122//              Created: 27/5/04
123//
124// --------------------------------------------------------------------------
125CompressStream &CompressStream::operator=(const CompressStream &)
126{
127        THROW_EXCEPTION(CompressException, CopyCompressStreamNotAllowed)
128}
129
130
131// --------------------------------------------------------------------------
132//
133// Function
134//              Name:    CompressStream::Read(void *, int, int)
135//              Purpose: As interface
136//              Created: 27/5/04
137//
138// --------------------------------------------------------------------------
139int CompressStream::Read(void *pBuffer, int NBytes, int Timeout)
140{
141        USE_READ_COMPRESSOR
142        if(pDecompress == 0)
143        {
144                return mpStream->Read(pBuffer, NBytes, Timeout);
145        }
146
147        // Where is the buffer? (note if writing as well, read buffer is second in a block of two buffer sizes)
148        void *pbuf = (mDecompressRead && mCompressWrite)?(((uint8_t*)mpBuffer) + BUFFER_SIZE):mpBuffer;
149
150        // Any data left to go?
151        if(!pDecompress->InputRequired())
152        {
153                // Output some data from the existing data read
154                return pDecompress->Output(pBuffer, NBytes, true /* write as much as possible */);
155        }
156
157        // Read data into the buffer -- read as much as possible in one go
158        int s = mpStream->Read(pbuf, BUFFER_SIZE, Timeout);
159        if(s == 0)
160        {
161                return 0;
162        }
163       
164        // Give input to the compressor
165        pDecompress->Input(pbuf, s);
166
167        // Output as much as possible
168        return pDecompress->Output(pBuffer, NBytes, true /* write as much as possible */);
169}
170
171
172// --------------------------------------------------------------------------
173//
174// Function
175//              Name:    CompressStream::Write(const void *, int)
176//              Purpose: As interface
177//              Created: 27/5/04
178//
179// --------------------------------------------------------------------------
180void CompressStream::Write(const void *pBuffer, int NBytes)
181{
182        USE_WRITE_COMPRESSOR
183        if(pCompress == 0)
184        {
185                mpStream->Write(pBuffer, NBytes);
186                return;
187        }
188       
189        if(mIsClosed)
190        {
191                THROW_EXCEPTION(CompressException, CannotWriteToClosedCompressStream)
192        }
193
194        // Give the data to the compressor
195        pCompress->Input(pBuffer, NBytes);
196       
197        // Write the data to the stream
198        WriteCompressedData();
199}
200
201
202// --------------------------------------------------------------------------
203//
204// Function
205//              Name:    CompressStream::WriteAllBuffered()
206//              Purpose: As interface
207//              Created: 27/5/04
208//
209// --------------------------------------------------------------------------
210void CompressStream::WriteAllBuffered()
211{
212        if(mIsClosed)
213        {
214                THROW_EXCEPTION(CompressException, CannotWriteToClosedCompressStream)
215        }
216
217        // Just ask compressed data to be written out, but with the sync flag set
218        WriteCompressedData(true);
219}
220
221
222// --------------------------------------------------------------------------
223//
224// Function
225//              Name:    CompressStream::Close()
226//              Purpose: As interface
227//              Created: 27/5/04
228//
229// --------------------------------------------------------------------------
230void CompressStream::Close()
231{
232        if(mCompressWrite)
233        {
234                USE_WRITE_COMPRESSOR
235                if(pCompress != 0)
236                {
237                        // Flush anything from the write buffer
238                        pCompress->FinishInput();
239                        WriteCompressedData();
240                       
241                        // Mark as definately closed
242                        mIsClosed = true;
243                }
244        }
245
246        // Close
247        mpStream->Close();
248}
249
250
251// --------------------------------------------------------------------------
252//
253// Function
254//              Name:    CompressStream::WriteCompressedData(bool)
255//              Purpose: Private. Writes the output of the compressor to the stream,
256//                               optionally doing a sync flush.
257//              Created: 28/5/04
258//
259// --------------------------------------------------------------------------
260void CompressStream::WriteCompressedData(bool SyncFlush)
261{
262        USE_WRITE_COMPRESSOR
263        if(pCompress == 0) {THROW_EXCEPTION(CompressException, Internal)}
264       
265        int s = 0;
266        do
267        {
268                s = pCompress->Output(mpBuffer, BUFFER_SIZE, SyncFlush);
269                if(s > 0)
270                {
271                        mpStream->Write(mpBuffer, s);
272                }
273        } while(s > 0);
274        // Check assumption -- all input has been consumed
275        if(!pCompress->InputRequired()) {THROW_EXCEPTION(CompressException, Internal)}
276}
277
278
279// --------------------------------------------------------------------------
280//
281// Function
282//              Name:    CompressStream::StreamDataLeft()
283//              Purpose: As interface
284//              Created: 27/5/04
285//
286// --------------------------------------------------------------------------
287bool CompressStream::StreamDataLeft()
288{
289        USE_READ_COMPRESSOR
290        if(pDecompress == 0)
291        {
292                return mpStream->StreamDataLeft();
293        }
294
295        // Any bytes left in our buffer?
296        if(!pDecompress->InputRequired())
297        {
298                // Still buffered data to decompress
299                return true;
300        }
301
302        // Otherwise ask the stream
303        return mpStream->StreamDataLeft();
304}
305
306
307// --------------------------------------------------------------------------
308//
309// Function
310//              Name:    CompressStream::StreamClosed()
311//              Purpose: As interface
312//              Created: 27/5/04
313//
314// --------------------------------------------------------------------------
315bool CompressStream::StreamClosed()
316{
317        if(!mIsClosed && mpStream->StreamClosed())
318        {
319                mIsClosed = true;
320        }
321        return mIsClosed;
322}
323
324
325// --------------------------------------------------------------------------
326//
327// Function
328//              Name:    CompressStream::CheckRead()
329//              Purpose: Checks that everything is set up to read
330//              Created: 27/5/04
331//
332// --------------------------------------------------------------------------
333void CompressStream::CheckRead()
334{
335        // Has the read compressor already been created?
336        if(mpReadCompressor != 0)
337        {
338                return;
339        }
340       
341        // Need to create one?
342        if(mDecompressRead)
343        {
344                mpReadCompressor = new Compress<false>();
345                // And make sure there's a buffer
346                CheckBuffer();
347        }
348        else
349        {
350                // Not decompressing. Should be passing through data?
351                if(!mPassThroughWhenNotCompressed)
352                {
353                        THROW_EXCEPTION(CompressException, CompressStreamReadSupportNotRequested)
354                }
355        }
356}
357
358
359// --------------------------------------------------------------------------
360//
361// Function
362//              Name:    CompressStream::CheckWrite()
363//              Purpose: Checks that everything is set up to write
364//              Created: 27/5/04
365//
366// --------------------------------------------------------------------------
367void CompressStream::CheckWrite()
368{
369        // Has the read compressor already been created?
370        if(mpWriteCompressor != 0)
371        {
372                return;
373        }
374       
375        // Need to create one?
376        if(mCompressWrite)
377        {
378                mpWriteCompressor = new Compress<true>();
379                // And make sure there's a buffer
380                CheckBuffer();
381        }
382        else
383        {
384                // Not decompressing. Should be passing through data?
385                if(!mPassThroughWhenNotCompressed)
386                {
387                        THROW_EXCEPTION(CompressException, CompressStreamWriteSupportNotRequested)
388                }
389        }
390}
391
392
393// --------------------------------------------------------------------------
394//
395// Function
396//              Name:    CompressStream::CheckBuffer()
397//              Purpose: Allocates the buffer for (de)compression operations
398//              Created: 28/5/04
399//
400// --------------------------------------------------------------------------
401void CompressStream::CheckBuffer()
402{
403        // Already done
404        if(mpBuffer != 0)
405        {
406                return;
407        }
408       
409        // Allocate the buffer -- which may actually be two buffers in one
410        // The temporary use buffer is first (used by write only, so only present if writing)
411        // and the read buffer follows.
412        int size = BUFFER_SIZE;
413        if(mDecompressRead && mCompressWrite)
414        {
415                size *= 2;
416        }
417        BOX_TRACE("Allocating CompressStream buffer, size " << size);
418        mpBuffer = ::malloc(size);
419        if(mpBuffer == 0)
420        {
421                throw std::bad_alloc();
422        }
423}
424
425
Note: See TracBrowser for help on using the repository browser.