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