aboutsummaryrefslogtreecommitdiff
path: root/src/bzip2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bzip2.cpp')
-rw-r--r--src/bzip2.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/bzip2.cpp b/src/bzip2.cpp
new file mode 100644
index 0000000..fbe5712
--- /dev/null
+++ b/src/bzip2.cpp
@@ -0,0 +1,196 @@
1#include "bu/bzip2.h"
2#include "bu/exceptions.h"
3
4using namespace Bu;
5
6Bu::BZip2::BZip2( Bu::Stream &rNext, int nCompression ) :
7 Bu::Filter( rNext ),
8 nCompression( nCompression )
9{
10 start();
11}
12
13Bu::BZip2::~BZip2()
14{
15 stop();
16}
17
18void Bu::BZip2::start()
19{
20 bzState.state = NULL;
21 bzState.bzalloc = NULL;
22 bzState.bzfree = NULL;
23 bzState.opaque = NULL;
24
25 nBufSize = 50000;
26 pBuf = new char[nBufSize];
27}
28
29size_t Bu::BZip2::stop()
30{
31 if( bzState.state )
32 {
33 if( bReading )
34 {
35 BZ2_bzDecompressEnd( &bzState );
36 delete[] pBuf;
37 pBuf = NULL;
38 return 0;
39 }
40 else
41 {
42 size_t sTotal = 0;
43 for(;;)
44 {
45 bzState.next_in = NULL;
46 bzState.avail_in = 0;
47 bzState.avail_out = nBufSize;
48 bzState.next_out = pBuf;
49 int res = BZ2_bzCompress( &bzState, BZ_FINISH );
50 if( bzState.avail_out < nBufSize )
51 {
52 sTotal += rNext.write( pBuf, nBufSize-bzState.avail_out );
53 }
54 if( res == BZ_STREAM_END )
55 break;
56 }
57 BZ2_bzCompressEnd( &bzState );
58 delete[] pBuf;
59 pBuf = NULL;
60 return sTotal;
61 }
62 }
63 return 0;
64}
65
66void Bu::BZip2::bzError( int code )
67{
68 switch( code )
69 {
70 case BZ_OK:
71 case BZ_RUN_OK:
72 case BZ_FLUSH_OK:
73 case BZ_FINISH_OK:
74 return;
75
76 case BZ_CONFIG_ERROR:
77 throw ExceptionBase("BZip2: Library configured improperly, reinstall.");
78
79 case BZ_SEQUENCE_ERROR:
80 throw ExceptionBase("BZip2: Functions were called in an invalid sequence.");
81
82 case BZ_PARAM_ERROR:
83 throw ExceptionBase("BZip2: Invalid parameter was passed into a function.");
84
85 case BZ_MEM_ERROR:
86 throw ExceptionBase("BZip2: Couldn't allocate sufficient memory.");
87
88 case BZ_DATA_ERROR:
89 throw ExceptionBase("BZip2: Data was corrupted before decompression.");
90
91 case BZ_DATA_ERROR_MAGIC:
92 throw ExceptionBase("BZip2: Stream does not appear to be bzip2 data.");
93
94 case BZ_IO_ERROR:
95 throw ExceptionBase("BZip2: File couldn't be read from / written to.");
96
97 case BZ_UNEXPECTED_EOF:
98 throw ExceptionBase("BZip2: End of file encountered before end of stream.");
99
100 case BZ_OUTBUFF_FULL:
101 throw ExceptionBase("BZip2: Buffer not large enough to accomidate data.");
102
103 default:
104 throw ExceptionBase("BZip2: Unknown error encountered.");
105
106 }
107}
108
109size_t Bu::BZip2::read( void *pData, size_t nBytes )
110{
111 if( !bzState.state )
112 {
113 bReading = true;
114 BZ2_bzDecompressInit( &bzState, 0, 0 );
115 bzState.next_in = pBuf;
116 bzState.avail_in = 0;
117 }
118 if( bReading == false )
119 throw ExceptionBase("This bzip2 filter is in writing mode, you can't read.");
120
121 int nRead = 0;
122 int nReadTotal = bzState.total_out_lo32;
123 bzState.next_out = (char *)pData;
124 bzState.avail_out = nBytes;
125 for(;;)
126 {
127 int ret = BZ2_bzDecompress( &bzState );
128
129 nReadTotal += nRead-bzState.avail_out;
130
131 if( ret == BZ_STREAM_END )
132 {
133 if( bzState.avail_in > 0 )
134 {
135 if( rNext.isSeekable() )
136 {
137 rNext.seek( -bzState.avail_in );
138 }
139 }
140 return nBytes-bzState.avail_out;
141 }
142 bzError( ret );
143
144 if( bzState.avail_out )
145 {
146 if( bzState.avail_in == 0 )
147 {
148 nRead = rNext.read( pBuf, nBufSize );
149 bzState.next_in = pBuf;
150 bzState.avail_in = nRead;
151 }
152 }
153 else
154 {
155 return nBytes-bzState.avail_out;
156 }
157 }
158 return 0;
159}
160
161size_t Bu::BZip2::write( const void *pData, size_t nBytes )
162{
163 if( !bzState.state )
164 {
165 bReading = false;
166 BZ2_bzCompressInit( &bzState, nCompression, 0, 30 );
167 }
168 if( bReading == true )
169 throw ExceptionBase("This bzip2 filter is in reading mode, you can't write.");
170
171 size_t sTotalOut = 0;
172 bzState.next_in = (char *)pData;
173 bzState.avail_in = nBytes;
174 for(;;)
175 {
176 bzState.avail_out = nBufSize;
177 bzState.next_out = pBuf;
178
179 bzError( BZ2_bzCompress( &bzState, BZ_RUN ) );
180
181 if( bzState.avail_out < nBufSize )
182 {
183 sTotalOut += rNext.write( pBuf, nBufSize-bzState.avail_out );
184 }
185 if( bzState.avail_in == 0 )
186 break;
187 }
188
189 return sTotalOut;
190}
191
192bool Bu::BZip2::isOpen()
193{
194 return (bzState.state != NULL);
195}
196