6
6
using ICSharpCode . SharpZipLib . Zip ;
7
7
using SevenZip ;
8
8
using System . IO ;
9
- using System . Linq ;
10
9
using System . Text ;
10
+ using UtfUnknown ;
11
11
using Windows . Storage ;
12
12
using Windows . Win32 ;
13
13
@@ -90,7 +90,8 @@ public async Task<bool> CompressAsync(ICompressArchiveModel compressionModel)
90
90
/// <inheritdoc/>
91
91
public Task < bool > DecompressAsync ( string archiveFilePath , string destinationFolderPath , string password = "" , Encoding ? encoding = null )
92
92
{
93
- if ( encoding == null ) {
93
+ if ( encoding == null )
94
+ {
94
95
return DecompressAsyncWithSevenZip ( archiveFilePath , destinationFolderPath , password ) ;
95
96
}
96
97
else
@@ -203,22 +204,22 @@ async Task<bool> DecompressAsyncWithSharpZipLib(string archiveFilePath, string d
203
204
string . IsNullOrEmpty ( destinationFolderPath ) )
204
205
return false ;
205
206
using var zipFile = new ZipFile ( archiveFilePath , StringCodec . FromEncoding ( encoding ) ) ;
206
- if ( zipFile is null )
207
+ if ( zipFile is null )
207
208
return false ;
208
-
209
- if ( ! string . IsNullOrEmpty ( password ) )
209
+
210
+ if ( ! string . IsNullOrEmpty ( password ) )
210
211
zipFile . Password = password ;
211
212
212
213
// Initialize a new in-progress status card
213
214
var statusCard = StatusCenterHelper . AddCard_Decompress (
214
215
archiveFilePath . CreateEnumerable ( ) ,
215
216
destinationFolderPath . CreateEnumerable ( ) ,
216
217
ReturnResult . InProgress ) ;
217
-
218
+
218
219
// Check if the decompress operation canceled
219
220
if ( statusCard . CancellationToken . IsCancellationRequested )
220
221
return false ;
221
-
222
+
222
223
StatusCenterItemProgressModel fsProgress = new (
223
224
statusCard . ProgressEventSource ,
224
225
enumerationCompleted : true ,
@@ -233,51 +234,52 @@ async Task<bool> DecompressAsyncWithSharpZipLib(string archiveFilePath, string d
233
234
{
234
235
long processedBytes = 0 ;
235
236
int processedFiles = 0 ;
236
-
237
- foreach ( ZipEntry zipEntry in zipFile )
237
+ await Task . Run ( async ( ) =>
238
238
{
239
- if ( statusCard . CancellationToken . IsCancellationRequested )
239
+ foreach ( ZipEntry zipEntry in zipFile )
240
240
{
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
+ }
249
246
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
+ }
253
251
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 ) ;
258
255
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 ) )
264
257
{
265
- fsProgress . FileName = entryFileName ;
266
- fsProgress . Report ( ) ;
267
- } ) ;
258
+ Directory . CreateDirectory ( directoryName ) ;
259
+ }
268
260
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 ( ) ;
275
281
}
276
- processedFiles ++ ;
277
- fsProgress . AddProcessedItemsCount ( 1 ) ;
278
- fsProgress . Report ( ) ;
279
- }
280
-
282
+ } ) ;
281
283
if ( ! statusCard . CancellationToken . IsCancellationRequested )
282
284
{
283
285
isSuccess = true ;
@@ -321,7 +323,7 @@ await ThreadingService.ExecuteOnUiThreadAsync(() =>
321
323
return isSuccess ;
322
324
}
323
325
324
-
326
+
325
327
/// <inheritdoc/>
326
328
public string GenerateArchiveNameFromItems ( IReadOnlyList < ListedItem > items )
327
329
{
@@ -355,7 +357,7 @@ public async Task<bool> IsEncodingUndeterminedAsync(string archiveFilePath)
355
357
{
356
358
using ( ZipFile zipFile = new ZipFile ( archiveFilePath ) )
357
359
{
358
- return ! zipFile . Cast < ZipEntry > ( ) . All ( entry=> entry . IsUnicodeText ) ;
360
+ return ! zipFile . Cast < ZipEntry > ( ) . All ( entry => entry . IsUnicodeText ) ;
359
361
}
360
362
}
361
363
catch ( Exception ex )
@@ -365,6 +367,42 @@ public async Task<bool> IsEncodingUndeterminedAsync(string archiveFilePath)
365
367
}
366
368
}
367
369
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
+
368
406
/// <inheritdoc/>
369
407
public async Task < SevenZipExtractor ? > GetSevenZipExtractorAsync ( string archiveFilePath , string password = "" )
370
408
{
0 commit comments