diff options
author | Mike Buland <eichlan@xagasoft.com> | 2011-10-24 16:19:09 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2011-10-24 16:19:09 +0000 |
commit | e2fbc414b932ae9fd305c8e9fc315a306a876a09 (patch) | |
tree | 324b2c70cd39b49d1513f64ec7d4b009fda938e9 /src | |
parent | 27c2cbbbc0ed1e1b38274261c33b0427f976f22c (diff) | |
download | libbu++-e2fbc414b932ae9fd305c8e9fc315a306a876a09.tar.gz libbu++-e2fbc414b932ae9fd305c8e9fc315a306a876a09.tar.bz2 libbu++-e2fbc414b932ae9fd305c8e9fc315a306a876a09.tar.xz libbu++-e2fbc414b932ae9fd305c8e9fc315a306a876a09.zip |
Lzma filter added. Now we're really getting somewhere. Libbu++ now supports
all major, common compression algorithms.
Diffstat (limited to '')
-rw-r--r-- | src/deflate.h | 2 | ||||
-rw-r--r-- | src/lzma.cpp | 248 | ||||
-rw-r--r-- | src/lzma.h | 56 | ||||
-rw-r--r-- | src/tests/lzma.cpp | 53 |
4 files changed, 358 insertions, 1 deletions
diff --git a/src/deflate.h b/src/deflate.h index cab9b51..8ce283b 100644 --- a/src/deflate.h +++ b/src/deflate.h | |||
@@ -34,7 +34,7 @@ namespace Bu | |||
34 | AutoGzip = 0x04|0x03 | 34 | AutoGzip = 0x04|0x03 |
35 | }; | 35 | }; |
36 | 36 | ||
37 | Deflate( Bu::Stream &rNext, int nCompression=9, Format eFmt=AutoRaw ); | 37 | Deflate( Bu::Stream &rNext, int nCompression=-1, Format eFmt=AutoRaw ); |
38 | virtual ~Deflate(); | 38 | virtual ~Deflate(); |
39 | 39 | ||
40 | virtual void start(); | 40 | virtual void start(); |
diff --git a/src/lzma.cpp b/src/lzma.cpp new file mode 100644 index 0000000..6ed0806 --- /dev/null +++ b/src/lzma.cpp | |||
@@ -0,0 +1,248 @@ | |||
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/lzma.h" | ||
9 | #include "bu/trace.h" | ||
10 | |||
11 | #include <lzma.h> | ||
12 | |||
13 | #define pState ((lzma_stream *)prState) | ||
14 | |||
15 | using namespace Bu; | ||
16 | |||
17 | Bu::Lzma::Lzma( 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 | |||
29 | Bu::Lzma::~Lzma() | ||
30 | { | ||
31 | TRACE(); | ||
32 | stop(); | ||
33 | } | ||
34 | |||
35 | void Bu::Lzma::start() | ||
36 | { | ||
37 | TRACE(); | ||
38 | nBufSize = 64*1024; | ||
39 | pBuf = new char[nBufSize]; | ||
40 | } | ||
41 | |||
42 | Bu::size Bu::Lzma::stop() | ||
43 | { | ||
44 | TRACE(); | ||
45 | if( pState ) | ||
46 | { | ||
47 | if( bReading ) | ||
48 | { | ||
49 | lzma_end( pState ); | ||
50 | delete[] pBuf; | ||
51 | pBuf = NULL; | ||
52 | delete pState; | ||
53 | prState = NULL; | ||
54 | return 0; | ||
55 | } | ||
56 | else | ||
57 | { | ||
58 | for(;;) | ||
59 | { | ||
60 | pState->next_in = NULL; | ||
61 | pState->avail_in = 0; | ||
62 | pState->avail_out = nBufSize; | ||
63 | pState->next_out = (uint8_t *)pBuf; | ||
64 | int res = lzma_code( pState, LZMA_FINISH ); | ||
65 | if( pState->avail_out < nBufSize ) | ||
66 | { | ||
67 | sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out ); | ||
68 | } | ||
69 | if( res == LZMA_STREAM_END ) | ||
70 | break; | ||
71 | } | ||
72 | lzma_end( pState ); | ||
73 | delete[] pBuf; | ||
74 | pBuf = NULL; | ||
75 | delete pState; | ||
76 | prState = NULL; | ||
77 | return sTotalOut; | ||
78 | } | ||
79 | } | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | void Bu::Lzma::lzmaError( int code ) | ||
84 | { | ||
85 | TRACE( code ); | ||
86 | switch( code ) | ||
87 | { | ||
88 | case LZMA_OK: | ||
89 | case LZMA_STREAM_END: | ||
90 | case LZMA_NO_CHECK: | ||
91 | case LZMA_UNSUPPORTED_CHECK: | ||
92 | break; | ||
93 | |||
94 | case LZMA_MEM_ERROR: | ||
95 | throw ExceptionBase("Lzma: Memory allocation error."); | ||
96 | |||
97 | case LZMA_MEMLIMIT_ERROR: | ||
98 | throw ExceptionBase("Lzma: Memory usage limit was reached."); | ||
99 | |||
100 | case LZMA_FORMAT_ERROR: | ||
101 | throw ExceptionBase("Lzma: File format not recognized."); | ||
102 | |||
103 | case LZMA_OPTIONS_ERROR: | ||
104 | throw ExceptionBase("Lzma: Invalid or unsupported options."); | ||
105 | |||
106 | case LZMA_DATA_ERROR: | ||
107 | throw ExceptionBase("Lzma: Data is corrupt."); | ||
108 | |||
109 | case LZMA_BUF_ERROR: | ||
110 | throw ExceptionBase("Lzma: No progress is possible."); | ||
111 | |||
112 | case LZMA_PROG_ERROR: | ||
113 | throw ExceptionBase("Lzma: Programming error."); | ||
114 | |||
115 | default: | ||
116 | throw ExceptionBase("Lzma: Unknown error encountered." ); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | Bu::size Bu::Lzma::read( void *pData, Bu::size nBytes ) | ||
121 | { | ||
122 | TRACE( pData, nBytes ); | ||
123 | if( !pState ) | ||
124 | { | ||
125 | prState = new ::lzma_stream; | ||
126 | lzma_stream zEmpty = LZMA_STREAM_INIT; | ||
127 | Bu::memcpy( prState, &zEmpty, sizeof(lzma_stream) ); | ||
128 | |||
129 | bReading = true; | ||
130 | lzmaError( lzma_auto_decoder( pState, UINT64_MAX, 0 ) ); | ||
131 | pState->next_in = (uint8_t *)pBuf; | ||
132 | pState->avail_in = 0; | ||
133 | } | ||
134 | if( bReading == false ) | ||
135 | throw ExceptionBase("This lzma filter is in writing mode, you can't read."); | ||
136 | |||
137 | int nRead = 0; | ||
138 | int nReadTotal = pState->total_out; | ||
139 | pState->next_out = (uint8_t *)pData; | ||
140 | pState->avail_out = nBytes; | ||
141 | for(;;) | ||
142 | { | ||
143 | int ret = lzma_code( pState, LZMA_RUN ); | ||
144 | printf("inflate returned %d; avail in=%d, out=%d\n", ret, | ||
145 | pState->avail_in, pState->avail_out ); | ||
146 | |||
147 | nReadTotal += nRead-pState->avail_out; | ||
148 | |||
149 | if( ret == LZMA_STREAM_END ) | ||
150 | { | ||
151 | bEos = true; | ||
152 | if( pState->avail_in > 0 ) | ||
153 | { | ||
154 | if( rNext.isSeekable() ) | ||
155 | { | ||
156 | rNext.seek( -pState->avail_in ); | ||
157 | } | ||
158 | } | ||
159 | return nBytes-pState->avail_out; | ||
160 | } | ||
161 | // if( ret != LZMA_BUF_ERROR ) | ||
162 | lzmaError( ret ); | ||
163 | |||
164 | if( pState->avail_out ) | ||
165 | { | ||
166 | if( pState->avail_in == 0 ) | ||
167 | { | ||
168 | nRead = rNext.read( pBuf, nBufSize ); | ||
169 | if( nRead == 0 && rNext.isEos() ) | ||
170 | { | ||
171 | throw Bu::ExceptionBase("Premature end of underlying " | ||
172 | "stream found reading deflate stream."); | ||
173 | } | ||
174 | pState->next_in = (uint8_t *)pBuf; | ||
175 | pState->avail_in = nRead; | ||
176 | } | ||
177 | } | ||
178 | else | ||
179 | { | ||
180 | return nBytes-pState->avail_out; | ||
181 | } | ||
182 | } | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | Bu::size Bu::Lzma::write( const void *pData, Bu::size nBytes ) | ||
187 | { | ||
188 | TRACE( pData, nBytes ); | ||
189 | if( !pState ) | ||
190 | { | ||
191 | prState = new ::lzma_stream; | ||
192 | lzma_stream zEmpty = LZMA_STREAM_INIT; | ||
193 | Bu::memcpy( prState, &zEmpty, sizeof(lzma_stream) ); | ||
194 | |||
195 | bReading = false; | ||
196 | if( eFmt == Xz ) | ||
197 | lzmaError( | ||
198 | lzma_easy_encoder( pState, nCompression, LZMA_CHECK_CRC64 ) | ||
199 | ); | ||
200 | else if( eFmt == LzmaAlone ) | ||
201 | { | ||
202 | lzma_options_lzma opt; | ||
203 | lzma_lzma_preset( &opt, nCompression ); | ||
204 | lzmaError( lzma_alone_encoder( pState, &opt ) ); | ||
205 | } | ||
206 | else | ||
207 | throw Bu::ExceptionBase("Invalid format for lzma."); | ||
208 | } | ||
209 | if( bReading == true ) | ||
210 | throw ExceptionBase("This lzma filter is in reading mode, you can't write."); | ||
211 | |||
212 | pState->next_in = (uint8_t *)pData; | ||
213 | pState->avail_in = nBytes; | ||
214 | for(;;) | ||
215 | { | ||
216 | pState->avail_out = nBufSize; | ||
217 | pState->next_out = (uint8_t *)pBuf; | ||
218 | |||
219 | lzmaError( lzma_code( pState, LZMA_RUN ) ); | ||
220 | |||
221 | if( pState->avail_out < nBufSize ) | ||
222 | { | ||
223 | sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out ); | ||
224 | } | ||
225 | if( pState->avail_in == 0 ) | ||
226 | break; | ||
227 | } | ||
228 | |||
229 | return nBytes; | ||
230 | } | ||
231 | |||
232 | bool Bu::Lzma::isOpen() | ||
233 | { | ||
234 | TRACE(); | ||
235 | return (pState != NULL); | ||
236 | } | ||
237 | |||
238 | bool Bu::Lzma::isEos() | ||
239 | { | ||
240 | TRACE(); | ||
241 | return bEos; | ||
242 | } | ||
243 | |||
244 | Bu::size Bu::Lzma::getCompressedSize() | ||
245 | { | ||
246 | return sTotalOut; | ||
247 | } | ||
248 | |||
diff --git a/src/lzma.h b/src/lzma.h new file mode 100644 index 0000000..21da6e8 --- /dev/null +++ b/src/lzma.h | |||
@@ -0,0 +1,56 @@ | |||
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 | #ifndef BU_LZMA_H | ||
9 | #define BU_LZMA_H | ||
10 | |||
11 | #include <stdint.h> | ||
12 | |||
13 | #include "bu/filter.h" | ||
14 | |||
15 | namespace Bu | ||
16 | { | ||
17 | /** | ||
18 | * | ||
19 | *@ingroup Streams | ||
20 | */ | ||
21 | class Lzma : public Bu::Filter | ||
22 | { | ||
23 | public: | ||
24 | enum Format | ||
25 | { | ||
26 | Xz = 0x01, | ||
27 | LzmaAlone = 0x02, | ||
28 | }; | ||
29 | |||
30 | Lzma( Bu::Stream &rNext, int nCompression=6, Format eFmt=Xz ); | ||
31 | virtual ~Lzma(); | ||
32 | |||
33 | virtual void start(); | ||
34 | virtual Bu::size stop(); | ||
35 | virtual Bu::size read( void *pBuf, Bu::size nBytes ); | ||
36 | virtual Bu::size write( const void *pBuf, Bu::size nBytes ); | ||
37 | |||
38 | virtual bool isOpen(); | ||
39 | virtual bool isEos(); | ||
40 | |||
41 | Bu::size getCompressedSize(); | ||
42 | |||
43 | private: | ||
44 | void lzmaError( int code ); | ||
45 | void *prState; | ||
46 | bool bReading; | ||
47 | int nCompression; | ||
48 | char *pBuf; | ||
49 | uint32_t nBufSize; | ||
50 | Bu::size sTotalOut; | ||
51 | Format eFmt; | ||
52 | bool bEos; | ||
53 | }; | ||
54 | } | ||
55 | |||
56 | #endif | ||
diff --git a/src/tests/lzma.cpp b/src/tests/lzma.cpp new file mode 100644 index 0000000..752357a --- /dev/null +++ b/src/tests/lzma.cpp | |||
@@ -0,0 +1,53 @@ | |||
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/lzma.h" | ||
9 | #include "bu/file.h" | ||
10 | |||
11 | int main( int argc, char *argv[] ) | ||
12 | { | ||
13 | if( argc < 3 ) | ||
14 | { | ||
15 | printf("usage: %s <in> <out>\n", argv[0] ); | ||
16 | return -1; | ||
17 | } | ||
18 | |||
19 | char buf[1024]; | ||
20 | size_t nRead; | ||
21 | |||
22 | /* | ||
23 | Bu::File fin( argv[1], Bu::File::Read ); | ||
24 | fin.seek( 4 ); | ||
25 | Bu::Deflate def( fin ); | ||
26 | |||
27 | Bu::File f( argv[2], Bu::File::WriteNew ); | ||
28 | |||
29 | for(;;) | ||
30 | { | ||
31 | nRead = def.read( buf, 1024 ); | ||
32 | if( nRead > 0 ) | ||
33 | f.write( buf, nRead ); | ||
34 | if( def.isEos() ) | ||
35 | break; | ||
36 | } | ||
37 | */ | ||
38 | |||
39 | Bu::File fin( argv[1], Bu::File::Read ); | ||
40 | |||
41 | Bu::File f( argv[2], Bu::File::WriteNew ); | ||
42 | Bu::Lzma def( f, 9 ); | ||
43 | |||
44 | for(;;) | ||
45 | { | ||
46 | nRead = fin.read( buf, 1024 ); | ||
47 | if( nRead > 0 ) | ||
48 | def.write( buf, nRead ); | ||
49 | if( fin.isEos() ) | ||
50 | break; | ||
51 | } | ||
52 | } | ||
53 | |||