cejs
Version:
A JavaScript module framework that is simple to use.
397 lines (351 loc) • 10.3 kB
JavaScript
/**
* @name CeL function for archive file.
* @fileoverview 本檔案包含了壓縮 compress / archive file 的 functions。
*
* @see CeL.application.storage.archive
*
* @since
*/
;
// 'use asm';
// --------------------------------------------------------------------------------------------
if (typeof CeL === 'function') {
CeL.run({
// module name
name : 'application.OS.Windows.archive',
require : 'data.code.compatibility.'
//
+ '|application.OS.Windows.execute.run_command',
code : module_code
});
}
function module_code(library_namespace) {
// requiring
var run_command = this.r('run_command');
/**
* null module constructor
*
* @class executing program 的 functions
*/
var _// JSDT:_module_
= function() {
// null module constructor
};
/**
* for JSDT: 有 prototype 才會將之當作 Class
*/
_// JSDT:_module_
.prototype = {};
// 2007/5/31 21:5:16
// default configuration
var compress_tool_set = {
WinRAR : {
// rar.exe
path : '"%ProgramFiles%\\WinRAR\\WinRAR.exe"',
extension : 'rar',
// compress switch
c : {
// cL:command line, c:compress, s:switch
cL : '$path $cmd $s $archive -- $files',
cmd : 'a',
// l:'-ilog logFN',
// -rr1p -s<N> -ap -as -ep1 -tl -x<f> -x@<lf> -z<f> -p[p] -hp[p]
// rar等
// -v690m
s : '-m5 -u -dh -os -r -ts -scuc -ep1 -ilog'
},
// uncompress switch
u : {
// command line
cL : '$path $cmd $archive $eF $eTo',
cmd : 'e'
},
// test switch
t : {
cL : '$path $cmd $archive',
cmd : 't'
},
// command line
command : '%path %command %switch %archive %files'
},
'7-Zip' : {
// The path of p7z executable file.
// TODO: use library_namespace.nodejs.executable_file_path('7z')
// 7zG.exe
path : '"%ProgramFiles%\\7-Zip\\7z.exe"',
extension : '7z',
// compress switch
c : {
cL : '$path $cmd $s $archive $files',
cmd : 'u',
s : '-mx9 -ms -mhe -mmt -uy2'
},
// uncompress switch
u : {
cL : '$path $cmd $s $archive $eF',
// cmd : 'e',
cmd : 'x',
s : function(fO) {
var s = ' -ssc -y';
if (fO.eTo)
s += ' -o"' + fO.eTo + '"';
return s;
}
},
// test switch
t : {
cL : '$path $cmd $archive',
cmd : 't'
}
}
};
/**
* <code>
test:
var base='C:\\kanashimi\\www\\cgi-bin\\program\\misc\\';
compress(base+'jit','_jit.htm',{tool:'7-Zip',s:''});
uncompress(base+'jit',base,{tool:'7-Zip'});
fO={
tool:'WinRAR' // or'7-Zip'
,m:'c' // method
,s:'' // switch
,archive:'' // archivefile
,files='' // whattocompress
,eTo='' // wheretouncompress
,eF='' // whattouncompress
,rcL=1 // rebuildcommandline
}
</code>
*/
// solid, overwrite, compressLevel, password
/**
* compress FSO
*
* @param {Object}fO
* flags object
* @returns
*/
function compressF(fO) {
// 參數檢查: 未完全
if (!fO)
fO = {};
if (typeof fO !== 'object')
return;
if (!fO.tool)
fO.tool = 'WinRAR';
// method
if (false && !fO.m)
fO.m = 'c';
if (!fO.m || !fO.archive && (fO.m !== 'c' || fO.m === 'c' && !fO.files))
return;
if (fO.m === 'c') {
if (typeof fO.files !== 'object')
fO.files = fO.files ? [ fO.files ] : fO.archive.replace(
/\...+$/, '');
if (!fO.archive)
fO.archive = fO.files[0].replace(/[\\\/]$/, '') + _t.extension;
fO.files = '"' + fO.files.join('" "') + '"';
}
var i, _t = compress_tool_set[fO.tool], _m, _c;
if (!_t || !(_m = _t[fO.m]))
return;
else if (!/\.[a-z]+$/.test(fO.archive))
fO.archive += '.' + _t.extension;
if (false && fO.bD)
// base directory, work directory, base folder
fO.archive = fO.bD + (/[\\\/]$/.test(fO.bD) ? '' : '\\')
+ fO.archive;
fO.archive = '"' + fO.archive.replace(/"/g, '""') + '"';
library_namespace.debug('compressF(): check OK.');
// 構築 command line arguments。
if (_m._cL && !fO.rcL) {
_c = _m._cL;
} else {
// rebuild command line arguments
_c = _m.cL.replace(/\$path/, _t.path);
for (i in _m)
if (typeof fO[i] === 'undefined')
_c = _c.replace(new RegExp('\\$' + i),
typeof _m[i] === 'function' ? _m[i](fO) : _m[i]
|| '');
_m._cL = _c;
library_namespace.debug(_c, 2, 'compressF');
}
for (i in fO)
_c = _c.replace(new RegExp('\\$' + i), fO[i] || '');
if (_c.indexOf('$') !== -1) {
library_namespace.debug('compressF() error:\n' + _c);
return;
}
library_namespace.debug('compressF() '
+ (_c.indexOf('$') === -1 ? 'run' : 'error') + ':\n' + _c);
// run
return WshShell.Run(_c, 0, true);
// run_command.Unicode(_c);
}
// compress[generateCode.dLK]='compressF';
/**
* compress files.
*
* @param {String}archive
* compress file path.
* @param {Array}files
* what to compress
* @param {Object}options
* flags object
* @returns
*/
function compress(archive, files, options) {
// 前置處理。
options = library_namespace.setup_options(options);
if (!options.m)
options.m = 'c';
if (archive)
options.archive = archive;
if (files)
options.files = files;
return compressF(options);
}
_.compress = compress;
// uncompress[generateCode.dLK]='uncompressF';
/**
* uncompress archive file
*
* @param archive
* compressed archive file path
* @param eTo
* where to uncompress/target
* @param {Object}
* flag flags
* @returns
*/
function uncompress(archive, eTo, flag) {
if (!flag)
flag = {};
else if (typeof flag !== 'object')
return;
if (!flag.m)
flag.m = 'u';
if (!flag.eF)
flag.eF = '';
if (archive)
flag.archive = archive;
if (eTo)
flag.eTo = eTo;
return compressF(flag);
}
function parse_7z_data(status, log, error) {
if (error && library_namespace.is_debug())
library_namespace.error(error);
var message = log.match(/\nError:\s+(?:[A-Za-z]:)?[^:\n]+: ([^\n]+)/);
if (message) {
if (library_namespace.is_debug())
library_namespace.error(message[1]);
this.callback.call(this['this'], this.path, new Error(message[1]));
return;
}
library_namespace.debug(log.replace(/\n/g, '<br/>'), 4);
message = log
.match(/\r?\n([^\r\n]+)\r?\n([ \-]+)\r?\n((?:.+|\n)+?)\r?\n[ \-]+\r?\n/);
library_namespace.debug(message, 3);
if (!message) {
if (library_namespace.is_debug())
library_namespace.warn('無法 parse header!');
this.callback(this.path, new Error('無法 parse header!'));
return;
}
// TODO: 系統化讀入固定欄位長度之 data。
var header = [], i = 0, length, match, file_list, file_array = [], pattern = [],
//
start = [], end = [];
message[1].replace(/\s*(\S+)/g, function($0, $1) {
library_namespace.debug('header: +[' + $1 + '] / [' + $0 + ']', 2);
header.push($1);
end.push(i += $0.length);
start.push(i - $1.length);
return '';
});
start[0] = 0;
file_list = message[3].replace(/\r/g, '').split(/\n/);
library_namespace.debug(file_list.join('<br />'), 3);
var no_calculate_count = 0, calculate_done = true;
for (i = 0, length = file_list.length; i < length; i++) {
calculate_done = true;
var no_calculate = true;
library_namespace.debug('一個個猜測邊界: ' + i + '/' + length
+ '<br />start: ' + start + '<br />end: ' + end, 2);
for (var j = 1, fragment; j < header.length; j++) {
if (end[j - 1] + 1 < start[j]) {
calculate_done = false;
fragment = file_list[i].slice(end[j - 1], start[j]);
if (match = fragment.match(/^\S+/))
if (match[0].length < fragment.length) {
library_namespace.debug('end: [' + (j - 1)
+ '] += ' + match[0].length, 2);
end[j - 1] += match[0].length;
no_calculate = false;
} else {
library_namespace.warn('無法判別 ' + header[j - 1]
+ ' 與 ' + header[j] + ' 之邊界。fragment: ['
+ fragment + ']');
continue;
}
if (match = fragment.match(/\S+$/)) {
library_namespace.debug('start: [' + j + '] -= '
+ match[0].length, 2);
start[j] -= match[0].length;
no_calculate = false;
}
}
}
if (no_calculate)
++no_calculate_count;
else
no_calculate_count = 0;
if (calculate_done || no_calculate_count > 20) {
library_namespace.debug('於 ' + i + '/' + length + ' 跳出邊界判別作業: '
+ (calculate_done ? '已' : '未') + '完成。');
break;
}
}
for (i = 0; i < header.length - 1; i++)
pattern.push('(.{' + (start[i + 1] - start[i]) + '})');
pattern.push('(.+)');
pattern = new RegExp(pattern.join(''));
library_namespace.debug('header: ['
+ header.join('<b style="color:#e44;">|</b>')
+ '], using pattern ' + pattern);
for (i = 0, length = file_list.length; i < length; i++) {
if (match = file_list[i].match(pattern)) {
var j = 1, data = [];
for (; j < match.length; j++)
data.push(match[j].trim());
library_namespace.debug(data
.join('<b style="color:#e44;">|</b>'), 3);
file_array.push(data);
} else {
library_namespace.warn('無法 parse [' + file_list[i] + ']');
}
}
this.callback(this.path, file_array, header);
}
// List archive file.
// read file list of .7z archive
// callback(status, log, error)
function archive_data(path, callback, options) {
if (path && typeof callback === 'function') {
// 前置處理。
options = Object.assign(Object.create(null), options, {
path : path,
callback : callback
});
run_command.Unicode(compress_tool_set['7-Zip'].path + ' l "' + path
+ '"', parse_7z_data.bind(options));
}
}
_.archive_data = archive_data;
// --------------------------------------------------------------------------------------------
// export 導出.
return (_// JSDT:_module_
);
}