Comparing version 2.0.2 to 2.1.0
80
index.js
@@ -22,6 +22,6 @@ var fs = require("fs"); | ||
var self = this; | ||
validateMetadataPath(metadataPath); | ||
metadataPath = validateMetadataPath(metadataPath, false); | ||
if (options == null) options = {}; | ||
var entry = new Entry(metadataPath, options); | ||
var entry = new Entry(metadataPath, false, options); | ||
self.entries.push(entry); | ||
@@ -32,4 +32,4 @@ fs.stat(realPath, function(err, stats) { | ||
entry.uncompressedSize = stats.size; | ||
if (entry.lastModFileTime == null || entry.lastModFileDate == null) entry.setLastModDate(stats.mtime); | ||
if (entry.externalFileAttributes == null) entry.setFileAttributesMode(stats.mode); | ||
if (options.mtime == null) entry.setLastModDate(stats.mtime); | ||
if (options.mode == null) entry.setFileAttributesMode(stats.mode); | ||
entry.setFileDataPumpFunction(function() { | ||
@@ -49,6 +49,5 @@ var readStream = fs.createReadStream(realPath); | ||
var self = this; | ||
validateMetadataPath(metadataPath); | ||
metadataPath = validateMetadataPath(metadataPath, false); | ||
if (options == null) options = {}; | ||
var entry = new Entry(metadataPath, options); | ||
validateFilelessEntryProperties(entry); | ||
var entry = new Entry(metadataPath, false, options); | ||
self.entries.push(entry); | ||
@@ -65,6 +64,6 @@ entry.setFileDataPumpFunction(function() { | ||
var self = this; | ||
validateMetadataPath(metadataPath); | ||
metadataPath = validateMetadataPath(metadataPath, false); | ||
if (options == null) options = {}; | ||
var entry = new Entry(metadataPath, options); | ||
validateFilelessEntryProperties(entry, buffer.length); | ||
if (options.size != null) throw new Error("options.size not allowed"); | ||
var entry = new Entry(metadataPath, false, options); | ||
entry.uncompressedSize = buffer.length; | ||
@@ -92,2 +91,18 @@ entry.crc32 = crc32.unsigned(buffer); | ||
ZipFile.prototype.addEmptyDirectory = function(metadataPath, options) { | ||
var self = this; | ||
metadataPath = validateMetadataPath(metadataPath, true); | ||
if (options == null) options = {}; | ||
if (options.size != null) throw new Error("options.size not allowed"); | ||
if (options.compress != null) throw new Error("options.compress not allowed"); | ||
var entry = new Entry(metadataPath, true, options); | ||
self.entries.push(entry); | ||
entry.setFileDataPumpFunction(function() { | ||
writeToOutputStream(self, entry.getFileDescriptor()); | ||
entry.state = Entry.FILE_DATA_DONE; | ||
pumpEntries(self); | ||
}); | ||
pumpEntries(self); | ||
}; | ||
ZipFile.prototype.end = function(finalSizeCallback) { | ||
@@ -211,24 +226,43 @@ if (this.ended) return; | ||
function validateMetadataPath(metadataPath) { | ||
function validateMetadataPath(metadataPath, isDirectory) { | ||
if (metadataPath === "") throw new Erorr("empty metadataPath"); | ||
if (metadataPath.indexOf("\\") !== -1) throw new Error("invalid characters in path: " + metadataPath); | ||
if (/^[a-zA-Z]:/.test(metadataPath) || /^\//.test(metadataPath)) throw new Error("absolute path: " + metadataPath); | ||
if (metadataPath.split("/").indexOf("..") !== -1) throw new Error("invalid relative path: " + metadataPath); | ||
var looksLikeDirectory = /\/$/.test(metadataPath); | ||
if (isDirectory) { | ||
// append a trailing '/' if necessary. | ||
if (!looksLikeDirectory) metadataPath += "/"; | ||
} else { | ||
if (looksLikeDirectory) throw new Error("file path cannot end with '/': " + metadataPath); | ||
} | ||
return metadataPath; | ||
} | ||
function validateFilelessEntryProperties(entry, length) { | ||
if (entry.lastModFileTime == null || entry.lastModFileDate == null) throw new Error("missing options.mtime"); | ||
if (entry.externalFileAttributes == null) throw new Error("missing options.mode"); | ||
if (entry.uncompressedSize != null && length != null && entry.uncompressedSize !== length) throw new Error("invalid options.size"); | ||
} | ||
// this class is not part of the public API | ||
function Entry(metadataPath, options) { | ||
function Entry(metadataPath, isDirectory, options) { | ||
this.utf8FileName = new Buffer(metadataPath); | ||
if (this.utf8FileName.length > 0xffff) throw new Error("utf8 file name too long. " + utf8FileName.length + " > " + 0xffff); | ||
this.isDirectory = isDirectory; | ||
this.state = Entry.WAITING_FOR_METADATA; | ||
if (options.mtime != null) this.setLastModDate(options.mtime); | ||
if (options.mode != null) this.setFileAttributesMode(options.mode); | ||
this.uncompressedSize = null; // unknown | ||
if (options.size != null) this.uncompressedSize = options.size; | ||
this.compress = true; // default | ||
if (options.compress != null) this.compress = !!options.compress; | ||
this.setLastModDate(options.mtime != null ? options.mtime : new Date()); | ||
if (options.mode != null) { | ||
this.setFileAttributesMode(options.mode); | ||
} else { | ||
this.setFileAttributesMode(isDirectory ? 040775 : 0100664); | ||
} | ||
if (isDirectory) { | ||
this.crc32 = 0; | ||
this.uncompressedSize = 0; | ||
this.compressedSize = 0; | ||
} else { | ||
this.uncompressedSize = null; // unknown | ||
if (options.size != null) this.uncompressedSize = options.size; | ||
} | ||
if (isDirectory) { | ||
this.compress = false; | ||
} else { | ||
this.compress = true; // default | ||
if (options.compress != null) this.compress = !!options.compress; | ||
} | ||
} | ||
@@ -235,0 +269,0 @@ Entry.WAITING_FOR_METADATA = 0; |
{ | ||
"name": "yazl", | ||
"version": "2.0.2", | ||
"version": "2.1.0", | ||
"description": "yet another zip library for node", | ||
@@ -14,3 +14,6 @@ "main": "index.js", | ||
"keywords": [ | ||
"zip" | ||
"zip", | ||
"stream", | ||
"archive", | ||
"file" | ||
], | ||
@@ -17,0 +20,0 @@ "author": "Josh Wolfe <thejoshwolfe@gmail.com>", |
# yazl | ||
yet another zip library for node | ||
yet another zip library for node. For unzipping, see | ||
[yauzl](https://github.com/thejoshwolfe/yauzl). | ||
@@ -57,13 +58,13 @@ Design principles: | ||
This function throws an error if `metadataPath` starts with `"/"` or `/[A-Za-z]:\//` | ||
or if it contains `".."` path segments or `"\\"`. | ||
These would be illegal file names according to the spec. | ||
A valid `metadataPath` must not be blank, must not start with `"/"` or `/[A-Za-z]:\//`, | ||
and must not contain `"\\"` or `".."` path segments. | ||
File paths must not end with `"/"`. | ||
`options` may be omitted or null has the following structure and default values: | ||
`options` may be omitted or null and has the following structure and default values: | ||
```js | ||
{ | ||
mtime: stats.mtime, // optional | ||
mode: stats.mode, // optional | ||
compress: true, // optional | ||
mtime: stats.mtime, | ||
mode: stats.mode, | ||
compress: true, | ||
} | ||
@@ -74,4 +75,5 @@ ``` | ||
that would normally be obtained by the `fs.Stats` for the `realPath`. | ||
The mtime and mode (unix permission bits and file type) are stored in the zip file | ||
in the fields "last mod file time", "last mod file date", and "external file attributes". | ||
The mode is the unix permission bits and file type. | ||
The mtime and mode are stored in the zip file in the fields "last mod file time", | ||
"last mod file date", and "external file attributes". | ||
yazl does not store group and user ids in the zip file. | ||
@@ -84,14 +86,14 @@ | ||
#### addReadStream(readStream, metadataPath, options) | ||
#### addReadStream(readStream, metadataPath, [options]) | ||
Adds a file to the zip file whose content is read from `readStream`. | ||
See `addFile()` for info about the `metadataPath` parameter. | ||
`options` is an `Object` and has the following structure: | ||
`options` may be omitted or null and has the following structure and default values: | ||
```js | ||
{ | ||
mtime: new Date(), // required | ||
mode: 0100664, // required | ||
compress: true, // optional (default true) | ||
size: 12345, // optional | ||
mtime: new Date(), | ||
mode: 0100664, | ||
compress: true, | ||
size: 12345, // example value | ||
} | ||
@@ -104,13 +106,13 @@ ``` | ||
#### addBuffer(buffer, metadataPath, options) | ||
#### addBuffer(buffer, metadataPath, [options]) | ||
Adds a file to the zip file whose content is `buffer`. | ||
See `addFile()` for info about the `metadataPath` parameter. | ||
`options` is an `Object` and has the following structure: | ||
`options` may be omitted or null and has the following structure and default values: | ||
```js | ||
{ | ||
mtime: new Date(), // required | ||
mode: 0100664, // required | ||
compress: true, // optional (default true) | ||
mtime: new Date(), | ||
mode: 0100664, | ||
compress: true, | ||
} | ||
@@ -121,2 +123,22 @@ ``` | ||
#### addEmptyDirectory(metadataPath, [options]) | ||
Adds an entry to the zip file that indicates a directory should be created, | ||
even if no other items in the zip file are contained in the directory. | ||
This method is only required if the zip file is intended to contain an empty directory. | ||
See `addFile()` for info about the `metadataPath` parameter. | ||
If `metadataPath` does not end with a `"/"`, a `"/"` will be appended. | ||
`options` may be omitted or null and has the following structure and default values: | ||
```js | ||
{ | ||
mtime: new Date(), | ||
mode: 040775, | ||
} | ||
``` | ||
See `addFile()` for the meaning of `mtime` and `mode`. | ||
#### end([finalSizeCallback]) | ||
@@ -219,9 +241,22 @@ | ||
Note that for directory entries (see `addEmptyDirectory()`), | ||
it is conventional to use the lower 8 bits for the MS-DOS directory attribute byte. | ||
However, the spec says this is only required if the Version Made By is DOS, | ||
so this library does not do that. | ||
### Directory Entries | ||
yazl does not record directories themselves as separate entries in the zipfile metadata. | ||
Instead, file entries with paths (such as "directory/file.txt") imply the need for their parent directories. | ||
Unzip clients seems to respect this style of pathing, | ||
When adding a `metadataPath` such as `"parent/file.txt"`, yazl does not add a directory entry for `"parent/"`, | ||
because file entries imply the need for their parent directories. | ||
Unzip clients seem to respect this style of pathing, | ||
and the zip file spec does not specify what is standard in this regard. | ||
Directory entries would be required to archive empty directories (see issue #4). | ||
In order to create empty directories, use `addEmptyDirectory()`. | ||
## Change History | ||
* 2.1.0 | ||
* Added `addEmptyDirectory()`. | ||
* `options` is now optional for `addReadStream()` and `addBuffer()`. | ||
* 2.0.0 | ||
* Initial release. |
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
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
28298
364
257