summaryrefslogtreecommitdiff
path: root/src/stable/deflate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/stable/deflate.cpp')
-rw-r--r--src/stable/deflate.cpp253
1 files changed, 253 insertions, 0 deletions
diff --git a/src/stable/deflate.cpp b/src/stable/deflate.cpp
new file mode 100644
index 0000000..704d172
--- /dev/null
+++ b/src/stable/deflate.cpp
@@ -0,0 +1,253 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/deflate.h"
9#include "bu/trace.h"
10
11#include <zlib.h>
12
13#define pState ((z_stream *)prState)
14
15using namespace Bu;
16
17Bu::Deflate::Deflate( Bu::Stream &rNext, int nCompression, Format eFmt ) :
18 Bu::Filter( rNext ),
19 prState( NULL ),
20 nCompression( nCompression ),
21 sTotalOut( 0 ),
22 eFmt( eFmt ),
23 bEos( false )
24{
25 TRACE( nCompression );
26 start();
27}
28
29Bu::Deflate::~Deflate()
30{
31 TRACE();
32 stop();
33}
34
35void Bu::Deflate::start()
36{
37 TRACE();
38 prState = new z_stream;
39 pState->zalloc = NULL;
40 pState->zfree = NULL;
41 pState->opaque = NULL;
42 pState->state = NULL;
43
44 nBufSize = 64*1024;
45 pBuf = new char[nBufSize];
46}
47
48Bu::size Bu::Deflate::stop()
49{
50 TRACE();
51 if( pState && pState->state )
52 {
53 if( bReading )
54 {
55 inflateEnd( pState );
56 delete[] pBuf;
57 pBuf = NULL;
58 delete pState;
59 prState = NULL;
60 return 0;
61 }
62 else
63 {
64 for(;;)
65 {
66 pState->next_in = NULL;
67 pState->avail_in = 0;
68 pState->avail_out = nBufSize;
69 pState->next_out = (Bytef *)pBuf;
70 int res = deflate( pState, Z_FINISH );
71 if( pState->avail_out < nBufSize )
72 {
73 sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out );
74 }
75 if( res == Z_STREAM_END )
76 break;
77 }
78 deflateEnd( pState );
79 delete[] pBuf;
80 pBuf = NULL;
81 delete pState;
82 prState = NULL;
83 return sTotalOut;
84 }
85 }
86 return 0;
87}
88
89void Bu::Deflate::zError( int code )
90{
91 TRACE( code );
92 switch( code )
93 {
94 case Z_OK:
95 case Z_STREAM_END:
96 case Z_NEED_DICT:
97 return;
98
99 case Z_ERRNO:
100 throw ExceptionBase("Deflate: Errno - %s", pState->msg );
101
102 case Z_STREAM_ERROR:
103 throw ExceptionBase("Deflate: Stream Error - %s", pState->msg );
104
105 case Z_DATA_ERROR:
106 throw ExceptionBase("Deflate: Data Error - %s", pState->msg );
107
108 case Z_MEM_ERROR:
109 throw ExceptionBase("Deflate: Mem Error - %s", pState->msg );
110
111 case Z_BUF_ERROR:
112 throw ExceptionBase("Deflate: Buf Error - %s", pState->msg );
113
114 case Z_VERSION_ERROR:
115 throw ExceptionBase("Deflate: Version Error - %s", pState->msg );
116
117 default:
118 throw ExceptionBase("Deflate: Unknown error encountered - %s.", pState->msg );
119
120 }
121}
122
123Bu::size Bu::Deflate::read( void *pData, Bu::size nBytes )
124{
125 TRACE( pData, nBytes );
126 if( nBytes <= 0 )
127 return 0;
128 if( !pState->state )
129 {
130 bReading = true;
131 if( eFmt&AutoDetect )
132 inflateInit2( pState, 32+15 ); // Auto-detect, large window
133 else if( eFmt == Raw )
134 inflateInit2( pState, -15 ); // Raw
135 else if( eFmt == Zlib )
136 inflateInit2( pState, 15 ); // Zlib
137 else if( eFmt == Gzip )
138 inflateInit2( pState, 16+15 ); // GZip
139 else
140 throw Bu::ExceptionBase("Format mode for deflate read.");
141 pState->next_in = (Bytef *)pBuf;
142 pState->avail_in = 0;
143 }
144 if( bReading == false )
145 throw ExceptionBase("This deflate filter is in writing mode, you can't read.");
146
147 int nRead = 0;
148 int nReadTotal = pState->total_out;
149 pState->next_out = (Bytef *)pData;
150 pState->avail_out = nBytes;
151 for(;;)
152 {
153 int ret = inflate( pState, Z_NO_FLUSH );
154 nReadTotal += nRead-pState->avail_out;
155
156 if( ret == Z_STREAM_END )
157 {
158 bEos = true;
159 if( pState->avail_in > 0 )
160 {
161 if( rNext.isSeekable() )
162 {
163 rNext.seek( -pState->avail_in );
164 }
165 }
166 return nBytes-pState->avail_out;
167 }
168 if( ret != Z_BUF_ERROR )
169 zError( ret );
170
171 if( pState->avail_out )
172 {
173 if( pState->avail_in == 0 )
174 {
175 nRead = rNext.read( pBuf, nBufSize );
176 if( nRead == 0 && rNext.isEos() )
177 {
178 throw Bu::ExceptionBase("Premature end of underlying "
179 "stream found reading deflate stream.");
180 }
181 pState->next_in = (Bytef *)pBuf;
182 pState->avail_in = nRead;
183 }
184 }
185 else
186 {
187 return nBytes-pState->avail_out;
188 }
189 }
190 return 0;
191}
192
193Bu::size Bu::Deflate::write( const void *pData, Bu::size nBytes )
194{
195 TRACE( pData, nBytes );
196 if( nBytes <= 0 )
197 return 0;
198 if( !pState->state )
199 {
200 bReading = false;
201 int iFmt = eFmt&Gzip;
202 if( iFmt == Raw )
203 deflateInit2( pState, nCompression, Z_DEFLATED, -15, 9,
204 Z_DEFAULT_STRATEGY );
205 else if( iFmt == Zlib )
206 deflateInit2( pState, nCompression, Z_DEFLATED, 15, 9,
207 Z_DEFAULT_STRATEGY );
208 else if( iFmt == Gzip )
209 deflateInit2( pState, nCompression, Z_DEFLATED, 16+15, 9,
210 Z_DEFAULT_STRATEGY );
211 else
212 throw Bu::ExceptionBase("Invalid format for deflate.");
213 }
214 if( bReading == true )
215 throw ExceptionBase("This deflate filter is in reading mode, you can't write.");
216
217 pState->next_in = (Bytef *)pData;
218 pState->avail_in = nBytes;
219 for(;;)
220 {
221 pState->avail_out = nBufSize;
222 pState->next_out = (Bytef *)pBuf;
223
224 zError( deflate( pState, Z_NO_FLUSH ) );
225
226 if( pState->avail_out < nBufSize )
227 {
228 sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out );
229 }
230 if( pState->avail_in == 0 )
231 break;
232 }
233
234 return nBytes;
235}
236
237bool Bu::Deflate::isOpen()
238{
239 TRACE();
240 return (pState != NULL && pState->state != NULL);
241}
242
243bool Bu::Deflate::isEos()
244{
245 TRACE();
246 return bEos;
247}
248
249Bu::size Bu::Deflate::getCompressedSize()
250{
251 return sTotalOut;
252}
253