mirror of
				https://github.com/flynx/PortableMag.git
				synced 2025-10-31 12:00:11 +00:00 
			
		
		
		
	
		
			
	
	
		
			546 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			546 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | /** | ||
|  | 
 | ||
|  | JSZip - A Javascript class for generating and reading zip files | ||
|  | <http://stuartk.com/jszip>
 | ||
|  | 
 | ||
|  | (c) 2011 David Duponchel <d.duponchel@gmail.com> | ||
|  | Dual licenced under the MIT license or GPLv3. See LICENSE.markdown. | ||
|  | 
 | ||
|  | **/ | ||
|  | /*global JSZip,JSZipBase64 */ | ||
|  | (function () { | ||
|  | 
 | ||
|  |    var MAX_VALUE_16BITS = 65535; | ||
|  |    var MAX_VALUE_32BITS = -1; // well, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" is parsed as -1
 | ||
|  | 
 | ||
|  |    /** | ||
|  |     * Prettify a string read as binary. | ||
|  |     * @param {string} str the string to prettify. | ||
|  |     * @return {string} a pretty string. | ||
|  |     */ | ||
|  |    var pretty = function (str) { | ||
|  |       var res = '', code, i; | ||
|  |       for (i = 0; i < (str||"").length; i++) { | ||
|  |          code = str.charCodeAt(i); | ||
|  |          res += '\\x' + (code < 16 ? "0" : "") + code.toString(16).toUpperCase(); | ||
|  |       } | ||
|  |       return res; | ||
|  |    }; | ||
|  | 
 | ||
|  |    /** | ||
|  |     * Find a compression registered in JSZip. | ||
|  |     * @param {string} compressionMethod the method magic to find. | ||
|  |     * @return {Object|null} the JSZip compression object, null if none found. | ||
|  |     */ | ||
|  |    var findCompression = function (compressionMethod) { | ||
|  |       for (var method in JSZip.compressions) { | ||
|  |          if( !JSZip.compressions.hasOwnProperty(method) ) { continue; } | ||
|  |          if (JSZip.compressions[method].magic === compressionMethod) { | ||
|  |             return JSZip.compressions[method]; | ||
|  |          } | ||
|  |       } | ||
|  |       return null; | ||
|  |    }; | ||
|  | 
 | ||
|  |    // class StreamReader {{{
 | ||
|  |    /** | ||
|  |     * Read bytes from a stream. | ||
|  |     * Developer tip : when debugging, a watch on pretty(this.reader.stream.slice(this.reader.index)) | ||
|  |     * is very useful :) | ||
|  |     * @constructor | ||
|  |     * @param {String|ArrayBuffer|Uint8Array} stream the stream to read. | ||
|  |     */ | ||
|  |    function StreamReader(stream) { | ||
|  |       this.stream = ""; | ||
|  |       if (JSZip.support.uint8array && stream instanceof Uint8Array) { | ||
|  |          this.stream = JSZip.utils.uint8Array2String(stream); | ||
|  |       } else if (JSZip.support.arraybuffer && stream instanceof ArrayBuffer) { | ||
|  |          var bufferView = new Uint8Array(stream); | ||
|  |          this.stream = JSZip.utils.uint8Array2String(bufferView); | ||
|  |       } else { | ||
|  |          this.stream = JSZip.utils.string2binary(stream); | ||
|  |       } | ||
|  |       this.index = 0; | ||
|  |    } | ||
|  |    StreamReader.prototype = { | ||
|  |       /** | ||
|  |        * Check that the offset will not go too far. | ||
|  |        * @param {string} offset the additional offset to check. | ||
|  |        * @throws {Error} an Error if the offset is out of bounds. | ||
|  |        */ | ||
|  |       checkOffset : function (offset) { | ||
|  |          this.checkIndex(this.index + offset); | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Check that the specifed index will not be too far. | ||
|  |        * @param {string} newIndex the index to check. | ||
|  |        * @throws {Error} an Error if the index is out of bounds. | ||
|  |        */ | ||
|  |       checkIndex : function (newIndex) { | ||
|  |          if (this.stream.length < newIndex || newIndex < 0) { | ||
|  |             throw new Error("End of stream reached (stream length = " + | ||
|  |                             this.stream.length + ", asked index = " + | ||
|  |                             (newIndex) + "). Corrupted zip ?"); | ||
|  |          } | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Change the index. | ||
|  |        * @param {number} newIndex The new index. | ||
|  |        * @throws {Error} if the new index is out of the stream. | ||
|  |        */ | ||
|  |       setIndex : function (newIndex) { | ||
|  |          this.checkIndex(newIndex); | ||
|  |          this.index = newIndex; | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Skip the next n bytes. | ||
|  |        * @param {number} n the number of bytes to skip. | ||
|  |        * @throws {Error} if the new index is out of the stream. | ||
|  |        */ | ||
|  |       skip : function (n) { | ||
|  |          this.setIndex(this.index + n); | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Get the byte at the specified index. | ||
|  |        * @param {number} i the index to use. | ||
|  |        * @return {number} a byte. | ||
|  |        */ | ||
|  |       byteAt : function(i) { | ||
|  |          return this.stream.charCodeAt(i); | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Get the next number with a given byte size. | ||
|  |        * @param {number} size the number of bytes to read. | ||
|  |        * @return {number} the corresponding number. | ||
|  |        */ | ||
|  |       readInt : function (size) { | ||
|  |          var result = 0, i; | ||
|  |          this.checkOffset(size); | ||
|  |          for(i = this.index + size - 1; i >= this.index; i--) { | ||
|  |             result = (result << 8) + this.byteAt(i); | ||
|  |          } | ||
|  |          this.index += size; | ||
|  |          return result; | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Get the next string with a given byte size. | ||
|  |        * @param {number} size the number of bytes to read. | ||
|  |        * @return {string} the corresponding string. | ||
|  |        */ | ||
|  |       readString : function (size) { | ||
|  |          this.checkOffset(size); | ||
|  |          // this will work because the constructor applied the "& 0xff" mask.
 | ||
|  |          var result = this.stream.slice(this.index, this.index + size); | ||
|  |          this.index += size; | ||
|  |          return result; | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Get the next date. | ||
|  |        * @return {Date} the date. | ||
|  |        */ | ||
|  |       readDate : function () { | ||
|  |          var dostime = this.readInt(4); | ||
|  |          return new Date( | ||
|  |             ((dostime >> 25) & 0x7f) + 1980, // year
 | ||
|  |             ((dostime >> 21) & 0x0f) - 1, // month
 | ||
|  |             (dostime >> 16) & 0x1f, // day
 | ||
|  |             (dostime >> 11) & 0x1f, // hour
 | ||
|  |             (dostime >> 5) & 0x3f, // minute
 | ||
|  |             (dostime & 0x1f) << 1); // second
 | ||
|  |       } | ||
|  |    }; | ||
|  |    // }}} end of StreamReader
 | ||
|  | 
 | ||
|  |    // class ZipEntry {{{
 | ||
|  |    /** | ||
|  |     * An entry in the zip file. | ||
|  |     * @constructor | ||
|  |     * @param {Object} options Options of the current file. | ||
|  |     * @param {Object} loadOptions Options for loading the stream. | ||
|  |     */ | ||
|  |    function ZipEntry(options, loadOptions) { | ||
|  |       this.options = options; | ||
|  |       this.loadOptions = loadOptions; | ||
|  |    } | ||
|  |    ZipEntry.prototype = { | ||
|  |       /** | ||
|  |        * say if the file is encrypted. | ||
|  |        * @return {boolean} true if the file is encrypted, false otherwise. | ||
|  |        */ | ||
|  |       isEncrypted : function () { | ||
|  |          // bit 1 is set
 | ||
|  |          return (this.bitFlag & 0x0001) === 0x0001; | ||
|  |       }, | ||
|  |       /** | ||
|  |        * say if the file has utf-8 filename/comment. | ||
|  |        * @return {boolean} true if the filename/comment is in utf-8, false otherwise. | ||
|  |        */ | ||
|  |       useUTF8 : function () { | ||
|  |          // bit 11 is set
 | ||
|  |          return (this.bitFlag & 0x0800) === 0x0800; | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Read the local part of a zip file and add the info in this object. | ||
|  |        * @param {StreamReader} reader the reader to use. | ||
|  |        */ | ||
|  |       readLocalPart : function(reader) { | ||
|  |          var compression, localExtraFieldsLength; | ||
|  | 
 | ||
|  |          // we already know everything from the central dir !
 | ||
|  |          // If the central dir data are false, we are doomed.
 | ||
|  |          // On the bright side, the local part is scary  : zip64, data descriptors, both, etc.
 | ||
|  |          // The less data we get here, the more reliable this should be.
 | ||
|  |          // Let's skip the whole header and dash to the data !
 | ||
|  |          reader.skip(22); | ||
|  |          // in some zip created on windows, the filename stored in the central dir contains \ instead of /.
 | ||
|  |          // Strangely, the filename here is OK.
 | ||
|  |          // I would love to treat these zip files as corrupted (see http://www.info-zip.org/FAQ.html#backslashes
 | ||
|  |          // or APPNOTE#4.4.17.1, "All slashes MUST be forward slashes '/'") but there are a lot of bad zip generators...
 | ||
|  |          // Search "unzip mismatching "local" filename continuing with "central" filename version" on
 | ||
|  |          // the internet.
 | ||
|  |          //
 | ||
|  |          // I think I see the logic here : the central directory is used to display
 | ||
|  |          // content and the local directory is used to extract the files. Mixing / and \
 | ||
|  |          // may be used to display \ to windows users and use / when extracting the files.
 | ||
|  |          // Unfortunately, this lead also to some issues : http://seclists.org/fulldisclosure/2009/Sep/394
 | ||
|  |          this.fileNameLength = reader.readInt(2); | ||
|  |          localExtraFieldsLength = reader.readInt(2); // can't be sure this will be the same as the central dir
 | ||
|  |          this.fileName = reader.readString(this.fileNameLength); | ||
|  |          reader.skip(localExtraFieldsLength); | ||
|  | 
 | ||
|  |          if (this.compressedSize == -1 || this.uncompressedSize == -1) { | ||
|  |             throw new Error("Bug or corrupted zip : didn't get enough informations from the central directory " + | ||
|  |                             "(compressedSize == -1 || uncompressedSize == -1)"); | ||
|  |          } | ||
|  |          this.compressedFileData = reader.readString(this.compressedSize); | ||
|  | 
 | ||
|  |          compression = findCompression(this.compressionMethod); | ||
|  |          if (compression === null) { // no compression found
 | ||
|  |             throw new Error("Corrupted zip : compression " + pretty(this.compressionMethod) + | ||
|  |                             " unknown (inner file : " + this.fileName + ")"); | ||
|  |          } | ||
|  |          this.uncompressedFileData = compression.uncompress(this.compressedFileData); | ||
|  | 
 | ||
|  |          if (this.uncompressedFileData.length !== this.uncompressedSize) { | ||
|  |             throw new Error("Bug : uncompressed data size mismatch"); | ||
|  |          } | ||
|  | 
 | ||
|  |          if (this.loadOptions.checkCRC32 && JSZip.prototype.crc32(this.uncompressedFileData) !== this.crc32) { | ||
|  |             throw new Error("Corrupted zip : CRC32 mismatch"); | ||
|  |          } | ||
|  |       }, | ||
|  | 
 | ||
|  |       /** | ||
|  |        * Read the central part of a zip file and add the info in this object. | ||
|  |        * @param {StreamReader} reader the reader to use. | ||
|  |        */ | ||
|  |       readCentralPart : function(reader) { | ||
|  |          this.versionMadeBy          = reader.readString(2); | ||
|  |          this.versionNeeded          = reader.readInt(2); | ||
|  |          this.bitFlag                = reader.readInt(2); | ||
|  |          this.compressionMethod      = reader.readString(2); | ||
|  |          this.date                   = reader.readDate(); | ||
|  |          this.crc32                  = reader.readInt(4); | ||
|  |          this.compressedSize         = reader.readInt(4); | ||
|  |          this.uncompressedSize       = reader.readInt(4); | ||
|  |          this.fileNameLength         = reader.readInt(2); | ||
|  |          this.extraFieldsLength      = reader.readInt(2); | ||
|  |          this.fileCommentLength      = reader.readInt(2); | ||
|  |          this.diskNumberStart        = reader.readInt(2); | ||
|  |          this.internalFileAttributes = reader.readInt(2); | ||
|  |          this.externalFileAttributes = reader.readInt(4); | ||
|  |          this.localHeaderOffset      = reader.readInt(4); | ||
|  | 
 | ||
|  |          if (this.isEncrypted()) { | ||
|  |             throw new Error("Encrypted zip are not supported"); | ||
|  |          } | ||
|  | 
 | ||
|  |          this.fileName = reader.readString(this.fileNameLength); | ||
|  |          this.readExtraFields(reader); | ||
|  |          this.parseZIP64ExtraField(reader); | ||
|  |          this.fileComment = reader.readString(this.fileCommentLength); | ||
|  | 
 | ||
|  |          // warning, this is true only for zip with madeBy == DOS (plateform dependent feature)
 | ||
|  |          this.dir = this.externalFileAttributes & 0x00000010 ? true : false; | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Parse the ZIP64 extra field and merge the info in the current ZipEntry. | ||
|  |        * @param {StreamReader} reader the reader to use. | ||
|  |        */ | ||
|  |       parseZIP64ExtraField : function(reader) { | ||
|  | 
 | ||
|  |          if(!this.extraFields[0x0001]) { | ||
|  |             return; | ||
|  |          } | ||
|  | 
 | ||
|  |          // should be something, preparing the extra reader
 | ||
|  |          var extraReader = new StreamReader(this.extraFields[0x0001].value); | ||
|  | 
 | ||
|  |          // I really hope that these 64bits integer can fit in 32 bits integer, because js
 | ||
|  |          // won't let us have more.
 | ||
|  |          if(this.uncompressedSize === MAX_VALUE_32BITS) { | ||
|  |             this.uncompressedSize = extraReader.readInt(8); | ||
|  |          } | ||
|  |          if(this.compressedSize === MAX_VALUE_32BITS) { | ||
|  |             this.compressedSize = extraReader.readInt(8); | ||
|  |          } | ||
|  |          if(this.localHeaderOffset === MAX_VALUE_32BITS) { | ||
|  |             this.localHeaderOffset = extraReader.readInt(8); | ||
|  |          } | ||
|  |          if(this.diskNumberStart === MAX_VALUE_32BITS) { | ||
|  |             this.diskNumberStart = extraReader.readInt(4); | ||
|  |          } | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Read the central part of a zip file and add the info in this object. | ||
|  |        * @param {StreamReader} reader the reader to use. | ||
|  |        */ | ||
|  |       readExtraFields : function(reader) { | ||
|  |          var start = reader.index, | ||
|  |              extraFieldId, | ||
|  |              extraFieldLength, | ||
|  |              extraFieldValue; | ||
|  | 
 | ||
|  |          this.extraFields = this.extraFields || {}; | ||
|  | 
 | ||
|  |          while (reader.index < start + this.extraFieldsLength) { | ||
|  |             extraFieldId     = reader.readInt(2); | ||
|  |             extraFieldLength = reader.readInt(2); | ||
|  |             extraFieldValue  = reader.readString(extraFieldLength); | ||
|  | 
 | ||
|  |             this.extraFields[extraFieldId] = { | ||
|  |                id:     extraFieldId, | ||
|  |                length: extraFieldLength, | ||
|  |                value:  extraFieldValue | ||
|  |             }; | ||
|  |          } | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Apply an UTF8 transformation if needed. | ||
|  |        */ | ||
|  |       handleUTF8 : function() { | ||
|  |          if (this.useUTF8()) { | ||
|  |             this.fileName    = JSZip.prototype.utf8decode(this.fileName); | ||
|  |             this.fileComment = JSZip.prototype.utf8decode(this.fileComment); | ||
|  |          } | ||
|  |       } | ||
|  |    }; | ||
|  |    // }}} end of ZipEntry
 | ||
|  | 
 | ||
|  |    //  class ZipEntries {{{
 | ||
|  |    /** | ||
|  |     * All the entries in the zip file. | ||
|  |     * @constructor | ||
|  |     * @param {String|ArrayBuffer|Uint8Array} data the binary stream to load. | ||
|  |     * @param {Object} loadOptions Options for loading the stream. | ||
|  |     */ | ||
|  |    function ZipEntries(data, loadOptions) { | ||
|  |       this.files = []; | ||
|  |       this.loadOptions = loadOptions; | ||
|  |       if (data) { | ||
|  |          this.load(data); | ||
|  |       } | ||
|  |    } | ||
|  |    ZipEntries.prototype = { | ||
|  |       /** | ||
|  |        * Check that the reader is on the speficied signature. | ||
|  |        * @param {string} expectedSignature the expected signature. | ||
|  |        * @throws {Error} if it is an other signature. | ||
|  |        */ | ||
|  |       checkSignature : function(expectedSignature) { | ||
|  |          var signature = this.reader.readString(4); | ||
|  |          if (signature !== expectedSignature) { | ||
|  |             throw new Error("Corrupted zip or bug : unexpected signature " + | ||
|  |                             "(" + pretty(signature) + ", expected " + pretty(expectedSignature) + ")"); | ||
|  |          } | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Read the end of the central directory. | ||
|  |        */ | ||
|  |       readBlockEndOfCentral : function () { | ||
|  |          this.diskNumber                  = this.reader.readInt(2); | ||
|  |          this.diskWithCentralDirStart     = this.reader.readInt(2); | ||
|  |          this.centralDirRecordsOnThisDisk = this.reader.readInt(2); | ||
|  |          this.centralDirRecords           = this.reader.readInt(2); | ||
|  |          this.centralDirSize              = this.reader.readInt(4); | ||
|  |          this.centralDirOffset            = this.reader.readInt(4); | ||
|  | 
 | ||
|  |          this.zipCommentLength            = this.reader.readInt(2); | ||
|  |          this.zipComment                  = this.reader.readString(this.zipCommentLength); | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Read the end of the Zip 64 central directory. | ||
|  |        * Not merged with the method readEndOfCentral : | ||
|  |        * The end of central can coexist with its Zip64 brother, | ||
|  |        * I don't want to read the wrong number of bytes ! | ||
|  |        */ | ||
|  |       readBlockZip64EndOfCentral : function () { | ||
|  |          this.zip64EndOfCentralSize       = this.reader.readInt(8); | ||
|  |          this.versionMadeBy               = this.reader.readString(2); | ||
|  |          this.versionNeeded               = this.reader.readInt(2); | ||
|  |          this.diskNumber                  = this.reader.readInt(4); | ||
|  |          this.diskWithCentralDirStart     = this.reader.readInt(4); | ||
|  |          this.centralDirRecordsOnThisDisk = this.reader.readInt(8); | ||
|  |          this.centralDirRecords           = this.reader.readInt(8); | ||
|  |          this.centralDirSize              = this.reader.readInt(8); | ||
|  |          this.centralDirOffset            = this.reader.readInt(8); | ||
|  | 
 | ||
|  |          this.zip64ExtensibleData = {}; | ||
|  |          var extraDataSize = this.zip64EndOfCentralSize - 44, | ||
|  |          index = 0, | ||
|  |          extraFieldId, | ||
|  |          extraFieldLength, | ||
|  |          extraFieldValue; | ||
|  |          while(index < extraDataSize) { | ||
|  |             extraFieldId     = this.reader.readInt(2); | ||
|  |             extraFieldLength = this.reader.readInt(4); | ||
|  |             extraFieldValue  = this.reader.readString(extraFieldLength); | ||
|  |             this.zip64ExtensibleData[extraFieldId] = { | ||
|  |                id:     extraFieldId, | ||
|  |                length: extraFieldLength, | ||
|  |                value:  extraFieldValue | ||
|  |             }; | ||
|  |          } | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Read the end of the Zip 64 central directory locator. | ||
|  |        */ | ||
|  |       readBlockZip64EndOfCentralLocator : function () { | ||
|  |          this.diskWithZip64CentralDirStart       = this.reader.readInt(4); | ||
|  |          this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8); | ||
|  |          this.disksCount                         = this.reader.readInt(4); | ||
|  |          if (this.disksCount > 1) { | ||
|  |             throw new Error("Multi-volumes zip are not supported"); | ||
|  |          } | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Read the local files, based on the offset read in the central part. | ||
|  |        */ | ||
|  |       readLocalFiles : function() { | ||
|  |          var i, file; | ||
|  |          for(i = 0; i < this.files.length; i++) { | ||
|  |             file = this.files[i]; | ||
|  |             this.reader.setIndex(file.localHeaderOffset); | ||
|  |             this.checkSignature(JSZip.signature.LOCAL_FILE_HEADER); | ||
|  |             file.readLocalPart(this.reader); | ||
|  |             file.handleUTF8(); | ||
|  |          } | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Read the central directory. | ||
|  |        */ | ||
|  |       readCentralDir : function() { | ||
|  |          var file; | ||
|  | 
 | ||
|  |          this.reader.setIndex(this.centralDirOffset); | ||
|  |          while(this.reader.readString(4) === JSZip.signature.CENTRAL_FILE_HEADER) { | ||
|  |             file = new ZipEntry({ | ||
|  |                zip64: this.zip64 | ||
|  |             }, this.loadOptions); | ||
|  |             file.readCentralPart(this.reader); | ||
|  |             this.files.push(file); | ||
|  |          } | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Read the end of central directory. | ||
|  |        */ | ||
|  |       readEndOfCentral : function() { | ||
|  |             var offset = this.reader.stream.lastIndexOf(JSZip.signature.CENTRAL_DIRECTORY_END); | ||
|  |             if (offset === -1) { | ||
|  |                throw new Error("Corrupted zip : can't find end of central directory"); | ||
|  |             } | ||
|  |             this.reader.setIndex(offset); | ||
|  |             this.checkSignature(JSZip.signature.CENTRAL_DIRECTORY_END); | ||
|  |             this.readBlockEndOfCentral(); | ||
|  | 
 | ||
|  |           | ||
|  |             /* extract from the zip spec : | ||
|  |                4)  If one of the fields in the end of central directory | ||
|  |                    record is too small to hold required data, the field | ||
|  |                    should be set to -1 (0xFFFF or 0xFFFFFFFF) and the | ||
|  |                    ZIP64 format record should be created. | ||
|  |                5)  The end of central directory record and the | ||
|  |                    Zip64 end of central directory locator record must | ||
|  |                    reside on the same disk when splitting or spanning | ||
|  |                    an archive. | ||
|  |             */ | ||
|  |             if (  this.diskNumber                  === MAX_VALUE_16BITS | ||
|  |                || this.diskWithCentralDirStart     === MAX_VALUE_16BITS | ||
|  |                || this.centralDirRecordsOnThisDisk === MAX_VALUE_16BITS | ||
|  |                || this.centralDirRecords           === MAX_VALUE_16BITS | ||
|  |                || this.centralDirSize              === MAX_VALUE_32BITS | ||
|  |                || this.centralDirOffset            === MAX_VALUE_32BITS | ||
|  |             ) { | ||
|  |                this.zip64 = true; | ||
|  | 
 | ||
|  |                /* | ||
|  |                Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from | ||
|  |                the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents | ||
|  |                all numbers as 64-bit double precision IEEE 754 floating point numbers. | ||
|  |                So, we have 53bits for integers and bitwise operations treat everything as 32bits. | ||
|  |                see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators
 | ||
|  |                and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5
 | ||
|  |                */ | ||
|  | 
 | ||
|  |                // should look for a zip64 EOCD locator
 | ||
|  |                offset = this.reader.stream.lastIndexOf(JSZip.signature.ZIP64_CENTRAL_DIRECTORY_LOCATOR); | ||
|  |                if (offset === -1) { | ||
|  |                   throw new Error("Corrupted zip : can't find the ZIP64 end of central directory locator"); | ||
|  |                } | ||
|  |                this.reader.setIndex(offset); | ||
|  |                this.checkSignature(JSZip.signature.ZIP64_CENTRAL_DIRECTORY_LOCATOR); | ||
|  |                this.readBlockZip64EndOfCentralLocator(); | ||
|  | 
 | ||
|  |                // now the zip64 EOCD record
 | ||
|  |                this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir); | ||
|  |                this.checkSignature(JSZip.signature.ZIP64_CENTRAL_DIRECTORY_END); | ||
|  |                this.readBlockZip64EndOfCentral(); | ||
|  |             } | ||
|  |       }, | ||
|  |       /** | ||
|  |        * Read a zip file and create ZipEntries. | ||
|  |        * @param {String|ArrayBuffer|Uint8Array} data the binary string representing a zip file. | ||
|  |        */ | ||
|  |       load : function(data) { | ||
|  |          this.reader = new StreamReader(data); | ||
|  | 
 | ||
|  |          this.readEndOfCentral(); | ||
|  |          this.readCentralDir(); | ||
|  |          this.readLocalFiles(); | ||
|  |       } | ||
|  |    }; | ||
|  |    // }}} end of ZipEntries
 | ||
|  | 
 | ||
|  |    /** | ||
|  |     * Implementation of the load method of JSZip. | ||
|  |     * It uses the above classes to decode a zip file, and load every files. | ||
|  |     * @param {String|ArrayBuffer|Uint8Array} data the data to load. | ||
|  |     * @param {Object} options Options for loading the stream. | ||
|  |     *  options.base64 : is the stream in base64 ? default : false | ||
|  |     */ | ||
|  |    JSZip.prototype.load = function(data, options) { | ||
|  |       var files, zipEntries, i, input; | ||
|  |       options = options || {}; | ||
|  |       if(options.base64) { | ||
|  |          data = JSZipBase64.decode(data); | ||
|  |       } | ||
|  | 
 | ||
|  |       zipEntries = new ZipEntries(data, options); | ||
|  |       files = zipEntries.files; | ||
|  |       for (i = 0; i < files.length; i++) { | ||
|  |          input = files[i]; | ||
|  |          this.file(input.fileName, input.uncompressedFileData, { | ||
|  |             binary:true, | ||
|  |             optimizedBinaryString:true, | ||
|  |             date:input.date, | ||
|  |             dir:input.dir | ||
|  |          }); | ||
|  |       } | ||
|  | 
 | ||
|  |       return this; | ||
|  |    }; | ||
|  | 
 | ||
|  | }()); | ||
|  | // enforcing Stuk's coding style
 | ||
|  | // vim: set shiftwidth=3 softtabstop=3 foldmethod=marker:
 |