TrinetraLabs/Placebo_AI
0
1"use strict";2var readerFor = require("./reader/readerFor");3var utils = require("./utils");4var sig = require("./signature");5var ZipEntry = require("./zipEntry");6var support = require("./support");7// class ZipEntries {{{8/**9 * All the entries in the zip file.10 * @constructor11 * @param {Object} loadOptions Options for loading the stream.12 */13function ZipEntries(loadOptions) {14 this.files = [];15 this.loadOptions = loadOptions;16}17ZipEntries.prototype = {18 /**19 * Check that the reader is on the specified signature.20 * @param {string} expectedSignature the expected signature.21 * @throws {Error} if it is an other signature.22 */23 checkSignature: function(expectedSignature) {24 if (!this.reader.readAndCheckSignature(expectedSignature)) {25 this.reader.index -= 4;26 var signature = this.reader.readString(4);27 throw new Error("Corrupted zip or bug: unexpected signature " + "(" + utils.pretty(signature) + ", expected " + utils.pretty(expectedSignature) + ")");28 }29 },30 /**31 * Check if the given signature is at the given index.32 * @param {number} askedIndex the index to check.33 * @param {string} expectedSignature the signature to expect.34 * @return {boolean} true if the signature is here, false otherwise.35 */36 isSignature: function(askedIndex, expectedSignature) {37 var currentIndex = this.reader.index;38 this.reader.setIndex(askedIndex);39 var signature = this.reader.readString(4);40 var result = signature === expectedSignature;41 this.reader.setIndex(currentIndex);42 return result;43 },44 /**45 * Read the end of the central directory.46 */47 readBlockEndOfCentral: function() {48 this.diskNumber = this.reader.readInt(2);49 this.diskWithCentralDirStart = this.reader.readInt(2);50 this.centralDirRecordsOnThisDisk = this.reader.readInt(2);51 this.centralDirRecords = this.reader.readInt(2);52 this.centralDirSize = this.reader.readInt(4);53 this.centralDirOffset = this.reader.readInt(4);54 55 this.zipCommentLength = this.reader.readInt(2);56 // warning : the encoding depends of the system locale57 // On a linux machine with LANG=en_US.utf8, this field is utf8 encoded.58 // On a windows machine, this field is encoded with the localized windows code page.59 var zipComment = this.reader.readData(this.zipCommentLength);60 var decodeParamType = support.uint8array ? "uint8array" : "array";61 // To get consistent behavior with the generation part, we will assume that62 // this is utf8 encoded unless specified otherwise.63 var decodeContent = utils.transformTo(decodeParamType, zipComment);64 this.zipComment = this.loadOptions.decodeFileName(decodeContent);65 },66 /**67 * Read the end of the Zip 64 central directory.68 * Not merged with the method readEndOfCentral :69 * The end of central can coexist with its Zip64 brother,70 * I don't want to read the wrong number of bytes !71 */72 readBlockZip64EndOfCentral: function() {73 this.zip64EndOfCentralSize = this.reader.readInt(8);74 this.reader.skip(4);75 // this.versionMadeBy = this.reader.readString(2);76 // this.versionNeeded = this.reader.readInt(2);77 this.diskNumber = this.reader.readInt(4);78 this.diskWithCentralDirStart = this.reader.readInt(4);79 this.centralDirRecordsOnThisDisk = this.reader.readInt(8);80 this.centralDirRecords = this.reader.readInt(8);81 this.centralDirSize = this.reader.readInt(8);82 this.centralDirOffset = this.reader.readInt(8);83 84 this.zip64ExtensibleData = {};85 var extraDataSize = this.zip64EndOfCentralSize - 44,86 index = 0,87 extraFieldId,88 extraFieldLength,89 extraFieldValue;90 while (index < extraDataSize) {91 extraFieldId = this.reader.readInt(2);92 extraFieldLength = this.reader.readInt(4);93 extraFieldValue = this.reader.readData(extraFieldLength);94 this.zip64ExtensibleData[extraFieldId] = {95 id: extraFieldId,96 length: extraFieldLength,97 value: extraFieldValue98 };99 }100 },101 /**102 * Read the end of the Zip 64 central directory locator.103 */104 readBlockZip64EndOfCentralLocator: function() {105 this.diskWithZip64CentralDirStart = this.reader.readInt(4);106 this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8);107 this.disksCount = this.reader.readInt(4);108 if (this.disksCount > 1) {109 throw new Error("Multi-volumes zip are not supported");110 }111 },112 /**113 * Read the local files, based on the offset read in the central part.114 */115 readLocalFiles: function() {116 var i, file;117 for (i = 0; i < this.files.length; i++) {118 file = this.files[i];119 this.reader.setIndex(file.localHeaderOffset);120 this.checkSignature(sig.LOCAL_FILE_HEADER);121 file.readLocalPart(this.reader);122 file.handleUTF8();123 file.processAttributes();124 }125 },126 /**127 * Read the central directory.128 */129 readCentralDir: function() {130 var file;131 132 this.reader.setIndex(this.centralDirOffset);133 while (this.reader.readAndCheckSignature(sig.CENTRAL_FILE_HEADER)) {134 file = new ZipEntry({135 zip64: this.zip64136 }, this.loadOptions);137 file.readCentralPart(this.reader);138 this.files.push(file);139 }140 141 if (this.centralDirRecords !== this.files.length) {142 if (this.centralDirRecords !== 0 && this.files.length === 0) {143 // We expected some records but couldn't find ANY.144 // This is really suspicious, as if something went wrong.145 throw new Error("Corrupted zip or bug: expected " + this.centralDirRecords + " records in central dir, got " + this.files.length);146 } else {147 // We found some records but not all.148 // Something is wrong but we got something for the user: no error here.149 // console.warn("expected", this.centralDirRecords, "records in central dir, got", this.files.length);150 }151 }152 },153 /**154 * Read the end of central directory.155 */156 readEndOfCentral: function() {157 var offset = this.reader.lastIndexOfSignature(sig.CENTRAL_DIRECTORY_END);158 if (offset < 0) {159 // Check if the content is a truncated zip or complete garbage.160 // A "LOCAL_FILE_HEADER" is not required at the beginning (auto161 // extractible zip for example) but it can give a good hint.162 // If an ajax request was used without responseType, we will also163 // get unreadable data.164 var isGarbage = !this.isSignature(0, sig.LOCAL_FILE_HEADER);165 166 if (isGarbage) {167 throw new Error("Can't find end of central directory : is this a zip file ? " +168 "If it is, see https://stuk.github.io/jszip/documentation/howto/read_zip.html");169 } else {170 throw new Error("Corrupted zip: can't find end of central directory");171 }172 173 }174 this.reader.setIndex(offset);175 var endOfCentralDirOffset = offset;176 this.checkSignature(sig.CENTRAL_DIRECTORY_END);177 this.readBlockEndOfCentral();178 179 180 /* extract from the zip spec :181 4) If one of the fields in the end of central directory182 record is too small to hold required data, the field183 should be set to -1 (0xFFFF or 0xFFFFFFFF) and the184 ZIP64 format record should be created.185 5) The end of central directory record and the186 Zip64 end of central directory locator record must187 reside on the same disk when splitting or spanning188 an archive.189 */190 if (this.diskNumber === utils.MAX_VALUE_16BITS || this.diskWithCentralDirStart === utils.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === utils.MAX_VALUE_16BITS || this.centralDirRecords === utils.MAX_VALUE_16BITS || this.centralDirSize === utils.MAX_VALUE_32BITS || this.centralDirOffset === utils.MAX_VALUE_32BITS) {191 this.zip64 = true;192 193 /*194 Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from195 the zip file can fit into a 32bits integer. This cannot be solved : JavaScript represents196 all numbers as 64-bit double precision IEEE 754 floating point numbers.197 So, we have 53bits for integers and bitwise operations treat everything as 32bits.198 see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators199 and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5200 */201 202 // should look for a zip64 EOCD locator203 offset = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);204 if (offset < 0) {205 throw new Error("Corrupted zip: can't find the ZIP64 end of central directory locator");206 }207 this.reader.setIndex(offset);208 this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);209 this.readBlockZip64EndOfCentralLocator();210 211 // now the zip64 EOCD record212 if (!this.isSignature(this.relativeOffsetEndOfZip64CentralDir, sig.ZIP64_CENTRAL_DIRECTORY_END)) {213 // console.warn("ZIP64 end of central directory not where expected.");214 this.relativeOffsetEndOfZip64CentralDir = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_END);215 if (this.relativeOffsetEndOfZip64CentralDir < 0) {216 throw new Error("Corrupted zip: can't find the ZIP64 end of central directory");217 }218 }219 this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir);220 this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_END);221 this.readBlockZip64EndOfCentral();222 }223 224 var expectedEndOfCentralDirOffset = this.centralDirOffset + this.centralDirSize;225 if (this.zip64) {226 expectedEndOfCentralDirOffset += 20; // end of central dir 64 locator227 expectedEndOfCentralDirOffset += 12 /* should not include the leading 12 bytes */ + this.zip64EndOfCentralSize;228 }229 230 var extraBytes = endOfCentralDirOffset - expectedEndOfCentralDirOffset;231 232 if (extraBytes > 0) {233 // console.warn(extraBytes, "extra bytes at beginning or within zipfile");234 if (this.isSignature(endOfCentralDirOffset, sig.CENTRAL_FILE_HEADER)) {235 // The offsets seem wrong, but we have something at the specified offset.236 // So… we keep it.237 } else {238 // the offset is wrong, update the "zero" of the reader239 // this happens if data has been prepended (crx files for example)240 this.reader.zero = extraBytes;241 }242 } else if (extraBytes < 0) {243 throw new Error("Corrupted zip: missing " + Math.abs(extraBytes) + " bytes.");244 }245 },246 prepareReader: function(data) {247 this.reader = readerFor(data);248 },249 /**250 * Read a zip file and create ZipEntries.251 * @param {String|ArrayBuffer|Uint8Array|Buffer} data the binary string representing a zip file.252 */253 load: function(data) {254 this.prepareReader(data);255 this.readEndOfCentral();256 this.readCentralDir();257 this.readLocalFiles();258 }259};260// }}} end of ZipEntries261module.exports = ZipEntries;262 