[Pkg-javascript-commits] [node-yazl] 02/03: Imported Upstream version 2.2.2
Andrew Kelley
andrewrk-guest at moszumanska.debian.org
Sat May 16 19:59:25 UTC 2015
This is an automated email from the git hooks/post-receive script.
andrewrk-guest pushed a commit to branch master
in repository node-yazl.
commit 5c7e3789666ef4fb6e94b98a3a3d0f2bf124f6d4
Author: Andrew Kelley <superjoe30 at gmail.com>
Date: Sat May 16 19:57:14 2015 +0000
Imported Upstream version 2.2.2
---
README.md | 122 ++++++++++++++++++++++++++++++++++++++++++-------------
index.js | 130 ++++++++++++++++++++++++++++++++++++++++++++---------------
package.json | 7 +++-
test/test.js | 55 +++++++++++++++++++++++++
test/zip.js | 48 +++++++++++++++++-----
5 files changed, 291 insertions(+), 71 deletions(-)
diff --git a/README.md b/README.md
index a10f0d5..6d9b646 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# yazl
-yet another zip library for node
+yet another zip library for node. For unzipping, see
+[yauzl](https://github.com/thejoshwolfe/yauzl).
Design principles:
@@ -54,24 +55,25 @@ Typically `metadataPath` would be calculated as `path.relative(root, realPath)`.
Unzip programs would extract the file from the zipfile as `metadataPath`.
`realPath` is not stored in the zipfile.
-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,
}
```
Use `options.mtime` and/or `options.mode` to override the values
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.
Internally, `fs.stat()` is called immediately in the `addFile` function,
@@ -79,18 +81,18 @@ and `fs.createReadStream()` is used later when the file data is actually require
Throughout adding and encoding `n` files with `addFile()`,
the number of simultaneous open files is `O(1)`, probably just 1 at a time.
-#### 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
}
```
@@ -98,17 +100,49 @@ See `addFile()` for the meaning of `mtime` and `mode`.
If `size` is given, it will be checked against the actual number of bytes in the `readStream`,
and an error will be emitted if there is a mismatch.
-#### addBuffer(buffer, metadataPath, options)
+Note that yazl will `.pipe()` data from `readStream`, so be careful using `.on('data')`.
+In certain versions of node, `.on('data')` makes `.pipe()` behave incorrectly.
+
+#### 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,
+}
+```
+
+See `addFile()` for the meaning of `mtime` and `mode`.
+
+This method has the unique property that General Purpose Bit `3` will not be used in the Local File Header.
+This doesn't matter for unzip implementations that conform to the Zip File Spec.
+However, 7-Zip 9.20 has a known bug where General Purpose Bit `3` is declared an unsupported compression method
+(note that it really has nothing to do with the compression method.).
+See [issue #11](https://github.com/thejoshwolfe/yazl/issues/11).
+If you would like to create zip files that 7-Zip 9.20 can understand,
+you must use `addBuffer()` instead of `addFile()` or `addReadStream()` for all entries in the zip file
+(and `addEmptyDirectory()` is fine too).
+
+#### 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,
}
```
@@ -147,6 +181,9 @@ Data becomes available in this stream soon after calling one of `addFile()`, `ad
Clients can call `pipe()` on this stream at any time,
such as immediately after getting a new `ZipFile` instance, or long after calling `end()`.
+As a reminder, be careful using both `.on('data')` and `.pipe()` with this stream.
+In certain versions of node, you cannot use both `.on('data')` and `.pipe()` successfully.
+
### dateToDosDateTime(jsDate)
`jsDate` is a `Date` instance.
@@ -187,15 +224,19 @@ refuse to acknowledge General Purpose Bit `8`, which enables utf8 filename encod
Bit `8` is always set.
Filenames are always encoded in utf8, even if the result is indistinguishable from ascii.
-Bit `3` is set in the Local File Header.
+Bit `3` is usually set in the Local File Header.
To support both a streaming input and streaming output api,
it is impossible to know the crc32 before processing the file data.
-File Descriptors are given after each file data with this information, as per the spec.
+When bit `3` is set, file Descriptors are given after each file data with this information, as per the spec.
But remember a complete metadata listing is still always available in the central directory record,
so if unzip implementations are relying on that, like they should,
none of this paragraph will matter anyway.
-Even so, Mac's Archive Utility requires File Descriptors to include the optional signature,
+Even so, some popular unzip implementations do not follow the spec.
+Mac's Archive Utility requires File Descriptors to include the optional signature,
so yazl includes the optional file descriptor signature.
+When bit `3` is not used, Mac's Archive Utility requires there to be no file descriptor, so yazl skips it in that case.
+Additionally, 7-Zip 9.20 does not seem to support bit `3` at all
+(see [issue #11](https://github.com/thejoshwolfe/yazl/issues/11)).
All other bits are unset.
@@ -211,11 +252,36 @@ and is probably not significant in any modern unzip implementation.
Always `stats.mode << 16`.
This is apparently the convention for "version made by" = `0x03xx` (UNIX).
+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.2.2
+ * Fix 7-Zip compatibility issue. [pull request #17](https://github.com/thejoshwolfe/yazl/pull/17)
+ * 2.2.1
+ * Fix Mac Archive Utility compatibility issue. [issue #14](https://github.com/thejoshwolfe/yazl/issues/14)
+ * 2.2.0
+ * Avoid using general purpose bit 3 for `addBuffer()` calls. [issue #13](https://github.com/thejoshwolfe/yazl/issues/13)
+ * 2.1.3
+ * Fix bug when only addBuffer() and end() are called. [issue #12](https://github.com/thejoshwolfe/yazl/issues/12)
+ * 2.1.2
+ * Fixed typo in parameter validation. [pull request #10](https://github.com/thejoshwolfe/yazl/pull/10)
+ * 2.1.1
+ * Fixed stack overflow when using addBuffer() in certain ways. [issue #9](https://github.com/thejoshwolfe/yazl/issues/9)
+ * 2.1.0
+ * Added `addEmptyDirectory()`.
+ * `options` is now optional for `addReadStream()` and `addBuffer()`.
+ * 2.0.0
+ * Initial release.
diff --git a/index.js b/index.js
index 3f4b218..f3eec7a 100644
--- a/index.js
+++ b/index.js
@@ -14,22 +14,23 @@ function ZipFile() {
this.outputStream = new PassThrough();
this.entries = [];
this.outputStreamCursor = 0;
- this.ended = false;
+ this.ended = false; // .end() sets this
+ this.allDone = false; // set when we've written the last bytes
}
ZipFile.prototype.addFile = function(realPath, metadataPath, options) {
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);
fs.stat(realPath, function(err, stats) {
if (err) return self.emit("error", err);
if (!stats.isFile()) return self.emit("error", new Error("not a file: " + realPath));
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() {
var readStream = fs.createReadStream(realPath);
entry.state = Entry.FILE_DATA_IN_PROGRESS;
@@ -44,27 +45,26 @@ ZipFile.prototype.addFile = function(realPath, metadataPath, options) {
ZipFile.prototype.addReadStream = function(readStream, metadataPath, options) {
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);
entry.setFileDataPumpFunction(function() {
entry.state = Entry.FILE_DATA_IN_PROGRESS;
pumpFileDataReadStream(self, entry, readStream);
- pumpEntries(self);
});
pumpEntries(self);
};
ZipFile.prototype.addBuffer = function(buffer, metadataPath, options) {
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;
entry.crc32 = crc32.unsigned(buffer);
+ entry.crcAndFileSizeKnown = true;
self.entries.push(entry);
if (!entry.compress) {
setCompressedBuffer(buffer);
@@ -79,12 +79,33 @@ ZipFile.prototype.addBuffer = function(buffer, metadataPath, options) {
writeToOutputStream(self, compressedBuffer);
writeToOutputStream(self, entry.getFileDescriptor());
entry.state = Entry.FILE_DATA_DONE;
- pumpEntries(self);
+
+ // don't call pumpEntries() recursively.
+ // (also, don't call process.nextTick recursively.)
+ setImmediate(function() {
+ pumpEntries(self);
+ });
});
pumpEntries(self);
}
};
+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) {
if (this.ended) return;
this.ended = true;
@@ -123,6 +144,7 @@ function pumpFileDataReadStream(self, entry, readStream) {
}
function pumpEntries(self) {
+ if (self.allDone) return;
// first check if finalSize is finally known
if (self.ended && self.finalSizeCallback != null) {
var finalSize = calculateFinalSize(self);
@@ -162,6 +184,7 @@ function pumpEntries(self) {
});
writeToOutputStream(self, getEndOfCentralDirectoryRecord(self));
self.outputStream.end();
+ self.allDone = true;
}
}
}
@@ -181,8 +204,8 @@ function calculateFinalSize(self) {
}
result += LOCAL_FILE_HEADER_FIXED_SIZE + entry.utf8FileName.length +
entry.uncompressedSize +
- FILE_DESCRIPTOR_SIZE +
CENTRAL_DIRECTORY_RECORD_FIXED_SIZE + entry.utf8FileName.length;
+ if (!entry.crcAndFileSizeKnown) result += FILE_DESCRIPTOR_SIZE;
}
result += END_OF_CENTRAL_DIRECTORY_RECORD_SIZE;
return result;
@@ -203,28 +226,52 @@ function getEndOfCentralDirectoryRecord(self) {
return buffer;
}
-function validateMetadataPath(metadataPath) {
+function validateMetadataPath(metadataPath, isDirectory) {
+ if (metadataPath === "") throw new Error("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);
-}
-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");
+ 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;
}
// 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.crcAndFileSizeKnown = true;
+ this.crc32 = 0;
+ this.uncompressedSize = 0;
+ this.compressedSize = 0;
+ } else {
+ // unknown so far
+ this.crcAndFileSizeKnown = false;
+ this.crc32 = null;
+ this.uncompressedSize = null;
+ this.compressedSize = null;
+ 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;
+ }
}
Entry.WAITING_FOR_METADATA = 0;
Entry.READY_TO_PUMP_FILE_DATA = 1;
@@ -240,6 +287,7 @@ Entry.prototype.setFileAttributesMode = function(mode) {
// http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute/14727#14727
this.externalFileAttributes = (mode << 16) >>> 0;
};
+// doFileDataPump() should not call pumpEntries() directly. see issue #9.
Entry.prototype.setFileDataPumpFunction = function(doFileDataPump) {
this.doFileDataPump = doFileDataPump;
this.state = Entry.READY_TO_PUMP_FILE_DATA;
@@ -252,17 +300,28 @@ var VERSION_MADE_BY_INFO_ZIP = 0x031e;
var FILE_NAME_IS_UTF8 = 1 << 11;
var UNKNOWN_CRC32_AND_FILE_SIZES = 1 << 3;
Entry.prototype.getLocalFileHeader = function() {
+ var crc32 = 0;
+ var compressedSize = 0;
+ var uncompressedSize = 0;
+ if (this.crcAndFileSizeKnown) {
+ crc32 = this.crc32;
+ compressedSize = this.compressedSize;
+ uncompressedSize = this.uncompressedSize;
+ }
+
var fixedSizeStuff = new Buffer(LOCAL_FILE_HEADER_FIXED_SIZE);
- var generalPurposeBitFlag = UNKNOWN_CRC32_AND_FILE_SIZES | FILE_NAME_IS_UTF8;
+ var generalPurposeBitFlag = FILE_NAME_IS_UTF8;
+ if (!this.crcAndFileSizeKnown) generalPurposeBitFlag |= UNKNOWN_CRC32_AND_FILE_SIZES;
+
fixedSizeStuff.writeUInt32LE(0x04034b50, 0); // local file header signature 4 bytes (0x04034b50)
fixedSizeStuff.writeUInt16LE(VERSION_NEEDED_TO_EXTRACT, 4); // version needed to extract 2 bytes
fixedSizeStuff.writeUInt16LE(generalPurposeBitFlag, 6); // general purpose bit flag 2 bytes
fixedSizeStuff.writeUInt16LE(this.getCompressionMethod(), 8); // compression method 2 bytes
fixedSizeStuff.writeUInt16LE(this.lastModFileTime, 10); // last mod file time 2 bytes
fixedSizeStuff.writeUInt16LE(this.lastModFileDate, 12); // last mod file date 2 bytes
- fixedSizeStuff.writeUInt32LE(0, 14); // crc-32 4 bytes
- fixedSizeStuff.writeUInt32LE(0, 18); // compressed size 4 bytes
- fixedSizeStuff.writeUInt32LE(0, 22); // uncompressed size 4 bytes
+ fixedSizeStuff.writeUInt32LE(crc32, 14); // crc-32 4 bytes
+ fixedSizeStuff.writeUInt32LE(compressedSize, 18); // compressed size 4 bytes
+ fixedSizeStuff.writeUInt32LE(uncompressedSize, 22); // uncompressed size 4 bytes
fixedSizeStuff.writeUInt16LE(this.utf8FileName.length, 26); // file name length 2 bytes
fixedSizeStuff.writeUInt16LE(0, 28); // extra field length 2 bytes
return Buffer.concat([
@@ -273,6 +332,10 @@ Entry.prototype.getLocalFileHeader = function() {
};
var FILE_DESCRIPTOR_SIZE = 16
Entry.prototype.getFileDescriptor = function() {
+ if (this.crcAndFileSizeKnown) {
+ // MAC's Archive Utility requires this not be present unless we set general purpose bit 3
+ return new Buffer(0);
+ }
var buffer = new Buffer(FILE_DESCRIPTOR_SIZE);
buffer.writeUInt32LE(0x08074b50, 0); // optional signature (required according to Archive Utility)
buffer.writeUInt32LE(this.crc32, 4); // crc-32 4 bytes
@@ -283,10 +346,13 @@ Entry.prototype.getFileDescriptor = function() {
var CENTRAL_DIRECTORY_RECORD_FIXED_SIZE = 46;
Entry.prototype.getCentralDirectoryRecord = function() {
var fixedSizeStuff = new Buffer(CENTRAL_DIRECTORY_RECORD_FIXED_SIZE);
+ var generalPurposeBitFlag = FILE_NAME_IS_UTF8;
+ if (!this.crcAndFileSizeKnown) generalPurposeBitFlag |= UNKNOWN_CRC32_AND_FILE_SIZES;
+
fixedSizeStuff.writeUInt32LE(0x02014b50, 0); // central file header signature 4 bytes (0x02014b50)
fixedSizeStuff.writeUInt16LE(VERSION_MADE_BY_INFO_ZIP, 4); // version made by 2 bytes
fixedSizeStuff.writeUInt16LE(VERSION_NEEDED_TO_EXTRACT, 6); // version needed to extract 2 bytes
- fixedSizeStuff.writeUInt16LE(FILE_NAME_IS_UTF8, 8); // general purpose bit flag 2 bytes
+ fixedSizeStuff.writeUInt16LE(generalPurposeBitFlag, 8); // general purpose bit flag 2 bytes
fixedSizeStuff.writeUInt16LE(this.getCompressionMethod(), 10); // compression method 2 bytes
fixedSizeStuff.writeUInt16LE(this.lastModFileTime, 12); // last mod file time 2 bytes
fixedSizeStuff.writeUInt16LE(this.lastModFileDate, 14); // last mod file date 2 bytes
diff --git a/package.json b/package.json
index 4f9d55f..2ee9c37 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "yazl",
- "version": "2.0.2",
+ "version": "2.2.2",
"description": "yet another zip library for node",
"main": "index.js",
"scripts": {
@@ -11,7 +11,10 @@
"url": "https://github.com/thejoshwolfe/yazl.git"
},
"keywords": [
- "zip"
+ "zip",
+ "stream",
+ "archive",
+ "file"
],
"author": "Josh Wolfe <thejoshwolfe at gmail.com>",
"license": "MIT",
diff --git a/test/test.js b/test/test.js
index 61985a6..0e935f9 100644
--- a/test/test.js
+++ b/test/test.js
@@ -55,3 +55,58 @@ var BufferList = require("bl");
}));
});
})();
+
+(function() {
+ var zipfile = new yazl.ZipFile();
+ // all options parameters are optional
+ zipfile.addFile(__filename, "a.txt");
+ zipfile.addBuffer(new Buffer("buffer"), "b.txt");
+ zipfile.addReadStream(new BufferList().append("stream"), "c.txt");
+ zipfile.addEmptyDirectory("d/");
+ zipfile.addEmptyDirectory("e");
+ zipfile.end(function(finalSize) {
+ if (finalSize !== -1) throw new Error("finalSize should be unknown");
+ zipfile.outputStream.pipe(new BufferList(function(err, data) {
+ if (err) throw err;
+ yauzl.fromBuffer(data, function(err, zipfile) {
+ if (err) throw err;
+ var entryNames = ["a.txt", "b.txt", "c.txt", "d/", "e/"];
+ zipfile.on("entry", function(entry) {
+ var expectedName = entryNames.shift();
+ if (entry.fileName !== expectedName) {
+ throw new Error("unexpected entry fileName: " + entry.fileName + ", expected: " + expectedName);
+ }
+ });
+ zipfile.on("end", function() {
+ if (entryNames.length === 0) console.log("optional parameters and directories: pass");
+ });
+ });
+ }));
+ });
+})();
+
+(function() {
+ var zipfile = new yazl.ZipFile();
+ // all options parameters are optional
+ zipfile.addBuffer(new Buffer("hello"), "hello.txt", {compress: false});
+ zipfile.end(function(finalSize) {
+ if (finalSize === -1) throw new Error("finalSize should be known");
+ zipfile.outputStream.pipe(new BufferList(function(err, data) {
+ if (err) throw err;
+ if (data.length !== finalSize) throw new Error("finalSize prediction is wrong. " + finalSize + " !== " + data.length);
+ yauzl.fromBuffer(data, function(err, zipfile) {
+ if (err) throw err;
+ var entryNames = ["hello.txt"];
+ zipfile.on("entry", function(entry) {
+ var expectedName = entryNames.shift();
+ if (entry.fileName !== expectedName) {
+ throw new Error("unexpected entry fileName: " + entry.fileName + ", expected: " + expectedName);
+ }
+ });
+ zipfile.on("end", function() {
+ if (entryNames.length === 0) console.log("justAddBuffer: pass");
+ });
+ });
+ }));
+ });
+})();
diff --git a/test/zip.js b/test/zip.js
index a8c6a96..24dce5d 100644
--- a/test/zip.js
+++ b/test/zip.js
@@ -1,24 +1,54 @@
var usage = "node " + __filename.replace(/.*[\/\\]/, "") + " " +
- "[FILE | --compress | --no-compress]... -o OUTPUT.zip";
+ "[FILE | --compress | --no-compress | --buffer | --no-buffer]... -o OUTPUT.zip" + "\n" +
+ "\n" +
+ "all arguments and switches are processed in order. for example:" + "\n" +
+ " node zip.js --compress a.txt --no-compress b.txt -o out.zip" + "\n" +
+ "would result in compression for a.txt, but not for b.txt.";
var yazl = require("../");
var fs = require("fs");
var zipfile = new yazl.ZipFile();
var options = {compress: false};
+var use_buffer = false;
var args = process.argv.slice(2);
-if (Math.max(args.indexOf("-h"), args.indexOf("--help")) !== -1) throw new Error("usage: " + usage);
-var outputFileIndex = args.indexOf("-o");
-if (outputFileIndex === -1) throw new Error("missing -o");
-zipfile.outputStream.pipe(fs.createWriteStream(args[outputFileIndex + 1]));
-args.splice(outputFileIndex, 2);
+if (Math.max(args.indexOf("-h"), args.indexOf("--help")) !== -1) {
+ console.log("usage: " + usage);
+ process.exit(1);
+}
+// this one's important
+if (args.indexOf("-o") === -1) throw new Error("missing -o");
+if (args.indexOf("-o") + 1 >= args.length) throw new Error("missing argument after -o");
+
+var its_the_dash_o = false;
args.forEach(function(arg) {
- if (/--compress/.test(arg)) {
+ if (its_the_dash_o) {
+ its_the_dash_o = false;
+ zipfile.outputStream.pipe(fs.createWriteStream(arg));
+ } else if (arg === "--compress") {
options.compress = true;
- } else if (/--no-compress/.test(arg)) {
+ } else if (arg === "--no-compress") {
options.compress = false;
+ } else if (arg === "--buffer") {
+ use_buffer = true;
+ } else if (arg === "--no-buffer") {
+ use_buffer = false;
+ } else if (arg === "-o") {
+ its_the_dash_o = true;
} else {
- zipfile.addFile(arg, arg, options);
+ // file thing
+ var stats = fs.statSync(arg);
+ if (stats.isFile()) {
+ if (use_buffer) {
+ zipfile.addBuffer(fs.readFileSync(arg), arg, options);
+ } else {
+ zipfile.addFile(arg, arg, options);
+ }
+ } else if (stats.isDirectory()) {
+ zipfile.addEmptyDirectory(arg);
+ } else {
+ throw new Error("what is this: " + arg);
+ }
}
});
zipfile.end();
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-yazl.git
More information about the Pkg-javascript-commits
mailing list