@@ -647,10 +647,23 @@ static int mz_stat64(const char *path, struct __stat64 *buffer)
647
647
return MZ_TRUE ;
648
648
}
649
649
650
+ static mz_bool mz_zip_reader_eocd64_valid (mz_zip_archive * pZip , uint64_t offset , uint8_t * buf )
651
+ {
652
+ if (pZip -> m_pRead (pZip -> m_pIO_opaque , offset , buf , MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE ) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE )
653
+ {
654
+ if (MZ_READ_LE32 (buf + MZ_ZIP64_ECDH_SIG_OFS ) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG )
655
+ {
656
+ return MZ_TRUE ;
657
+ }
658
+ }
659
+
660
+ return MZ_FALSE ;
661
+ }
662
+
650
663
static mz_bool mz_zip_reader_read_central_dir (mz_zip_archive * pZip , mz_uint flags )
651
664
{
652
665
mz_uint cdir_size = 0 , cdir_entries_on_this_disk = 0 , num_this_disk = 0 , cdir_disk_index = 0 ;
653
- mz_uint64 cdir_ofs = 0 ;
666
+ mz_uint64 cdir_ofs = 0 , eocd_ofs = 0 , archive_ofs = 0 ;
654
667
mz_int64 cur_file_ofs = 0 ;
655
668
const mz_uint8 * p ;
656
669
@@ -672,6 +685,7 @@ static int mz_stat64(const char *path, struct __stat64 *buffer)
672
685
if (!mz_zip_reader_locate_header_sig (pZip , MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG , MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE , & cur_file_ofs ))
673
686
return mz_zip_set_error (pZip , MZ_ZIP_FAILED_FINDING_CENTRAL_DIR );
674
687
688
+ eocd_ofs = cur_file_ofs ;
675
689
/* Read and verify the end of central directory record. */
676
690
if (pZip -> m_pRead (pZip -> m_pIO_opaque , cur_file_ofs , pBuf , MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE ) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE )
677
691
return mz_zip_set_error (pZip , MZ_ZIP_FILE_READ_FAILED );
@@ -685,21 +699,40 @@ static int mz_stat64(const char *path, struct __stat64 *buffer)
685
699
{
686
700
if (MZ_READ_LE32 (pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS ) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG )
687
701
{
688
- zip64_end_of_central_dir_ofs = MZ_READ_LE64 (pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS );
689
- if (zip64_end_of_central_dir_ofs > (pZip -> m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE ))
690
- return mz_zip_set_error (pZip , MZ_ZIP_NOT_AN_ARCHIVE );
691
-
692
- if (pZip -> m_pRead (pZip -> m_pIO_opaque , zip64_end_of_central_dir_ofs , pZip64_end_of_central_dir , MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE ) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE )
693
- {
694
- if (MZ_READ_LE32 (pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS ) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG )
695
- {
696
- pZip -> m_pState -> m_zip64 = MZ_TRUE ;
697
- }
698
- }
702
+ pZip -> m_pState -> m_zip64 = MZ_TRUE ;
699
703
}
700
704
}
701
705
}
702
706
707
+ if (pZip -> m_pState -> m_zip64 )
708
+ {
709
+ /* Try locating the EOCD64 right before the EOCD64 locator. This works even
710
+ * when the effective start of the zip header is not yet known. */
711
+ if (cur_file_ofs < MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE +
712
+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE )
713
+ return mz_zip_set_error (pZip , MZ_ZIP_NOT_AN_ARCHIVE );
714
+
715
+ zip64_end_of_central_dir_ofs = cur_file_ofs -
716
+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE -
717
+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE ;
718
+
719
+ if (!mz_zip_reader_eocd64_valid (pZip , zip64_end_of_central_dir_ofs ,
720
+ pZip64_end_of_central_dir ))
721
+ {
722
+ /* That failed, try reading where the locator tells us to. */
723
+ zip64_end_of_central_dir_ofs = MZ_READ_LE64 (
724
+ pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS );
725
+
726
+ if (zip64_end_of_central_dir_ofs >
727
+ (pZip -> m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE ))
728
+ return mz_zip_set_error (pZip , MZ_ZIP_NOT_AN_ARCHIVE );
729
+
730
+ if (!mz_zip_reader_eocd64_valid (pZip , zip64_end_of_central_dir_ofs ,
731
+ pZip64_end_of_central_dir ))
732
+ return mz_zip_set_error (pZip , MZ_ZIP_NOT_AN_ARCHIVE );
733
+ }
734
+ }
735
+
703
736
pZip -> m_total_files = MZ_READ_LE16 (pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS );
704
737
cdir_entries_on_this_disk = MZ_READ_LE16 (pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS );
705
738
num_this_disk = MZ_READ_LE16 (pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS );
@@ -757,6 +790,26 @@ static int mz_stat64(const char *path, struct __stat64 *buffer)
757
790
if ((cdir_ofs + (mz_uint64 )cdir_size ) > pZip -> m_archive_size )
758
791
return mz_zip_set_error (pZip , MZ_ZIP_INVALID_HEADER_OR_CORRUPTED );
759
792
793
+ /* The end of central dir follows the central dir, unless the zip file has
794
+ * some trailing data (e.g. it is appended to an executable file). */
795
+ archive_ofs = eocd_ofs - (cdir_ofs + cdir_size );
796
+ if (pZip -> m_pState -> m_zip64 )
797
+ {
798
+ if (archive_ofs < MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE +
799
+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE )
800
+ return mz_zip_set_error (pZip , MZ_ZIP_INVALID_HEADER_OR_CORRUPTED );
801
+
802
+ archive_ofs -= MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE +
803
+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE ;
804
+ }
805
+
806
+ /* Update the archive start position, but only if not specified. */
807
+ if (pZip -> m_pState -> m_file_archive_start_ofs == 0 )
808
+ {
809
+ pZip -> m_pState -> m_file_archive_start_ofs = archive_ofs ;
810
+ pZip -> m_archive_size -= archive_ofs ;
811
+ }
812
+
760
813
pZip -> m_central_directory_file_ofs = cdir_ofs ;
761
814
762
815
if (pZip -> m_total_files )
0 commit comments