Skip to content

Commit

Permalink
Merge pull request #327 from Cruaier/fix_zip64_extra_field
Browse files Browse the repository at this point in the history
Fix zip64 extra field
  • Loading branch information
ZJONSSON authored Jul 14, 2024
2 parents d358d58 + 9965039 commit 1238dfc
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 10 deletions.
2 changes: 1 addition & 1 deletion lib/Open/directory.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ module.exports = function centralDirectory(source, options) {
// https://github.com/golang/go/blob/master/src/archive/zip/reader.go#L503
// For zip64 files, need to find zip64 central directory locator header to extract
// relative offset for zip64 central directory record.
if (vars.numberOfRecords == 0xffff|| vars.numberOfRecords == 0xffff ||
if (vars.diskNumber == 0xffff || vars.numberOfRecords == 0xffff ||
vars.offsetToStartOfCentralDirectory == 0xffffffff) {

// Offset to zip64 CDL is 20 bytes before normal CDR
Expand Down
19 changes: 11 additions & 8 deletions lib/parseExtraField.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@ module.exports = function(extraField, vars) {
while(!extra && extraField && extraField.length) {
const candidateExtra = parseBuffer.parse(extraField, [
['signature', 2],
['partsize', 2],
['uncompressedSize', 8],
['compressedSize', 8],
['offset', 8],
['disknum', 8],
['partSize', 2],
]);

if(candidateExtra.signature === 0x0001) {
extra = candidateExtra;
// parse buffer based on data in ZIP64 central directory; order is important!
const fieldsToExpect = [];
if (vars.uncompressedSize === 0xffffffff) fieldsToExpect.push(['uncompressedSize', 8]);
if (vars.compressedSize === 0xffffffff) fieldsToExpect.push(['compressedSize', 8]);
if (vars.offsetToLocalFileHeader === 0xffffffff) fieldsToExpect.push(['offsetToLocalFileHeader', 8]);

// slice off the 4 bytes for signature and partSize
extra = parseBuffer.parse(extraField.slice(4), fieldsToExpect);
} else {
// Advance the buffer to the next part.
// The total size of this part is the 4 byte header + partsize.
extraField = extraField.slice(candidateExtra.partsize + 4);
extraField = extraField.slice(candidateExtra.partSize + 4);
}
}

Expand All @@ -31,7 +34,7 @@ module.exports = function(extraField, vars) {
vars.uncompressedSize= extra.uncompressedSize;

if (vars.offsetToLocalFileHeader === 0xffffffff)
vars.offsetToLocalFileHeader= extra.offset;
vars.offsetToLocalFileHeader = extra.offsetToLocalFileHeader;

return extra;
};
73 changes: 72 additions & 1 deletion test/zip64.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const temp = require('temp');
const UNCOMPRESSED_SIZE = 5368709120;
const ZIP64_OFFSET = 72;
const ZIP64_SIZE = 36;
const ZIP64_EXTRA_FIELD_OFFSET = 0;

t.test('Correct uncompressed size for zip64', function (t) {
const archive = path.join(__dirname, '../testData/big.zip');
Expand Down Expand Up @@ -43,7 +44,77 @@ t.test('Correct uncompressed size for zip64', function (t) {
t.end();
});

t.test('Parse files from zip64 format correctly', function (t) {
t.test('Parse files with all zip64 extra fields correctly', function (t) {
const archive = path.join(__dirname, '../testData/zip64-allextrafields.zip');

t.test('in unzipper.Open', function(t) {
unzip.Open.file(archive)
.then(function(d) {
d.files[0].stream()
.on('vars', function(vars) {
t.same(vars.extra.uncompressedSize, ZIP64_SIZE, 'Open: Extra field');
t.same(vars.extra.compressedSize, ZIP64_SIZE, 'Open: Extra field');
t.same(vars.extra.offsetToLocalFileHeader, ZIP64_EXTRA_FIELD_OFFSET, 'Open: Extra field');
t.same(vars.uncompressedSize, ZIP64_SIZE, 'Open: File header');
t.same(vars.compressedSize, ZIP64_SIZE, 'Open: File header');
t.same(vars.offsetToLocalFileHeader, ZIP64_EXTRA_FIELD_OFFSET, 'Open: File header');
t.end();
})
.on('error', function(e) {
t.same(e.message, 'FILE_ENDED');
t.end();
});
});
});

t.test('in unzipper.extract', function (t) {
temp.mkdir('node-unzip-', function (err, dirPath) {
if (err) {
throw err;
}
fs.createReadStream(archive)
.pipe(unzip.Extract({ path: dirPath }))
.on('close', function() { t.end(); });
});
});

t.end();
});

t.test('Parse files with zip64 extra field with only offset length correctly', function (t) {
const archive = path.join(__dirname, '../testData/zip64-extrafieldoffsetlength.zip');

t.test('in unzipper.Open', function(t) {
unzip.Open.file(archive)
.then(function(d) {
d.files[0].stream()
.on('vars', function(vars) {
t.same(vars.extra.offsetToLocalFileHeader, ZIP64_EXTRA_FIELD_OFFSET, 'Open: Extra field');
t.same(vars.offsetToLocalFileHeader, ZIP64_EXTRA_FIELD_OFFSET, 'Open: File header');
t.end();
})
.on('error', function(e) {
t.same(e.message, 'FILE_ENDED');
t.end();
});
});
});

t.test('in unzipper.extract', function (t) {
temp.mkdir('node-unzip-', function (err, dirPath) {
if (err) {
throw err;
}
fs.createReadStream(archive)
.pipe(unzip.Extract({ path: dirPath }))
.on('close', function() { t.end(); });
});
});

t.end();
});

t.test('Parse files from regular zip64 format correctly', function (t) {
const archive = path.join(__dirname, '../testData/zip64.zip');

t.test('in unzipper.Open', function(t) {
Expand Down
Binary file added testData/zip64-allextrafields.zip
Binary file not shown.
Binary file added testData/zip64-extrafieldoffsetlength.zip
Binary file not shown.

0 comments on commit 1238dfc

Please sign in to comment.