mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-07-24 01:43:19 +00:00
175 lines
4.8 KiB
C#
175 lines
4.8 KiB
C#
namespace SharpCompress.Compressor.LZMA.LZ
|
|
{
|
|
internal class OutWindow
|
|
{
|
|
private byte[] _buffer = null;
|
|
private int _windowSize = 0;
|
|
private int _pos;
|
|
private int _streamPos;
|
|
private int _pendingLen;
|
|
private int _pendingDist;
|
|
private System.IO.Stream _stream;
|
|
|
|
public long Total;
|
|
public long Limit;
|
|
|
|
public void Create(int windowSize)
|
|
{
|
|
if (_windowSize != windowSize)
|
|
_buffer = new byte[windowSize];
|
|
else
|
|
_buffer[windowSize - 1] = 0;
|
|
_windowSize = windowSize;
|
|
_pos = 0;
|
|
_streamPos = 0;
|
|
_pendingLen = 0;
|
|
Total = 0;
|
|
Limit = 0;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
Create(_windowSize);
|
|
}
|
|
|
|
public void Init(System.IO.Stream stream)
|
|
{
|
|
ReleaseStream();
|
|
_stream = stream;
|
|
}
|
|
|
|
public void Train(System.IO.Stream stream)
|
|
{
|
|
long len = stream.Length;
|
|
int size = (len < _windowSize) ? (int) len : _windowSize;
|
|
stream.Position = len - size;
|
|
Total = 0;
|
|
Limit = size;
|
|
_pos = _windowSize - size;
|
|
CopyStream(stream, size);
|
|
if (_pos == _windowSize)
|
|
_pos = 0;
|
|
_streamPos = _pos;
|
|
}
|
|
|
|
public void ReleaseStream()
|
|
{
|
|
Flush();
|
|
_stream = null;
|
|
}
|
|
|
|
public void Flush()
|
|
{
|
|
if (_stream == null)
|
|
return;
|
|
int size = _pos - _streamPos;
|
|
if (size == 0)
|
|
return;
|
|
_stream.Write(_buffer, _streamPos, size);
|
|
if (_pos >= _windowSize)
|
|
_pos = 0;
|
|
_streamPos = _pos;
|
|
}
|
|
|
|
public void CopyBlock(int distance, int len)
|
|
{
|
|
int size = len;
|
|
int pos = _pos - distance - 1;
|
|
if (pos < 0)
|
|
pos += _windowSize;
|
|
for (; size > 0 && _pos < _windowSize && Total < Limit; size--)
|
|
{
|
|
if (pos >= _windowSize)
|
|
pos = 0;
|
|
_buffer[_pos++] = _buffer[pos++];
|
|
Total++;
|
|
if (_pos >= _windowSize)
|
|
Flush();
|
|
}
|
|
_pendingLen = size;
|
|
_pendingDist = distance;
|
|
}
|
|
|
|
public void PutByte(byte b)
|
|
{
|
|
_buffer[_pos++] = b;
|
|
Total++;
|
|
if (_pos >= _windowSize)
|
|
Flush();
|
|
}
|
|
|
|
public byte GetByte(int distance)
|
|
{
|
|
int pos = _pos - distance - 1;
|
|
if (pos < 0)
|
|
pos += _windowSize;
|
|
return _buffer[pos];
|
|
}
|
|
|
|
public int CopyStream(System.IO.Stream stream, int len)
|
|
{
|
|
int size = len;
|
|
while (size > 0 && _pos < _windowSize && Total < Limit)
|
|
{
|
|
int curSize = _windowSize - _pos;
|
|
if (curSize > Limit - Total)
|
|
curSize = (int) (Limit - Total);
|
|
if (curSize > size)
|
|
curSize = size;
|
|
int numReadBytes = stream.Read(_buffer, _pos, curSize);
|
|
if (numReadBytes == 0)
|
|
throw new DataErrorException();
|
|
size -= numReadBytes;
|
|
_pos += numReadBytes;
|
|
Total += numReadBytes;
|
|
if (_pos >= _windowSize)
|
|
Flush();
|
|
}
|
|
return len - size;
|
|
}
|
|
|
|
public void SetLimit(long size)
|
|
{
|
|
Limit = Total + size;
|
|
}
|
|
|
|
public bool HasSpace
|
|
{
|
|
get { return _pos < _windowSize && Total < Limit; }
|
|
}
|
|
|
|
public bool HasPending
|
|
{
|
|
get { return _pendingLen > 0; }
|
|
}
|
|
|
|
public int Read(byte[] buffer, int offset, int count)
|
|
{
|
|
if (_streamPos >= _pos)
|
|
return 0;
|
|
|
|
int size = _pos - _streamPos;
|
|
if (size > count)
|
|
size = count;
|
|
System.Buffer.BlockCopy(_buffer, _streamPos, buffer, offset, size);
|
|
_streamPos += size;
|
|
if (_streamPos >= _windowSize)
|
|
{
|
|
_pos = 0;
|
|
_streamPos = 0;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
public void CopyPending()
|
|
{
|
|
if (_pendingLen > 0)
|
|
CopyBlock(_pendingDist, _pendingLen);
|
|
}
|
|
|
|
public int AvailableBytes
|
|
{
|
|
get { return _pos - _streamPos; }
|
|
}
|
|
}
|
|
} |