diff --git a/test/assets/maximum3.zip b/test/assets/maximum3.zip new file mode 100644 index 0000000..a382338 Binary files /dev/null and b/test/assets/maximum3.zip differ diff --git a/test/methods/methods.test.js b/test/methods/methods.test.js index dc4405a..e02c588 100644 --- a/test/methods/methods.test.js +++ b/test/methods/methods.test.js @@ -121,6 +121,7 @@ describe("adm-zip.js - methods handling local files", () => { }); describe(".extractEntryTo() - sync", () => { + // each entry one by one it("zip.extractEntryTo(entry, destination, false, true)", () => { const zip = new Zip("./test/assets/ultra.zip"); var zipEntries = zip.getEntries(); @@ -132,6 +133,7 @@ describe("adm-zip.js - methods handling local files", () => { expect(files.sort()).to.deep.equal(ultrazip.sort()); }); + // each entry one by one it("zip.extractEntryTo(entry, destination, true, true)", () => { const zip = new Zip("./test/assets/ultra.zip"); var zipEntries = zip.getEntries(); @@ -149,6 +151,58 @@ describe("adm-zip.js - methods handling local files", () => { expect(files.sort()).to.deep.equal(ultrazip.sort()); }); + + it("zip.extractEntryTo(entry, destination, false, true) - [ extract folder from file where folders exists ]", () => { + const zip = new Zip("./test/assets/maximum.zip"); + + zip.extractEntryTo("./attributes_test/New folder/", destination, false, true); + + const files = walk(destination); + const maximumzip = ["hidden.txt", "hidden_readonly.txt", "readonly.txt", "somefile.txt"].map(wrapList); + + expect(files.sort()).to.deep.equal(maximumzip.sort()); + }); + + it("zip.extractEntryTo(entry, destination, false, true) - [ extract folder from file where folders does not exists ]", () => { + const zip = new Zip("./test/assets/maximum3.zip"); + + zip.extractEntryTo("./attributes_test/New folder/", destination, false, true); + + const files = walk(destination); + const maximumzip = ["hidden.txt", "hidden_readonly.txt", "readonly.txt", "somefile.txt"].map(wrapList); + + expect(files.sort()).to.deep.equal(maximumzip.sort()); + }); + + it("zip.extractEntryTo(entry, destination, true, true) - [ extract folder from file where folders exists ]", () => { + const zip = new Zip("./test/assets/maximum.zip"); + + zip.extractEntryTo("./attributes_test/New folder/", destination, true, true); + + const files = walk(destination); + const maximumzip = [ + "./attributes_test/New folder/hidden.txt", + "./attributes_test/New folder/hidden_readonly.txt", + "./attributes_test/New folder/readonly.txt", + "./attributes_test/New folder/somefile.txt" + ].map(wrapList); + expect(files.sort()).to.deep.equal(maximumzip.sort()); + }); + + it("zip.extractEntryTo(entry, destination, true, true) - [ extract folder from file where folders does not exists ]", () => { + const zip = new Zip("./test/assets/maximum3.zip"); + + zip.extractEntryTo("./attributes_test/New folder/", destination, true, true); + + const files = walk(destination); + const maximumzip = [ + "./attributes_test/New folder/hidden.txt", + "./attributes_test/New folder/hidden_readonly.txt", + "./attributes_test/New folder/readonly.txt", + "./attributes_test/New folder/somefile.txt" + ].map(wrapList); + expect(files.sort()).to.deep.equal(maximumzip.sort()); + }); }); describe(".addLocalFolder() - sync", () => { diff --git a/zipFile.js b/zipFile.js index d269e1c..43e69fe 100644 --- a/zipFile.js +++ b/zipFile.js @@ -9,6 +9,7 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) { mainHeader = new Headers.MainHeader(), loadedEntries = false; var password = null; + const temporary = new Set(); // assign options const opts = options; @@ -23,20 +24,31 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) { loadedEntries = true; } - function iterateEntries(callback) { - const totalEntries = mainHeader.diskEntries; // total number of entries - let index = mainHeader.offset; // offset of first CEN header - - for (let i = 0; i < totalEntries; i++) { - let tmp = index; - const entry = new ZipEntry(opts, inBuffer); - - entry.header = inBuffer.slice(tmp, (tmp += Utils.Constants.CENHDR)); - entry.entryName = inBuffer.slice(tmp, (tmp += entry.header.fileNameLength)); - - index += entry.header.centralHeaderSize; + function makeTemporaryFolders() { + const foldersList = new Set(); + + // Make list of all folders in file + for (const elem of Object.keys(entryTable)) { + const elements = elem.split("/"); + elements.pop(); // filename + if (!elements.length) continue; // no folders + for (let i = 0; i < elements.length; i++) { + const sub = elements.slice(0, i + 1).join("/") + "/"; + foldersList.add(sub); + } + } - callback(entry); + // create missing folders as temporary + for (const elem of foldersList) { + if (!(elem in entryTable)) { + const tempfolder = new ZipEntry(opts); + tempfolder.entryName = elem; + tempfolder.attr = 0x10; + tempfolder.temporary = true; + entryList.push(tempfolder); + entryTable[tempfolder.entryName] = tempfolder; + temporary.add(tempfolder); + } } } @@ -66,6 +78,8 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) { entryList[i] = entry; entryTable[entry.entryName] = entry; } + temporary.clear(); + makeTemporaryFolders(); } function readMainHeader(/*Boolean*/ readNow) { @@ -130,7 +144,7 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) { if (!loadedEntries) { readEntries(); } - return entryList; + return entryList.filter((e) => !temporary.has(e)); }, /** @@ -154,12 +168,7 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) { }, forEach: function (callback) { - if (!loadedEntries) { - iterateEntries(callback); - return; - } - - entryList.forEach(callback); + this.entries.forEach(callback); }, /** @@ -289,7 +298,7 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) { mainHeader.offset = 0; totalEntries = 0; - for (const entry of entryList) { + for (const entry of this.entries) { // compress data and set local and entry header accordingly. Reason why is called first const compressedData = entry.getCompressedData(); entry.header.offset = dindex; @@ -430,7 +439,7 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) { } }; - compress2Buffer(Array.from(entryList)); + compress2Buffer(Array.from(this.entries)); } catch (e) { onFail(e); }