Mercurial > vba-linux
comparison src/win32/7zip/7z/CPP/7zip/Compress/Bcj2Coder.cpp @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
1 // Bcj2Coder.cpp | |
2 | |
3 #include "StdAfx.h" | |
4 | |
5 extern "C" | |
6 { | |
7 #include "../../../C/Alloc.h" | |
8 } | |
9 | |
10 #include "Bcj2Coder.h" | |
11 | |
12 namespace NCompress { | |
13 namespace NBcj2 { | |
14 | |
15 inline bool IsJcc(Byte b0, Byte b1) { return (b0 == 0x0F && (b1 & 0xF0) == 0x80); } | |
16 inline bool IsJ(Byte b0, Byte b1) { return ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)); } | |
17 inline unsigned GetIndex(Byte b0, Byte b1) { return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257)); } | |
18 | |
19 #ifndef EXTRACT_ONLY | |
20 | |
21 static const int kBufferSize = 1 << 17; | |
22 | |
23 static bool inline Test86MSByte(Byte b) | |
24 { | |
25 return (b == 0 || b == 0xFF); | |
26 } | |
27 | |
28 bool CEncoder::Create() | |
29 { | |
30 if (!_mainStream.Create(1 << 16)) | |
31 return false; | |
32 if (!_callStream.Create(1 << 20)) | |
33 return false; | |
34 if (!_jumpStream.Create(1 << 20)) | |
35 return false; | |
36 if (!_rangeEncoder.Create(1 << 20)) | |
37 return false; | |
38 if (_buffer == 0) | |
39 { | |
40 _buffer = (Byte *)MidAlloc(kBufferSize); | |
41 if (_buffer == 0) | |
42 return false; | |
43 } | |
44 return true; | |
45 } | |
46 | |
47 CEncoder::~CEncoder() | |
48 { | |
49 ::MidFree(_buffer); | |
50 } | |
51 | |
52 HRESULT CEncoder::Flush() | |
53 { | |
54 RINOK(_mainStream.Flush()); | |
55 RINOK(_callStream.Flush()); | |
56 RINOK(_jumpStream.Flush()); | |
57 _rangeEncoder.FlushData(); | |
58 return _rangeEncoder.FlushStream(); | |
59 } | |
60 | |
61 const UInt32 kDefaultLimit = (1 << 24); | |
62 | |
63 HRESULT CEncoder::CodeReal(ISequentialInStream **inStreams, | |
64 const UInt64 **inSizes, | |
65 UInt32 numInStreams, | |
66 ISequentialOutStream **outStreams, | |
67 const UInt64 ** /* outSizes */, | |
68 UInt32 numOutStreams, | |
69 ICompressProgressInfo *progress) | |
70 { | |
71 if (numInStreams != 1 || numOutStreams != 4) | |
72 return E_INVALIDARG; | |
73 | |
74 if (!Create()) | |
75 return E_OUTOFMEMORY; | |
76 | |
77 bool sizeIsDefined = false; | |
78 UInt64 inSize = 0; | |
79 if (inSizes != NULL) | |
80 if (inSizes[0] != NULL) | |
81 { | |
82 inSize = *inSizes[0]; | |
83 if (inSize <= kDefaultLimit) | |
84 sizeIsDefined = true; | |
85 } | |
86 | |
87 ISequentialInStream *inStream = inStreams[0]; | |
88 | |
89 _mainStream.SetStream(outStreams[0]); | |
90 _mainStream.Init(); | |
91 _callStream.SetStream(outStreams[1]); | |
92 _callStream.Init(); | |
93 _jumpStream.SetStream(outStreams[2]); | |
94 _jumpStream.Init(); | |
95 _rangeEncoder.SetStream(outStreams[3]); | |
96 _rangeEncoder.Init(); | |
97 for (int i = 0; i < 256 + 2; i++) | |
98 _statusEncoder[i].Init(); | |
99 CCoderReleaser releaser(this); | |
100 | |
101 CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize; | |
102 { | |
103 inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize); | |
104 } | |
105 | |
106 UInt32 nowPos = 0; | |
107 UInt64 nowPos64 = 0; | |
108 UInt32 bufferPos = 0; | |
109 | |
110 Byte prevByte = 0; | |
111 | |
112 UInt64 subStreamIndex = 0; | |
113 UInt64 subStreamStartPos = 0; | |
114 UInt64 subStreamEndPos = 0; | |
115 | |
116 for (;;) | |
117 { | |
118 UInt32 processedSize = 0; | |
119 for (;;) | |
120 { | |
121 UInt32 size = kBufferSize - (bufferPos + processedSize); | |
122 UInt32 processedSizeLoc; | |
123 if (size == 0) | |
124 break; | |
125 RINOK(inStream->Read(_buffer + bufferPos + processedSize, size, &processedSizeLoc)); | |
126 if (processedSizeLoc == 0) | |
127 break; | |
128 processedSize += processedSizeLoc; | |
129 } | |
130 UInt32 endPos = bufferPos + processedSize; | |
131 | |
132 if (endPos < 5) | |
133 { | |
134 // change it | |
135 for (bufferPos = 0; bufferPos < endPos; bufferPos++) | |
136 { | |
137 Byte b = _buffer[bufferPos]; | |
138 _mainStream.WriteByte(b); | |
139 UInt32 index; | |
140 if (b == 0xE8) | |
141 index = prevByte; | |
142 else if (b == 0xE9) | |
143 index = 256; | |
144 else if (IsJcc(prevByte, b)) | |
145 index = 257; | |
146 else | |
147 { | |
148 prevByte = b; | |
149 continue; | |
150 } | |
151 _statusEncoder[index].Encode(&_rangeEncoder, 0); | |
152 prevByte = b; | |
153 } | |
154 return Flush(); | |
155 } | |
156 | |
157 bufferPos = 0; | |
158 | |
159 UInt32 limit = endPos - 5; | |
160 while(bufferPos <= limit) | |
161 { | |
162 Byte b = _buffer[bufferPos]; | |
163 _mainStream.WriteByte(b); | |
164 if (!IsJ(prevByte, b)) | |
165 { | |
166 bufferPos++; | |
167 prevByte = b; | |
168 continue; | |
169 } | |
170 Byte nextByte = _buffer[bufferPos + 4]; | |
171 UInt32 src = | |
172 (UInt32(nextByte) << 24) | | |
173 (UInt32(_buffer[bufferPos + 3]) << 16) | | |
174 (UInt32(_buffer[bufferPos + 2]) << 8) | | |
175 (_buffer[bufferPos + 1]); | |
176 UInt32 dest = (nowPos + bufferPos + 5) + src; | |
177 // if (Test86MSByte(nextByte)) | |
178 bool convert; | |
179 if (getSubStreamSize != NULL) | |
180 { | |
181 UInt64 currentPos = (nowPos64 + bufferPos); | |
182 while (subStreamEndPos < currentPos) | |
183 { | |
184 UInt64 subStreamSize; | |
185 HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize); | |
186 if (result == S_OK) | |
187 { | |
188 subStreamStartPos = subStreamEndPos; | |
189 subStreamEndPos += subStreamSize; | |
190 subStreamIndex++; | |
191 } | |
192 else if (result == S_FALSE || result == E_NOTIMPL) | |
193 { | |
194 getSubStreamSize.Release(); | |
195 subStreamStartPos = 0; | |
196 subStreamEndPos = subStreamStartPos - 1; | |
197 } | |
198 else | |
199 return result; | |
200 } | |
201 if (getSubStreamSize == NULL) | |
202 { | |
203 if (sizeIsDefined) | |
204 convert = (dest < inSize); | |
205 else | |
206 convert = Test86MSByte(nextByte); | |
207 } | |
208 else if (subStreamEndPos - subStreamStartPos > kDefaultLimit) | |
209 convert = Test86MSByte(nextByte); | |
210 else | |
211 { | |
212 UInt64 dest64 = (currentPos + 5) + Int64(Int32(src)); | |
213 convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos); | |
214 } | |
215 } | |
216 else if (sizeIsDefined) | |
217 convert = (dest < inSize); | |
218 else | |
219 convert = Test86MSByte(nextByte); | |
220 unsigned index = GetIndex(prevByte, b); | |
221 if (convert) | |
222 { | |
223 _statusEncoder[index].Encode(&_rangeEncoder, 1); | |
224 bufferPos += 5; | |
225 COutBuffer &s = (b == 0xE8) ? _callStream : _jumpStream; | |
226 for (int i = 24; i >= 0; i -= 8) | |
227 s.WriteByte((Byte)(dest >> i)); | |
228 prevByte = nextByte; | |
229 } | |
230 else | |
231 { | |
232 _statusEncoder[index].Encode(&_rangeEncoder, 0); | |
233 bufferPos++; | |
234 prevByte = b; | |
235 } | |
236 } | |
237 nowPos += bufferPos; | |
238 nowPos64 += bufferPos; | |
239 | |
240 if (progress != NULL) | |
241 { | |
242 /* | |
243 const UInt64 compressedSize = | |
244 _mainStream.GetProcessedSize() + | |
245 _callStream.GetProcessedSize() + | |
246 _jumpStream.GetProcessedSize() + | |
247 _rangeEncoder.GetProcessedSize(); | |
248 */ | |
249 RINOK(progress->SetRatioInfo(&nowPos64, NULL)); | |
250 } | |
251 | |
252 UInt32 i = 0; | |
253 while(bufferPos < endPos) | |
254 _buffer[i++] = _buffer[bufferPos++]; | |
255 bufferPos = i; | |
256 } | |
257 } | |
258 | |
259 STDMETHODIMP CEncoder::Code(ISequentialInStream **inStreams, | |
260 const UInt64 **inSizes, | |
261 UInt32 numInStreams, | |
262 ISequentialOutStream **outStreams, | |
263 const UInt64 **outSizes, | |
264 UInt32 numOutStreams, | |
265 ICompressProgressInfo *progress) | |
266 { | |
267 try | |
268 { | |
269 return CodeReal(inStreams, inSizes, numInStreams, | |
270 outStreams, outSizes,numOutStreams, progress); | |
271 } | |
272 catch(const COutBufferException &e) { return e.ErrorCode; } | |
273 catch(...) { return S_FALSE; } | |
274 } | |
275 | |
276 #endif | |
277 | |
278 HRESULT CDecoder::CodeReal(ISequentialInStream **inStreams, | |
279 const UInt64 ** /* inSizes */, | |
280 UInt32 numInStreams, | |
281 ISequentialOutStream **outStreams, | |
282 const UInt64 ** /* outSizes */, | |
283 UInt32 numOutStreams, | |
284 ICompressProgressInfo *progress) | |
285 { | |
286 if (numInStreams != 4 || numOutStreams != 1) | |
287 return E_INVALIDARG; | |
288 | |
289 if (!_mainInStream.Create(1 << 16)) | |
290 return E_OUTOFMEMORY; | |
291 if (!_callStream.Create(1 << 20)) | |
292 return E_OUTOFMEMORY; | |
293 if (!_jumpStream.Create(1 << 16)) | |
294 return E_OUTOFMEMORY; | |
295 if (!_rangeDecoder.Create(1 << 20)) | |
296 return E_OUTOFMEMORY; | |
297 if (!_outStream.Create(1 << 16)) | |
298 return E_OUTOFMEMORY; | |
299 | |
300 _mainInStream.SetStream(inStreams[0]); | |
301 _callStream.SetStream(inStreams[1]); | |
302 _jumpStream.SetStream(inStreams[2]); | |
303 _rangeDecoder.SetStream(inStreams[3]); | |
304 _outStream.SetStream(outStreams[0]); | |
305 | |
306 _mainInStream.Init(); | |
307 _callStream.Init(); | |
308 _jumpStream.Init(); | |
309 _rangeDecoder.Init(); | |
310 _outStream.Init(); | |
311 | |
312 for (int i = 0; i < 256 + 2; i++) | |
313 _statusDecoder[i].Init(); | |
314 | |
315 CCoderReleaser releaser(this); | |
316 | |
317 Byte prevByte = 0; | |
318 UInt32 processedBytes = 0; | |
319 for (;;) | |
320 { | |
321 if (processedBytes >= (1 << 20) && progress != NULL) | |
322 { | |
323 /* | |
324 const UInt64 compressedSize = | |
325 _mainInStream.GetProcessedSize() + | |
326 _callStream.GetProcessedSize() + | |
327 _jumpStream.GetProcessedSize() + | |
328 _rangeDecoder.GetProcessedSize(); | |
329 */ | |
330 const UInt64 nowPos64 = _outStream.GetProcessedSize(); | |
331 RINOK(progress->SetRatioInfo(NULL, &nowPos64)); | |
332 processedBytes = 0; | |
333 } | |
334 UInt32 i; | |
335 Byte b = 0; | |
336 const UInt32 kBurstSize = (1 << 18); | |
337 for (i = 0; i < kBurstSize; i++) | |
338 { | |
339 if (!_mainInStream.ReadByte(b)) | |
340 return Flush(); | |
341 _outStream.WriteByte(b); | |
342 if (IsJ(prevByte, b)) | |
343 break; | |
344 prevByte = b; | |
345 } | |
346 processedBytes += i; | |
347 if (i == kBurstSize) | |
348 continue; | |
349 unsigned index = GetIndex(prevByte, b); | |
350 if (_statusDecoder[index].Decode(&_rangeDecoder) == 1) | |
351 { | |
352 UInt32 src = 0; | |
353 CInBuffer &s = (b == 0xE8) ? _callStream : _jumpStream; | |
354 for (int i = 0; i < 4; i++) | |
355 { | |
356 Byte b0; | |
357 if(!s.ReadByte(b0)) | |
358 return S_FALSE; | |
359 src <<= 8; | |
360 src |= ((UInt32)b0); | |
361 } | |
362 UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ; | |
363 _outStream.WriteByte((Byte)(dest)); | |
364 _outStream.WriteByte((Byte)(dest >> 8)); | |
365 _outStream.WriteByte((Byte)(dest >> 16)); | |
366 _outStream.WriteByte((Byte)(dest >> 24)); | |
367 prevByte = (Byte)(dest >> 24); | |
368 processedBytes += 4; | |
369 } | |
370 else | |
371 prevByte = b; | |
372 } | |
373 } | |
374 | |
375 STDMETHODIMP CDecoder::Code(ISequentialInStream **inStreams, | |
376 const UInt64 **inSizes, | |
377 UInt32 numInStreams, | |
378 ISequentialOutStream **outStreams, | |
379 const UInt64 **outSizes, | |
380 UInt32 numOutStreams, | |
381 ICompressProgressInfo *progress) | |
382 { | |
383 try | |
384 { | |
385 return CodeReal(inStreams, inSizes, numInStreams, | |
386 outStreams, outSizes,numOutStreams, progress); | |
387 } | |
388 catch(const CInBufferException &e) { return e.ErrorCode; } | |
389 catch(const COutBufferException &e) { return e.ErrorCode; } | |
390 catch(...) { return S_FALSE; } | |
391 } | |
392 | |
393 }} |