@@ -1003,16 +1003,19 @@ public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandl
1003
1003
if ( this [ entryIndex ] . Crc != data . Crc )
1004
1004
{
1005
1005
status . AddError ( ) ;
1006
+ resultHandler ? . Invoke ( status , "Descriptor CRC mismatch" ) ;
1006
1007
}
1007
1008
1008
1009
if ( this [ entryIndex ] . CompressedSize != data . CompressedSize )
1009
1010
{
1010
1011
status . AddError ( ) ;
1012
+ resultHandler ? . Invoke ( status , "Descriptor compressed size mismatch" ) ;
1011
1013
}
1012
1014
1013
1015
if ( this [ entryIndex ] . Size != data . Size )
1014
1016
{
1015
1017
status . AddError ( ) ;
1018
+ resultHandler ? . Invoke ( status , "Descriptor size mismatch" ) ;
1016
1019
}
1017
1020
}
1018
1021
}
@@ -1921,11 +1924,9 @@ public void Modify(ZipEntry original, ZipEntry updated)
1921
1924
if ( original == null ) {
1922
1925
throw new ArgumentNullException("original");
1923
1926
}
1924
-
1925
1927
if ( updated == null ) {
1926
1928
throw new ArgumentNullException("updated");
1927
1929
}
1928
-
1929
1930
CheckUpdating();
1930
1931
contentsEdited_ = true;
1931
1932
updates_.Add(new ZipUpdate(original, updated));
@@ -2386,26 +2387,37 @@ private byte[] GetBuffer()
2386
2387
2387
2388
private void CopyDescriptorBytes ( ZipUpdate update , Stream dest , Stream source )
2388
2389
{
2389
- int bytesToCopy = GetDescriptorSize ( update ) ;
2390
+ // Don't include the signature size to allow copy without seeking
2391
+ var bytesToCopy = GetDescriptorSize ( update , false ) ;
2392
+
2393
+ // Don't touch the source stream if no descriptor is present
2394
+ if ( bytesToCopy == 0 ) return ;
2390
2395
2391
- if ( bytesToCopy > 0 )
2396
+ var buffer = GetBuffer ( ) ;
2397
+
2398
+ // Copy the first 4 bytes of the descriptor
2399
+ source . Read ( buffer , 0 , sizeof ( int ) ) ;
2400
+ dest . Write ( buffer , 0 , sizeof ( int ) ) ;
2401
+
2402
+ if ( BitConverter . ToUInt32 ( buffer , 0 ) != ZipConstants . DataDescriptorSignature )
2392
2403
{
2393
- byte [ ] buffer = GetBuffer ( ) ;
2404
+ // The initial bytes wasn't the descriptor, reduce the pending byte count
2405
+ bytesToCopy -= buffer . Length ;
2406
+ }
2394
2407
2395
- while ( bytesToCopy > 0 )
2396
- {
2397
- int readSize = Math . Min ( buffer . Length , bytesToCopy ) ;
2408
+ while ( bytesToCopy > 0 )
2409
+ {
2410
+ int readSize = Math . Min ( buffer . Length , bytesToCopy ) ;
2398
2411
2399
- int bytesRead = source . Read ( buffer , 0 , readSize ) ;
2400
- if ( bytesRead > 0 )
2401
- {
2402
- dest . Write ( buffer , 0 , bytesRead ) ;
2403
- bytesToCopy -= bytesRead ;
2404
- }
2405
- else
2406
- {
2407
- throw new ZipException ( "Unxpected end of stream" ) ;
2408
- }
2412
+ int bytesRead = source . Read ( buffer , 0 , readSize ) ;
2413
+ if ( bytesRead > 0 )
2414
+ {
2415
+ dest . Write ( buffer , 0 , bytesRead ) ;
2416
+ bytesToCopy -= bytesRead ;
2417
+ }
2418
+ else
2419
+ {
2420
+ throw new ZipException ( "Unxpected end of stream" ) ;
2409
2421
}
2410
2422
}
2411
2423
}
@@ -2464,32 +2476,37 @@ private void CopyBytes(ZipUpdate update, Stream destination, Stream source,
2464
2476
/// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.
2465
2477
/// </summary>
2466
2478
/// <param name="update">The update to get the size for.</param>
2467
- /// <returns>The descriptor size, zero if there isnt one.</returns>
2468
- private int GetDescriptorSize ( ZipUpdate update )
2479
+ /// <param name="includingSignature">Whether to include the signature size</param>
2480
+ /// <returns>The descriptor size, zero if there isn't one.</returns>
2481
+ private int GetDescriptorSize ( ZipUpdate update , bool includingSignature )
2469
2482
{
2470
- int result = 0 ;
2471
- if ( ( update . Entry . Flags & ( int ) GeneralBitFlags . Descriptor ) != 0 )
2472
- {
2473
- result = ZipConstants . DataDescriptorSize - 4 ;
2474
- if ( update . Entry . LocalHeaderRequiresZip64 )
2475
- {
2476
- result = ZipConstants . Zip64DataDescriptorSize - 4 ;
2477
- }
2478
- }
2479
- return result ;
2483
+ if ( ! ( ( GeneralBitFlags ) update . Entry . Flags ) . HasFlag ( GeneralBitFlags . Descriptor ) )
2484
+ return 0 ;
2485
+
2486
+ var descriptorWithSignature = update . Entry . LocalHeaderRequiresZip64
2487
+ ? ZipConstants . Zip64DataDescriptorSize
2488
+ : ZipConstants . DataDescriptorSize ;
2489
+
2490
+ return includingSignature
2491
+ ? descriptorWithSignature
2492
+ : descriptorWithSignature - sizeof ( int ) ;
2480
2493
}
2481
2494
2482
2495
private void CopyDescriptorBytesDirect ( ZipUpdate update , Stream stream , ref long destinationPosition , long sourcePosition )
2483
2496
{
2484
- int bytesToCopy = GetDescriptorSize ( update ) ;
2497
+ var buffer = GetBuffer ( ) ; ;
2498
+
2499
+ stream . Position = sourcePosition ;
2500
+ stream . Read ( buffer , 0 , sizeof ( int ) ) ;
2501
+ var sourceHasSignature = BitConverter . ToUInt32 ( buffer , 0 ) == ZipConstants . DataDescriptorSignature ;
2502
+
2503
+ var bytesToCopy = GetDescriptorSize ( update , sourceHasSignature ) ;
2485
2504
2486
2505
while ( bytesToCopy > 0 )
2487
2506
{
2488
- var readSize = ( int ) bytesToCopy ;
2489
- byte [ ] buffer = GetBuffer ( ) ;
2490
-
2491
2507
stream . Position = sourcePosition ;
2492
- int bytesRead = stream . Read ( buffer , 0 , readSize ) ;
2508
+
2509
+ var bytesRead = stream . Read ( buffer , 0 , bytesToCopy ) ;
2493
2510
if ( bytesRead > 0 )
2494
2511
{
2495
2512
stream . Position = destinationPosition ;
@@ -2500,7 +2517,7 @@ private void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long
2500
2517
}
2501
2518
else
2502
2519
{
2503
- throw new ZipException ( "Unxpected end of stream" ) ;
2520
+ throw new ZipException ( "Unexpected end of stream" ) ;
2504
2521
}
2505
2522
}
2506
2523
}
@@ -2757,6 +2774,7 @@ private void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destin
2757
2774
2758
2775
// Clumsy way of handling retrieving the original name and extra data length for now.
2759
2776
// TODO: Stop re-reading name and data length in CopyEntryDirect.
2777
+
2760
2778
uint nameLength = ReadLEUshort ( ) ;
2761
2779
uint extraLength = ReadLEUshort ( ) ;
2762
2780
@@ -2765,14 +2783,25 @@ private void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destin
2765
2783
if ( skipOver )
2766
2784
{
2767
2785
if ( update . OffsetBasedSize != - 1 )
2786
+ {
2768
2787
destinationPosition += update . OffsetBasedSize ;
2788
+ }
2769
2789
else
2770
- // TODO: Find out why this calculation comes up 4 bytes short on some entries in ODT (Office Document Text) archives.
2771
- // WinZip produces a warning on these entries:
2772
- // "caution: value of lrec.csize (compressed size) changed from ..."
2773
- destinationPosition +=
2774
- ( sourcePosition - entryDataOffset ) + NameLengthOffset + // Header size
2775
- update . Entry . CompressedSize + GetDescriptorSize ( update ) ;
2790
+ {
2791
+ // Skip entry header
2792
+ destinationPosition += ( sourcePosition - entryDataOffset ) + NameLengthOffset ;
2793
+
2794
+ // Skip entry compressed data
2795
+ destinationPosition += update . Entry . CompressedSize ;
2796
+
2797
+ // Seek to end of entry to check for descriptor signature
2798
+ baseStream_ . Seek ( destinationPosition , SeekOrigin . Begin ) ;
2799
+
2800
+ var descriptorHasSignature = ReadLEUint ( ) == ZipConstants . DataDescriptorSignature ;
2801
+
2802
+ // Skip descriptor and it's signature (if present)
2803
+ destinationPosition += GetDescriptorSize ( update , descriptorHasSignature ) ;
2804
+ }
2776
2805
}
2777
2806
else
2778
2807
{
0 commit comments