aboutsummaryrefslogtreecommitdiff
path: root/src/lzma.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lzma.cpp')
-rw-r--r--src/lzma.cpp248
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
15using namespace Bu;
16
17Bu::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
29Bu::Lzma::~Lzma()
30{
31 TRACE();
32 stop();
33}
34
35void Bu::Lzma::start()
36{
37 TRACE();
38 nBufSize = 64*1024;
39 pBuf = new char[nBufSize];
40}
41
42Bu::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
83void 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
120Bu::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
186Bu::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
232bool Bu::Lzma::isOpen()
233{
234 TRACE();
235 return (pState != NULL);
236}
237
238bool Bu::Lzma::isEos()
239{
240 TRACE();
241 return bEos;
242}
243
244Bu::size Bu::Lzma::getCompressedSize()
245{
246 return sTotalOut;
247}
248