33using System ;
44using System . Buffers ;
55using System . IO ;
6+ using System . Threading ;
7+ using System . Threading . Tasks ;
68
79namespace SharpCompress . Compressors . LZMA . LZ ;
810
@@ -85,6 +87,12 @@ public void ReleaseStream()
8587 _stream = null ;
8688 }
8789
90+ public async Task ReleaseStreamAsync ( CancellationToken cancellationToken = default )
91+ {
92+ await FlushAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
93+ _stream = null ;
94+ }
95+
8896 private void Flush ( )
8997 {
9098 if ( _stream is null )
@@ -104,6 +112,27 @@ private void Flush()
104112 _streamPos = _pos ;
105113 }
106114
115+ private async Task FlushAsync ( CancellationToken cancellationToken = default )
116+ {
117+ if ( _stream is null )
118+ {
119+ return ;
120+ }
121+ var size = _pos - _streamPos ;
122+ if ( size == 0 )
123+ {
124+ return ;
125+ }
126+ await _stream
127+ . WriteAsync ( _buffer , _streamPos , size , cancellationToken )
128+ . ConfigureAwait ( false ) ;
129+ if ( _pos >= _windowSize )
130+ {
131+ _pos = 0 ;
132+ }
133+ _streamPos = _pos ;
134+ }
135+
107136 public void CopyPending ( )
108137 {
109138 if ( _pendingLen < 1 )
@@ -124,6 +153,26 @@ public void CopyPending()
124153 _pendingLen = rem ;
125154 }
126155
156+ public async Task CopyPendingAsync ( CancellationToken cancellationToken = default )
157+ {
158+ if ( _pendingLen < 1 )
159+ {
160+ return ;
161+ }
162+ var rem = _pendingLen ;
163+ var pos = ( _pendingDist < _pos ? _pos : _pos + _windowSize ) - _pendingDist - 1 ;
164+ while ( rem > 0 && HasSpace )
165+ {
166+ if ( pos >= _windowSize )
167+ {
168+ pos = 0 ;
169+ }
170+ await PutByteAsync ( _buffer [ pos ++ ] , cancellationToken ) . ConfigureAwait ( false ) ;
171+ rem -- ;
172+ }
173+ _pendingLen = rem ;
174+ }
175+
127176 public void CopyBlock ( int distance , int len )
128177 {
129178 var rem = len ;
@@ -157,6 +206,43 @@ public void CopyBlock(int distance, int len)
157206 _pendingDist = distance ;
158207 }
159208
209+ public async Task CopyBlockAsync (
210+ int distance ,
211+ int len ,
212+ CancellationToken cancellationToken = default
213+ )
214+ {
215+ var rem = len ;
216+ var pos = ( distance < _pos ? _pos : _pos + _windowSize ) - distance - 1 ;
217+ var targetSize = HasSpace ? ( int ) Math . Min ( rem , _limit - _total ) : 0 ;
218+ var sizeUntilWindowEnd = Math . Min ( _windowSize - _pos , _windowSize - pos ) ;
219+ var sizeUntilOverlap = Math . Abs ( pos - _pos ) ;
220+ var fastSize = Math . Min ( Math . Min ( sizeUntilWindowEnd , sizeUntilOverlap ) , targetSize ) ;
221+ if ( fastSize >= 2 )
222+ {
223+ _buffer . AsSpan ( pos , fastSize ) . CopyTo ( _buffer . AsSpan ( _pos , fastSize ) ) ;
224+ _pos += fastSize ;
225+ pos += fastSize ;
226+ _total += fastSize ;
227+ if ( _pos >= _windowSize )
228+ {
229+ await FlushAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
230+ }
231+ rem -= fastSize ;
232+ }
233+ while ( rem > 0 && HasSpace )
234+ {
235+ if ( pos >= _windowSize )
236+ {
237+ pos = 0 ;
238+ }
239+ await PutByteAsync ( _buffer [ pos ++ ] , cancellationToken ) . ConfigureAwait ( false ) ;
240+ rem -- ;
241+ }
242+ _pendingLen = rem ;
243+ _pendingDist = distance ;
244+ }
245+
160246 public void PutByte ( byte b )
161247 {
162248 _buffer [ _pos ++ ] = b ;
@@ -167,6 +253,16 @@ public void PutByte(byte b)
167253 }
168254 }
169255
256+ public async Task PutByteAsync ( byte b , CancellationToken cancellationToken = default )
257+ {
258+ _buffer [ _pos ++ ] = b ;
259+ _total ++ ;
260+ if ( _pos >= _windowSize )
261+ {
262+ await FlushAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
263+ }
264+ }
265+
170266 public byte GetByte ( int distance )
171267 {
172268 var pos = _pos - distance - 1 ;
@@ -207,6 +303,44 @@ public int CopyStream(Stream stream, int len)
207303 return len - size ;
208304 }
209305
306+ public async Task < int > CopyStreamAsync (
307+ Stream stream ,
308+ int len ,
309+ CancellationToken cancellationToken = default
310+ )
311+ {
312+ var size = len ;
313+ while ( size > 0 && _pos < _windowSize && _total < _limit )
314+ {
315+ cancellationToken . ThrowIfCancellationRequested ( ) ;
316+
317+ var curSize = _windowSize - _pos ;
318+ if ( curSize > _limit - _total )
319+ {
320+ curSize = ( int ) ( _limit - _total ) ;
321+ }
322+ if ( curSize > size )
323+ {
324+ curSize = size ;
325+ }
326+ var numReadBytes = await stream
327+ . ReadAsync ( _buffer , _pos , curSize , cancellationToken )
328+ . ConfigureAwait ( false ) ;
329+ if ( numReadBytes == 0 )
330+ {
331+ throw new DataErrorException ( ) ;
332+ }
333+ size -= numReadBytes ;
334+ _pos += numReadBytes ;
335+ _total += numReadBytes ;
336+ if ( _pos >= _windowSize )
337+ {
338+ await FlushAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
339+ }
340+ }
341+ return len - size ;
342+ }
343+
210344 public void SetLimit ( long size ) => _limit = _total + size ;
211345
212346 public bool HasSpace => _pos < _windowSize && _total < _limit ;
0 commit comments