summaryrefslogtreecommitdiff
path: root/src/stable/bzip2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/stable/bzip2.cpp')
-rw-r--r--src/stable/bzip2.cpp233
1 files changed, 233 insertions, 0 deletions
diff --git a/src/stable/bzip2.cpp b/src/stable/bzip2.cpp
new file mode 100644
index 0000000..ca007b0
--- /dev/null
+++ b/src/stable/bzip2.cpp
@@ -0,0 +1,233 @@
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/bzip2.h"
9#include "bu/trace.h"
10
11#include <bzlib.h>
12
13#define pState ((bz_stream *)prState)
14
15using namespace Bu;
16
17Bu::BZip2::BZip2( Bu::Stream &rNext, int nCompression ) :
18 Bu::Filter( rNext ),
19 prState( NULL ),
20 nCompression( nCompression ),
21 sTotalOut( 0 )
22{
23 TRACE( nCompression );
24 start();
25}
26
27Bu::BZip2::~BZip2()
28{
29 TRACE();
30 stop();
31}
32
33void Bu::BZip2::start()
34{
35 TRACE();
36
37 prState = new bz_stream;
38 pState->state = NULL;
39 pState->bzalloc = NULL;
40 pState->bzfree = NULL;
41 pState->opaque = NULL;
42
43 nBufSize = 64*1024;
44 pBuf = new char[nBufSize];
45}
46
47Bu::size Bu::BZip2::stop()
48{
49 TRACE();
50 if( pState->state )
51 {
52 if( bReading )
53 {
54 BZ2_bzDecompressEnd( pState );
55 delete[] pBuf;
56 pBuf = NULL;
57 delete pState;
58 prState = NULL;
59 return 0;
60 }
61 else
62 {
63// Bu::size sTotal = 0;
64 for(;;)
65 {
66 pState->next_in = NULL;
67 pState->avail_in = 0;
68 pState->avail_out = nBufSize;
69 pState->next_out = pBuf;
70 int res = BZ2_bzCompress( pState, BZ_FINISH );
71 if( pState->avail_out < nBufSize )
72 {
73 sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out );
74 }
75 if( res == BZ_STREAM_END )
76 break;
77 }
78 BZ2_bzCompressEnd( 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::BZip2::bzError( int code )
90{
91 TRACE( code );
92 switch( code )
93 {
94 case BZ_OK:
95 case BZ_RUN_OK:
96 case BZ_FLUSH_OK:
97 case BZ_FINISH_OK:
98 return;
99
100 case BZ_CONFIG_ERROR:
101 throw ExceptionBase("BZip2: Library configured improperly, reinstall.");
102
103 case BZ_SEQUENCE_ERROR:
104 throw ExceptionBase("BZip2: Functions were called in an invalid sequence.");
105
106 case BZ_PARAM_ERROR:
107 throw ExceptionBase("BZip2: Invalid parameter was passed into a function.");
108
109 case BZ_MEM_ERROR:
110 throw ExceptionBase("BZip2: Couldn't allocate sufficient memory.");
111
112 case BZ_DATA_ERROR:
113 throw ExceptionBase("BZip2: Data was corrupted before decompression.");
114
115 case BZ_DATA_ERROR_MAGIC:
116 throw ExceptionBase("BZip2: Stream does not appear to be bzip2 data.");
117
118 case BZ_IO_ERROR:
119 throw ExceptionBase("BZip2: File couldn't be read from / written to.");
120
121 case BZ_UNEXPECTED_EOF:
122 throw ExceptionBase("BZip2: End of file encountered before end of stream.");
123
124 case BZ_OUTBUFF_FULL:
125 throw ExceptionBase("BZip2: Buffer not large enough to accomidate data.");
126
127 default:
128 throw ExceptionBase("BZip2: Unknown error encountered.");
129
130 }
131}
132
133Bu::size Bu::BZip2::read( void *pData, Bu::size nBytes )
134{
135 TRACE( pData, nBytes );
136 if( !pState->state )
137 {
138 bReading = true;
139 BZ2_bzDecompressInit( pState, 0, 0 );
140 pState->next_in = pBuf;
141 pState->avail_in = 0;
142 }
143 if( bReading == false )
144 throw ExceptionBase("This bzip2 filter is in writing mode, you can't read.");
145
146 int nRead = 0;
147 int nReadTotal = pState->total_out_lo32;
148 pState->next_out = (char *)pData;
149 pState->avail_out = nBytes;
150 for(;;)
151 {
152 int ret = BZ2_bzDecompress( pState );
153
154 nReadTotal += nRead-pState->avail_out;
155
156 if( ret == BZ_STREAM_END )
157 {
158 if( pState->avail_in > 0 )
159 {
160 if( rNext.isSeekable() )
161 {
162 rNext.seek( -pState->avail_in );
163 }
164 }
165 return nBytes-pState->avail_out;
166 }
167 bzError( 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 bzip2 stream.");
178 }
179 pState->next_in = 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::BZip2::write( const void *pData, Bu::size nBytes )
192{
193 TRACE( pData, nBytes );
194 if( !pState->state )
195 {
196 bReading = false;
197 BZ2_bzCompressInit( pState, nCompression, 0, 30 );
198 }
199 if( bReading == true )
200 throw ExceptionBase("This bzip2 filter is in reading mode, you can't write.");
201
202// Bu::size sTotalOut = 0;
203 pState->next_in = (char *)pData;
204 pState->avail_in = nBytes;
205 for(;;)
206 {
207 pState->avail_out = nBufSize;
208 pState->next_out = pBuf;
209
210 bzError( BZ2_bzCompress( pState, BZ_RUN ) );
211
212 if( pState->avail_out < nBufSize )
213 {
214 sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out );
215 }
216 if( pState->avail_in == 0 )
217 break;
218 }
219
220 return nBytes;
221}
222
223bool Bu::BZip2::isOpen()
224{
225 TRACE();
226 return (pState->state != NULL);
227}
228
229Bu::size Bu::BZip2::getCompressedSize()
230{
231 return sTotalOut;
232}
233