@@ -326,7 +326,6 @@ module.exports = {
326326"use strict" ;
327327var USE_TYPEDARRAY = ( typeof Uint8Array !== "undefined" ) && ( typeof Uint16Array !== "undefined" ) && ( typeof Uint32Array !== "undefined" ) ;
328328
329- var pako = require ( "pako" ) ;
330329var utils = require ( "./utils" ) ;
331330var GenericWorker = require ( "./stream/GenericWorker" ) ;
332331
@@ -389,6 +388,7 @@ FlateWorker.prototype.cleanUp = function () {
389388 * issue #446.
390389 */
391390FlateWorker . prototype . _createPako = function ( ) {
391+ var pako = require ( "pako" ) ;
392392 this . _pako = new pako [ this . _pakoAction ] ( {
393393 chunkSize : 65536 ,
394394 raw : true ,
@@ -1056,10 +1056,6 @@ JSZip.prototype.loadAsync = require("./load");
10561056JSZip . support = require ( "./support" ) ;
10571057JSZip . defaults = require ( "./defaults" ) ;
10581058
1059- // TODO find a better way to handle this version,
1060- // a require('package.json').version doesn't work with webpack, see #327
1061- JSZip . version = "3.10.1" ;
1062-
10631059JSZip . loadAsync = function ( content , options ) {
10641060 return new JSZip ( ) . loadAsync ( content , options ) ;
10651061} ;
@@ -1369,7 +1365,10 @@ var fileAdd = function(name, data, originalOptions) {
13691365 */
13701366
13711367 var o = utils . extend ( originalOptions || { } , defaults ) ;
1372- o . date = o . date || new Date ( ) ;
1368+ // Upstream JSZip defaults to current date which makes zips non-deterministic unless
1369+ // user overwrites dates themselves. Instead, we'll default to this arbitrary constant
1370+ // date. It comes from commit 19fbe1140c147adb830751d90fbf5b2332de8c07.
1371+ o . date = o . date || new Date ( 1716106843000 ) ;
13731372 if ( o . compression !== null ) {
13741373 o . compression = o . compression . toUpperCase ( ) ;
13751374 }
@@ -3715,8 +3714,7 @@ ZipEntries.prototype = {
37153714 var isGarbage = ! this . isSignature ( 0 , sig . LOCAL_FILE_HEADER ) ;
37163715
37173716 if ( isGarbage ) {
3718- throw new Error ( "Can't find end of central directory : is this a zip file ? " +
3719- "If it is, see https://stuk.github.io/jszip/documentation/howto/read_zip.html" ) ;
3717+ throw new Error ( "Corrupted zip: can't find zip signature or end of central directory" ) ;
37203718 } else {
37213719 throw new Error ( "Corrupted zip: can't find end of central directory" ) ;
37223720 }
@@ -3797,15 +3795,91 @@ ZipEntries.prototype = {
37973795 prepareReader : function ( data ) {
37983796 this . reader = readerFor ( data ) ;
37993797 } ,
3798+ /**
3799+ * Attempt to parse a zip without a central directory.
3800+ */
3801+ tryRecoverCorruptedZip : function ( ) {
3802+ // Undo anything done by the central directory reader
3803+ this . reader . setIndex ( 0 ) ;
3804+ this . files = [ ] ;
3805+
3806+ // Zip comment is in central directory, so we have no comment
3807+ this . zipCommentLength = 0 ;
3808+ this . zipComment = [ ] ;
3809+
3810+ var possibleHeaders = 0 ;
3811+
3812+ // Without central directory, have to just search for file entry magic bytes
3813+ var length = this . reader . length ;
3814+ for ( var i = 0 ; i < length - 4 ; i ++ ) {
3815+ if (
3816+ this . reader . byteAt ( i ) === 0x50 &&
3817+ this . reader . byteAt ( i + 1 ) === 0x4B &&
3818+ this . reader . byteAt ( i + 2 ) === 0x03 &&
3819+ this . reader . byteAt ( i + 3 ) === 0x04
3820+ ) {
3821+ possibleHeaders ++ ;
3822+ var zipEntry = this . tryRecoverFileEntry ( i ) ;
3823+ if ( zipEntry ) {
3824+ this . files . push ( zipEntry ) ;
3825+ }
3826+ }
3827+ }
3828+
3829+ if ( this . files . length === 0 ) {
3830+ if ( possibleHeaders === 0 ) {
3831+ throw new Error ( "Corrupted zip: no central directory or any file headers" ) ;
3832+ }
3833+ throw new Error ( "Corrupted zip: no central directory, and " + possibleHeaders + " possible local headers could not be recovered" ) ;
3834+ }
3835+ } ,
3836+ /**
3837+ * Attempts to read a zip entry from only the local header.
3838+ * @param {number } index Index in this.reader where a file header appears to start
3839+ * @returns {ZipEntry|null } The zip entry if a valid one could be parsed, otherwise null.
3840+ */
3841+ tryRecoverFileEntry : function ( index ) {
3842+ this . reader . setIndex ( index ) ;
3843+
3844+ var zipEntry = new ZipEntry ( {
3845+ zip64 : this . zip64
3846+ } , this . loadOptions ) ;
3847+
3848+ try {
3849+ zipEntry . readLocalPartFromCorruptedZip ( this . reader ) ;
3850+ zipEntry . handleUTF8 ( ) ;
3851+ zipEntry . processAttributes ( ) ;
3852+ return zipEntry ;
3853+ } catch ( error ) {
3854+ // Invalid entry. Ignore it.
3855+ if ( this . loadOptions . onUnrecoverableFileEntry ) {
3856+ this . loadOptions . onUnrecoverableFileEntry ( error ) ;
3857+ }
3858+ return null ;
3859+ }
3860+ } ,
38003861 /**
38013862 * Read a zip file and create ZipEntries.
38023863 * @param {String|ArrayBuffer|Uint8Array|Buffer } data the binary string representing a zip file.
38033864 */
38043865 load : function ( data ) {
38053866 this . prepareReader ( data ) ;
3806- this . readEndOfCentral ( ) ;
3807- this . readCentralDir ( ) ;
3808- this . readLocalFiles ( ) ;
3867+
3868+ try {
3869+ this . readEndOfCentral ( ) ;
3870+ this . readCentralDir ( ) ;
3871+ this . readLocalFiles ( ) ;
3872+ } catch ( centralDirectoryError ) {
3873+ if ( this . loadOptions . recoverCorrupted ) {
3874+ if ( this . loadOptions . onCorruptCentralDirectory ) {
3875+ this . loadOptions . onCorruptCentralDirectory ( centralDirectoryError ) ;
3876+ }
3877+
3878+ this . tryRecoverCorruptedZip ( ) ;
3879+ } else {
3880+ throw centralDirectoryError ;
3881+ }
3882+ }
38093883 }
38103884} ;
38113885// }}} end of ZipEntries
@@ -3820,6 +3894,7 @@ var crc32fn = require("./crc32");
38203894var utf8 = require ( "./utf8" ) ;
38213895var compressions = require ( "./compressions" ) ;
38223896var support = require ( "./support" ) ;
3897+ var sig = require ( "./signature" ) ;
38233898
38243899var MADE_BY_DOS = 0x00 ;
38253900var MADE_BY_UNIX = 0x03 ;
@@ -3943,6 +4018,36 @@ ZipEntry.prototype = {
39434018 this . fileComment = reader . readData ( this . fileCommentLength ) ;
39444019 } ,
39454020
4021+ /**
4022+ * Reads the local part of a zip file. Used when the central part of the zip is missing.
4023+ * @param {DataReader } reader Reader pointing to the start of local part header signature
4024+ * @throws if the header is invalid
4025+ */
4026+ readLocalPartFromCorruptedZip : function ( reader ) {
4027+ // Read everything in the possible header
4028+ reader . readAndCheckSignature ( sig . LOCAL_FILE_HEADER ) ;
4029+ this . versionMadeBy = reader . readInt ( 2 ) ;
4030+ this . bitFlag = reader . readInt ( 2 ) ;
4031+ this . compressionMethod = reader . readString ( 2 ) ;
4032+ this . date = reader . readDate ( ) ;
4033+ this . crc32 = reader . readInt ( 4 ) ;
4034+ this . compressedSize = reader . readInt ( 4 ) ;
4035+ this . uncompressedSize = reader . readInt ( 4 ) ;
4036+ this . fileNameLength = reader . readInt ( 2 ) ;
4037+ this . extraFieldsLength = reader . readInt ( 2 ) ;
4038+ this . fileName = reader . readData ( this . fileNameLength ) ;
4039+ this . readExtraFields ( reader ) ;
4040+ this . parseZIP64ExtraField ( reader ) ;
4041+
4042+ // TODO: more checks to verify that the header makes sense
4043+
4044+ var compression = findCompression ( this . compressionMethod ) ;
4045+ if ( compression === null ) {
4046+ throw new Error ( "Corrupted zip : compression " + utils . pretty ( this . compressionMethod ) + " unknown (inner file : " + utils . transformTo ( "string" , this . fileName ) + ")" ) ;
4047+ }
4048+ this . decompressed = new CompressedObject ( this . compressedSize , this . uncompressedSize , this . crc32 , compression , reader . readData ( this . compressedSize ) ) ;
4049+ } ,
4050+
39464051 /**
39474052 * Parse the external file attributes and get the unix/dos permissions.
39484053 */
@@ -4106,7 +4211,7 @@ ZipEntry.prototype = {
41064211} ;
41074212module . exports = ZipEntry ;
41084213
4109- } , { "./compressedObject" :2 , "./compressions" :3 , "./crc32" :4 , "./reader/readerFor" :22 , "./support" :30 , "./utf8" :31 , "./utils" :32 } ] , 35 :[ function ( require , module , exports ) {
4214+ } , { "./compressedObject" :2 , "./compressions" :3 , "./crc32" :4 , "./reader/readerFor" :22 , "./signature" : 23 , "./ support" :30 , "./utf8" :31 , "./utils" :32 } ] , 35 :[ function ( require , module , exports ) {
41104215"use strict" ;
41114216
41124217var StreamHelper = require ( "./stream/StreamHelper" ) ;
0 commit comments