001 package railo.commons.io; 002 003 import java.io.ByteArrayInputStream; 004 import java.io.ByteArrayOutputStream; 005 import java.io.File; 006 import java.io.FileInputStream; 007 import java.io.FileOutputStream; 008 import java.io.IOException; 009 import java.io.InputStream; 010 import java.io.OutputStream; 011 import java.util.Enumeration; 012 import java.util.zip.GZIPInputStream; 013 import java.util.zip.GZIPOutputStream; 014 import java.util.zip.ZipEntry; 015 import java.util.zip.ZipFile; 016 import java.util.zip.ZipInputStream; 017 import java.util.zip.ZipOutputStream; 018 019 import org.apache.commons.compress.archivers.tar.TarEntry; 020 import org.apache.commons.compress.archivers.tar.TarInputStream; 021 import org.apache.commons.compress.archivers.tar.TarOutputStream; 022 import org.apache.commons.compress.bzip2.CBZip2OutputStream; 023 024 import railo.commons.io.res.Resource; 025 import railo.commons.io.res.ResourceProvider; 026 import railo.commons.io.res.ResourcesImpl; 027 import railo.commons.io.res.filter.ExtensionResourceFilter; 028 import railo.commons.io.res.filter.OrResourceFilter; 029 import railo.commons.io.res.filter.ResourceFilter; 030 import railo.commons.lang.StringUtil; 031 import railo.runtime.op.Caster; 032 033 /** 034 * Util to manipulate zip files 035 */ 036 public final class CompressUtil { 037 038 /** 039 * Field <code>FORMAT_ZIP</code> 040 */ 041 public static final int FORMAT_ZIP=0; 042 /** 043 * Field <code>FORMAT_TAR</code> 044 */ 045 public static final int FORMAT_TAR=1; 046 /** 047 * Field <code>FORMAT_TGZ</code> 048 */ 049 public static final int FORMAT_TGZ=2; 050 /** 051 * Field <code>FORMAT_GZIP</code> 052 */ 053 public static final int FORMAT_GZIP=3; 054 /** 055 * Field <code>FORMAT_BZIP</code> 056 */ 057 public static final int FORMAT_BZIP=4; 058 /** 059 * Field <code>FORMAT_BZIP</code> 060 */ 061 public static final int FORMAT_BZIP2=4; 062 063 /** 064 * Field <code>FORMAT_TBZ</code> 065 */ 066 public static final int FORMAT_TBZ=5; 067 /** 068 * Field <code>FORMAT_TBZ2</code> 069 */ 070 public static final int FORMAT_TBZ2=5; 071 072 /** 073 * Constructor of the class 074 */ 075 private CompressUtil(){} 076 077 /** 078 * extract a zip file to a directory 079 * @param format 080 * @param source 081 * @param target 082 * @throws IOException 083 */ 084 public static void extract(int format,Resource source, Resource target) throws IOException { 085 if(format==FORMAT_ZIP) extractZip(source,target); 086 else if(format==FORMAT_TAR) extractTar(source,target); 087 else if(format==FORMAT_GZIP)extractGZip(source,target); 088 else if(format==FORMAT_TGZ) extractTGZ(source,target); 089 else throw new IOException("can't extract in given format"); 090 } 091 092 093 private static void extractTGZ(Resource source, Resource target) throws IOException { 094 //File tmpTarget = File.createTempFile("_temp","tmp"); 095 Resource tmp = SystemUtil.getTempDirectory().getRealResource(System.currentTimeMillis()+".tmp"); 096 try { 097 // read Gzip 098 extractGZip(source, tmp); 099 100 // read Tar 101 extractTar(tmp, target); 102 } 103 finally { 104 tmp.delete(); 105 } 106 } 107 108 private static void extractGZip(Resource source, Resource target) throws IOException { 109 InputStream is=null; 110 OutputStream os=null; 111 try { 112 is = new GZIPInputStream(IOUtil.toBufferedInputStream(source.getInputStream())); 113 os = IOUtil.toBufferedOutputStream(target.getOutputStream()); 114 IOUtil.copy(is,os,false,false); 115 } 116 finally { 117 IOUtil.closeEL(is, os); 118 } 119 } 120 121 /** 122 * extract a zip file to a directory 123 * @param format 124 * @param sources 125 * @param target 126 * @throws IOException 127 */ 128 public static void extract(int format,Resource[] sources, Resource target) throws IOException { 129 if(format==FORMAT_ZIP || format==FORMAT_TAR) { 130 for(int i=0;i<sources.length;i++) { 131 extract(format,sources[i],target); 132 } 133 } 134 else throw new IOException("can't extract in given format"); 135 } 136 137 private static void extractTar(Resource tarFile, Resource targetDir) throws IOException { 138 if(!targetDir.exists() || !targetDir.isDirectory()) 139 throw new IOException(targetDir+" is not a existing directory"); 140 141 if(!tarFile.exists()) 142 throw new IOException(tarFile+" is not a existing file"); 143 144 if(tarFile.isDirectory()) { 145 Resource[] files = tarFile.listResources(new ExtensionResourceFilter("tar")); 146 if(files==null) 147 throw new IOException("directory "+tarFile+" is empty"); 148 extract(FORMAT_TAR,files,targetDir); 149 return; 150 } 151 152 // read the zip file and build a query from its contents 153 TarInputStream tis=null; 154 try { 155 tis = new TarInputStream( IOUtil.toBufferedInputStream(tarFile.getInputStream()) ) ; 156 TarEntry entry; 157 int mode; 158 while ( ( entry = tis.getNextEntry()) != null ) { 159 //print.ln(entry); 160 Resource target=targetDir.getRealResource(entry.getName()); 161 if(entry.isDirectory()) { 162 target.mkdirs(); 163 } 164 else { 165 Resource parent=target.getParentResource(); 166 if(!parent.exists())parent.mkdirs(); 167 IOUtil.copy(tis,target,false); 168 } 169 target.setLastModified(entry.getModTime().getTime()); 170 mode=entry.getMode(); 171 if(mode>0)target.setMode(mode); 172 //tis.closeEntry() ; 173 } 174 } 175 finally { 176 IOUtil.closeEL(tis); 177 } 178 } 179 180 private static void extractZipOld(Resource zipFile, Resource targetDir) throws IOException { 181 if(!targetDir.exists() || !targetDir.isDirectory()) 182 throw new IOException(targetDir+" is not a existing directory"); 183 184 if(!zipFile.exists()) 185 throw new IOException(zipFile+" is not a existing file"); 186 187 if(zipFile.isDirectory()) { 188 Resource[] files = zipFile.listResources(new ExtensionResourceFilter("tar")); 189 if(files==null) 190 throw new IOException("directory "+zipFile+" is empty"); 191 extract(FORMAT_ZIP,files,targetDir); 192 return; 193 } 194 195 // read the zip file and build a query from its contents 196 TarInputStream tis=null; 197 try { 198 tis = new TarInputStream( IOUtil.toBufferedInputStream(zipFile.getInputStream()) ) ; 199 TarEntry entry; 200 int mode; 201 while ( ( entry = tis.getNextEntry()) != null ) { 202 //print.ln(entry); 203 Resource target=targetDir.getRealResource(entry.getName()); 204 if(entry.isDirectory()) { 205 target.mkdirs(); 206 } 207 else { 208 Resource parent=target.getParentResource(); 209 if(!parent.exists())parent.mkdirs(); 210 211 IOUtil.copy(tis,target,false); 212 } 213 target.setLastModified(entry.getModTime().getTime()); 214 mode=entry.getMode(); 215 if(mode>0)target.setMode(mode); 216 //tis.closeEntry() ; 217 } 218 } 219 finally { 220 IOUtil.closeEL(tis); 221 } 222 } 223 224 private static void extractZip(Resource zipFile, Resource targetDir) throws IOException { 225 if(!targetDir.exists() || !targetDir.isDirectory()) 226 throw new IOException(targetDir+" is not a existing directory"); 227 228 if(!zipFile.exists()) 229 throw new IOException(zipFile+" is not a existing file"); 230 231 if(zipFile.isDirectory()) { 232 Resource[] files = zipFile.listResources( 233 new OrResourceFilter(new ResourceFilter[]{ 234 new ExtensionResourceFilter("zip"), 235 new ExtensionResourceFilter("jar"), 236 new ExtensionResourceFilter("war"), 237 new ExtensionResourceFilter("tar"), 238 new ExtensionResourceFilter("ear") 239 }) 240 ); 241 if(files==null) 242 throw new IOException("directory "+zipFile+" is empty"); 243 extract(FORMAT_ZIP,files,targetDir); 244 return; 245 } 246 247 // read the zip file and build a query from its contents 248 unzip(zipFile,targetDir); 249 /*ZipInputStream zis=null; 250 try { 251 zis = new ZipInputStream( IOUtil.toBufferedInputStream(zipFile.getInputStream()) ) ; 252 ZipEntry entry; 253 while ( ( entry = zis.getNextEntry()) != null ) { 254 Resource target=targetDir.getRealResource(entry.getName()); 255 if(entry.isDirectory()) { 256 target.mkdirs(); 257 } 258 else { 259 Resource parent=target.getParentResource(); 260 if(!parent.exists())parent.mkdirs(); 261 262 IOUtil.copy(zis,target,false); 263 } 264 target.setLastModified(entry.getTime()); 265 zis.closeEntry() ; 266 } 267 } 268 finally { 269 IOUtil.closeEL(zis); 270 }*/ 271 } 272 273 274 private static void unzip(Resource zipFile,Resource targetDir) throws IOException { 275 /*if(zipFile instanceof File){ 276 unzip((File)zipFile, targetDir); 277 return; 278 }*/ 279 280 ZipInputStream zis=null; 281 try { 282 zis = new ZipInputStream( IOUtil.toBufferedInputStream(zipFile.getInputStream()) ) ; 283 ZipEntry entry; 284 while ( ( entry = zis.getNextEntry()) != null ) { 285 Resource target=targetDir.getRealResource(entry.getName()); 286 if(entry.isDirectory()) { 287 target.mkdirs(); 288 } 289 else { 290 Resource parent=target.getParentResource(); 291 if(!parent.exists())parent.mkdirs(); 292 IOUtil.copy(zis,target,false); 293 } 294 target.setLastModified(entry.getTime()); 295 zis.closeEntry() ; 296 } 297 } 298 finally { 299 IOUtil.closeEL(zis); 300 } 301 } 302 303 private static void unzip2(File zipFile,Resource targetDir) throws IOException { 304 ZipFile zf=null; 305 try { 306 zf = new ZipFile(zipFile); 307 308 ZipEntry entry; 309 Enumeration en = zf.entries(); 310 while(en.hasMoreElements()){ 311 entry = (ZipEntry) en.nextElement(); 312 Resource target=targetDir.getRealResource(entry.getName()); 313 if(entry.isDirectory()) { 314 target.mkdirs(); 315 } 316 else { 317 Resource parent=target.getParentResource(); 318 if(!parent.exists())parent.mkdirs(); 319 InputStream is = zf.getInputStream(entry); 320 IOUtil.copy(is,target,true); 321 } 322 target.setLastModified(entry.getTime()); 323 } 324 } 325 finally { 326 IOUtil.closeEL(zf); 327 } 328 } 329 330 /** 331 * compress data to a zip file 332 * @param format format it that should by compressed usally is CompressUtil.FORMAT_XYZ 333 * @param source 334 * @param target 335 * @param includeBaseFolder 336 * @param mode 337 * @throws IOException 338 */ 339 public static void compress(int format, Resource source, Resource target, boolean includeBaseFolder, int mode) throws IOException { 340 if( format==FORMAT_GZIP) compressGZip(source,target); 341 else if(format==FORMAT_BZIP2) compressBZip2(source,target); 342 else { 343 Resource[] sources=(!includeBaseFolder && source.isDirectory())?source.listResources():new Resource[]{source}; 344 compress(format, sources, target,mode); 345 } 346 } 347 348 /** 349 * compress data to a zip file 350 * @param format format it that should by compressed usally is CompressUtil.FORMAT_XYZ 351 * @param sources 352 * @param target 353 * @param mode 354 * @throws IOException 355 */ 356 public static void compress(int format, Resource[] sources, Resource target, int mode) throws IOException { 357 358 if( format==FORMAT_ZIP) compressZip(sources,target,null); 359 else if(format==FORMAT_TAR) compressTar(sources,target,mode); 360 else if(format==FORMAT_TGZ) compressTGZ(sources,target,mode); 361 else if(format==FORMAT_TBZ2) compressTBZ2(sources,target,mode); 362 363 else throw new IOException("can't compress in given format"); 364 } 365 366 /** 367 * compress a source file/directory to a tar/gzip file 368 * @param sources 369 * @param target 370 * @param mode 371 * @throws IOException 372 */ 373 public static void compressTGZ(Resource[] sources, Resource target,int mode) throws IOException { 374 File tmpTarget = File.createTempFile("_temp","tmp"); 375 try { 376 // write Tar 377 OutputStream tmpOs=new FileOutputStream(tmpTarget); 378 try { 379 compressTar(sources,tmpOs,mode); 380 } 381 finally { 382 IOUtil.closeEL(tmpOs); 383 } 384 385 // write Gzip 386 InputStream is = null; 387 OutputStream os = null; 388 try { 389 is = new FileInputStream(tmpTarget); 390 os = target.getOutputStream(); 391 compressGZip(is, os); 392 } 393 finally { 394 IOUtil.closeEL(is,os); 395 } 396 } 397 finally { 398 tmpTarget.delete(); 399 } 400 } 401 402 /** 403 * compress a source file/directory to a tar/bzip2 file 404 * @param sources 405 * @param target 406 * @param mode 407 * @throws IOException 408 */ 409 private static void compressTBZ2(Resource[] sources, Resource target, int mode) throws IOException { 410 //File tmpTarget = File.createTempFile("_temp","tmp"); 411 ByteArrayOutputStream baos=new ByteArrayOutputStream(); 412 compressTar(sources,baos,mode); 413 _compressBZip2(new ByteArrayInputStream(baos.toByteArray()), target.getOutputStream()); 414 //tmpTarget.delete(); 415 } 416 417 /** 418 * compress a source file to a gzip file 419 * @param source 420 * @param target 421 * @throws IOException 422 * @throws IOException 423 */ 424 private static void compressGZip(Resource source, Resource target) throws IOException { 425 if(source.isDirectory()) { 426 throw new IOException("you can only create a GZIP File from a single source file, use TGZ (TAR-GZIP) to first TAR multiple files"); 427 } 428 InputStream is=null; 429 OutputStream os=null; 430 try { 431 is = source.getInputStream(); 432 os = target.getOutputStream(); 433 } catch(IOException ioe) { 434 IOUtil.closeEL(is, os); 435 throw ioe; 436 } 437 compressGZip(is,os); 438 439 } 440 441 public static void compressGZip(InputStream source, OutputStream target) throws IOException { 442 InputStream is = IOUtil.toBufferedInputStream(source); 443 if(!(target instanceof GZIPOutputStream)) target = new GZIPOutputStream(IOUtil.toBufferedOutputStream(target)); 444 IOUtil.copy(is,target,true,true); 445 } 446 447 /** 448 * compress a source file to a bzip2 file 449 * @param source 450 * @param target 451 * @throws IOException 452 */ 453 private static void compressBZip2(Resource source, Resource target) throws IOException { 454 if(source.isDirectory()) { 455 throw new IOException("you can only create a BZIP File from a single source file, use TBZ (TAR-BZIP2) to first TAR multiple files"); 456 } 457 InputStream is=null; 458 OutputStream os=null; 459 try { 460 is=source.getInputStream(); 461 os=target.getOutputStream(); 462 } 463 catch(IOException ioe) { 464 IOUtil.closeEL(is, os); 465 throw ioe; 466 } 467 468 _compressBZip2(is, os); 469 } 470 471 /** 472 * compress a source file to a bzip2 file 473 * @param source 474 * @param target 475 * @throws IOException 476 */ 477 private static void _compressBZip2(InputStream source, OutputStream target) throws IOException { 478 479 InputStream is = IOUtil.toBufferedInputStream(source); 480 OutputStream os = new CBZip2OutputStream(IOUtil.toBufferedOutputStream(target)); 481 IOUtil.copy(is,os,true,true); 482 } 483 484 /** 485 * compress a source file/directory to a zip file 486 * @param sources 487 * @param target 488 * @param filter 489 * @throws IOException 490 */ 491 public static void compressZip(Resource[] sources, Resource target, ResourceFilter filter) throws IOException { 492 ZipOutputStream zos = null; 493 try { 494 zos = new ZipOutputStream(IOUtil.toBufferedOutputStream(target.getOutputStream())); 495 compressZip("",sources, zos, filter); 496 } 497 finally { 498 IOUtil.closeEL(zos); 499 } 500 } 501 502 public static void compressZip( Resource[] sources, ZipOutputStream zos, ResourceFilter filter) throws IOException { 503 compressZip("",sources, zos, filter); 504 } 505 506 507 private static void compressZip(String parent, Resource[] sources, ZipOutputStream zos, ResourceFilter filter) throws IOException { 508 if(parent.length()>0)parent+="/"; 509 for(int i=0;i<sources.length;i++) { 510 compressZip(parent+sources[i].getName(),sources[i],zos,filter); 511 } 512 } 513 514 private static void compressZip(String parent, Resource source, ZipOutputStream zos, ResourceFilter filter) throws IOException { 515 if(source.isFile()) { 516 //if(filter.accept(source)) { 517 ZipEntry ze=new ZipEntry(parent); 518 ze.setTime(source.lastModified()); 519 zos.putNextEntry(ze); 520 try { 521 IOUtil.copy(source,zos,false); 522 } 523 finally { 524 zos.closeEntry(); 525 } 526 //} 527 } 528 else if(source.isDirectory()) { 529 if(!StringUtil.isEmpty(parent)) { 530 ZipEntry ze=new ZipEntry(parent+"/"); 531 ze.setTime(source.lastModified()); 532 try { 533 zos.putNextEntry(ze); 534 } 535 catch(IOException ioe) { 536 if(Caster.toString(ioe.getMessage()).indexOf("duplicate")==-1)throw ioe; 537 } 538 zos.closeEntry(); 539 } 540 compressZip(parent, filter==null?source.listResources():source.listResources(filter),zos,filter); 541 } 542 } 543 544 /** 545 * compress a source file/directory to a tar file 546 * @param sources 547 * @param target 548 * @param mode 549 * @throws IOException 550 */ 551 public static void compressTar(Resource[] sources,Resource target, int mode) throws IOException { 552 compressTar(sources, IOUtil.toBufferedOutputStream(target.getOutputStream()), mode); 553 } 554 555 public static void compressTar(Resource[] sources,OutputStream target, int mode) throws IOException { 556 if(target instanceof TarOutputStream){ 557 compressTar("",sources,(TarOutputStream)target,mode); 558 return; 559 } 560 TarOutputStream tos=new TarOutputStream(target); 561 tos.setLongFileMode(TarOutputStream.LONGFILE_GNU); 562 try { 563 compressTar("",sources, tos,mode); 564 } 565 finally { 566 IOUtil.closeEL(tos); 567 } 568 } 569 570 public static void compressTar(String parent, Resource[] sources, TarOutputStream tos, int mode) throws IOException { 571 572 if(parent.length()>0)parent+="/"; 573 for(int i=0;i<sources.length;i++) { 574 compressTar(parent+sources[i].getName(),sources[i],tos,mode); 575 } 576 } 577 578 private static void compressTar(String parent, Resource source,TarOutputStream tos, int mode) throws IOException { 579 if(source.isFile()) { 580 //TarEntry entry = (source instanceof FileResource)?new TarEntry((FileResource)source):new TarEntry(parent); 581 TarEntry entry = new TarEntry(parent); 582 583 entry.setName(parent); 584 585 // mode 586 //100777 TODO ist das so ok? 587 if(mode>0) entry.setMode(mode); 588 else if((mode=source.getMode())>0) entry.setMode(mode); 589 590 entry.setSize(source.length()); 591 entry.setModTime(source.lastModified()); 592 tos.putNextEntry(entry); 593 try { 594 IOUtil.copy(source,tos,false); 595 } 596 finally { 597 tos.closeEntry(); 598 } 599 } 600 else if(source.isDirectory()) { 601 compressTar(parent, source.listResources(),tos,mode); 602 } 603 } 604 605 public static void main(String[] args) throws IOException { 606 ResourceProvider frp = ResourcesImpl.getFileResourceProvider(); 607 Resource src = frp.getResource("/Users/mic/temp/a"); 608 609 Resource tgz = frp.getResource("/Users/mic/temp/b/a.tgz"); 610 tgz.getParentResource().mkdirs(); 611 Resource tar = frp.getResource("/Users/mic/temp/b/a.tar"); 612 tar.getParentResource().mkdirs(); 613 Resource zip = frp.getResource("/Users/mic/temp/b/a.zip"); 614 zip.getParentResource().mkdirs(); 615 616 Resource tgz1 = frp.getResource("/Users/mic/temp/b/tgz"); 617 tgz1.mkdirs(); 618 Resource tar1 = frp.getResource("/Users/mic/temp/b/tar"); 619 tar1.mkdirs(); 620 Resource zip1 = frp.getResource("/Users/mic/temp/b/zip"); 621 zip1.mkdirs(); 622 623 compressTGZ(new Resource[]{src}, tgz, -1); 624 compressTar(new Resource[]{src}, tar, -1); 625 compressZip(new Resource[]{src}, zip, null); 626 627 extractTGZ(tgz, tgz1); 628 extractTar(tar, tar1); 629 extractZip(src, zip1); 630 631 } 632 }