@@ -1003,16 +1003,19 @@ public bool TestArchive(bool testData, TestStrategy strategy, ZipTestResultHandl
10031003 if ( this [ entryIndex ] . Crc != data . Crc )
10041004 {
10051005 status . AddError ( ) ;
1006+ resultHandler ? . Invoke ( status , "Descriptor CRC mismatch" ) ;
10061007 }
10071008
10081009 if ( this [ entryIndex ] . CompressedSize != data . CompressedSize )
10091010 {
10101011 status . AddError ( ) ;
1012+ resultHandler ? . Invoke ( status , "Descriptor compressed size mismatch" ) ;
10111013 }
10121014
10131015 if ( this [ entryIndex ] . Size != data . Size )
10141016 {
10151017 status . AddError ( ) ;
1018+ resultHandler ? . Invoke ( status , "Descriptor size mismatch" ) ;
10161019 }
10171020 }
10181021 }
@@ -1921,11 +1924,9 @@ public void Modify(ZipEntry original, ZipEntry updated)
19211924 if ( original == null ) {
19221925 throw new ArgumentNullException("original");
19231926 }
1924-
19251927 if ( updated == null ) {
19261928 throw new ArgumentNullException("updated");
19271929 }
1928-
19291930 CheckUpdating();
19301931 contentsEdited_ = true;
19311932 updates_.Add(new ZipUpdate(original, updated));
@@ -2386,26 +2387,37 @@ private byte[] GetBuffer()
23862387
23872388 private void CopyDescriptorBytes ( ZipUpdate update , Stream dest , Stream source )
23882389 {
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 ;
23902395
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 )
23922403 {
2393- byte [ ] buffer = GetBuffer ( ) ;
2404+ // The initial bytes wasn't the descriptor, reduce the pending byte count
2405+ bytesToCopy -= buffer . Length ;
2406+ }
23942407
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 ) ;
23982411
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" ) ;
24092421 }
24102422 }
24112423 }
@@ -2464,32 +2476,37 @@ private void CopyBytes(ZipUpdate update, Stream destination, Stream source,
24642476 /// Get the size of the source descriptor for a <see cref="ZipUpdate"/>.
24652477 /// </summary>
24662478 /// <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 )
24692482 {
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 ) ;
24802493 }
24812494
24822495 private void CopyDescriptorBytesDirect ( ZipUpdate update , Stream stream , ref long destinationPosition , long sourcePosition )
24832496 {
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 ) ;
24852504
24862505 while ( bytesToCopy > 0 )
24872506 {
2488- var readSize = ( int ) bytesToCopy ;
2489- byte [ ] buffer = GetBuffer ( ) ;
2490-
24912507 stream . Position = sourcePosition ;
2492- int bytesRead = stream . Read ( buffer , 0 , readSize ) ;
2508+
2509+ var bytesRead = stream . Read ( buffer , 0 , bytesToCopy ) ;
24932510 if ( bytesRead > 0 )
24942511 {
24952512 stream . Position = destinationPosition ;
@@ -2500,7 +2517,7 @@ private void CopyDescriptorBytesDirect(ZipUpdate update, Stream stream, ref long
25002517 }
25012518 else
25022519 {
2503- throw new ZipException ( "Unxpected end of stream" ) ;
2520+ throw new ZipException ( "Unexpected end of stream" ) ;
25042521 }
25052522 }
25062523 }
@@ -2757,6 +2774,7 @@ private void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destin
27572774
27582775 // Clumsy way of handling retrieving the original name and extra data length for now.
27592776 // TODO: Stop re-reading name and data length in CopyEntryDirect.
2777+
27602778 uint nameLength = ReadLEUshort ( ) ;
27612779 uint extraLength = ReadLEUshort ( ) ;
27622780
@@ -2765,14 +2783,25 @@ private void CopyEntryDirect(ZipFile workFile, ZipUpdate update, ref long destin
27652783 if ( skipOver )
27662784 {
27672785 if ( update . OffsetBasedSize != - 1 )
2786+ {
27682787 destinationPosition += update . OffsetBasedSize ;
2788+ }
27692789 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+ }
27762805 }
27772806 else
27782807 {
0 commit comments