Skip to content

Commit d7a748c

Browse files
Add partial support for zip64 (larger number of entries)
1 parent ff17ae8 commit d7a748c

File tree

4 files changed

+83
-15
lines changed

4 files changed

+83
-15
lines changed

Diff for: headers/mainHeader.js

+29-11
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,37 @@ module.exports = function () {
3131

3232
loadFromBinary : function(/*Buffer*/data) {
3333
// data should be 22 bytes and start with "PK 05 06"
34-
if (data.length !== Constants.ENDHDR || data.readUInt32LE(0) !== Constants.ENDSIG)
34+
// or be 56+ bytes and start with "PK 06 06" for Zip64
35+
if ((data.length !== Constants.ENDHDR || data.readUInt32LE(0) !== Constants.ENDSIG) &&
36+
(data.length < Constants.ZIP64HDR || data.readUInt32LE(0) !== Constants.ZIP64SIG)) {
37+
3538
throw Utils.Errors.INVALID_END;
39+
}
40+
41+
if (data.readUInt32LE(0) === Constants.ENDSIG) {
42+
// number of entries on this volume
43+
_volumeEntries = data.readUInt16LE(Constants.ENDSUB);
44+
// total number of entries
45+
_totalEntries = data.readUInt16LE(Constants.ENDTOT);
46+
// central directory size in bytes
47+
_size = data.readUInt32LE(Constants.ENDSIZ);
48+
// offset of first CEN header
49+
_offset = data.readUInt32LE(Constants.ENDOFF);
50+
// zip file comment length
51+
_commentLength = data.readUInt16LE(Constants.ENDCOM);
52+
} else {
53+
// number of entries on this volume
54+
_volumeEntries = Utils.readBigUInt64LE(data, Constants.ZIP64SUB);
55+
// total number of entries
56+
_totalEntries = Utils.readBigUInt64LE(data, Constants.ZIP64TOT);
57+
// central directory size in bytes
58+
_size = Utils.readBigUInt64LE(data, Constants.ZIP64SIZ);
59+
// offset of first CEN header
60+
_offset = Utils.readBigUInt64LE(data, Constants.ZIP64OFF);
61+
62+
_commentLength = 0;
63+
}
3664

37-
// number of entries on this volume
38-
_volumeEntries = data.readUInt16LE(Constants.ENDSUB);
39-
// total number of entries
40-
_totalEntries = data.readUInt16LE(Constants.ENDTOT);
41-
// central directory size in bytes
42-
_size = data.readUInt32LE(Constants.ENDSIZ);
43-
// offset of first CEN header
44-
_offset = data.readUInt32LE(Constants.ENDOFF);
45-
// zip file comment length
46-
_commentLength = data.readUInt16LE(Constants.ENDCOM);
4765
},
4866

4967
toBinary : function() {

Diff for: util/constants.js

+20
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,26 @@ module.exports = {
4747
ENDOFF : 16, // offset of first CEN header
4848
ENDCOM : 20, // zip file comment length
4949

50+
END64HDR : 20, // zip64 END header size
51+
END64SIG : 0x07064b50, // zip64 Locator signature, "PK\006\007"
52+
END64START : 4, // number of the disk with the start of the zip64
53+
END64OFF : 8, // relative offset of the zip64 end of central directory
54+
END64NUMDISKS : 16, // total number of disks
55+
56+
ZIP64SIG : 0x06064b50, // zip64 signature, "PK\006\006"
57+
ZIP64HDR : 56, // zip64 record minimum size
58+
ZIP64LEAD : 12, // leading bytes at the start of the record, not counted by the value stored in ZIP64SIZE
59+
ZIP64SIZE : 4, // zip64 size of the central directory record
60+
ZIP64VEM : 12, // zip64 version made by
61+
ZIP64VER : 14, // zip64 version needed to extract
62+
ZIP64DSK : 16, // zip64 number of this disk
63+
ZIP64DSKDIR : 20, // number of the disk with the start of the record directory
64+
ZIP64SUB : 24, // number of entries on this disk
65+
ZIP64TOT : 32, // total number of entries
66+
ZIP64SIZB : 40, // zip64 central directory size in bytes
67+
ZIP64OFF : 48, // offset of start of central directory with respect to the starting disk number
68+
ZIP64EXTRA : 56, // extensible data sector
69+
5070
/* Compression methods */
5171
STORED : 0, // no compression
5272
SHRUNK : 1, // shrunk

Diff for: util/utils.js

+9
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ module.exports = (function() {
4848
return files;
4949
}
5050

51+
function readBigUInt64LE(/*Buffer*/buffer, /*int*/index) {
52+
var slice = Buffer.from(buffer.slice(index, index + 8));
53+
slice.swap64();
54+
55+
return parseInt(`0x${ slice.toString('hex') }`);
56+
}
57+
5158
return {
5259
makeDir : function(/*String*/path) {
5360
mkdirSync(path);
@@ -203,6 +210,8 @@ module.exports = (function() {
203210
}
204211
},
205212

213+
readBigUInt64LE,
214+
206215
Constants : Constants,
207216
Errors : Errors
208217
}

Diff for: zipFile.js

+25-4
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,43 @@ module.exports = function (/*String|Buffer*/input, /*Number*/inputType) {
5252

5353
function readMainHeader() {
5454
var i = inBuffer.length - Utils.Constants.ENDHDR, // END header size
55-
n = Math.max(0, i - 0xFFFF), // 0xFFFF is the max zip file comment length
56-
endOffset = -1; // Start offset of the END header
55+
max = Math.max(0, i - 0xFFFF), // 0xFFFF is the max zip file comment length
56+
n = max,
57+
endStart = inBuffer.length,
58+
endOffset = -1, // Start offset of the END header
59+
commentEnd = 0;
5760

5861
for (i; i >= n; i--) {
5962
if (inBuffer[i] !== 0x50) continue; // quick check that the byte is 'P'
6063
if (inBuffer.readUInt32LE(i) === Utils.Constants.ENDSIG) { // "PK\005\006"
6164
endOffset = i;
65+
commentEnd = i;
66+
endStart = i + Utils.Constants.ENDHDR;
67+
// We already found a regular signature, let's look just a bit further to check if there's any zip64 signature
68+
n = i - Utils.Constants.END64HDR;
69+
continue;
70+
}
71+
72+
if (inBuffer.readUInt32LE(i) === Utils.Constants.END64SIG) {
73+
// Found a zip64 signature, let's continue reading the whole zip64 record
74+
n = max;
75+
continue;
76+
}
77+
78+
if (inBuffer.readUInt32LE(i) == Utils.Constants.ZIP64SIG) {
79+
// Found the zip64 record, let's determine it's size
80+
endOffset = i;
81+
endStart = i + Utils.readBigUInt64LE(inBuffer, i + Utils.Constants.ZIP64SIZE) + Utils.Constants.ZIP64LEAD;
6282
break;
6383
}
6484
}
85+
6586
if (!~endOffset)
6687
throw Utils.Errors.INVALID_FORMAT;
6788

68-
mainHeader.loadFromBinary(inBuffer.slice(endOffset, endOffset + Utils.Constants.ENDHDR));
89+
mainHeader.loadFromBinary(inBuffer.slice(endOffset, endStart));
6990
if (mainHeader.commentLength) {
70-
_comment = inBuffer.slice(endOffset + Utils.Constants.ENDHDR);
91+
_comment = inBuffer.slice(commentEnd + Utils.Constants.ENDHDR);
7192
}
7293
readEntries();
7394
}

0 commit comments

Comments
 (0)