diff options
Diffstat (limited to 'src/bzip2.cpp')
-rw-r--r-- | src/bzip2.cpp | 196 |
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 | |||
4 | using namespace Bu; | ||
5 | |||
6 | Bu::BZip2::BZip2( Bu::Stream &rNext, int nCompression ) : | ||
7 | Bu::Filter( rNext ), | ||
8 | nCompression( nCompression ) | ||
9 | { | ||
10 | start(); | ||
11 | } | ||
12 | |||
13 | Bu::BZip2::~BZip2() | ||
14 | { | ||
15 | stop(); | ||
16 | } | ||
17 | |||
18 | void 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 | |||
29 | size_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 | |||
66 | void 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 | |||
109 | size_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 | |||
161 | size_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 | |||
192 | bool Bu::BZip2::isOpen() | ||
193 | { | ||
194 | return (bzState.state != NULL); | ||
195 | } | ||
196 | |||