11using System ;
22using System . IO ;
33using System . Linq ;
4+ using JetBrains . Annotations ;
5+ using PatchKit . Logging ;
46using PatchKit . Unity . Patcher . Debug ;
57
68namespace PatchKit . Unity . Patcher . AppData . Remote . Downloaders
@@ -12,20 +14,20 @@ namespace PatchKit.Unity.Patcher.AppData.Remote.Downloaders
1214 /// has to be predefined.
1315 ///
1416 /// Usage:
15- /// Use Write() function as usuall to write bytes. As soon as you will get false stop copying
17+ /// Use Write() function as usuall to write bytes. As soon as you will catch InvalidChunkDataException stop copying
1618 /// procedure and restart it from next byte after VerifiedLength. If you will try to write
1719 /// bytes above the limit, you will get ArgumentOutOfRangeException.
1820 /// </summary>
19- public class ChunkedFileStream : IDisposable
21+ public sealed class ChunkedFileStream : IDisposable
2022 {
2123 [ Flags ]
2224 public enum WorkFlags
2325 {
2426 None = 0 ,
2527 PreservePreviousFile = 1
2628 }
27-
28- private static readonly DebugLogger DebugLogger = new DebugLogger ( typeof ( ChunkedFileStream ) ) ;
29+
30+ private readonly ILogger _logger ;
2931
3032 public delegate byte [ ] HashFunction ( byte [ ] buffer , int offset , int length ) ;
3133
@@ -36,7 +38,7 @@ public enum WorkFlags
3638 private readonly byte [ ] _buffer ;
3739 private int _bufferPos ;
3840 private int _chunkIndex ;
39- private readonly FileStream _fileStream ;
41+ private FileStream _fileStream ;
4042
4143 private bool _disposed ;
4244
@@ -60,58 +62,85 @@ public long Length
6062 get { return _fileSize ; }
6163 }
6264
63- public ChunkedFileStream ( string path , long fileSize , ChunksData chunksData , HashFunction hashFunction ,
65+ public ChunkedFileStream ( [ NotNull ] string path , long fileSize , ChunksData chunksData ,
66+ [ NotNull ] HashFunction hashFunction ,
6467 WorkFlags workFlags = WorkFlags . None )
6568 {
66- Checks . ArgumentNotNullOrEmpty ( path , "path" ) ;
67- Checks . ArgumentMoreThanZero ( fileSize , "fileSize" ) ;
68- Checks . ArgumentNotNull ( hashFunction , "hashFunction" ) ;
69-
70- DebugLogger . LogConstructor ( ) ;
71- DebugLogger . LogVariable ( path , "path" ) ;
72- DebugLogger . LogVariable ( fileSize , "fileSize" ) ;
69+ if ( path == null ) throw new ArgumentNullException ( "path" ) ;
70+ if ( fileSize <= 0 ) throw new ArgumentOutOfRangeException ( "fileSize" ) ;
71+ if ( hashFunction == null ) throw new ArgumentNullException ( "hashFunction" ) ;
7372
73+ _logger = PatcherLogManager . DefaultLogger ;
7474 _fileSize = fileSize ;
7575 _chunksData = chunksData ;
7676 _hashFunction = hashFunction ;
7777
7878 _buffer = new byte [ _chunksData . ChunkSize ] ;
7979
80- if ( ( workFlags | WorkFlags . PreservePreviousFile ) != 0 )
80+ _logger . LogTrace ( "path = " + path ) ;
81+ _logger . LogTrace ( "fileSize = " + fileSize ) ;
82+ _logger . LogTrace ( "chunksData.ChunkSize = " + chunksData . ChunkSize ) ;
83+
84+ bool preservePreviousFile = ( workFlags | WorkFlags . PreservePreviousFile ) != 0 ;
85+
86+ _logger . LogTrace ( "preservePreviousFile = " + preservePreviousFile ) ;
87+
88+ if ( preservePreviousFile )
8189 {
8290 // Often you may want to continue downloading of a file if this exists
8391 // It tries to open a file and re-download it from the verified position.
8492 // It does not check the hash of the file. It trusts that the file is already valid up to that point.
8593 // Because the only way to download the file should be using Chunked Downloader.
86-
94+
95+ _logger . LogDebug ( "Opening file stream..." ) ;
8796 _fileStream = new FileStream ( path , FileMode . OpenOrCreate , FileAccess . Write , FileShare . None ) ;
8897 _fileStream . Seek ( 0 , SeekOrigin . End ) ; // seek and stay at the end, so we can append
8998 long currentFileSize = _fileStream . Position ;
99+ _logger . LogDebug ( "File stream opened." ) ;
100+ _logger . LogTrace ( "currentFileSize = " + currentFileSize ) ;
101+
102+ _logger . LogDebug ( "Checking whether stream can append to current file..." ) ;
90103
104+
105+ if ( currentFileSize == 0 )
106+ {
107+ _logger . LogDebug ( "File is new. Append is not possible." ) ;
108+ }
91109 // Let's make sure that file size is a multiply of chunk size.
92110 // If not, something is wrong with the file.
93- if ( currentFileSize % chunksData . ChunkSize == 0 )
111+ else if ( currentFileSize % chunksData . ChunkSize == 0 )
94112 {
95113 _chunkIndex = ( int ) ( currentFileSize / chunksData . ChunkSize ) ;
114+ _logger . LogDebug ( string . Format ( "Append is possible - starting from {0} chunk index." , _chunkIndex ) ) ;
96115 }
97116 else
98117 {
99- DebugLogger . LogWarningFormat (
100- "File {0} size {1} is not a multiply of chunk size: {2}. Will recreate it." , path ,
101- currentFileSize , chunksData . ChunkSize ) ;
102-
118+ _logger . LogDebug ( string . Format (
119+ "File size {0} is not a multiply of chunk size: {1}. Append is not possible - recreating file." ,
120+ currentFileSize ,
121+ chunksData . ChunkSize ) ) ;
122+
123+ _logger . LogDebug ( "Closing previous file stream..." ) ;
103124 _fileStream . Close ( ) ;
104125 _fileStream . Dispose ( ) ;
105-
106- _fileStream = new FileStream ( path , FileMode . Create , FileAccess . Write , FileShare . None ) ;
126+ _logger . LogDebug ( "Previous file stream closed." ) ;
127+
128+ OpenNewFileStream ( path ) ;
107129 }
108130 }
109131 else
110132 {
111- _fileStream = new FileStream ( path , FileMode . Create , FileAccess . Write , FileShare . None ) ;
133+ OpenNewFileStream ( path ) ;
112134 }
113135 }
114136
137+ private void OpenNewFileStream ( string path )
138+ {
139+ _logger . LogDebug ( "Opening new file stream..." ) ;
140+ _fileStream = new FileStream ( path , FileMode . Create , FileAccess . Write , FileShare . None ) ;
141+ _logger . LogDebug ( "New file stream opened." ) ;
142+ }
143+
115144 /// <summary>
116145 /// Writes buffer into the file. If false is returned, stop file transfer and resume it
117146 /// starting from VerifiedLength + 1 byte.
@@ -120,10 +149,11 @@ public ChunkedFileStream(string path, long fileSize, ChunksData chunksData, Hash
120149 /// <param name="offset"></param>
121150 /// <param name="count"></param>
122151 /// <returns></returns>
123- public void Write ( byte [ ] buffer , int offset , int count )
152+ public void Write ( [ NotNull ] byte [ ] buffer , int offset , int count )
124153 {
125- Checks . ArgumentNotNull ( buffer , "buffer" ) ;
126- // TODO: Rest of assertions
154+ if ( buffer == null ) throw new ArgumentNullException ( "buffer" ) ;
155+ if ( offset < 0 ) throw new ArgumentOutOfRangeException ( "offset" ) ;
156+ if ( count < 0 ) throw new ArgumentOutOfRangeException ( "count" ) ;
127157
128158 do
129159 {
@@ -133,7 +163,7 @@ public void Write(byte[] buffer, int offset, int count)
133163 "Cannot write bytes over the file size: " + _fileSize ) ;
134164 }
135165
136- int copyNum = ( int ) Math . Min ( Math . Min ( count , _chunksData . ChunkSize - _bufferPos ) , RemainingLength ) ;
166+ int copyNum = ( int ) Math . Min ( Math . Min ( count , _chunksData . ChunkSize - _bufferPos ) , RemainingLength ) ;
137167 Array . Copy ( buffer , offset , _buffer , _bufferPos , copyNum ) ;
138168
139169 count -= copyNum ;
@@ -151,7 +181,6 @@ public void Write(byte[] buffer, int offset, int count)
151181 DiscardBuffer ( ) ;
152182 throw new InvalidChunkDataException ( "Invalid chunk data." ) ;
153183 }
154-
155184 }
156185 } while ( count > 0 ) ;
157186 }
@@ -163,15 +192,15 @@ private bool ChunkFullyInBuffer()
163192
164193 private bool BufferedChunkValid ( )
165194 {
166- byte [ ] bufferHash = _hashFunction ( _buffer , 0 , ( int ) Math . Min ( _chunksData . ChunkSize , RemainingLength ) ) ;
195+ byte [ ] bufferHash = _hashFunction ( _buffer , 0 , ( int ) Math . Min ( _chunksData . ChunkSize , RemainingLength ) ) ;
167196 byte [ ] chunkHash = _chunksData . Chunks [ _chunkIndex ] . Hash ;
168197
169198 return bufferHash . SequenceEqual ( chunkHash ) ;
170199 }
171200
172201 private void FlushBuffer ( )
173202 {
174- _fileStream . Write ( _buffer , 0 , ( int ) Math . Min ( _chunksData . ChunkSize , RemainingLength ) ) ;
203+ _fileStream . Write ( _buffer , 0 , ( int ) Math . Min ( _chunksData . ChunkSize , RemainingLength ) ) ;
175204 _bufferPos = 0 ;
176205 _chunkIndex ++ ;
177206 }
@@ -192,21 +221,19 @@ public void Dispose()
192221 Dispose ( false ) ;
193222 }
194223
195- protected virtual void Dispose ( bool disposing )
224+ private void Dispose ( bool disposing )
196225 {
197- if ( _disposed )
226+ if ( _disposed )
198227 {
199228 return ;
200229 }
201230
202- DebugLogger . LogDispose ( ) ;
203-
204- if ( disposing )
231+ if ( disposing )
205232 {
206233 _fileStream . Dispose ( ) ;
207234 }
208235
209236 _disposed = true ;
210237 }
211238 }
212- }
239+ }
0 commit comments