Generic MIME types (file types) such as application/octet-stream can how have sub types for handlers (archive, info extract, ...)
+ Add Amiga DMS support via xdms
This commit is contained in:
parent
95422f71ba
commit
3ecadebf91
|
@ -11,6 +11,7 @@ const resolveMimeType = require('./mime_util.js').resolveMimeType;
|
||||||
const fs = require('graceful-fs');
|
const fs = require('graceful-fs');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const pty = require('node-pty');
|
const pty = require('node-pty');
|
||||||
|
const paths = require('path');
|
||||||
|
|
||||||
let archiveUtil;
|
let archiveUtil;
|
||||||
|
|
||||||
|
@ -75,32 +76,56 @@ module.exports = class ArchiveUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_.isObject(Config.fileTypes)) {
|
if(_.isObject(Config.fileTypes)) {
|
||||||
|
const updateSig = (ft) => {
|
||||||
|
ft.sig = Buffer.from(ft.sig, 'hex');
|
||||||
|
ft.offset = ft.offset || 0;
|
||||||
|
|
||||||
|
// :TODO: this is broken: sig is NOT this long, it's sig.length long; offset needs to allow for -negative values as well
|
||||||
|
const sigLen = ft.offset + ft.sig.length;
|
||||||
|
if(sigLen > this.longestSignature) {
|
||||||
|
this.longestSignature = sigLen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Object.keys(Config.fileTypes).forEach(mimeType => {
|
Object.keys(Config.fileTypes).forEach(mimeType => {
|
||||||
const fileType = Config.fileTypes[mimeType];
|
const fileType = Config.fileTypes[mimeType];
|
||||||
if(fileType.sig) {
|
if(Array.isArray(fileType)) {
|
||||||
fileType.sig = Buffer.from(fileType.sig, 'hex');
|
fileType.forEach(ft => {
|
||||||
fileType.offset = fileType.offset || 0;
|
if(ft.sig) {
|
||||||
|
updateSig(ft);
|
||||||
// :TODO: this is broken: sig is NOT this long, it's sig.length long; offset needs to allow for -negative values as well
|
}
|
||||||
const sigLen = fileType.offset + fileType.sig.length;
|
});
|
||||||
if(sigLen > this.longestSignature) {
|
} else if(fileType.sig) {
|
||||||
this.longestSignature = sigLen;
|
updateSig(fileType);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getArchiver(mimeTypeOrExtension) {
|
getArchiver(mimeTypeOrExtension, justExtention) {
|
||||||
mimeTypeOrExtension = resolveMimeType(mimeTypeOrExtension);
|
const mimeType = resolveMimeType(mimeTypeOrExtension);
|
||||||
|
|
||||||
if(!mimeTypeOrExtension) { // lookup returns false on failure
|
if(!mimeType) { // lookup returns false on failure
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const archiveHandler = _.get( Config, [ 'fileTypes', mimeTypeOrExtension, 'archiveHandler'] );
|
let fileType = _.get(Config, [ 'fileTypes', mimeType ] );
|
||||||
if(archiveHandler) {
|
|
||||||
return _.get( Config, [ 'archives', 'archivers', archiveHandler ] );
|
if(Array.isArray(fileType)) {
|
||||||
|
if(!justExtention) {
|
||||||
|
// need extention for lookup; ambiguous as-is :(
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// further refine by extention
|
||||||
|
fileType = fileType.find(ft => justExtention === ft.ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_.isObject(fileType)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fileType.archiveHandler) {
|
||||||
|
return _.get( Config, [ 'archives', 'archivers', fileType.archiveHandler ] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,18 +152,21 @@ module.exports = class ArchiveUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
const archFormat = _.findKey(Config.fileTypes, fileTypeInfo => {
|
const archFormat = _.findKey(Config.fileTypes, fileTypeInfo => {
|
||||||
if(!fileTypeInfo.sig) {
|
const fileTypeInfos = Array.isArray(fileTypeInfo) ? fileTypeInfo : [ fileTypeInfo ];
|
||||||
return false;
|
return fileTypeInfos.find(fti => {
|
||||||
}
|
if(!fti.sig || !fti.archiveHandler) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const lenNeeded = fileTypeInfo.offset + fileTypeInfo.sig.length;
|
const lenNeeded = fti.offset + fti.sig.length;
|
||||||
|
|
||||||
if(bytesRead < lenNeeded) {
|
if(bytesRead < lenNeeded) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const comp = buf.slice(fileTypeInfo.offset, fileTypeInfo.offset + fileTypeInfo.sig.length);
|
const comp = buf.slice(fti.offset, fti.offset + fti.sig.length);
|
||||||
return (fileTypeInfo.sig.equals(comp));
|
return (fti.sig.equals(comp));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return cb(archFormat ? null : Errors.General('Unknown type'), archFormat);
|
return cb(archFormat ? null : Errors.General('Unknown type'), archFormat);
|
||||||
|
@ -162,7 +190,7 @@ module.exports = class ArchiveUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
compressTo(archType, archivePath, files, cb) {
|
compressTo(archType, archivePath, files, cb) {
|
||||||
const archiver = this.getArchiver(archType);
|
const archiver = this.getArchiver(archType, paths.extname(archivePath));
|
||||||
|
|
||||||
if(!archiver) {
|
if(!archiver) {
|
||||||
return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
|
return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
|
||||||
|
@ -196,7 +224,7 @@ module.exports = class ArchiveUtil {
|
||||||
haveFileList = true;
|
haveFileList = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const archiver = this.getArchiver(archType);
|
const archiver = this.getArchiver(archType, paths.extname(archivePath));
|
||||||
|
|
||||||
if(!archiver) {
|
if(!archiver) {
|
||||||
return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
|
return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
|
||||||
|
@ -236,7 +264,7 @@ module.exports = class ArchiveUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
listEntries(archivePath, archType, cb) {
|
listEntries(archivePath, archType, cb) {
|
||||||
const archiver = this.getArchiver(archType);
|
const archiver = this.getArchiver(archType, paths.extname(archivePath));
|
||||||
|
|
||||||
if(!archiver) {
|
if(!archiver) {
|
||||||
return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
|
return cb(Errors.Invalid(`Unknown archive type: ${archType}`));
|
||||||
|
|
|
@ -297,6 +297,16 @@ function getDefaultConfig() {
|
||||||
'--filemodifydate', '--fileaccessdate', '--fileinodechangedate', '--createdate', '--modifydate',
|
'--filemodifydate', '--fileaccessdate', '--fileinodechangedate', '--createdate', '--modifydate',
|
||||||
'--metadatadate', '--xmptoolkit'
|
'--metadatadate', '--xmptoolkit'
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
XDMS2Desc : {
|
||||||
|
// http://manpages.ubuntu.com/manpages/trusty/man1/xdms.1.html
|
||||||
|
cmd : 'xdms',
|
||||||
|
args : [ 'd', '{filePath}' ]
|
||||||
|
},
|
||||||
|
XDMS2LongDesc : {
|
||||||
|
// http://manpages.ubuntu.com/manpages/trusty/man1/xdms.1.html
|
||||||
|
cmd : 'xdms',
|
||||||
|
args : [ 'f', '{filePath}' ]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -426,13 +436,20 @@ function getDefaultConfig() {
|
||||||
sig : '377abcaf271c',
|
sig : '377abcaf271c',
|
||||||
offset : 0,
|
offset : 0,
|
||||||
archiveHandler : '7Zip',
|
archiveHandler : '7Zip',
|
||||||
}
|
},
|
||||||
|
|
||||||
// :TODO: update archives::formats to fall here
|
//
|
||||||
// * archive handler -> archiveHandler (consider archive if archiveHandler present)
|
// Generics that need further mapping
|
||||||
// * sig, offset, ...
|
//
|
||||||
// * mime-db -> exts lookup
|
'application/octet-stream' : [
|
||||||
// *
|
{
|
||||||
|
desc : 'Amiga DISKMASHER',
|
||||||
|
sig : '444d5321', // DMS!
|
||||||
|
ext : '.dms',
|
||||||
|
shortDescUtil : 'XDMS2Desc',
|
||||||
|
longDescUtil : 'XDMS2LongDesc',
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
archives : {
|
archives : {
|
||||||
|
|
|
@ -24,6 +24,7 @@ const controlCodesToAnsi = require('./color_codes.js').controlCodesToAnsi;
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
|
const paths = require('path');
|
||||||
|
|
||||||
exports.moduleInfo = {
|
exports.moduleInfo = {
|
||||||
name : 'File Area List',
|
name : 'File Area List',
|
||||||
|
@ -252,7 +253,18 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||||
|
|
||||||
if(entryInfo.archiveType) {
|
if(entryInfo.archiveType) {
|
||||||
const mimeType = resolveMimeType(entryInfo.archiveType);
|
const mimeType = resolveMimeType(entryInfo.archiveType);
|
||||||
entryInfo.archiveTypeDesc = mimeType ? _.get(Config, [ 'fileTypes', mimeType, 'desc' ] ) || mimeType : entryInfo.archiveType;
|
let desc;
|
||||||
|
if(mimeType) {
|
||||||
|
let fileType = _.get(Config, [ 'fileTypes', mimeType ] );
|
||||||
|
|
||||||
|
if(Array.isArray(fileType)) {
|
||||||
|
// further refine by extention
|
||||||
|
fileType = fileType.find(ft => paths.extname(currEntry.fileName) === ft.ext);
|
||||||
|
}
|
||||||
|
desc = fileType && fileType.desc;
|
||||||
|
}
|
||||||
|
entryInfo.archiveTypeDesc = desc || mimeType || entryInfo.archiveType;
|
||||||
|
//entryInfo.archiveTypeDesc = mimeType ? _.get(Config, [ 'fileTypes', mimeType, 'desc' ] ) || mimeType : entryInfo.archiveType;
|
||||||
} else {
|
} else {
|
||||||
entryInfo.archiveTypeDesc = 'N/A';
|
entryInfo.archiveTypeDesc = 'N/A';
|
||||||
}
|
}
|
||||||
|
|
|
@ -487,8 +487,19 @@ function populateFileEntryWithArchive(fileEntry, filePath, stepInfo, iterator, c
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInfoExtractUtilForDesc(mimeType, descType) {
|
function getInfoExtractUtilForDesc(mimeType, filePath, descType) {
|
||||||
let util = _.get(Config, [ 'fileTypes', mimeType, `${descType}DescUtil` ]);
|
let fileType = _.get(Config, [ 'fileTypes', mimeType ] );
|
||||||
|
|
||||||
|
if(Array.isArray(fileType)) {
|
||||||
|
// further refine by extention
|
||||||
|
fileType = fileType.find(ft => paths.extname(filePath) === ft.ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_.isObject(fileType)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let util = _.get(fileType, `${descType}DescUtil`);
|
||||||
if(!_.isString(util)) {
|
if(!_.isString(util)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -508,7 +519,7 @@ function populateFileEntryInfoFromFile(fileEntry, filePath, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async.eachSeries( [ 'short', 'long' ], (descType, nextDesc) => {
|
async.eachSeries( [ 'short', 'long' ], (descType, nextDesc) => {
|
||||||
const util = getInfoExtractUtilForDesc(mimeType, descType);
|
const util = getInfoExtractUtilForDesc(mimeType, filePath, descType);
|
||||||
if(!util) {
|
if(!util) {
|
||||||
return nextDesc(null);
|
return nextDesc(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ ENiGMA BBS makes use of a few packages for unarchiving and modem support. They'r
|
||||||
running ENiGMA, but without them you'll miss certain functionality. Once installed, they should be made
|
running ENiGMA, but without them you'll miss certain functionality. Once installed, they should be made
|
||||||
available on your system path.
|
available on your system path.
|
||||||
|
|
||||||
| Package | Description | Ubuntu Package | CentOS Package Name | Windows Package |
|
| Package | Description | Debian/Ubuntu Package (APT/DEP) | Red Hat Package (YUM/RPM) | Windows Package |
|
||||||
|------------|-----------------------------------|--------------------------------------------|---------------------------------------------------|------------------------------------------------------------------|
|
|------------|-----------------------------------|--------------------------------------------|---------------------------------------------------|------------------------------------------------------------------|
|
||||||
| arj | Unpacking arj archives | `arj` | n/a, binaries [here](http://arj.sourceforge.net/) | [ARJ](http://arj.sourceforge.net/) |
|
| arj | Unpacking arj archives | `arj` | n/a, binaries [here](http://arj.sourceforge.net/) | [ARJ](http://arj.sourceforge.net/) |
|
||||||
| 7zip | Unpacking zip, rar, archives | `p7zip-full` | `p7zip-full` | [7-zip](http://www.7-zip.org/) |
|
| 7zip | Unpacking zip, rar, archives | `p7zip-full` | `p7zip-full` | [7-zip](http://www.7-zip.org/) |
|
||||||
|
@ -58,8 +58,8 @@ available on your system path.
|
||||||
| Rar | Unpacking rar archives | `unrar` | n/a, binaries [here](https://www.rarlab.com/download.htm) | Unknown |
|
| Rar | Unpacking rar archives | `unrar` | n/a, binaries [here](https://www.rarlab.com/download.htm) | Unknown |
|
||||||
| lrzsz | sz/rz: X/Y/Z modem support | `lrzsz` | `lrzsz` | Unknown |
|
| lrzsz | sz/rz: X/Y/Z modem support | `lrzsz` | `lrzsz` | Unknown |
|
||||||
| sexyz | SexyZ modem support | [sexyz](https://l33t.codes/outgoing/sexyz) | [sexyz](https://l33t.codes/outgoing/sexyz) | Available with [Synchronet](http://wiki.synchro.net/install:win) |
|
| sexyz | SexyZ modem support | [sexyz](https://l33t.codes/outgoing/sexyz) | [sexyz](https://l33t.codes/outgoing/sexyz) | Available with [Synchronet](http://wiki.synchro.net/install:win) |
|
||||||
|
| exiftool | [ExifTool](https://www.sno.phy.queensu.ca/~phil/exiftool/) | libimage-exiftool-perl | perl-Image-ExifTool | Unknown
|
||||||
- exiftool & other external tools
|
| xdms | Unpack/view Amiga DMS | [xdms](http://manpages.ubuntu.com/manpages/trusty/man1/xdms.1.html) | xdms | Unknown
|
||||||
|
|
||||||
## Config Files
|
## Config Files
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue