aboutsummaryrefslogtreecommitdiff
path: root/src/deflate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/deflate.cpp')
-rw-r--r--src/deflate.cpp249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/deflate.cpp b/src/deflate.cpp
new file mode 100644
index 0000000..2d925a7
--- /dev/null
+++ b/src/deflate.cpp
@@ -0,0 +1,249 @@
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( !pState->state )
127 {
128 bReading = true;
129 if( eFmt&AutoDetect )
130 inflateInit2( pState, 32+15 ); // Auto-detect, large window
131 else if( eFmt == Raw )
132 inflateInit2( pState, -15 ); // Raw
133 else if( eFmt == Zlib )
134 inflateInit2( pState, 15 ); // Zlib
135 else if( eFmt == Gzip )
136 inflateInit2( pState, 16+15 ); // GZip
137 else
138 throw Bu::ExceptionBase("Format mode for deflate read.");
139 pState->next_in = (Bytef *)pBuf;
140 pState->avail_in = 0;
141 }
142 if( bReading == false )
143 throw ExceptionBase("This deflate filter is in writing mode, you can't read.");
144
145 int nRead = 0;
146 int nReadTotal = pState->total_out;
147 pState->next_out = (Bytef *)pData;
148 pState->avail_out = nBytes;
149 for(;;)
150 {
151 int ret = inflate( pState, Z_NO_FLUSH );
152 nReadTotal += nRead-pState->avail_out;
153
154 if( ret == Z_STREAM_END )
155 {
156 bEos = true;
157 if( pState->avail_in > 0 )
158 {
159 if( rNext.isSeekable() )
160 {
161 rNext.seek( -pState->avail_in );
162 }
163 }
164 return nBytes-pState->avail_out;
165 }
166 if( ret != Z_BUF_ERROR )
167 zError( ret );
168
169 if( pState->avail_out )
170 {
171 if( pState->avail_in == 0 )
172 {
173 nRead = rNext.read( pBuf, nBufSize );
174 if( nRead == 0 && rNext.isEos() )
175 {
176 throw Bu::ExceptionBase("Premature end of underlying "
177 "stream found reading deflate stream.");
178 }
179 pState->next_in = (Bytef *)pBuf;
180 pState->avail_in = nRead;
181 }
182 }
183 else
184 {
185 return nBytes-pState->avail_out;
186 }
187 }
188 return 0;
189}
190
191Bu::size Bu::Deflate::write( const void *pData, Bu::size nBytes )
192{
193 TRACE( pData, nBytes );
194 if( !pState->state )
195 {
196 bReading = false;
197 int iFmt = eFmt&Gzip;
198 if( iFmt == Raw )
199 deflateInit2( pState, nCompression, Z_DEFLATED, -15, 9,
200 Z_DEFAULT_STRATEGY );
201 else if( iFmt == Zlib )
202 deflateInit2( pState, nCompression, Z_DEFLATED, 15, 9,
203 Z_DEFAULT_STRATEGY );
204 else if( iFmt == Gzip )
205 deflateInit2( pState, nCompression, Z_DEFLATED, 16+15, 9,
206 Z_DEFAULT_STRATEGY );
207 else
208 throw Bu::ExceptionBase("Invalid format for deflate.");
209 }
210 if( bReading == true )
211 throw ExceptionBase("This deflate filter is in reading mode, you can't write.");
212
213 pState->next_in = (Bytef *)pData;
214 pState->avail_in = nBytes;
215 for(;;)
216 {
217 pState->avail_out = nBufSize;
218 pState->next_out = (Bytef *)pBuf;
219
220 zError( deflate( pState, Z_NO_FLUSH ) );
221
222 if( pState->avail_out < nBufSize )
223 {
224 sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out );
225 }
226 if( pState->avail_in == 0 )
227 break;
228 }
229
230 return nBytes;
231}
232
233bool Bu::Deflate::isOpen()
234{
235 TRACE();
236 return (pState != NULL && pState->state != NULL);
237}
238
239bool Bu::Deflate::isEos()
240{
241 TRACE();
242 return bEos;
243}
244
245Bu::size Bu::Deflate::getCompressedSize()
246{
247 return sTotalOut;
248}
249