Comparing version 2.4.3 to 2.5.0
98
index.js
@@ -111,2 +111,4 @@ var fs = require("fs"); | ||
var eocdrSignatureBuffer = Buffer.from([0x50, 0x4b, 0x05, 0x06]); | ||
ZipFile.prototype.end = function(options, finalSizeCallback) { | ||
@@ -122,2 +124,16 @@ if (typeof options === "function") { | ||
this.forceZip64Eocd = !!options.forceZip64Format; | ||
if (options.comment) { | ||
if (typeof options.comment === "string") { | ||
this.comment = encodeCp437(options.comment); | ||
} else { | ||
// It should be a Buffer | ||
this.comment = options.comment; | ||
} | ||
if (this.comment.length > 0xffff) throw new Error("comment is too large"); | ||
// gotta check for this, because the zipfile format is actually ambiguous. | ||
if (this.comment.includes(eocdrSignatureBuffer)) throw new Error("comment contains end of central directory record signature"); | ||
} else { | ||
// no comment. | ||
this.comment = EMPTY_BUFFER; | ||
} | ||
pumpEntries(this); | ||
@@ -231,3 +247,3 @@ }; | ||
centralDirectorySize += CENTRAL_DIRECTORY_RECORD_FIXED_SIZE + entry.utf8FileName.length; | ||
centralDirectorySize += CENTRAL_DIRECTORY_RECORD_FIXED_SIZE + entry.utf8FileName.length + entry.fileComment.length; | ||
if (useZip64Format) { | ||
@@ -246,3 +262,3 @@ centralDirectorySize += ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE; | ||
} | ||
endOfCentralDirectorySize += END_OF_CENTRAL_DIRECTORY_RECORD_SIZE; | ||
endOfCentralDirectorySize += END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + self.comment.length; | ||
return pretendOutputCursor + centralDirectorySize + endOfCentralDirectorySize; | ||
@@ -284,3 +300,3 @@ } | ||
var eocdrBuffer = new Buffer(END_OF_CENTRAL_DIRECTORY_RECORD_SIZE); | ||
var eocdrBuffer = Buffer.allocUnsafe(END_OF_CENTRAL_DIRECTORY_RECORD_SIZE + self.comment.length); | ||
// end of central dir signature 4 bytes (0x06054b50) | ||
@@ -301,5 +317,5 @@ eocdrBuffer.writeUInt32LE(0x06054b50, 0); | ||
// .ZIP file comment length 2 bytes | ||
eocdrBuffer.writeUInt16LE(0, 20); | ||
eocdrBuffer.writeUInt16LE(self.comment.length, 20); | ||
// .ZIP file comment (variable size) | ||
// no comment | ||
self.comment.copy(eocdrBuffer, 22); | ||
@@ -310,3 +326,3 @@ if (!needZip64Format) return eocdrBuffer; | ||
// ZIP64 End of Central Directory Record | ||
var zip64EocdrBuffer = new Buffer(ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE); | ||
var zip64EocdrBuffer = Buffer.allocUnsafe(ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIZE); | ||
// zip64 end of central dir signature 4 bytes (0x06064b50) | ||
@@ -337,3 +353,3 @@ zip64EocdrBuffer.writeUInt32LE(0x06064b50, 0); | ||
// ZIP64 End of Central Directory Locator | ||
var zip64EocdlBuffer = new Buffer(ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE); | ||
var zip64EocdlBuffer = Buffer.allocUnsafe(ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIZE); | ||
// zip64 end of central dir locator signature 4 bytes (0x07064b50) | ||
@@ -371,8 +387,7 @@ zip64EocdlBuffer.writeUInt32LE(0x07064b50, 0); | ||
var defaultFileMode = parseInt("0100664", 8); | ||
var defaultDirectoryMode = parseInt("040775", 8); | ||
var EMPTY_BUFFER = Buffer.allocUnsafe(0); | ||
// this class is not part of the public API | ||
function Entry(metadataPath, isDirectory, options) { | ||
this.utf8FileName = new Buffer(metadataPath); | ||
this.utf8FileName = Buffer.from(metadataPath); | ||
if (this.utf8FileName.length > 0xffff) throw new Error("utf8 file name too long. " + utf8FileName.length + " > " + 0xffff); | ||
@@ -385,3 +400,3 @@ this.isDirectory = isDirectory; | ||
} else { | ||
this.setFileAttributesMode(isDirectory ? defaultDirectoryMode : defaultFileMode); | ||
this.setFileAttributesMode(isDirectory ? 0o40775 : 0o100664); | ||
} | ||
@@ -408,2 +423,14 @@ if (isDirectory) { | ||
this.forceZip64Format = !!options.forceZip64Format; | ||
if (options.fileComment) { | ||
if (typeof options.fileComment === "string") { | ||
this.fileComment = Buffer.from(options.fileComment, "utf-8"); | ||
} else { | ||
// It should be a Buffer | ||
this.fileComment = options.fileComment; | ||
} | ||
if (this.fileComment.length > 0xffff) throw new Error("fileComment is too large"); | ||
} else { | ||
// no comment. | ||
this.fileComment = EMPTY_BUFFER; | ||
} | ||
} | ||
@@ -454,3 +481,3 @@ Entry.WAITING_FOR_METADATA = 0; | ||
var fixedSizeStuff = new Buffer(LOCAL_FILE_HEADER_FIXED_SIZE); | ||
var fixedSizeStuff = Buffer.allocUnsafe(LOCAL_FILE_HEADER_FIXED_SIZE); | ||
var generalPurposeBitFlag = FILE_NAME_IS_UTF8; | ||
@@ -494,6 +521,6 @@ if (!this.crcAndFileSizeKnown) generalPurposeBitFlag |= UNKNOWN_CRC32_AND_FILE_SIZES; | ||
// the Mac Archive Utility requires this not be present unless we set general purpose bit 3 | ||
return new Buffer(0); | ||
return Buffer.allocUnsafe(0); | ||
} | ||
if (!this.useZip64Format()) { | ||
var buffer = new Buffer(DATA_DESCRIPTOR_SIZE); | ||
var buffer = Buffer.allocUnsafe(DATA_DESCRIPTOR_SIZE); | ||
// optional signature (required according to Archive Utility) | ||
@@ -510,3 +537,3 @@ buffer.writeUInt32LE(0x08074b50, 0); | ||
// ZIP64 format | ||
var buffer = new Buffer(ZIP64_DATA_DESCRIPTOR_SIZE); | ||
var buffer = Buffer.allocUnsafe(ZIP64_DATA_DESCRIPTOR_SIZE); | ||
// optional signature (unknown if anyone cares about this) | ||
@@ -526,3 +553,3 @@ buffer.writeUInt32LE(0x08074b50, 0); | ||
Entry.prototype.getCentralDirectoryRecord = function() { | ||
var fixedSizeStuff = new Buffer(CENTRAL_DIRECTORY_RECORD_FIXED_SIZE); | ||
var fixedSizeStuff = Buffer.allocUnsafe(CENTRAL_DIRECTORY_RECORD_FIXED_SIZE); | ||
var generalPurposeBitFlag = FILE_NAME_IS_UTF8; | ||
@@ -543,3 +570,3 @@ if (!this.crcAndFileSizeKnown) generalPurposeBitFlag |= UNKNOWN_CRC32_AND_FILE_SIZES; | ||
// ZIP64 extended information extra field | ||
zeiefBuffer = new Buffer(ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE); | ||
zeiefBuffer = Buffer.allocUnsafe(ZIP64_EXTENDED_INFORMATION_EXTRA_FIELD_SIZE); | ||
// 0x0001 2 bytes Tag for this "extra" block type | ||
@@ -559,3 +586,3 @@ zeiefBuffer.writeUInt16LE(0x0001, 0); | ||
versionNeededToExtract = VERSION_NEEDED_TO_EXTRACT_UTF8; | ||
zeiefBuffer = new Buffer(0); | ||
zeiefBuffer = Buffer.allocUnsafe(0); | ||
} | ||
@@ -588,3 +615,3 @@ | ||
// file comment length 2 bytes | ||
fixedSizeStuff.writeUInt16LE(0, 32); | ||
fixedSizeStuff.writeUInt16LE(this.fileComment.length, 32); | ||
// disk number start 2 bytes | ||
@@ -606,3 +633,3 @@ fixedSizeStuff.writeUInt16LE(0, 34); | ||
// file comment (variable size) | ||
// empty comment | ||
this.fileComment, | ||
]); | ||
@@ -631,3 +658,3 @@ }; | ||
function writeUInt64LE(buffer, n, offset) { | ||
// can't use bitshift here, because JavaScript only allows bitshiting on 32-bit integers. | ||
// can't use bitshift here, because JavaScript only allows bitshifting on 32-bit integers. | ||
var high = Math.floor(n / 0x100000000); | ||
@@ -662,1 +689,30 @@ var low = n % 0x100000000; | ||
}; | ||
var cp437 = '\u0000☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ '; | ||
if (cp437.length !== 256) throw new Error("assertion failure"); | ||
var reverseCp437 = null; | ||
function encodeCp437(string) { | ||
if (/^[\x20-\x7e]*$/.test(string)) { | ||
// CP437, ASCII, and UTF-8 overlap in this range. | ||
return Buffer.from(string, "utf-8"); | ||
} | ||
// This is the slow path. | ||
if (reverseCp437 == null) { | ||
// cache this once | ||
reverseCp437 = {}; | ||
for (var i = 0; i < cp437.length; i++) { | ||
reverseCp437[cp437[i]] = i; | ||
} | ||
} | ||
var result = Buffer.allocUnsafe(string.length); | ||
for (var i = 0; i < string.length; i++) { | ||
var b = reverseCp437[string[i]]; | ||
if (b == null) throw new Error("character not encodable in CP437: " + JSON.stringify(string[i])); | ||
result[i] = b; | ||
} | ||
return result; | ||
} |
{ | ||
"name": "yazl", | ||
"version": "2.4.3", | ||
"version": "2.5.0", | ||
"description": "yet another zip library for node", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -30,10 +30,4 @@ # yazl | ||
// alternate apis for adding files: | ||
zipfile.addReadStream(process.stdin, "stdin.txt", { | ||
mtime: new Date(), | ||
mode: parseInt("0100664", 8), // -rw-rw-r-- | ||
}); | ||
zipfile.addBuffer(new Buffer("hello"), "hello.txt", { | ||
mtime: new Date(), | ||
mode: parseInt("0100664", 8), // -rw-rw-r-- | ||
}); | ||
zipfile.addReadStream(process.stdin, "stdin.txt"); | ||
zipfile.addBuffer(Buffer.from("hello"), "hello.txt"); | ||
// call end() after all the files have been added | ||
@@ -63,3 +57,4 @@ zipfile.end(); | ||
and must not contain `".."` path segments. | ||
File paths must not end with `"/"`. | ||
File paths must not end with `"/"`, but see `addEmptyDirectory()`. | ||
After UTF-8 encoding, `metadataPath` must be at most `0xffff` bytes in length. | ||
@@ -74,2 +69,3 @@ `options` may be omitted or null and has the following structure and default values: | ||
forceZip64Format: false, | ||
fileComment: "", // or a UTF-8 Buffer | ||
} | ||
@@ -92,2 +88,7 @@ ``` | ||
If `fileComment` is a `string`, it will be encoded with UTF-8. | ||
If `fileComment` is a `Buffer`, it should be a UTF-8 encoded string. | ||
In UTF-8, `fileComment` must be at most `0xffff` bytes in length. | ||
This becomes the "file comment" field in this entry's central directory file header. | ||
Internally, `fs.stat()` is called immediately in the `addFile` function, | ||
@@ -107,5 +108,6 @@ and `fs.createReadStream()` is used later when the file data is actually required. | ||
mtime: new Date(), | ||
mode: parseInt("0100664", 8), | ||
mode: 0o100664, | ||
compress: true, | ||
forceZip64Format: false, | ||
fileComment: "", // or a UTF-8 Buffer | ||
size: 12345, // example value | ||
@@ -115,3 +117,3 @@ } | ||
See `addFile()` for the meaning of `mtime`, `mode`, `compress`, and `forceZip64Format`. | ||
See `addFile()` for the meaning of `mtime`, `mode`, `compress`, `forceZip64Format`, and `fileComment`. | ||
If `size` is given, it will be checked against the actual number of bytes in the `readStream`, | ||
@@ -133,9 +135,10 @@ and an error will be emitted if there is a mismatch. | ||
mtime: new Date(), | ||
mode: parseInt("0100664", 8), | ||
mode: 0o100664, | ||
compress: true, | ||
forceZip64Format: false, | ||
fileComment: "", // or a UTF-8 Buffer | ||
} | ||
``` | ||
See `addFile()` for the meaning of `mtime`, `mode`, `compress`, and `forceZip64Format`. | ||
See `addFile()` for the meaning of `mtime`, `mode`, `compress`, `forceZip64Format`, and `fileComment`. | ||
@@ -191,3 +194,4 @@ This method has the unique property that General Purpose Bit `3` will not be used in the Local File Header. | ||
Indicates that no more files will be added via `addFile()`, `addReadStream()`, or `addBuffer()`. | ||
Indicates that no more files will be added via `addFile()`, `addReadStream()`, or `addBuffer()`, | ||
and causes the eventual close of `outputStream`. | ||
@@ -199,2 +203,3 @@ `options` may be omitted or null and has the following structure and default values: | ||
forceZip64Format: false, | ||
comment: "", // or a CP437 Buffer | ||
} | ||
@@ -208,2 +213,14 @@ ``` | ||
If `comment` is a `string`, it will be encoded with CP437. | ||
If `comment` is a `Buffer`, it should be a CP437 encoded string. | ||
`comment` must be at most `0xffff` bytes in length and must not include the byte sequence `[0x50,0x4b,0x05,0x06]`. | ||
This becomes the ".ZIP file comment" field in the end of central directory record. | ||
Note that in practice, most zipfile readers interpret this field in UTF-8 instead of CP437. | ||
If your string uses only codepoints in the range `0x20...0x7e` | ||
(printable ASCII, no whitespace except for sinlge space `' '`), | ||
then UTF-8 and CP437 (and ASCII) encodings are all identical. | ||
This restriction is recommended for maxium compatibility. | ||
To use UTF-8 encoding at your own risk, pass a `Buffer` into this function; it will not be validated. | ||
If specified and non-null, `finalSizeCallback` is given the parameters `(finalSize)` | ||
@@ -240,2 +257,4 @@ sometime during or after the call to `end()`. | ||
This stream will remain open while you add entries until you `end()` the zip file. | ||
As a reminder, be careful using both `.on('data')` and `.pipe()` with this stream. | ||
@@ -280,7 +299,7 @@ In certain versions of node, you cannot use both `.on('data')` and `.pipe()` successfully. | ||
Note that the "UNIX" and has implications in the External File Attributes. | ||
Note that the "UNIX" has implications in the External File Attributes. | ||
### Version Needed to Extract | ||
Usually `20`, meaning 2.0. This allows filenames to be UTF-8 encoded. | ||
Usually `20`, meaning 2.0. This allows filenames and file comments to be UTF-8 encoded. | ||
@@ -292,4 +311,4 @@ When ZIP64 format is used, some of the Version Needed to Extract values will be `45`, meaning 4.5. | ||
Bit `8` is always set. | ||
Filenames are always encoded in utf8, even if the result is indistinguishable from ascii. | ||
Bit `11` is always set. | ||
Filenames (and file comments) are always encoded in UTF-8, even if the result is indistinguishable from ascii. | ||
@@ -338,4 +357,14 @@ Bit `3` is usually set in the Local File Header. | ||
### Size of Local File and Central Directory Entry Metadata | ||
The spec recommends that "The combined length of any directory record and [the file name, | ||
extra field, and comment fields] should not generally exceed 65,535 bytes". | ||
yazl makes no attempt to respect this recommendation. | ||
Instead, each of the fields is limited to 65,535 bytes due to the length of each being encoded as an unsigned 16 bit integer. | ||
## Change History | ||
* 2.5.0 | ||
* Add support for `comment` and `fileComment`. [pull #44](https://github.com/thejoshwolfe/yazl/pull/44) | ||
* Avoid `new Buffer()`. [pull #43](https://github.com/thejoshwolfe/yazl/pull/43) | ||
* 2.4.3 | ||
@@ -342,0 +371,0 @@ * Clarify readme. [pull #33](https://github.com/thejoshwolfe/yazl/pull/33) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
High entropy strings
Supply chain riskContains high entropy strings. This could be a sign of encrypted data, leaked secrets or obfuscated code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
47239
652
385
2