You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.js 1.7KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. 'use strict';
  2. const fileType = require('file-type');
  3. const getStream = require('get-stream');
  4. const pify = require('pify');
  5. const yauzl = require('yauzl');
  6. const getType = (entry, mode) => {
  7. const IFMT = 61440;
  8. const IFDIR = 16384;
  9. const IFLNK = 40960;
  10. const madeBy = entry.versionMadeBy >> 8;
  11. if ((mode & IFMT) === IFLNK) {
  12. return 'symlink';
  13. }
  14. if ((mode & IFMT) === IFDIR || (madeBy === 0 && entry.externalFileAttributes === 16)) {
  15. return 'directory';
  16. }
  17. return 'file';
  18. };
  19. const extractEntry = (entry, zip) => {
  20. const file = {
  21. mode: (entry.externalFileAttributes >> 16) & 0xFFFF,
  22. mtime: entry.getLastModDate(),
  23. path: entry.fileName
  24. };
  25. file.type = getType(entry, file.mode);
  26. if (file.mode === 0 && file.type === 'directory') {
  27. file.mode = 493;
  28. }
  29. if (file.mode === 0) {
  30. file.mode = 420;
  31. }
  32. return pify(zip.openReadStream.bind(zip))(entry)
  33. .then(getStream.buffer)
  34. .then(buf => {
  35. file.data = buf;
  36. if (file.type === 'symlink') {
  37. file.linkname = buf.toString();
  38. }
  39. return file;
  40. })
  41. .catch(err => {
  42. zip.close();
  43. throw err;
  44. });
  45. };
  46. const extractFile = zip => new Promise((resolve, reject) => {
  47. const files = [];
  48. zip.readEntry();
  49. zip.on('entry', entry => {
  50. extractEntry(entry, zip)
  51. .catch(reject)
  52. .then(file => {
  53. files.push(file);
  54. zip.readEntry();
  55. });
  56. });
  57. zip.on('error', reject);
  58. zip.on('end', () => resolve(files));
  59. });
  60. module.exports = () => buf => {
  61. if (!Buffer.isBuffer(buf)) {
  62. return Promise.reject(new TypeError(`Expected a Buffer, got ${typeof buf}`));
  63. }
  64. if (!fileType(buf) || fileType(buf).ext !== 'zip') {
  65. return Promise.resolve([]);
  66. }
  67. return pify(yauzl.fromBuffer)(buf, {lazyEntries: true}).then(extractFile);
  68. };