view 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
line wrap: on
line source
1 // Bcj2Coder.cpp
3 #include "StdAfx.h"
5 extern "C"
6 {
7 #include "../../../C/Alloc.h"
8 }
10 #include "Bcj2Coder.h"
12 namespace NCompress {
13 namespace NBcj2 {
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)); }
19 #ifndef EXTRACT_ONLY
21 static const int kBufferSize = 1 << 17;
23 static bool inline Test86MSByte(Byte b)
24 {
25 return (b == 0 || b == 0xFF);
26 }
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 }
47 CEncoder::~CEncoder()
48 {
49 ::MidFree(_buffer);
50 }
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 }
61 const UInt32 kDefaultLimit = (1 << 24);
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;
74 if (!Create())
75 return E_OUTOFMEMORY;
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 }
87 ISequentialInStream *inStream = inStreams[0];
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);
101 CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
102 {
103 inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
104 }
106 UInt32 nowPos = 0;
107 UInt64 nowPos64 = 0;
108 UInt32 bufferPos = 0;
110 Byte prevByte = 0;
112 UInt64 subStreamIndex = 0;
113 UInt64 subStreamStartPos = 0;
114 UInt64 subStreamEndPos = 0;
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;
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 }
157 bufferPos = 0;
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;
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 }
252 UInt32 i = 0;
253 while(bufferPos < endPos)
254 _buffer[i++] = _buffer[bufferPos++];
255 bufferPos = i;
256 }
257 }
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 }
276 #endif
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;
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;
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]);
306 _mainInStream.Init();
307 _callStream.Init();
308 _jumpStream.Init();
309 _rangeDecoder.Init();
310 _outStream.Init();
312 for (int i = 0; i < 256 + 2; i++)
313 _statusDecoder[i].Init();
315 CCoderReleaser releaser(this);
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 }
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 }
393 }}