1// LzOutWindow.cs
2
3namespace SevenZip.Compression.LZ
4{
5	public class OutWindow
6	{
7		byte[] _buffer = null;
8		uint _pos;
9		uint _windowSize = 0;
10		uint _streamPos;
11		System.IO.Stream _stream;
12
13		public uint TrainSize = 0;
14
15		public void Create(uint windowSize)
16		{
17			if (_windowSize != windowSize)
18			{
19				// System.GC.Collect();
20				_buffer = new byte[windowSize];
21			}
22			_windowSize = windowSize;
23			_pos = 0;
24			_streamPos = 0;
25		}
26
27		public void Init(System.IO.Stream stream, bool solid)
28		{
29			ReleaseStream();
30			_stream = stream;
31			if (!solid)
32			{
33				_streamPos = 0;
34				_pos = 0;
35				TrainSize = 0;
36			}
37		}
38
39		public bool Train(System.IO.Stream stream)
40		{
41			long len = stream.Length;
42			uint size = (len < _windowSize) ? (uint)len : _windowSize;
43			TrainSize = size;
44			stream.Position = len - size;
45			_streamPos = _pos = 0;
46			while (size > 0)
47			{
48				uint curSize = _windowSize - _pos;
49				if (size < curSize)
50					curSize = size;
51				int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize);
52				if (numReadBytes == 0)
53					return false;
54				size -= (uint)numReadBytes;
55				_pos += (uint)numReadBytes;
56				_streamPos += (uint)numReadBytes;
57				if (_pos == _windowSize)
58					_streamPos = _pos = 0;
59			}
60			return true;
61		}
62
63		public void ReleaseStream()
64		{
65			Flush();
66			_stream = null;
67		}
68
69		public void Flush()
70		{
71			uint size = _pos - _streamPos;
72			if (size == 0)
73				return;
74			_stream.Write(_buffer, (int)_streamPos, (int)size);
75			if (_pos >= _windowSize)
76				_pos = 0;
77			_streamPos = _pos;
78		}
79
80		public void CopyBlock(uint distance, uint len)
81		{
82			uint pos = _pos - distance - 1;
83			if (pos >= _windowSize)
84				pos += _windowSize;
85			for (; len > 0; len--)
86			{
87				if (pos >= _windowSize)
88					pos = 0;
89				_buffer[_pos++] = _buffer[pos++];
90				if (_pos >= _windowSize)
91					Flush();
92			}
93		}
94
95		public void PutByte(byte b)
96		{
97			_buffer[_pos++] = b;
98			if (_pos >= _windowSize)
99				Flush();
100		}
101
102		public byte GetByte(uint distance)
103		{
104			uint pos = _pos - distance - 1;
105			if (pos >= _windowSize)
106				pos += _windowSize;
107			return _buffer[pos];
108		}
109	}
110}
111