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