diff options
Diffstat (limited to 'src/lzma.cpp')
-rw-r--r-- | src/lzma.cpp | 248 |
1 files changed, 248 insertions, 0 deletions
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 | |||