66using ICSharpCode . SharpZipLib . Zip ;
77using SevenZip ;
88using System . IO ;
9- using System . Linq ;
109using System . Text ;
10+ using UtfUnknown ;
1111using Windows . Storage ;
1212using Windows . Win32 ;
1313
@@ -90,7 +90,8 @@ public async Task<bool> CompressAsync(ICompressArchiveModel compressionModel)
9090 /// <inheritdoc/>
9191 public Task < bool > DecompressAsync ( string archiveFilePath , string destinationFolderPath , string password = "" , Encoding ? encoding = null )
9292 {
93- if ( encoding == null ) {
93+ if ( encoding == null )
94+ {
9495 return DecompressAsyncWithSevenZip ( archiveFilePath , destinationFolderPath , password ) ;
9596 }
9697 else
@@ -203,22 +204,22 @@ async Task<bool> DecompressAsyncWithSharpZipLib(string archiveFilePath, string d
203204 string . IsNullOrEmpty ( destinationFolderPath ) )
204205 return false ;
205206 using var zipFile = new ZipFile ( archiveFilePath , StringCodec . FromEncoding ( encoding ) ) ;
206- if ( zipFile is null )
207+ if ( zipFile is null )
207208 return false ;
208-
209- if ( ! string . IsNullOrEmpty ( password ) )
209+
210+ if ( ! string . IsNullOrEmpty ( password ) )
210211 zipFile . Password = password ;
211212
212213 // Initialize a new in-progress status card
213214 var statusCard = StatusCenterHelper . AddCard_Decompress (
214215 archiveFilePath . CreateEnumerable ( ) ,
215216 destinationFolderPath . CreateEnumerable ( ) ,
216217 ReturnResult . InProgress ) ;
217-
218+
218219 // Check if the decompress operation canceled
219220 if ( statusCard . CancellationToken . IsCancellationRequested )
220221 return false ;
221-
222+
222223 StatusCenterItemProgressModel fsProgress = new (
223224 statusCard . ProgressEventSource ,
224225 enumerationCompleted : true ,
@@ -233,51 +234,52 @@ async Task<bool> DecompressAsyncWithSharpZipLib(string archiveFilePath, string d
233234 {
234235 long processedBytes = 0 ;
235236 int processedFiles = 0 ;
236-
237- foreach ( ZipEntry zipEntry in zipFile )
237+ await Task . Run ( async ( ) =>
238238 {
239- if ( statusCard . CancellationToken . IsCancellationRequested )
239+ foreach ( ZipEntry zipEntry in zipFile )
240240 {
241- isSuccess = false ;
242- break ;
243- }
244-
245- if ( ! zipEntry . IsFile )
246- {
247- continue ; // Ignore directories
248- }
241+ if ( statusCard . CancellationToken . IsCancellationRequested )
242+ {
243+ isSuccess = false ;
244+ break ;
245+ }
249246
250- string entryFileName = zipEntry . Name ;
251- string fullZipToPath = Path . Combine ( destinationFolderPath , entryFileName ) ;
252- string directoryName = Path . GetDirectoryName ( fullZipToPath ) ;
247+ if ( ! zipEntry . IsFile )
248+ {
249+ continue ; // Ignore directories
250+ }
253251
254- if ( ! Directory . Exists ( directoryName ) )
255- {
256- Directory . CreateDirectory ( directoryName ) ;
257- }
252+ string entryFileName = zipEntry . Name ;
253+ string fullZipToPath = Path . Combine ( destinationFolderPath , entryFileName ) ;
254+ string directoryName = Path . GetDirectoryName ( fullZipToPath ) ;
258255
259- byte [ ] buffer = new byte [ 4096 ] ; // 4K is a good default
260- using ( Stream zipStream = zipFile . GetInputStream ( zipEntry ) )
261- using ( FileStream streamWriter = File . Create ( fullZipToPath ) )
262- {
263- await ThreadingService . ExecuteOnUiThreadAsync ( ( ) =>
256+ if ( ! Directory . Exists ( directoryName ) )
264257 {
265- fsProgress . FileName = entryFileName ;
266- fsProgress . Report ( ) ;
267- } ) ;
258+ Directory . CreateDirectory ( directoryName ) ;
259+ }
268260
269- StreamUtils . Copy ( zipStream , streamWriter , buffer ) ;
270- }
271- processedBytes += zipEntry . Size ;
272- if ( fsProgress . TotalSize > 0 )
273- {
274- fsProgress . Report ( processedBytes / ( double ) fsProgress . TotalSize * 100 ) ;
261+ byte [ ] buffer = new byte [ 4096 ] ; // 4K is a good default
262+ using ( Stream zipStream = zipFile . GetInputStream ( zipEntry ) )
263+ using ( FileStream streamWriter = File . Create ( fullZipToPath ) )
264+ {
265+ await ThreadingService . ExecuteOnUiThreadAsync ( ( ) =>
266+ {
267+ fsProgress . FileName = entryFileName ;
268+ fsProgress . Report ( ) ;
269+ } ) ;
270+
271+ StreamUtils . Copy ( zipStream , streamWriter , buffer ) ;
272+ }
273+ processedBytes += zipEntry . Size ;
274+ if ( fsProgress . TotalSize > 0 )
275+ {
276+ fsProgress . Report ( processedBytes / ( double ) fsProgress . TotalSize * 100 ) ;
277+ }
278+ processedFiles ++ ;
279+ fsProgress . AddProcessedItemsCount ( 1 ) ;
280+ fsProgress . Report ( ) ;
275281 }
276- processedFiles ++ ;
277- fsProgress . AddProcessedItemsCount ( 1 ) ;
278- fsProgress . Report ( ) ;
279- }
280-
282+ } ) ;
281283 if ( ! statusCard . CancellationToken . IsCancellationRequested )
282284 {
283285 isSuccess = true ;
@@ -321,7 +323,7 @@ await ThreadingService.ExecuteOnUiThreadAsync(() =>
321323 return isSuccess ;
322324 }
323325
324-
326+
325327 /// <inheritdoc/>
326328 public string GenerateArchiveNameFromItems ( IReadOnlyList < ListedItem > items )
327329 {
@@ -355,7 +357,7 @@ public async Task<bool> IsEncodingUndeterminedAsync(string archiveFilePath)
355357 {
356358 using ( ZipFile zipFile = new ZipFile ( archiveFilePath ) )
357359 {
358- return ! zipFile . Cast < ZipEntry > ( ) . All ( entry=> entry . IsUnicodeText ) ;
360+ return ! zipFile . Cast < ZipEntry > ( ) . All ( entry => entry . IsUnicodeText ) ;
359361 }
360362 }
361363 catch ( Exception ex )
@@ -365,6 +367,42 @@ public async Task<bool> IsEncodingUndeterminedAsync(string archiveFilePath)
365367 }
366368 }
367369
370+ public async Task < Encoding ? > DetectEncodingAsync ( string archiveFilePath )
371+ {
372+ //Temporarily using cp437 to decode zip file
373+ //because SharpZipLib requires an encoding when decoding
374+ //and cp437 contains all bytes as character
375+ //which means that we can store any byte array as cp437 string losslessly
376+ var cp437 = Encoding . GetEncoding ( 437 ) ;
377+ try
378+ {
379+ using ( ZipFile zipFile = new ZipFile ( archiveFilePath , StringCodec . FromEncoding ( cp437 ) ) )
380+ {
381+ var fileNameBytes = cp437 . GetBytes (
382+ String . Join ( "\n " ,
383+ zipFile . Cast < ZipEntry > ( )
384+ . Where ( e => ! e . IsUnicodeText )
385+ . Select ( e => e . Name )
386+ )
387+ ) ;
388+ var detectionResult = CharsetDetector . DetectFromBytes ( fileNameBytes ) ;
389+ if ( detectionResult . Detected != null && detectionResult . Detected . Confidence > 0.5 )
390+ {
391+ return detectionResult . Detected . Encoding ;
392+ }
393+ else
394+ {
395+ return null ;
396+ }
397+ }
398+ }
399+ catch ( Exception ex )
400+ {
401+ Console . WriteLine ( $ "SharpZipLib error: { ex . Message } ") ;
402+ return null ;
403+ }
404+ }
405+
368406 /// <inheritdoc/>
369407 public async Task < SevenZipExtractor ? > GetSevenZipExtractorAsync ( string archiveFilePath , string password = "" )
370408 {
0 commit comments