001 package railo.commons.io.res.util; 002 003 import java.io.File; 004 import java.io.FileNotFoundException; 005 import java.io.IOException; 006 import java.io.InputStream; 007 import java.util.ArrayList; 008 import java.util.HashMap; 009 010 import railo.commons.io.IOUtil; 011 import railo.commons.io.SystemUtil; 012 import railo.commons.io.res.ContentType; 013 import railo.commons.io.res.ContentTypeImpl; 014 import railo.commons.io.res.Resource; 015 import railo.commons.io.res.ResourcesImpl; 016 import railo.commons.io.res.filter.ExtensionResourceFilter; 017 import railo.commons.io.res.filter.ResourceFilter; 018 import railo.commons.io.res.filter.ResourceNameFilter; 019 import railo.commons.io.res.type.http.HTTPResource; 020 import railo.commons.lang.StringUtil; 021 import railo.runtime.PageContext; 022 import railo.runtime.PageContextImpl; 023 import railo.runtime.PageSource; 024 import railo.runtime.PageSourceImpl; 025 import railo.runtime.config.Config; 026 import railo.runtime.config.ConfigWebImpl; 027 import railo.runtime.exp.ExpressionException; 028 import railo.runtime.exp.PageException; 029 import railo.runtime.type.util.ArrayUtil; 030 import railo.runtime.type.util.ListUtil; 031 032 public final class ResourceUtil { 033 034 public static final int MIMETYPE_CHECK_EXTENSION=1; 035 public static final int MIMETYPE_CHECK_HEADER=2; 036 037 038 /** 039 * Field <code>FILE_SEPERATOR</code> 040 */ 041 public static final char FILE_SEPERATOR=File.separatorChar; 042 /** 043 * Field <code>FILE_ANTI_SEPERATOR</code> 044 */ 045 public static final char FILE_ANTI_SEPERATOR=(FILE_SEPERATOR=='/')?'\\':'/'; 046 047 /** 048 * Field <code>TYPE_DIR</code> 049 */ 050 public static final short TYPE_DIR=0; 051 052 /** 053 * Field <code>TYPE_FILE</code> 054 */ 055 public static final short TYPE_FILE=1; 056 057 /** 058 * Field <code>LEVEL_FILE</code> 059 */ 060 public static final short LEVEL_FILE=0; 061 /** 062 * Field <code>LEVEL_PARENT_FILE</code> 063 */ 064 public static final short LEVEL_PARENT_FILE=1; 065 /** 066 * Field <code>LEVEL_GRAND_PARENT_FILE</code> 067 */ 068 public static final short LEVEL_GRAND_PARENT_FILE=2; 069 070 071 private static boolean isUnix=SystemUtil.isUnix(); 072 073 private static final HashMap<String, String> EXT_MT=new HashMap<String, String>(); 074 static { 075 EXT_MT.put("ai","application/postscript"); 076 EXT_MT.put("aif","audio/x-aiff"); 077 EXT_MT.put("aifc","audio/x-aiff"); 078 EXT_MT.put("aiff","audio/x-aiff"); 079 EXT_MT.put("au","audio/basic"); 080 EXT_MT.put("avi","video/x-msvideo"); 081 EXT_MT.put("bin","application/octet-stream"); 082 EXT_MT.put("bmp","image/x-ms-bmp"); 083 EXT_MT.put("cgm","image/cgm"); 084 EXT_MT.put("cmx","image/x-cmx"); 085 EXT_MT.put("csh","application/x-csh"); 086 EXT_MT.put("cfm","text/html"); 087 EXT_MT.put("cfml","text/html"); 088 EXT_MT.put("css","text/css"); 089 EXT_MT.put("doc","application/msword"); 090 EXT_MT.put("docx","application/msword"); 091 EXT_MT.put("eps","application/postscript"); 092 EXT_MT.put("exe","application/octet-stream"); 093 EXT_MT.put("gif","image/gif"); 094 EXT_MT.put("gtar","application/x-gtar"); 095 EXT_MT.put("hqx","application/mac-binhex40"); 096 EXT_MT.put("htm","text/html"); 097 EXT_MT.put("html","text/html"); 098 EXT_MT.put("jpe","image/jpeg"); 099 EXT_MT.put("jpeg","image/jpeg"); 100 EXT_MT.put("jpg","image/jpeg"); 101 EXT_MT.put("js","text/javascript"); 102 EXT_MT.put("mmid","x-music/x-midi"); 103 EXT_MT.put("mov","video/quicktime"); 104 EXT_MT.put("mp2a","audio/x-mpeg-2"); 105 EXT_MT.put("mp2v","video/mpeg-2"); 106 EXT_MT.put("mp3","audio/mpeg"); 107 EXT_MT.put("mp4","video/mp4"); 108 EXT_MT.put("mpa","audio/x-mpeg"); 109 EXT_MT.put("mpa2","audio/x-mpeg-2"); 110 EXT_MT.put("mpeg","video/mpeg"); 111 EXT_MT.put("mpega","audio/x-mpeg"); 112 EXT_MT.put("mpg","video/mpeg"); 113 EXT_MT.put("mpv2","video/mpeg-2"); 114 EXT_MT.put("pbm","image/x-portable-bitmap"); 115 EXT_MT.put("pcd","image/x-photo-cd"); 116 EXT_MT.put("pdf","application/pdf"); 117 EXT_MT.put("pgm","image/x-portable-graymap"); 118 EXT_MT.put("pict","image/x-pict"); 119 EXT_MT.put("pl","application/x-perl"); 120 EXT_MT.put("png","image/png"); 121 EXT_MT.put("php","text/html"); 122 EXT_MT.put("pnm","image/x-portable-anymap"); 123 EXT_MT.put("ppm","image/x-portable-pixmap"); 124 EXT_MT.put("ppt","application/vnd.ms-powerpoint"); 125 EXT_MT.put("pptx","application/vnd.ms-powerpoint"); 126 EXT_MT.put("ps","application/postscript"); 127 EXT_MT.put("qt","video/quicktime"); 128 EXT_MT.put("rgb","image/rgb"); 129 EXT_MT.put("rtf","application/rtf"); 130 EXT_MT.put("sh","application/x-sh"); 131 EXT_MT.put("sit","application/x-stuffit"); 132 EXT_MT.put("swf","application/x-shockwave-flash"); 133 EXT_MT.put("tar","application/x-tar"); 134 EXT_MT.put("tcl","application/x-tcl"); 135 EXT_MT.put("tif","image/tiff"); 136 EXT_MT.put("tiff","image/tiff"); 137 EXT_MT.put("txt","text/plain"); 138 EXT_MT.put("wav","audio/x-wav"); 139 EXT_MT.put("wma","audio/x-ms-wma"); 140 EXT_MT.put("wmv","video/x-ms-wmv"); 141 EXT_MT.put("xbm","image/x-xbitmap"); 142 EXT_MT.put("xhtml","application/xhtml+xml"); 143 EXT_MT.put("xls","application/vnd.ms-excel"); 144 EXT_MT.put("xlsx","application/vnd.ms-excel"); 145 EXT_MT.put("xpm","image/x-xpixmap"); 146 EXT_MT.put("zip","application/zip"); 147 148 } 149 150 151 //private static Magic mimeTypeParser; 152 153 /** 154 * cast a String (argumet destination) to a File Object, 155 * if destination is not a absolute, file object will be relative to current position (get from PageContext) 156 * file must exist otherwise throw exception 157 * @param pc Page Context to et actuell position in filesystem 158 * @param path relative or absolute path for file object 159 * @return file object from destination 160 * @throws ExpressionException 161 */ 162 public static Resource toResourceExisting(PageContext pc ,String path) throws ExpressionException { 163 return toResourceExisting(pc, path,pc.getConfig().allowRealPath()); 164 } 165 public static Resource toResourceExisting(PageContext pc ,String path,boolean allowRealpath) throws ExpressionException { 166 path=path.replace('\\','/'); 167 Resource res = pc.getConfig().getResource(path); 168 169 // not allow realpath 170 if(!allowRealpath){ 171 if(res.exists()) return res; 172 throw new ExpressionException("file or directory "+path+" not exist"); 173 } 174 175 if(res.isAbsolute() && res.exists()) { 176 return res; 177 } 178 179 //if(allowRealpath){ 180 if(StringUtil.startsWith(path,'/')) { 181 PageContextImpl pci=(PageContextImpl) pc; 182 ConfigWebImpl cwi=(ConfigWebImpl) pc.getConfig(); 183 PageSource[] sources = cwi.getPageSources(pci, pc.getApplicationContext().getMappings(), path, false, pci.useSpecialMappings(), true); 184 //Resource[] reses = cwi.getPhysicalResourcesX(pc,pc.getApplicationContext().getMappings(),path,false,pci.useSpecialMappings(),true); 185 if(!ArrayUtil.isEmpty(sources)) { 186 187 for(int i=0;i<sources.length;i++){ 188 if(sources[i].exists()) return sources[i].getResource(); 189 } 190 } 191 //res = pc.getPhysical(path,true); 192 //if(res!=null && res.exists()) return res; 193 } 194 res=getRealResource(pc, path, res); 195 if(res.exists()) return res; 196 //} 197 198 throw new ExpressionException("file or directory "+path+" not exist"); 199 } 200 201 public static Resource toResourceExisting(Config config ,String path) throws ExpressionException { 202 path=path.replace('\\','/'); 203 Resource res = config.getResource(path); 204 205 if(res.exists()) return res; 206 throw new ExpressionException("file or directory "+path+" not exist"); 207 } 208 209 public static Resource toResourceNotExisting(Config config ,String path) { 210 Resource res; 211 path=path.replace('\\','/'); 212 res=config.getResource(path); 213 return res; 214 } 215 216 217 218 /** 219 * cast a String (argumet destination) to a File Object, 220 * if destination is not a absolute, file object will be relative to current position (get from PageContext) 221 * at least parent must exist 222 * @param pc Page Context to et actuell position in filesystem 223 * @param destination relative or absolute path for file object 224 * @return file object from destination 225 * @throws ExpressionException 226 */ 227 228 public static Resource toResourceExistingParent(PageContext pc ,String destination) throws ExpressionException { 229 return toResourceExistingParent(pc, destination, pc.getConfig().allowRealPath()); 230 } 231 232 public static Resource toResourceExistingParent(PageContext pc ,String destination, boolean allowRealpath) throws ExpressionException { 233 destination=destination.replace('\\','/'); 234 Resource res=pc.getConfig().getResource(destination); 235 236 // not allow realpath 237 if(!allowRealpath){ 238 if(res.exists() || parentExists(res)) 239 return res; 240 throw new ExpressionException("parent directory "+res.getParent()+" for file "+destination+" doesn't exist"); 241 242 } 243 244 // allow realpath 245 if(res.isAbsolute() && (res.exists() || parentExists(res))) { 246 return res; 247 } 248 249 if(StringUtil.startsWith(destination,'/')) { 250 PageContextImpl pci=(PageContextImpl) pc; 251 ConfigWebImpl cwi=(ConfigWebImpl) pc.getConfig(); 252 PageSource[] sources = cwi.getPageSources(pci, pc.getApplicationContext().getMappings(), destination, 253 false, pci.useSpecialMappings(),true); 254 //Resource[] reses = cwi.getPhysicalResourcesX(pc,pc.getApplicationContext().getMappings(),destination,false,pci.useSpecialMappings(),true); 255 if(!ArrayUtil.isEmpty(sources)) { 256 for(int i=0;i<sources.length;i++){ 257 if(sources[i].exists() || parentExists(sources[i])) { 258 res=sources[i].getResource(); 259 if(res!=null) return res; 260 } 261 } 262 } 263 } 264 res=getRealResource(pc, destination, res); 265 if(res!=null && (res.exists() || parentExists(res))) return res; 266 267 throw new ExpressionException("parent directory "+res.getParent()+" for file "+destination+" doesn't exist"); 268 269 } 270 271 /** 272 * cast a String (argument destination) to a File Object, 273 * if destination is not a absolute, file object will be relative to current position (get from PageContext) 274 * existing file is prefered but dont must exist 275 * @param pc Page Context to et actuell position in filesystem 276 * @param destination relative or absolute path for file object 277 * @return file object from destination 278 */ 279 280 public static Resource toResourceNotExisting(PageContext pc ,String destination) { 281 return toResourceNotExisting(pc ,destination,pc.getConfig().allowRealPath()); 282 } 283 284 public static Resource toResourceNotExisting(PageContext pc ,String destination,boolean allowRealpath) { 285 Resource res; 286 destination=destination.replace('\\','/'); 287 288 if(!allowRealpath){ 289 res=pc.getConfig().getResource(destination); 290 return res; 291 } 292 293 boolean isUNC; 294 if(!(isUNC=isUNCPath(destination)) && StringUtil.startsWith(destination,'/')) { 295 PageContextImpl pci=(PageContextImpl) pc; 296 ConfigWebImpl cwi=(ConfigWebImpl) pc.getConfig(); 297 PageSource[] sources = cwi.getPageSources(pci, pc.getApplicationContext().getMappings(), destination, false, 298 pci.useSpecialMappings(), SystemUtil.isWindows()); 299 //Resource[] arr = cwi.getPhysicalResources(pc,pc.getApplicationContext().getMappings(),destination,false,pci.useSpecialMappings(),SystemUtil.isWindows()); 300 if(!ArrayUtil.isEmpty(sources)) { 301 for(int i=0;i<sources.length;i++){ 302 res=sources[i].getResource(); 303 if(res!=null) return res; 304 } 305 } 306 //Resource res2 = pc.getPhysical(destination,SystemUtil.isWindows()); 307 //if(res2!=null) return res2; 308 } 309 if(isUNC) { 310 res=pc.getConfig().getResource(destination.replace('/','\\')); 311 } 312 else res=pc.getConfig().getResource(destination); 313 if(res.isAbsolute()) return res; 314 315 return getRealResource(pc,destination,res); 316 } 317 318 private static Resource getRealResource(PageContext pc, String destination, Resource defaultValue) { 319 PageSource ps = pc.getCurrentPageSource(); 320 if(ps!=null) { 321 ps=ps.getRealPage(destination); 322 323 if(ps!=null){ 324 Resource res = ps.getResource(); 325 if(res!=null)return getCanonicalResourceEL(res); 326 } 327 328 } 329 return defaultValue; 330 } 331 332 public static boolean isUNCPath(String path) { 333 return SystemUtil.isWindows() && ( path.startsWith("//") || path.startsWith( "\\\\" ) ); 334 } 335 336 /** 337 * transalte the path of the file to a existing file path by changing case of letters 338 * Works only on Linux, becasue 339 * 340 * Example Unix: 341 * we have a existing file with path "/usr/virtual/myFile.txt" 342 * now you call this method with path "/Usr/Virtual/myfile.txt" 343 * the result of the method will be "/usr/virtual/myFile.txt" 344 * 345 * if there are more file with rhe same name but different cases 346 * Example: 347 * /usr/virtual/myFile.txt 348 * /usr/virtual/myfile.txt 349 * /Usr/Virtual/myFile.txt 350 * the nearest case wil returned 351 * 352 * @param res 353 * @return file 354 */ 355 public static Resource toExactResource(Resource res) { 356 res=getCanonicalResourceEL(res); 357 if(isUnix) { 358 if(res.exists()) return res; 359 return _check(res); 360 361 } 362 return res; 363 } 364 private static Resource _check(Resource file) { 365 // todo cascade durch while ersetzten 366 Resource parent=file.getParentResource(); 367 if(parent==null) return file; 368 369 if(!parent.exists()) { 370 Resource op=parent; 371 parent=_check(parent); 372 if(op==parent) return file; 373 if((file = parent.getRealResource(file.getName())).exists()) return file; 374 } 375 376 String[] files = parent.list(); 377 if(files==null) return file; 378 String name=file.getName(); 379 for(int i=0;i<files.length;i++) { 380 if(name.equalsIgnoreCase(files[i])) 381 return parent.getRealResource(files[i]); 382 } 383 return file; 384 } 385 386 /** 387 * create a file if possible, return file if ok, otherwise return null 388 * @param res file to touch 389 * @param level touch also parent and grand parent 390 * @param type is file or directory 391 * @return file if exists, otherwise null 392 */ 393 public static Resource createResource(Resource res, short level, short type) { 394 395 boolean asDir=type==TYPE_DIR; 396 // File 397 if(level>=LEVEL_FILE && res.exists() && ((res.isDirectory() && asDir)||(res.isFile() && !asDir))) { 398 return getCanonicalResourceEL(res); 399 } 400 401 // Parent 402 Resource parent=res.getParentResource(); 403 if(level>=LEVEL_PARENT_FILE && parent!=null && parent.exists() && canRW(parent)) { 404 if(asDir) { 405 if(res.mkdirs()) return getCanonicalResourceEL(res); 406 } 407 else { 408 if(createNewResourceEL(res))return getCanonicalResourceEL(res); 409 } 410 return getCanonicalResourceEL(res); 411 } 412 413 // Grand Parent 414 if(level>=LEVEL_GRAND_PARENT_FILE && parent!=null) { 415 Resource gparent=parent.getParentResource(); 416 if(gparent!=null && gparent.exists() && canRW(gparent)) { 417 if(asDir) { 418 if(res.mkdirs())return getCanonicalResourceEL(res); 419 } 420 else { 421 if(parent.mkdirs() && createNewResourceEL(res)) 422 return getCanonicalResourceEL(res); 423 } 424 } 425 } 426 return null; 427 } 428 429 public static void setAttribute(Resource res,String attributes) throws IOException { 430 /*if(res instanceof File && SystemUtil.isWindows()) { 431 if(attributes.length()>0) { 432 attributes=ResourceUtil.translateAttribute(attributes); 433 Runtime.getRuntime().exec("attrib "+attributes+" " + res.getAbsolutePath()); 434 } 435 } 436 else {*/ 437 short[] flags = strAttrToBooleanFlags(attributes); 438 439 if(flags[READ_ONLY]==YES)res.setWritable(false); 440 else if(flags[READ_ONLY]==NO)res.setWritable(true); 441 442 if(flags[HIDDEN]==YES) res.setAttribute(Resource.ATTRIBUTE_HIDDEN, true);//setHidden(true); 443 else if(flags[HIDDEN]==NO) res.setAttribute(Resource.ATTRIBUTE_HIDDEN, false);//res.setHidden(false); 444 445 if(flags[ARCHIVE]==YES) res.setAttribute(Resource.ATTRIBUTE_ARCHIVE, true);//res.setArchive(true); 446 else if(flags[ARCHIVE]==NO) res.setAttribute(Resource.ATTRIBUTE_ARCHIVE, false);//res.setArchive(false); 447 448 if(flags[SYSTEM]==YES) res.setAttribute(Resource.ATTRIBUTE_SYSTEM, true);//res.setSystem(true); 449 else if(flags[SYSTEM]==NO) res.setAttribute(Resource.ATTRIBUTE_SYSTEM, false);//res.setSystem(false); 450 451 //} 452 } 453 454 //private static final int NORMAL=0; 455 private static final int READ_ONLY=0; 456 private static final int HIDDEN=1; 457 private static final int ARCHIVE=2; 458 private static final int SYSTEM=3; 459 460 //private static final int IGNORE=0; 461 private static final int NO=1; 462 private static final int YES=2; 463 464 465 466 private static short[] strAttrToBooleanFlags(String attributes) throws IOException { 467 468 String[] arr; 469 try { 470 arr = ListUtil.toStringArray(ListUtil.listToArrayRemoveEmpty(attributes.toLowerCase(),',')); 471 } 472 catch (PageException e) { 473 arr=new String[0]; 474 } 475 476 boolean hasNormal=false; 477 boolean hasReadOnly=false; 478 boolean hasHidden=false; 479 boolean hasArchive=false; 480 boolean hasSystem=false; 481 482 for(int i=0;i<arr.length;i++) { 483 String str=arr[i].trim().toLowerCase(); 484 if(str.equals("readonly") || str.equals("read-only") || str.equals("+r")) hasReadOnly=true; 485 else if(str.equals("normal") || str.equals("temporary")) hasNormal=true; 486 else if(str.equals("hidden") || str.equals("+h")) hasHidden=true; 487 else if(str.equals("system") || str.equals("+s")) hasSystem=true; 488 else if(str.equals("archive") || str.equals("+a")) hasArchive=true; 489 else throw new IOException("invalid attribute definition ["+str+"]"); 490 } 491 492 short[] flags=new short[4]; 493 494 if(hasReadOnly)flags[READ_ONLY]=YES; 495 else if(hasNormal)flags[READ_ONLY]=NO; 496 497 if(hasHidden)flags[HIDDEN]=YES; 498 else if(hasNormal)flags[HIDDEN]=NO; 499 500 if(hasSystem)flags[SYSTEM]=YES; 501 else if(hasNormal)flags[SYSTEM]=NO; 502 503 if(hasArchive)flags[ARCHIVE]=YES; 504 else if(hasNormal)flags[ARCHIVE]=NO; 505 506 return flags; 507 } 508 509 510 /** 511 * sets attributes of a file on Windows system 512 * @param res 513 * @param attributes 514 * @throws PageException 515 * @throws IOException 516 */ 517 public static String translateAttribute(String attributes) throws IOException { 518 short[] flags = strAttrToBooleanFlags(attributes); 519 520 StringBuilder sb=new StringBuilder(); 521 if(flags[READ_ONLY]==YES)sb.append(" +R"); 522 else if(flags[READ_ONLY]==NO)sb.append(" -R"); 523 524 if(flags[HIDDEN]==YES)sb.append(" +H"); 525 else if(flags[HIDDEN]==NO)sb.append(" -H"); 526 527 if(flags[SYSTEM]==YES)sb.append(" +S"); 528 else if(flags[SYSTEM]==NO)sb.append(" -S"); 529 530 if(flags[ARCHIVE]==YES)sb.append(" +A"); 531 else if(flags[ARCHIVE]==NO)sb.append(" -A"); 532 533 return sb.toString(); 534 } 535 536 /* * 537 * transalte a path in a proper form 538 * example susi\petere -> /susi/peter 539 * @param path 540 * @return path 541 * / 542 public static String translatePath(String path) { 543 /*path=prettifyPath(path); 544 if(path.indexOf('/')!=0)path='/'+path; 545 int index=path.lastIndexOf('/'); 546 // remove slash at the end 547 if(index==path.length()-1) path=path.substring(0,path.length()-1); 548 return path;* / 549 return translatePath(path, true, false); 550 }*/ 551 552 /* * 553 * transalte a path in a proper form 554 * example susi\petere -> susi/peter/ 555 * @param path 556 * @return path 557 * / 558 public static String translatePath2x(String path) { 559 /*path=prettifyPath(path); 560 if(path.indexOf('/')==0)path=path.substring(1); 561 int index=path.lastIndexOf('/'); 562 // remove slash at the end 563 if(index!=path.length()-1) path=path+'/';* / 564 return translatePath(path, false, true); 565 }*/ 566 567 568 public static String translatePath(String path, boolean slashAdBegin, boolean slashAddEnd) { 569 path=prettifyPath(path); 570 571 // begin 572 if(slashAdBegin) { 573 if(path.indexOf('/')!=0)path='/'+path; 574 } 575 else { 576 if(path.indexOf('/')==0)path=path.substring(1); 577 } 578 579 // end 580 int index=path.lastIndexOf('/'); 581 if(slashAddEnd) { 582 if(index!=path.length()-1) path=path+'/'; 583 } 584 else { 585 if(index==path.length()-1 && index>-1) path=path.substring(0,path.length()-1); 586 } 587 return path; 588 } 589 590 591 592 593 /** 594 * transalte a path in a proper form and cut name away 595 * example susi\petere -> /susi/ and peter 596 * @param path 597 * @return 598 */ 599 public static String[] translatePathName(String path) { 600 path=prettifyPath(path); 601 if(path.indexOf('/')!=0)path='/'+path; 602 int index=path.lastIndexOf('/'); 603 // remove slash at the end 604 if(index==path.length()-1) path=path.substring(0,path.length()-1); 605 606 index=path.lastIndexOf('/'); 607 String name; 608 if(index==-1) { 609 name=path; 610 path = "/"; 611 } 612 else { 613 name = path.substring(index+1); 614 path = path.substring(0,index+1); 615 } 616 return new String[] {path,name}; 617 } 618 619 public static String prettifyPath(String path) { 620 if(path==null) return null; 621 path=path.replace('\\','/'); 622 return StringUtil.replace(path, "//", "/", false); 623 // TODO /aaa/../bbb/ 624 } 625 626 public static String removeScheme(String scheme, String path) { 627 if(path.indexOf("://")==scheme.length() && StringUtil.startsWithIgnoreCase(path,scheme)) path=path.substring(3+scheme.length()); 628 return path; 629 } 630 631 /** 632 * merge to path parts to one 633 * @param parent 634 * @param child 635 * @return 636 */ 637 public static String merge(String parent, String child) { 638 if(child.length()<=2) { 639 if(child.length()==0) return parent; 640 if(child.equals(".")) return parent; 641 if(child.equals("..")) child="../"; 642 } 643 644 645 646 parent=translatePath(parent, true, false); 647 child=prettifyPath(child);//child.replace('\\', '/'); 648 649 if(child.startsWith("./"))child=child.substring(2); 650 if(StringUtil.startsWith(child, '/'))return parent.concat(child); 651 if(!StringUtil.startsWith(child, '.'))return parent.concat("/").concat(child); 652 653 654 while(child.startsWith("../")) { 655 parent=pathRemoveLast(parent); 656 child=child.substring(3); 657 } 658 if(StringUtil.startsWith(child, '/'))return parent.concat(child); 659 return parent.concat("/").concat(child); 660 } 661 662 private static String pathRemoveLast(String path) { 663 if(path.length()==0) return ".."; 664 665 else if(path.endsWith("..")){ 666 return path.concat("/.."); 667 } 668 return path.substring(0,path.lastIndexOf('/')); 669 } 670 671 /** 672 * Returns the canonical form of this abstract pathname. 673 * @param res file to get canoncial form from it 674 * 675 * @return The canonical pathname string denoting the same file or 676 * directory as this abstract pathname 677 * 678 * @throws SecurityException 679 * If a required system property value cannot be accessed. 680 */ 681 public static String getCanonicalPathEL(Resource res) { 682 try { 683 return res.getCanonicalPath(); 684 } catch (IOException e) { 685 return res.toString(); 686 } 687 } 688 689 690 /** 691 * Returns the canonical form of this abstract pathname. 692 * @param res file to get canoncial form from it 693 * 694 * @return The canonical pathname string denoting the same file or 695 * directory as this abstract pathname 696 * 697 * @throws SecurityException 698 * If a required system property value cannot be accessed. 699 */ 700 public static Resource getCanonicalResourceEL(Resource res) { 701 if(res==null) return res; 702 try { 703 return res.getCanonicalResource(); 704 } catch (IOException e) { 705 return res.getAbsoluteResource(); 706 } 707 } 708 709 /** 710 * creates a new File 711 * @param res 712 * @return was successfull 713 */ 714 public static boolean createNewResourceEL(Resource res) { 715 try { 716 res.createFile(false); 717 return true; 718 } catch (IOException e) { 719 return false; 720 } 721 } 722 723 public static boolean exists(Resource res) { 724 return res!=null && res.exists(); 725 } 726 727 728 /** 729 * check if file is read and writable 730 * @param res 731 * @return is or not 732 */ 733 public static boolean canRW(Resource res) { 734 return res.isReadable() && res.isWriteable(); 735 } 736 737 738 /** 739 * similat to linux bash fuction toch, create file if not exist oherwise change last modified date 740 * @param res 741 * @throws IOException 742 */ 743 public static void touch(Resource res) throws IOException { 744 if(res.exists()) { 745 res.setLastModified(System.currentTimeMillis()); 746 } 747 else { 748 res.createFile(true); 749 } 750 } 751 752 public static void clear(Resource res) throws IOException { 753 if(res.exists()) { 754 IOUtil.write(res, new byte[0]); 755 } 756 else { 757 res.createFile(true); 758 } 759 } 760 761 762 763 /** 764 * return the mime type of a file, dont check extension 765 * @param res 766 * @param defaultValue 767 * @return mime type of the file 768 */ 769 public static String getMimeType(Resource res, String defaultValue) { 770 return getMimeType(res, MIMETYPE_CHECK_HEADER,defaultValue); 771 } 772 773 public static String getMimeType(Resource res, int checkingType, String defaultValue) { 774 775 // check Extension 776 if((checkingType&MIMETYPE_CHECK_EXTENSION)!=0) { 777 String ext = getExtension(res, null); 778 if(!StringUtil.isEmpty(ext)){ 779 String mt=EXT_MT.get(ext.trim().toLowerCase()); 780 if(mt!=null) return mt; 781 } 782 } 783 784 // check mimetype 785 if((checkingType&MIMETYPE_CHECK_HEADER)!=0) { 786 InputStream is=null; 787 try { 788 is = res.getInputStream(); 789 return IOUtil.getMimeType(is, defaultValue); 790 } 791 catch (Throwable t) { 792 return defaultValue; 793 } 794 finally { 795 IOUtil.closeEL(is); 796 } 797 } 798 799 return defaultValue; 800 } 801 802 803 804 805 /** 806 * check if file is a child of given directory 807 * @param file file to search 808 * @param dir directory to search 809 * @return is inside or not 810 */ 811 public static boolean isChildOf(Resource file, Resource dir) { 812 while(file!=null) { 813 if(file.equals(dir)) return true; 814 file=file.getParentResource(); 815 } 816 return false; 817 } 818 /** 819 * return diffrents of one file to a other if first is child of second otherwise return null 820 * @param file file to search 821 * @param dir directory to search 822 */ 823 public static String getPathToChild(Resource file, Resource dir) { 824 if(dir==null || !file.getResourceProvider().getScheme().equals(dir.getResourceProvider().getScheme())) return null; 825 boolean isFile=file.isFile(); 826 String str="/"; 827 while(file!=null) { 828 if(file.equals(dir)) { 829 if(isFile) return str.substring(0,str.length()-1); 830 return str; 831 } 832 str="/"+file.getName()+str; 833 file=file.getParentResource(); 834 } 835 return null; 836 } 837 838 /** 839 * get the Extension of a file 840 * @param res 841 * @return extension of file 842 */ 843 public static String getExtension(Resource res, String defaultValue) { 844 return getExtension(res.getName(),defaultValue); 845 } 846 847 /** 848 * get the Extension of a file 849 * @param strFile 850 * @return extension of file 851 */ 852 public static String getExtension(String strFile, String defaultValue) { 853 int pos=strFile.lastIndexOf('.'); 854 if(pos==-1)return defaultValue; 855 return strFile.substring(pos+1); 856 } 857 858 public static String getName(String strFileName) { 859 int pos=strFileName.lastIndexOf('.'); 860 if(pos==-1)return strFileName; 861 return strFileName.substring(0,pos); 862 } 863 864 /** 865 * split a FileName in Parts 866 * @param fileName 867 * @return new String[]{name[,extension]} 868 */ 869 public static String[] splitFileName(String fileName) { 870 int pos=fileName.lastIndexOf('.'); 871 if(pos==-1) { 872 return new String[]{fileName}; 873 } 874 return new String[]{fileName.substring(0,pos),fileName.substring(pos+1)}; 875 } 876 877 /** 878 * change extesnion of file and return new file 879 * @param file 880 * @param newExtension 881 * @return file with new Extension 882 */ 883 public static Resource changeExtension(Resource file, String newExtension) { 884 String ext=getExtension(file,null); 885 if(ext==null) return file.getParentResource().getRealResource(file.getName()+'.'+newExtension); 886 //new File(file.getParentFile(),file.getName()+'.'+newExtension); 887 String name=file.getName(); 888 return file.getParentResource().getRealResource(name.substring(0,name.length()-ext.length())+newExtension); 889 //new File(file.getParentFile(),name.substring(0,name.length()-ext.length())+newExtension); 890 } 891 892 /** 893 * @param res delete the content of a directory 894 */ 895 896 public static void deleteContent(Resource src,ResourceFilter filter) { 897 _deleteContent(src, filter,false); 898 } 899 public static void _deleteContent(Resource src,ResourceFilter filter,boolean deleteDirectories) { 900 if(src.isDirectory()) { 901 Resource[] files=filter==null?src.listResources():src.listResources(filter); 902 for(int i=0;i<files.length;i++) { 903 _deleteContent(files[i],filter,true); 904 if(deleteDirectories){ 905 try { 906 src.remove(false); 907 } catch (IOException e) {} 908 } 909 } 910 911 } 912 else if(src.isFile()) { 913 src.delete(); 914 } 915 } 916 917 918 /** 919 * copy a file or directory recursive (with his content) 920 * @param res file or directory to delete 921 * @throws IOException 922 * @throws FileNotFoundException 923 */ 924 public static void copyRecursive(Resource src,Resource trg) throws IOException { 925 copyRecursive(src, trg,null); 926 } 927 928 929 /** 930 * copy a file or directory recursive (with his content) 931 * @param src 932 * @param trg 933 * @param filter 934 * @throws IOException 935 * @throws FileNotFoundException 936 */ 937 public static void copyRecursive(Resource src,Resource trg,ResourceFilter filter) throws IOException { 938 //print.out(src); 939 //print.out(trg); 940 if(!src.exists()) return ; 941 if(src.isDirectory()) { 942 if(!trg.exists())trg.createDirectory(true); 943 Resource[] files=filter==null?src.listResources():src.listResources(filter); 944 for(int i=0;i<files.length;i++) { 945 copyRecursive(files[i],trg.getRealResource(files[i].getName()),filter); 946 } 947 } 948 else if(src.isFile()) { 949 touch(trg); 950 IOUtil.copy(src,trg); 951 } 952 } 953 954 public static void copy(Resource src, Resource trg) throws IOException { 955 if(src.equals(trg)) return; 956 ResourceUtil.checkCopyToOK(src,trg); 957 IOUtil.copy(src,trg); 958 } 959 960 961 /** 962 * return if parent file exists 963 * @param res file to check 964 * @return parent exists? 965 */ 966 private static boolean parentExists(Resource res) { 967 res=res.getParentResource(); 968 return res!=null && res.exists(); 969 } 970 private static boolean parentExists(PageSource ps) { 971 PageSource p = ((PageSourceImpl)ps).getParent(); 972 return p!=null && p.exists(); 973 } 974 975 public static void removeChildren(Resource res) throws IOException { 976 removeChildren(res, (ResourceFilter)null); 977 } 978 979 public static void removeChildren(Resource res,ResourceNameFilter filter) throws IOException { 980 Resource[] children = filter==null?res.listResources():res.listResources(filter); 981 if(children==null) return; 982 983 for(int i=0;i<children.length;i++) { 984 children[i].remove(true); 985 } 986 } 987 988 public static void removeChildren(Resource res,ResourceFilter filter) throws IOException { 989 Resource[] children = filter==null?res.listResources():res.listResources(filter); 990 if(children==null) return; 991 992 for(int i=0;i<children.length;i++) { 993 children[i].remove(true); 994 } 995 } 996 997 public static void removeChildrenEL(Resource res,ResourceNameFilter filter) { 998 try { 999 removeChildren(res,filter); 1000 } 1001 catch(Throwable e) {} 1002 } 1003 1004 public static void removeChildrenEL(Resource res,ResourceFilter filter) { 1005 try { 1006 removeChildren(res,filter); 1007 } 1008 catch(Throwable e) {} 1009 } 1010 1011 public static void removeChildrenEL(Resource res) { 1012 try { 1013 removeChildren(res); 1014 } 1015 catch(Throwable e) {} 1016 } 1017 1018 public static void removeEL(Resource res, boolean force) { 1019 try { 1020 res.remove(force); 1021 } 1022 catch (Throwable t) {} 1023 } 1024 1025 public static void createFileEL(Resource res, boolean force) { 1026 try { 1027 res.createFile(force); 1028 } 1029 catch (IOException e) {} 1030 } 1031 1032 public static void createDirectoryEL(Resource res, boolean force) { 1033 try { 1034 res.createDirectory(force); 1035 } 1036 catch (IOException e) {} 1037 } 1038 1039 public static ContentType getContentType(Resource resource) { 1040 // TODO make this part of a interface 1041 if(resource instanceof HTTPResource) { 1042 try { 1043 return ((HTTPResource)resource).getContentType(); 1044 } catch (IOException e) {} 1045 } 1046 InputStream is=null; 1047 try { 1048 is = resource.getInputStream(); 1049 return new ContentTypeImpl(is); 1050 } 1051 catch(IOException e) { 1052 return ContentTypeImpl.APPLICATION_UNKNOW; 1053 } 1054 finally { 1055 IOUtil.closeEL(is); 1056 } 1057 } 1058 1059 public static void moveTo(Resource src, Resource dest) throws IOException { 1060 ResourceUtil.checkMoveToOK(src, dest); 1061 1062 if(src.isFile()){ 1063 try{ 1064 src.moveTo(dest); 1065 } 1066 catch(IOException e){ 1067 if(!dest.exists()) dest.createFile(false); 1068 IOUtil.copy(src,dest); 1069 src.remove(false); 1070 } 1071 } 1072 else { 1073 if(!dest.exists()) dest.createDirectory(false); 1074 Resource[] children = src.listResources(); 1075 for(int i=0;i<children.length;i++){ 1076 moveTo(children[i],dest.getRealResource(children[i].getName())); 1077 } 1078 src.remove(false); 1079 } 1080 dest.setLastModified(System.currentTimeMillis()); 1081 } 1082 1083 /** 1084 * return the size of the Resource, other than method length of Resource this mthod return the size of all files in a directory 1085 * @param collectionDir 1086 * @return 1087 */ 1088 public static long getRealSize(Resource res) { 1089 return getRealSize(res,null); 1090 } 1091 1092 /** 1093 * return the size of the Resource, other than method length of Resource this mthod return the size of all files in a directory 1094 * @param collectionDir 1095 * @return 1096 */ 1097 public static long getRealSize(Resource res, ResourceFilter filter) { 1098 if(res.isFile()) { 1099 return res.length(); 1100 } 1101 else if(res.isDirectory()) { 1102 long size=0; 1103 Resource[] children = filter==null?res.listResources():res.listResources(filter); 1104 for(int i=0;i<children.length;i++) { 1105 size+=getRealSize(children[i]); 1106 } 1107 return size; 1108 } 1109 1110 return 0; 1111 } 1112 1113 1114 /** 1115 * return if Resource is empty, means is directory and has no children or a empty file, 1116 * if not exist return false. 1117 * @param res 1118 * @return 1119 */ 1120 public static boolean isEmpty(Resource res) { 1121 return isEmptyDirectory(res) || isEmptyFile(res); 1122 } 1123 1124 public static boolean isEmptyDirectory(Resource res) { 1125 if(res.isDirectory()) { 1126 String[] children = res.list(); 1127 return children==null || children.length==0; 1128 } 1129 return false; 1130 } 1131 1132 public static boolean isEmptyFile(Resource res) { 1133 if(res.isFile()) { 1134 return res.length()==0; 1135 } 1136 return false; 1137 } 1138 1139 public static Resource toResource(File file) { 1140 return ResourcesImpl.getFileResourceProvider().getResource(file.getPath()); 1141 } 1142 1143 1144 /** 1145 * list childrn of all given resources 1146 * @param resources 1147 * @return 1148 */ 1149 public static Resource[] listResources(Resource[] resources,ResourceFilter filter) { 1150 int count=0; 1151 Resource[] children; 1152 ArrayList<Resource[]> list=new ArrayList<Resource[]>(); 1153 for(int i=0;i<resources.length;i++) { 1154 children=filter==null?resources[i].listResources():resources[i].listResources(filter); 1155 if(children!=null){ 1156 count+=children.length; 1157 list.add(children); 1158 } 1159 else list.add(new Resource[0]); 1160 } 1161 Resource[] rtn=new Resource[count]; 1162 int index=0; 1163 for(int i=0;i<resources.length;i++) { 1164 children=list.get(i); 1165 for(int y=0;y<children.length;y++) { 1166 rtn[index++]=children[y]; 1167 } 1168 } 1169 //print.out(rtn); 1170 return rtn; 1171 } 1172 1173 1174 public static Resource[] listResources(Resource res,ResourceFilter filter) { 1175 return filter==null?res.listResources():res.listResources(filter); 1176 } 1177 1178 1179 public static void deleteFileOlderThan(Resource res, long date, ExtensionResourceFilter filter) { 1180 if(res.isFile()) { 1181 if(res.lastModified()<=date) res.delete(); 1182 } 1183 else if(res.isDirectory()) { 1184 Resource[] children = filter==null?res.listResources():res.listResources(filter); 1185 for(int i=0;i<children.length;i++) { 1186 deleteFileOlderThan(children[i],date,filter); 1187 } 1188 } 1189 } 1190 1191 /** 1192 * check if directory creation is ok with the rules for the Resource interface, to not change this rules. 1193 * @param resource 1194 * @param createParentWhenNotExists 1195 * @throws IOException 1196 */ 1197 public static void checkCreateDirectoryOK(Resource resource, boolean createParentWhenNotExists) throws IOException { 1198 if(resource.exists()) { 1199 if(resource.isFile()) 1200 throw new IOException("can't create directory ["+resource.getPath()+"], resource already exists as a file"); 1201 if(resource.isDirectory()) 1202 throw new IOException("can't create directory ["+resource.getPath()+"], directory already exists"); 1203 } 1204 1205 Resource parent = resource.getParentResource(); 1206 // when there is a parent but the parent does not exist 1207 if(parent!=null) { 1208 if(!parent.exists()) { 1209 if(createParentWhenNotExists)parent.createDirectory(true); 1210 else throw new IOException("can't create file ["+resource.getPath()+"], missng parent directory"); 1211 } 1212 else if(parent.isFile()) { 1213 throw new IOException("can't create directory ["+resource.getPath()+"], parent is a file"); 1214 } 1215 } 1216 } 1217 1218 1219 /** 1220 * check if file creating is ok with the rules for the Resource interface, to not change this rules. 1221 * @param resource 1222 * @param createParentWhenNotExists 1223 * @throws IOException 1224 */ 1225 public static void checkCreateFileOK(Resource resource, boolean createParentWhenNotExists) throws IOException { 1226 if(resource.exists()) { 1227 if(resource.isDirectory()) 1228 throw new IOException("can't create file ["+resource.getPath()+"], resource already exists as a directory"); 1229 if(resource.isFile()) 1230 throw new IOException("can't create file ["+resource.getPath()+"], file already exists"); 1231 } 1232 1233 Resource parent = resource.getParentResource(); 1234 // when there is a parent but the parent does not exist 1235 if(parent!=null) { 1236 if(!parent.exists()) { 1237 if(createParentWhenNotExists)parent.createDirectory(true); 1238 else throw new IOException("can't create file ["+resource.getPath()+"], missng parent directory"); 1239 } 1240 else if(parent.isFile()) { 1241 throw new IOException("can't create file ["+resource.getPath()+"], parent is a file"); 1242 } 1243 } 1244 } 1245 1246 /** 1247 * check if copying a file is ok with the rules for the Resource interface, to not change this rules. 1248 * @param source 1249 * @param target 1250 * @throws IOException 1251 */ 1252 public static void checkCopyToOK(Resource source, Resource target) throws IOException { 1253 if(!source.isFile()) { 1254 if(source.isDirectory()) 1255 throw new IOException("can't copy ["+source.getPath()+"] to ["+target.getPath()+"], source is a directory"); 1256 throw new IOException("can't copy ["+source.getPath()+"] to ["+target.getPath()+"], source file does not exist"); 1257 } 1258 else if(target.isDirectory()) { 1259 throw new IOException("can't copy ["+source.getPath()+"] to ["+target.getPath()+"], target is a directory"); 1260 } 1261 } 1262 1263 /** 1264 * check if moveing a file is ok with the rules for the Resource interface, to not change this rules. 1265 * @param source 1266 * @param target 1267 * @throws IOException 1268 */ 1269 public static void checkMoveToOK(Resource source, Resource target) throws IOException { 1270 if(!source.exists()) { 1271 throw new IOException("can't move ["+source.getPath()+"] to ["+target.getPath()+"], source file does not exist"); 1272 } 1273 if(source.isDirectory() && target.isFile()) 1274 throw new IOException("can't move ["+source.getPath()+"] directory to ["+target.getPath()+"], target is a file"); 1275 if(source.isFile() && target.isDirectory()) 1276 throw new IOException("can't move ["+source.getPath()+"] file to ["+target.getPath()+"], target is a directory"); 1277 } 1278 1279 /** 1280 * check if getting a inputstream of the file is ok with the rules for the Resource interface, to not change this rules. 1281 * @param resource 1282 * @throws IOException 1283 */ 1284 public static void checkGetInputStreamOK(Resource resource) throws IOException { 1285 if(!resource.exists()) 1286 throw new IOException("file ["+resource.getPath()+"] does not exist"); 1287 1288 if(resource.isDirectory()) 1289 throw new IOException("can't read directory ["+resource.getPath()+"] as a file"); 1290 1291 } 1292 1293 /** 1294 * check if getting a outputstream of the file is ok with the rules for the Resource interface, to not change this rules. 1295 * @param resource 1296 * @throws IOException 1297 */ 1298 public static void checkGetOutputStreamOK(Resource resource) throws IOException { 1299 if(resource.exists() && !resource.isWriteable()) { 1300 throw new IOException("can't write to file ["+resource.getPath()+"],file is readonly"); 1301 } 1302 if(resource.isDirectory()) 1303 throw new IOException("can't write directory ["+resource.getPath()+"] as a file"); 1304 if(!resource.getParentResource().exists()) 1305 throw new IOException("can't write file ["+resource.getPath()+"] as a file, missing parent directory ["+resource.getParent()+"]"); 1306 } 1307 1308 /** 1309 * check if removing the file is ok with the rules for the Resource interface, to not change this rules. 1310 * @param resource 1311 * @throws IOException 1312 */ 1313 public static void checkRemoveOK(Resource resource) throws IOException { 1314 if(!resource.exists())throw new IOException("can't delete resource "+resource+", resource does not exist"); 1315 if(!resource.canWrite())throw new IOException("can't delete resource "+resource+", no access"); 1316 1317 } 1318 1319 public static void deleteEmptyFolders(Resource res) throws IOException { 1320 if(res.isDirectory()){ 1321 Resource[] children = res.listResources(); 1322 for(int i=0;i<children.length;i++){ 1323 deleteEmptyFolders(children[i]); 1324 } 1325 if(res.listResources().length==0){ 1326 res.remove(false); 1327 } 1328 } 1329 } 1330 1331 /** 1332 * if the pageSource is based on a archive, translate the source to a zip:// Resource 1333 * @return return the Resource matching this PageSource 1334 * @param pc the Page Context Object 1335 * @deprecated use instead <code>PageSource.getResourceTranslated(PageContext)</code> 1336 */ 1337 public static Resource getResource(PageContext pc,PageSource ps) throws PageException { 1338 return ps.getResourceTranslated(pc); 1339 } 1340 1341 public static Resource getResource(PageContext pc,PageSource ps, Resource defaultValue) { 1342 try { 1343 return ps.getResourceTranslated(pc); 1344 } 1345 catch (Throwable t) { 1346 return defaultValue; 1347 } 1348 } 1349 1350 public static int directrySize(Resource dir,ResourceFilter filter) { 1351 if(dir==null || !dir.isDirectory()) return 0; 1352 if(filter==null) return dir.list().length; 1353 return dir.list(filter).length; 1354 } 1355 1356 public static int directrySize(Resource dir,ResourceNameFilter filter) { 1357 if(dir==null || !dir.isDirectory()) return 0; 1358 if(filter==null) return dir.list().length; 1359 return dir.list(filter).length; 1360 } 1361 1362 public static String[] names(Resource[] resources) { 1363 String[] names=new String[resources.length]; 1364 for(int i=0;i<names.length;i++){ 1365 names[i]=resources[i].getName(); 1366 } 1367 return names; 1368 } 1369 1370 public static Resource[] merge(Resource[] srcs, Resource[] trgs) { 1371 java.util.List<Resource> list=new ArrayList<Resource>(); 1372 1373 if(srcs!=null){ 1374 for(int i=0;i<srcs.length;i++){ 1375 list.add(srcs[i]); 1376 } 1377 } 1378 if(trgs!=null){ 1379 for(int i=0;i<trgs.length;i++){ 1380 if(!list.contains(trgs[i]))list.add(trgs[i]); 1381 } 1382 } 1383 return list.toArray(new Resource[list.size()]); 1384 } 1385 1386 }