      1 ﻿
      2
      3 /**
      4  * @name	CeL file function
      5  * @fileoverview
      6  * 本檔案包含了 file functions。
      7  * @since
      8  * @see
      9  * <a href="http://dev.w3.org/2006/webapi/FileAPI/" accessdate="2010/6/20 14:49">File API</a>
     10  */
     11
     12
     13 /*
     14
     15
     16 */
     17
     18 if (typeof CeL === 'function'){
     19
     20 /**
     21  * 本 module 之 name(id)，<span style="text-decoration:line-through;">不設定時會從呼叫時之 path 取得</span>。
     22  * @type	String
     23  * @constant
     24  * @inner
     25  * @ignore
     26  */
     27 var module_name = 'IO.file';
     28
     29 //===================================================
     30 /**
     31  * 若欲 include 整個 module 時，需囊括之 code。
     32  * @type	Function
     33  * @param	{Function} library_namespace	namespace of library
     34  * @param	load_arguments	呼叫時之 argument(s)
     35  * @return
     36  * @name	CeL.IO.file
     37  * @constant
     38  * @inner
     39  * @ignore
     40  */
     41 var code_for_including = function() {
     42
     43 /**
     44  * null module constructor
     45  * @class	檔案操作相關之 function。
     46  */
     47 CeL.IO.file
     48 = function() {
     49 	//	null module constructor
     50 };
     51
     52 /**
     53  * for JSDT: 有 prototype 才會將之當作 Class
     54  */
     55 CeL.IO.file
     56 .prototype = {
     57 };
     58
     59
     60
     61
     62 //	path處理	-------------------------------------------------------
     63
     64 //	path,mode=1:去除檔名，只餘目錄，如輸入http://hostname/aaa/bbb/ccc得到http://hostname/aaa/bbb/	尚未處理：: * ?
     65 //reducePath[generateCode.dLK]='dirSp,dirSpR';
     66 function reducePath(p,m){
     67  //alert(typeof p+'\n'+p);
     68  if(!(p=''+p))return;
     69  var t;
     70  if(t=p.match(/^"([^"]*)/))p=t[1];
     71  if(t=p.match(/(.*)\|<>/))p=t[1];
     72  //Windows environment variables在真實path前,尚未測試！
     73  if(typeof WinEnvironment=='object'&&(t=p.match(/%(.+)%/g)))for(i in t)
     74   if(WinEnvironment[i])p.replace(new RegExp(i,"ig"),WinEnvironment[i]);
     75  p=p.replace(new RegExp(dirSp=='/'?'\\\\':'/',"g"),dirSp);
     76  if(m&&(t=p.lastIndexOf(dirSp))!=-1&&t+1!=p.length)p=p.slice(0,t+1);//去除檔名：假如輸入sss/ddd，會把ddd除去！需輸入sss/ddd/以標示ddd為目錄
     77  //p=p.replace(new RegExp(dirSp+dirSp,'g'),dirSp);	//	\\→\，未考慮到'\\pictures\scenic\canyon.bmp'的情況
     78  return p.replace(new RegExp('^(\\.'+dirSpR+')+'),'')	//	.\→''
     79  .replace(new RegExp(dirSpR+'(\\.'+dirSpR+')+','g'),dirSp)	//	\.\→\
     80  .replace(new RegExp('[^.'+dirSpR+']+'+dirSpR+'\\.\\.'+dirSpR,'g'),'');	//	xx\..\→''
     81 }
     82 //alert(reducePath('http://hostname/../aaa/bbb/../ccc/../ddd',1));
     83
     84 //	去除hostname等，如輸入http://hostname/aaa/bbb/ccc得到aaa/bbb/ccc/
     85 //	假如輸入的格式不正確，可能得出不預期的回應值！
     86 /*	對dirSp.length>1的情形（嚴謹）
     87 function getPathOnly(p){
     88  //discard hash & search
     89  var i=p.lastIndexOf('?'),j=p.lastIndexOf('#'),dirSpL=dirSp.length;
     90  if(i==-1)i=j;else if(j!=-1&&i>j)i=j;if(i!=-1)p=p.slice(0,i);
     91  //	去除http://hostname/等
     92  if(p.slice(0,5)=='file:///')p=p.substr('file:///'.length);	//	對file:///特別處理！
     93  else if((i=p.indexOf(':'+dirSp+dirSp))!=-1&&(i=p.indexOf(dirSp,i+(':'+dirSp+dirSp).length))!=-1))p=p.substr(i+dirSpL);	//	http://hostname/path→path
     94  else if(p.slice(0,dirSpL)==dirSp)
     95  //	/usr/local/→usr/local/
     96  if(p.substr(dirSpL,dirSpL)!=dirSp)p=p.substr(dirSpL);
     97  //	去除\\hostname\
     98  else if((i=p.indexOf(dirSp,dirSpL+dirSpL))>dirSpL+dirSpL)p=p.substr(i+dirSpL);
     99  //	\\\zzzz的情形：不合法的路徑
    100  else if(i!=-1)throw new Error(1,'illegal path:'+p);
    101  return p;
    102 }
    103 */
    104 //	對dirSp.length==1的情形簡化
    105 //getPathOnly[generateCode.dLK]='dirSp';//,isFile
    106 function getPathOnly(p){
    107  //discard hash & search
    108  var i=p.lastIndexOf('?'),j=p.lastIndexOf('#');
    109  if(i==-1)i=j;else if(j!=-1&&i>j)i=j;if(i!=-1)p=p.slice(0,i);
    110  //	去除http://hostname/等
    111  if(p.slice(0,8)=='file:///')p=p.substr(8);	//	對file:///（應該是file:）特別處理！
    112  else if((i=p.indexOf(':'+dirSp+dirSp))!=-1&&(i=p.indexOf(dirSp,i+3)!=-1))p=p.substr(i+1);	//	http://hostname/path→path
    113  else if(p.charAt(0)==dirSp)
    114   //	/usr/local/→usr/local/
    115   if(p.charAt(1)!=dirSp)p=p.substr(1);
    116   //	去除\\hostname\	不去除：.replace(/[^\\]+$/,'')
    117   else if((i=p.indexOf(dirSp,2))>2)p=p.substr(i+1);
    118   //	\\\zzzz的情形：不合法的路徑
    119   else if(i!=-1)throw new Error(1,'illegal path:'+p);
    120  if(typeof isFile=='function'&&isFile(p))	//	!isWeb()&&~
    121   p=p.replace(new RegExp(dirSpR+'[^'+dirSpR+']+$'),dirSp);
    122  return p;
    123 }
    124
    125
    126
    127
    128 /*	2003/10/1 15:57
    129 	pn(path now)相對於bp(base path)之path(增加../等)
    130 */
    131 //relative_path[generateCode.dLK]='reducePath,is_absolute_path,same_length,dirSp,dirSpR';
    132 //,WScript,WshShell
    133 function relative_path(bp,pn){
    134  if(!pn)pn=typeof location=='object'?location.href:typeof WScript=='object'?WScript.ScriptFullName:'';
    135  if(!bp)bp=typeof location=='object'?location.href:typeof WshShell=='object'?WshShell.CurrentDirectory:typeof WScript=='object'?WScript.ScriptFullName:'';
    136  //alert('relative_path: parse 1\n'+bp+'\n'+pn);
    137  var p=reducePath(pn);
    138  if(!p)return;
    139  var d=reducePath(bp,1);
    140  if(!d||!is_absolute_path(d))return p;	//	bp需要是絕對路徑
    141
    142  //alert('relative_path: parse 2\n'+d+'\n'+p);
    143  if(!is_absolute_path(p)){	//	p非絕對路徑時先處理成絕對路徑
    144   var q=p.indexOf(dirSp,1);	//	預防第一字元為dirSp
    145   if(q==-1)q=p;else q=p.slice(0,q);	//	取得第一識別用目錄名
    146   //alert('relative_path: parse 3\n'+d+'\n'+q);
    147   q=d.indexOf(q);
    148   if(q==-1)return p;
    149   p=d.slice(0,q)+p;
    150
    151 /*
    152   var i=0,q=p.split(dirSp),s=new Array(q.length),a=-1,P,bigPC=0,bigP;
    153   //	找出最大連續相同路徑:尚未最佳化
    154   for(i=0;i<q.length;i++){
    155    if(a==-1)P=q[i];else P+=dirSp+q[i];
    156    if(d.indexOf(P)==-1){if(a!=-1&&s[a]>bigPC)bigPC=s[a],bigP=P;a=-1;}
    157    else{if(a==-1)a=i;++s[a];}
    158   }
    159   d=d.indexOf(bigP);
    160 */
    161  }
    162  var s=same_length(p,d);
    163
    164  //alert('dirSp:	'+dirSp+'\npath now:\n	'+p+'\nbase path:\n	'+d+'\nsame:	'+s);
    165  //alert(p+'\n'+d+'\n'+s+'\n'+d.substr(s)+'\n'+d.substr(s).match(new RegExp(dirSp,'g')).length);
    166  //pLog(d.charAt(s-1)+','+d.slice(0,s)+':'+s+','+d.slice(0,s).lastIndexOf(dirSp));
    167  if(s>0&&d.charAt(s-1)!=dirSp)s=d.slice(0,s).lastIndexOf(dirSp)+1;
    168  return s>0?d.substr(s).replace(new RegExp('([^'+dirSpR+']+'+dirSpR+')','g'),'..'+dirSp)+p.substr(s):p;
    169 }
    170 //	想要保持 Protocol，但卻是不同機器時	http://nedbatchelder.com/blog/200710.html#e20071017T215538
    171 //alert(relative_path('//lyrics.meicho.com.tw/game/game.pl?seg=diary21','cgi-bin/game/photo/'));WScript.Quit();
    172
    173
    174
    175 CeL.IO.file
    176 .
    177 /**
    178  * determine base path.
    179  * 給定 base path 的結構後，藉由 path_now 推測 base path 的 full path.
    180  * cf.
    181  * @param {String} base_path_structure	base path 的範本結構
    182  * @param {String} path_now
    183  * @return	{String}	推測的 base path full path
    184  * @example
    185  * alert(determine_base_path('kanashimi/www/cgi-bin/game/'));
    186  * @requres	reducePath,getPathOnly,dirSp,dirSpR
    187  * @memberOf	CeL.IO.file
    188  */
    189 determine_base_path=function (base_path_structure, path_now) {
    190 	if (!path_now)
    191 		path_now = library_namespace.get_base_path();
    192
    193 	var p = reducePath(path_now, 1);
    194 	if (!p)
    195 		return;
    196 	if (!base_path_structure)
    197 		return p;
    198
    199 	var i, j, k, t,
    200 	// or use .split()
    201 	d = getPathOnly(reducePath(base_path_structure, 1))
    202 		.match(new RegExp('([^' + dirSpR + ']+' + dirSpR + ')', 'g'));
    203 	if (!d)
    204 		return;
    205
    206 	for (i = 0, t = ''; i < d.length; i++)
    207 		if (p.lastIndexOf(dirSp + d[i]) !== -1) {
    208 			t = dirSp;
    209 			while (d[i] && (k = p.lastIndexOf(t + d[i])) !== -1)
    210 				j = k, t += d[i++];
    211 			while (d[i])
    212 				t += d[i++];
    213 			break;
    214 		}
    215 	if (!t)
    216 		//alert("Can't find base directory of this file!\n" + path_name + '\n\nTreat base directory as:\n' + p);
    217 		return p;
    218
    219 	//alert('determine_base_path:\nbp='+bp+'\npn='+pn+'\n\n'+p.slice(0,j)+'\n'+t+'\n'+(t.replace(new RegExp('([^'+dirSpR+']+'+dirSpR+')','g'),' ').length-1));
    220 	return p.slice(0, j) + t;
    221 };
    222
    223
    224 CeL.IO.file
    225 .
    226 /**
    227  * cf: getFN()
    228  * @param {String} path	path name
    229  * @return
    230  * @memberOf	CeL.IO.file
    231  */
    232 parse_path=function (path) {
    233 	if (typeof path !== 'string' || !path)
    234 		return;
    235
    236 	var path_data = {
    237 		oInput : path
    238 	}, m;
    239
    240 	if (m = path.match(/^(([A-Za-z]):\\)(([^\\]+\\)*)([^\\]+)?$/))
    241 		path_data.drive = m[2],
    242 		path_data.path_name = m[3],
    243 		path_data.file_name = m[5];
    244 	else if (m = path
    245 			.match(/^file:\/\/\/([A-Za-z]):\/(([^\/]+\/)*)([^\/]+)?$/))
    246 		path_data.drive = m[1],
    247 		path_data.path_name = m[2].replace(/\//g, '\\'),
    248 		path_data.file_name = m[4].replace(/\//g, '\\');
    249
    250 	path_data.path = path_data.path_name + path_data.file_name;
    251 	path_data.location = path_data.drive + ':\\' + path_data.path;
    252 	path_data.directory = path_data.drive + ':\\' + path_data.path_name;
    253
    254 	return path_data;
    255 };
    256
    257
    258 CeL.IO.file
    259 .
    260 /**
    261  * is absolute or relative path, not very good solution
    262  * @param {String} path
    263  * @return
    264  * @requires	dirSp,dirSpR
    265  * @memberOf	CeL.IO.file
    266  */
    267 is_absolute_path=function (path) {
    268 	//alert(typeof path + '\n' + path);
    269 	return path
    270 		&& (dirSp === '/' && path.charAt(0) === dirSp || new RegExp(
    271 		'^(\\\\|[A-Za-z]+:)' + dirSpR).test(path))
    272 		// ?true:false
    273 		;
    274 };
    275
    276
    277 //	轉成path（加'\'）
    278 function turnToPath(p){return p?p+(p.slice(-1)=='\\'?'':'\\'):'';}
    279 //	僅取得path部分(包括 dirSp)，不包括檔名。
    280 //getFilePath[generateCode.dLK]='dirSp';
    281 function getFilePath(p){
    282  var i=p.lastIndexOf(dirSp);
    283  if(i==-1)p+=dirSp;	//	相對路徑?
    284  else if(i<p.length-1)p=p.slice(0,i+1);	//	取得path部分
    285  return p;
    286 }
    287 /*	傳回包括檔名之絕對/相對路徑，假如是資料夾，也會回傳資料夾路徑。可包含'.','..'等	the return value include ? #
    288 	在Win/DOS下輸入'\'..會加上base driver
    289 	若只要相對路徑，可用reducePath()。取得如'..\out'的絕對路徑可用getFP('../out',1)
    290 */
    291 //getFP[generateCode.dLK]='determine_base_path,reducePath,is_absolute_path,getPathOnly,relative_path';
    292 function getFP(p,m,bp){	//	path,mode=0:傳回auto(維持原狀),1:傳回絕對路徑,2:傳回相對路徑,base path
    293  //old:	return (p.lastIndexOf('\\')==-1&&p.lastIndexOf('/')==-1?getFolder(getScriptFullName()):'')+p;//getF
    294  if(!p)return'';
    295  if(p.charAt(0)=='\\'&&determine_base_path(bp).match(/^(\\\\|[A-Za-z]+:)/))p=RegExp.$1+p;
    296  p=reducePath(p);
    297  if(m==1){
    298   if(!is_absolute_path(p))p=reducePath((bp?getPathOnly(bp):determine_base_path())+p);	//	當為相對路徑時前置base path
    299  }else if(m==2&&is_absolute_path(p))p=relative_path(determine_base_path(bp),p);
    300  return p;
    301 }
    302 //	傳回檔名部分，the return value include ? #
    303 //getFN[generateCode.dLK]='getFP,dirSp';
    304 function getFN(p,bp,m){	//	path,base path,mode=0:檔名,1:(當輸入為不可信賴的字串時)去除檔名中不允許的字元，割掉? #等
    305  p=getFP(p,0,bp);
    306  p=p.slice(p.lastIndexOf(dirSp)+1);	//	不能用.substr(p.lastIndexOf(dirSp))+dirSp,因為p.lastIndexOf(dirSp)可能==-1	//	比起(m=p.lastIndexOf(dirSp))==-1?p:p.substr(m+1);此法比較直接，不過感覺多一道手續…
    307  if(m){
    308   if(p.match(/[#?]/))p=p.substr(0,RegExp.lastIndex-1);
    309   p=p.replace(/[\\\/:*?"<>|]/g,'_');//[ \.]	//	去除檔名中不允許的字元
    310  }
    311  return p;
    312 }
    313 //	傳回檔案/資料夾物件	FileSystemObjectのバグ(制限)で、環境によっては2G以上の領域を認識できません。WSH5.6ではこのバグが修正されています。
    314 //getF[generateCode.dLK]='isFile,dealShortcut,getFP,dirSp,getFolder,initWScriptObj';
    315 function getF(p,m,bp){	//	path,mode=0:auto(維持原狀),1:絕對路徑,2:相對路徑,base path
    316  try{return isFile(p=dealShortcut(getFP(p,m,bp),1))?fso.GetFile(p):fso.GetFolder(p);}
    317  catch(e){return p.indexOf(dirSp)==-1?getF(getFolder(WScript.ScriptFullName)+p,m,bp):null;}
    318 }
    319 //alert(getFP('\program files\\xxx\\xxx.exe',2));
    320
    321
    322
    323
    324
    325 return (
    326 	CeL.IO.file
    327 );
    328 };
    329
    330 //===================================================
    331
    332 CeL.setup_module(module_name, code_for_including);
    333
    334 };
    335