diff options
author | Mike Buland <eichlan@xagasoft.com> | 2011-10-23 07:43:50 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2011-10-23 07:43:50 +0000 |
commit | da1e0ef0772b078bd295301bd675afdee00d40e9 (patch) | |
tree | 7d1703bbb5c2d76e6e6300e51f0ed1e09704af4f /src/deflate.cpp | |
parent | 208b983734d7431699f4bd3534e08321e42ada86 (diff) | |
download | libbu++-da1e0ef0772b078bd295301bd675afdee00d40e9.tar.gz libbu++-da1e0ef0772b078bd295301bd675afdee00d40e9.tar.bz2 libbu++-da1e0ef0772b078bd295301bd675afdee00d40e9.tar.xz libbu++-da1e0ef0772b078bd295301bd675afdee00d40e9.zip |
Switched ito* to synchro*, except the server, I'm thinking of takeing the core
in a different direction anyway.
Added the Deflate class, it uses zlib, and can do raw (headerless) deflate
streams, zlib format, or gzip format. It's easy to use and quite versitile.
Diffstat (limited to '')
-rw-r--r-- | src/deflate.cpp | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/src/deflate.cpp b/src/deflate.cpp new file mode 100644 index 0000000..aec2a18 --- /dev/null +++ b/src/deflate.cpp | |||
@@ -0,0 +1,242 @@ | |||
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 | using namespace Bu; | ||
12 | |||
13 | Bu::Deflate::Deflate( Bu::Stream &rNext, int nCompression, Format eFmt ) : | ||
14 | Bu::Filter( rNext ), | ||
15 | nCompression( nCompression ), | ||
16 | sTotalOut( 0 ), | ||
17 | eFmt( eFmt ), | ||
18 | bEos( false ) | ||
19 | { | ||
20 | TRACE( nCompression ); | ||
21 | start(); | ||
22 | } | ||
23 | |||
24 | Bu::Deflate::~Deflate() | ||
25 | { | ||
26 | TRACE(); | ||
27 | stop(); | ||
28 | } | ||
29 | |||
30 | void Bu::Deflate::start() | ||
31 | { | ||
32 | TRACE(); | ||
33 | zState.zalloc = NULL; | ||
34 | zState.zfree = NULL; | ||
35 | zState.opaque = NULL; | ||
36 | zState.state = NULL; | ||
37 | |||
38 | nBufSize = 64*1024; | ||
39 | pBuf = new char[nBufSize]; | ||
40 | } | ||
41 | |||
42 | Bu::size Bu::Deflate::stop() | ||
43 | { | ||
44 | TRACE(); | ||
45 | if( zState.state ) | ||
46 | { | ||
47 | if( bReading ) | ||
48 | { | ||
49 | inflateEnd( &zState ); | ||
50 | delete[] pBuf; | ||
51 | pBuf = NULL; | ||
52 | return 0; | ||
53 | } | ||
54 | else | ||
55 | { | ||
56 | for(;;) | ||
57 | { | ||
58 | zState.next_in = NULL; | ||
59 | zState.avail_in = 0; | ||
60 | zState.avail_out = nBufSize; | ||
61 | zState.next_out = (Bytef *)pBuf; | ||
62 | int res = deflate( &zState, Z_FINISH ); | ||
63 | if( zState.avail_out < nBufSize ) | ||
64 | { | ||
65 | sTotalOut += rNext.write( pBuf, nBufSize-zState.avail_out ); | ||
66 | } | ||
67 | if( res == Z_STREAM_END ) | ||
68 | break; | ||
69 | } | ||
70 | deflateEnd( &zState ); | ||
71 | delete[] pBuf; | ||
72 | pBuf = NULL; | ||
73 | return sTotalOut; | ||
74 | } | ||
75 | } | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | void Bu::Deflate::zError( int code ) | ||
80 | { | ||
81 | TRACE( code ); | ||
82 | switch( code ) | ||
83 | { | ||
84 | case Z_OK: | ||
85 | case Z_STREAM_END: | ||
86 | case Z_NEED_DICT: | ||
87 | return; | ||
88 | |||
89 | case Z_ERRNO: | ||
90 | throw ExceptionBase("Deflate: Errno - %s", zState.msg ); | ||
91 | |||
92 | case Z_STREAM_ERROR: | ||
93 | throw ExceptionBase("Deflate: Stream Error - %s", zState.msg ); | ||
94 | |||
95 | case Z_DATA_ERROR: | ||
96 | throw ExceptionBase("Deflate: Data Error - %s", zState.msg ); | ||
97 | |||
98 | case Z_MEM_ERROR: | ||
99 | throw ExceptionBase("Deflate: Mem Error - %s", zState.msg ); | ||
100 | |||
101 | case Z_BUF_ERROR: | ||
102 | throw ExceptionBase("Deflate: Buf Error - %s", zState.msg ); | ||
103 | |||
104 | case Z_VERSION_ERROR: | ||
105 | throw ExceptionBase("Deflate: Version Error - %s", zState.msg ); | ||
106 | |||
107 | default: | ||
108 | throw ExceptionBase("Deflate: Unknown error encountered - %s.", zState.msg ); | ||
109 | |||
110 | } | ||
111 | } | ||
112 | |||
113 | Bu::size Bu::Deflate::read( void *pData, Bu::size nBytes ) | ||
114 | { | ||
115 | TRACE( pData, nBytes ); | ||
116 | if( !zState.state ) | ||
117 | { | ||
118 | bReading = true; | ||
119 | if( eFmt&AutoDetect ) | ||
120 | inflateInit2( &zState, 32+15 ); // Auto-detect, large window | ||
121 | else if( eFmt == Raw ) | ||
122 | inflateInit2( &zState, -15 ); // Raw | ||
123 | else if( eFmt == Zlib ) | ||
124 | inflateInit2( &zState, 15 ); // Zlib | ||
125 | else if( eFmt == Gzip ) | ||
126 | inflateInit2( &zState, 16+15 ); // GZip | ||
127 | else | ||
128 | throw Bu::ExceptionBase("Format mode for deflate read."); | ||
129 | zState.next_in = (Bytef *)pBuf; | ||
130 | zState.avail_in = 0; | ||
131 | } | ||
132 | if( bReading == false ) | ||
133 | throw ExceptionBase("This deflate filter is in writing mode, you can't read."); | ||
134 | |||
135 | int nRead = 0; | ||
136 | int nReadTotal = zState.total_out; | ||
137 | zState.next_out = (Bytef *)pData; | ||
138 | zState.avail_out = nBytes; | ||
139 | for(;;) | ||
140 | { | ||
141 | int ret = inflate( &zState, Z_NO_FLUSH ); | ||
142 | printf("inflate returned %d; avail in=%d, out=%d\n", ret, | ||
143 | zState.avail_in, zState.avail_out ); | ||
144 | |||
145 | nReadTotal += nRead-zState.avail_out; | ||
146 | |||
147 | if( ret == Z_STREAM_END ) | ||
148 | { | ||
149 | bEos = true; | ||
150 | if( zState.avail_in > 0 ) | ||
151 | { | ||
152 | if( rNext.isSeekable() ) | ||
153 | { | ||
154 | rNext.seek( -zState.avail_in ); | ||
155 | } | ||
156 | } | ||
157 | return nBytes-zState.avail_out; | ||
158 | } | ||
159 | if( ret != Z_BUF_ERROR ) | ||
160 | zError( ret ); | ||
161 | |||
162 | if( zState.avail_out ) | ||
163 | { | ||
164 | if( zState.avail_in == 0 ) | ||
165 | { | ||
166 | nRead = rNext.read( pBuf, nBufSize ); | ||
167 | if( nRead == 0 && rNext.isEos() ) | ||
168 | { | ||
169 | throw Bu::ExceptionBase("Premature end of underlying " | ||
170 | "stream found reading deflate stream."); | ||
171 | } | ||
172 | zState.next_in = (Bytef *)pBuf; | ||
173 | zState.avail_in = nRead; | ||
174 | } | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | return nBytes-zState.avail_out; | ||
179 | } | ||
180 | } | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | Bu::size Bu::Deflate::write( const void *pData, Bu::size nBytes ) | ||
185 | { | ||
186 | TRACE( pData, nBytes ); | ||
187 | if( !zState.state ) | ||
188 | { | ||
189 | bReading = false; | ||
190 | int iFmt = eFmt&Gzip; | ||
191 | if( iFmt == Raw ) | ||
192 | deflateInit2( &zState, nCompression, Z_DEFLATED, -15, 9, | ||
193 | Z_DEFAULT_STRATEGY ); | ||
194 | else if( iFmt == Zlib ) | ||
195 | deflateInit2( &zState, nCompression, Z_DEFLATED, 15, 9, | ||
196 | Z_DEFAULT_STRATEGY ); | ||
197 | else if( iFmt == Gzip ) | ||
198 | deflateInit2( &zState, nCompression, Z_DEFLATED, 16+15, 9, | ||
199 | Z_DEFAULT_STRATEGY ); | ||
200 | else | ||
201 | throw Bu::ExceptionBase("Invalid format for deflate."); | ||
202 | } | ||
203 | if( bReading == true ) | ||
204 | throw ExceptionBase("This deflate filter is in reading mode, you can't write."); | ||
205 | |||
206 | zState.next_in = (Bytef *)pData; | ||
207 | zState.avail_in = nBytes; | ||
208 | for(;;) | ||
209 | { | ||
210 | zState.avail_out = nBufSize; | ||
211 | zState.next_out = (Bytef *)pBuf; | ||
212 | |||
213 | zError( deflate( &zState, Z_NO_FLUSH ) ); | ||
214 | |||
215 | if( zState.avail_out < nBufSize ) | ||
216 | { | ||
217 | sTotalOut += rNext.write( pBuf, nBufSize-zState.avail_out ); | ||
218 | } | ||
219 | if( zState.avail_in == 0 ) | ||
220 | break; | ||
221 | } | ||
222 | |||
223 | return nBytes; | ||
224 | } | ||
225 | |||
226 | bool Bu::Deflate::isOpen() | ||
227 | { | ||
228 | TRACE(); | ||
229 | return (zState.state != NULL); | ||
230 | } | ||
231 | |||
232 | bool Bu::Deflate::isEos() | ||
233 | { | ||
234 | TRACE(); | ||
235 | return bEos; | ||
236 | } | ||
237 | |||
238 | Bu::size Bu::Deflate::getCompressedSize() | ||
239 | { | ||
240 | return sTotalOut; | ||
241 | } | ||
242 | |||