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