diff --git a/.gitignore b/.gitignore index 23b40b5..ecf23aa 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ lib/ npm-debug.log .node-version .DS_Store +.idea \ No newline at end of file diff --git a/README.md b/README.md index a5671f4..621a31c 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,14 @@ Buffer contents of the uncompressed paths. The `callback` gets two arguments `callback` - The function to call after reading completes with an error or the Buffer contents. +### archive.configureExtensions(additionalExtensions) + +Adds custom file extensions to zip, tar, and/or gzip handling to support archives with atypical extensions. + +`additionalExtensions` - Object literal with string arrays for zip, tar, and gzip + +Example: `archive.configureExtensions(zip: ['.docx'])` + ### ArchiveEntry Class representing a path entry inside an archive file. diff --git a/spec/fixtures/one-file.customZip b/spec/fixtures/one-file.customZip new file mode 100644 index 0000000..c59cd1d Binary files /dev/null and b/spec/fixtures/one-file.customZip differ diff --git a/spec/fixtures/word.docx b/spec/fixtures/word.docx new file mode 100644 index 0000000..5d59308 Binary files /dev/null and b/spec/fixtures/word.docx differ diff --git a/spec/zip-spec.coffee b/spec/zip-spec.coffee index 1b78de5..5514996 100644 --- a/spec/zip-spec.coffee +++ b/spec/zip-spec.coffee @@ -71,6 +71,20 @@ describe "zip files", -> waitsFor -> pathError? runs -> expect(pathError.message.length).toBeGreaterThan 0 + describe "listing when custom extensions are added", -> + it "lists files and folders in the docx archive", -> + zipPaths = null + callback = (error, paths) -> zipPaths = paths + archive.configureExtensions(zip: ['.docx']) + archive.list(path.join(fixturesRoot, 'word.docx'), forceZip: true, callback) + waitsFor -> zipPaths? + runs -> + expect(zipPaths.length).toBe 13 + expect(zipPaths[0].path).toBe '[Content_Types].xml' + expect(zipPaths[0].isDirectory()).toBe false + expect(zipPaths[0].isFile()).toBe true + expect(zipPaths[0].isSymbolicLink()).toBe false + describe ".readFile()", -> describe "when the path exists in the archive", -> it "calls back with the contents of the given path", -> @@ -116,3 +130,14 @@ describe "zip files", -> archive.readFile(archivePath, "folder#{path.sep}", callback) waitsFor -> pathError? runs -> expect(pathError.message.length).toBeGreaterThan 0 + + describe "reading when custom extensions are added", -> + it "calls back with the contents of the given path", -> + archivePath = path.join(fixturesRoot, 'one-file.customZip') + pathContents = null + callback = (error, contents) -> pathContents = contents + archive.configureExtensions(zip: ['.customZip']) + archive.readFile(archivePath, 'file.txt', callback) + waitsFor -> pathContents? + runs -> expect(pathContents.toString()).toBe 'hello\n' + diff --git a/src/ls-archive.coffee b/src/ls-archive.coffee index 793629f..0d34795 100644 --- a/src/ls-archive.coffee +++ b/src/ls-archive.coffee @@ -172,43 +172,54 @@ readEntry = (entry, callback) -> entry.on 'data', (data) -> contents.push(data) entry.on 'end', -> callback(null, Buffer.concat(contents)) -isTarPath = (archivePath) -> - path.extname(archivePath) is '.tar' +isTarPath = (archivePath, extensions) -> + path.extname(archivePath) in extensions -isZipPath = (archivePath) -> +isZipPath = (archivePath, extensions) -> extension = path.extname(archivePath) - extension in ['.epub', '.jar', '.love', '.war', '.zip', '.egg', '.whl', '.xpi', '.nupkg'] + extension in extensions -isGzipPath = (archivePath) -> - path.extname(archivePath) is '.tgz' or - path.extname(path.basename(archivePath, '.gz')) is '.tar' +isGzipPath = (archivePath, extensions) -> + path.extname(archivePath) in extensions.gzip or + path.extname(path.basename(archivePath, '.gz')) in extensions.tar module.exports = + + extensions: + zip: ['.epub', '.jar', '.love', '.war', '.zip', '.egg', '.whl', '.xpi', '.nupkg'] + tar: ['.tar'] + gzip: ['.tgz'] + + configureExtensions: (addlExtensions) -> + @extensions.zip.push(addlExtensions.zip...) + @extensions.tar.push(addlExtensions.tar...) + @extensions.gzip.push(addlExtensions.gzip...) + isPathSupported: (archivePath) -> return false unless archivePath - isTarPath(archivePath) or isZipPath(archivePath) or isGzipPath(archivePath) + isTarPath(archivePath, @extensions.tar) or isZipPath(archivePath, @extensions.zip) or isGzipPath(archivePath, @extensions) list: (archivePath, options={}, callback) -> if typeof options is 'function' callback = options options = {} - if isTarPath(archivePath) + if isTarPath(archivePath, @extensions.tar) listTar(archivePath, options, wrapCallback(callback)) - else if isGzipPath(archivePath) + else if isGzipPath(archivePath, @extensions) listGzip(archivePath, options, wrapCallback(callback)) - else if isZipPath(archivePath) + else if isZipPath(archivePath, @extensions.zip) listZip(archivePath, options, wrapCallback(callback)) else callback(new Error("'#{path.extname(archivePath)}' files are not supported")) undefined readFile: (archivePath, filePath, callback) -> - if isTarPath(archivePath) + if isTarPath(archivePath, @extensions.tar) readFileFromTar(archivePath, filePath, wrapCallback(callback)) - else if isGzipPath(archivePath) + else if isGzipPath(archivePath, @extensions) readFileFromGzip(archivePath, filePath, wrapCallback(callback)) - else if isZipPath(archivePath) + else if isZipPath(archivePath, @extensions.zip) readFileFromZip(archivePath, filePath, wrapCallback(callback)) else callback(new Error("'#{path.extname(archivePath)}' files are not supported"))