LzOutWindow.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. using System;
  2. using System.IO;
  3. namespace SharpCompress.Compressors.LZMA.LZ
  4. {
  5. internal class OutWindow
  6. {
  7. private byte[] _buffer;
  8. private int _windowSize;
  9. private int _pos;
  10. private int _streamPos;
  11. private int _pendingLen;
  12. private int _pendingDist;
  13. private Stream _stream;
  14. public long _total;
  15. public long _limit;
  16. public void Create(int windowSize)
  17. {
  18. if (_windowSize != windowSize)
  19. {
  20. _buffer = new byte[windowSize];
  21. }
  22. else
  23. {
  24. _buffer[windowSize - 1] = 0;
  25. }
  26. _windowSize = windowSize;
  27. _pos = 0;
  28. _streamPos = 0;
  29. _pendingLen = 0;
  30. _total = 0;
  31. _limit = 0;
  32. }
  33. public void Reset()
  34. {
  35. Create(_windowSize);
  36. }
  37. public void Init(Stream stream)
  38. {
  39. ReleaseStream();
  40. _stream = stream;
  41. }
  42. public void Train(Stream stream)
  43. {
  44. long len = stream.Length;
  45. int size = (len < _windowSize) ? (int)len : _windowSize;
  46. stream.Position = len - size;
  47. _total = 0;
  48. _limit = size;
  49. _pos = _windowSize - size;
  50. CopyStream(stream, size);
  51. if (_pos == _windowSize)
  52. {
  53. _pos = 0;
  54. }
  55. _streamPos = _pos;
  56. }
  57. public void ReleaseStream()
  58. {
  59. Flush();
  60. _stream = null;
  61. }
  62. public void Flush()
  63. {
  64. if (_stream == null)
  65. {
  66. return;
  67. }
  68. int size = _pos - _streamPos;
  69. if (size == 0)
  70. {
  71. return;
  72. }
  73. _stream.Write(_buffer, _streamPos, size);
  74. if (_pos >= _windowSize)
  75. {
  76. _pos = 0;
  77. }
  78. _streamPos = _pos;
  79. }
  80. public void CopyBlock(int distance, int len)
  81. {
  82. int size = len;
  83. int pos = _pos - distance - 1;
  84. if (pos < 0)
  85. {
  86. pos += _windowSize;
  87. }
  88. for (; size > 0 && _pos < _windowSize && _total < _limit; size--)
  89. {
  90. if (pos >= _windowSize)
  91. {
  92. pos = 0;
  93. }
  94. _buffer[_pos++] = _buffer[pos++];
  95. _total++;
  96. if (_pos >= _windowSize)
  97. {
  98. Flush();
  99. }
  100. }
  101. _pendingLen = size;
  102. _pendingDist = distance;
  103. }
  104. public void PutByte(byte b)
  105. {
  106. _buffer[_pos++] = b;
  107. _total++;
  108. if (_pos >= _windowSize)
  109. {
  110. Flush();
  111. }
  112. }
  113. public byte GetByte(int distance)
  114. {
  115. int pos = _pos - distance - 1;
  116. if (pos < 0)
  117. {
  118. pos += _windowSize;
  119. }
  120. return _buffer[pos];
  121. }
  122. public int CopyStream(Stream stream, int len)
  123. {
  124. int size = len;
  125. while (size > 0 && _pos < _windowSize && _total < _limit)
  126. {
  127. int curSize = _windowSize - _pos;
  128. if (curSize > _limit - _total)
  129. {
  130. curSize = (int)(_limit - _total);
  131. }
  132. if (curSize > size)
  133. {
  134. curSize = size;
  135. }
  136. int numReadBytes = stream.Read(_buffer, _pos, curSize);
  137. if (numReadBytes == 0)
  138. {
  139. throw new DataErrorException();
  140. }
  141. size -= numReadBytes;
  142. _pos += numReadBytes;
  143. _total += numReadBytes;
  144. if (_pos >= _windowSize)
  145. {
  146. Flush();
  147. }
  148. }
  149. return len - size;
  150. }
  151. public void SetLimit(long size)
  152. {
  153. _limit = _total + size;
  154. }
  155. public bool HasSpace => _pos < _windowSize && _total < _limit;
  156. public bool HasPending => _pendingLen > 0;
  157. public int Read(byte[] buffer, int offset, int count)
  158. {
  159. if (_streamPos >= _pos)
  160. {
  161. return 0;
  162. }
  163. int size = _pos - _streamPos;
  164. if (size > count)
  165. {
  166. size = count;
  167. }
  168. Buffer.BlockCopy(_buffer, _streamPos, buffer, offset, size);
  169. _streamPos += size;
  170. if (_streamPos >= _windowSize)
  171. {
  172. _pos = 0;
  173. _streamPos = 0;
  174. }
  175. return size;
  176. }
  177. public void CopyPending()
  178. {
  179. if (_pendingLen > 0)
  180. {
  181. CopyBlock(_pendingDist, _pendingLen);
  182. }
  183. }
  184. public int AvailableBytes => _pos - _streamPos;
  185. }
  186. }