| 'use strict'; |
| const fileType = require('file-type'); |
| const getStream = require('get-stream'); |
| const pify = require('pify'); |
| const yauzl = require('yauzl'); |
| |
| const getType = (entry, mode) => { |
| const IFMT = 61440; |
| const IFDIR = 16384; |
| const IFLNK = 40960; |
| const madeBy = entry.versionMadeBy >> 8; |
| |
| if ((mode & IFMT) === IFLNK) { |
| return 'symlink'; |
| } |
| |
| if ((mode & IFMT) === IFDIR || (madeBy === 0 && entry.externalFileAttributes === 16)) { |
| return 'directory'; |
| } |
| |
| return 'file'; |
| }; |
| |
| const extractEntry = (entry, zip) => { |
| const file = { |
| mode: (entry.externalFileAttributes >> 16) & 0xFFFF, |
| mtime: entry.getLastModDate(), |
| path: entry.fileName |
| }; |
| |
| file.type = getType(entry, file.mode); |
| |
| if (file.mode === 0 && file.type === 'directory') { |
| file.mode = 493; |
| } |
| |
| if (file.mode === 0) { |
| file.mode = 420; |
| } |
| |
| return pify(zip.openReadStream.bind(zip))(entry) |
| .then(getStream.buffer) |
| .then(buf => { |
| file.data = buf; |
| |
| if (file.type === 'symlink') { |
| file.linkname = buf.toString(); |
| } |
| |
| return file; |
| }) |
| .catch(err => { |
| zip.close(); |
| throw err; |
| }); |
| }; |
| |
| const extractFile = zip => new Promise((resolve, reject) => { |
| const files = []; |
| |
| zip.readEntry(); |
| |
| zip.on('entry', entry => { |
| extractEntry(entry, zip) |
| .catch(reject) |
| .then(file => { |
| files.push(file); |
| zip.readEntry(); |
| }); |
| }); |
| |
| zip.on('error', reject); |
| zip.on('end', () => resolve(files)); |
| }); |
| |
| module.exports = () => buf => { |
| if (!Buffer.isBuffer(buf)) { |
| return Promise.reject(new TypeError(`Expected a Buffer, got ${typeof buf}`)); |
| } |
| |
| if (!fileType(buf) || fileType(buf).ext !== 'zip') { |
| return Promise.resolve([]); |
| } |
| |
| return pify(yauzl.fromBuffer)(buf, {lazyEntries: true}).then(extractFile); |
| }; |