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.TarArchiveEntry; 020 import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; 021 import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; 022 import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; 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 TarArchiveInputStream tis=null; 154 try { 155 tis = new TarArchiveInputStream( IOUtil.toBufferedInputStream(tarFile.getInputStream()) ) ; 156 TarArchiveEntry entry; 157 int mode; 158 while ( ( entry = tis.getNextTarEntry()) != 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 extractZip(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( 189 new OrResourceFilter(new ResourceFilter[]{ 190 new ExtensionResourceFilter("zip"), 191 new ExtensionResourceFilter("jar"), 192 new ExtensionResourceFilter("war"), 193 new ExtensionResourceFilter("tar"), 194 new ExtensionResourceFilter("ear") 195 }) 196 ); 197 if(files==null) 198 throw new IOException("directory "+zipFile+" is empty"); 199 extract(FORMAT_ZIP,files,targetDir); 200 return; 201 } 202 203 // read the zip file and build a query from its contents 204 unzip(zipFile,targetDir); 205 /*ZipInputStream zis=null; 206 try { 207 zis = new ZipInputStream( IOUtil.toBufferedInputStream(zipFile.getInputStream()) ) ; 208 ZipEntry entry; 209 while ( ( entry = zis.getNextEntry()) != null ) { 210 Resource target=targetDir.getRealResource(entry.getName()); 211 if(entry.isDirectory()) { 212 target.mkdirs(); 213 } 214 else { 215 Resource parent=target.getParentResource(); 216 if(!parent.exists())parent.mkdirs(); 217 218 IOUtil.copy(zis,target,false); 219 } 220 target.setLastModified(entry.getTime()); 221 zis.closeEntry() ; 222 } 223 } 224 finally { 225 IOUtil.closeEL(zis); 226 }*/ 227 } 228 229 230 private static void unzip(Resource zipFile,Resource targetDir) throws IOException { 231 /*if(zipFile instanceof File){ 232 unzip((File)zipFile, targetDir); 233 return; 234 }*/ 235 236 ZipInputStream zis=null; 237 try { 238 zis = new ZipInputStream( IOUtil.toBufferedInputStream(zipFile.getInputStream()) ) ; 239 ZipEntry entry; 240 while ( ( entry = zis.getNextEntry()) != null ) { 241 Resource target=targetDir.getRealResource(entry.getName()); 242 if(entry.isDirectory()) { 243 target.mkdirs(); 244 } 245 else { 246 Resource parent=target.getParentResource(); 247 if(!parent.exists())parent.mkdirs(); 248 IOUtil.copy(zis,target,false); 249 } 250 target.setLastModified(entry.getTime()); 251 zis.closeEntry() ; 252 } 253 } 254 finally { 255 IOUtil.closeEL(zis); 256 } 257 } 258 259 private static void unzip2(File zipFile,Resource targetDir) throws IOException { 260 ZipFile zf=null; 261 try { 262 zf = new ZipFile(zipFile); 263 264 ZipEntry entry; 265 Enumeration en = zf.entries(); 266 while(en.hasMoreElements()){ 267 entry = (ZipEntry) en.nextElement(); 268 Resource target=targetDir.getRealResource(entry.getName()); 269 if(entry.isDirectory()) { 270 target.mkdirs(); 271 } 272 else { 273 Resource parent=target.getParentResource(); 274 if(!parent.exists())parent.mkdirs(); 275 InputStream is = zf.getInputStream(entry); 276 IOUtil.copy(is,target,true); 277 } 278 target.setLastModified(entry.getTime()); 279 } 280 } 281 finally { 282 IOUtil.closeEL(zf); 283 } 284 } 285 286 /** 287 * compress data to a zip file 288 * @param format format it that should by compressed usally is CompressUtil.FORMAT_XYZ 289 * @param source 290 * @param target 291 * @param includeBaseFolder 292 * @param mode 293 * @throws IOException 294 */ 295 public static void compress(int format, Resource source, Resource target, boolean includeBaseFolder, int mode) throws IOException { 296 if( format==FORMAT_GZIP) compressGZip(source,target); 297 else if(format==FORMAT_BZIP2) compressBZip2(source,target); 298 else { 299 Resource[] sources=(!includeBaseFolder && source.isDirectory())?source.listResources():new Resource[]{source}; 300 compress(format, sources, target,mode); 301 } 302 } 303 304 /** 305 * compress data to a zip file 306 * @param format format it that should by compressed usally is CompressUtil.FORMAT_XYZ 307 * @param sources 308 * @param target 309 * @param mode 310 * @throws IOException 311 */ 312 public static void compress(int format, Resource[] sources, Resource target, int mode) throws IOException { 313 314 if( format==FORMAT_ZIP) compressZip(sources,target,null); 315 else if(format==FORMAT_TAR) compressTar(sources,target,mode); 316 else if(format==FORMAT_TGZ) compressTGZ(sources,target,mode); 317 else if(format==FORMAT_TBZ2) compressTBZ2(sources,target,mode); 318 319 else throw new IOException("can't compress in given format"); 320 } 321 322 /** 323 * compress a source file/directory to a tar/gzip file 324 * @param sources 325 * @param target 326 * @param mode 327 * @throws IOException 328 */ 329 public static void compressTGZ(Resource[] sources, Resource target,int mode) throws IOException { 330 File tmpTarget = File.createTempFile("_temp","tmp"); 331 try { 332 // write Tar 333 OutputStream tmpOs=new FileOutputStream(tmpTarget); 334 try { 335 compressTar(sources,tmpOs,mode); 336 } 337 finally { 338 IOUtil.closeEL(tmpOs); 339 } 340 341 // write Gzip 342 InputStream is = null; 343 OutputStream os = null; 344 try { 345 is = new FileInputStream(tmpTarget); 346 os = target.getOutputStream(); 347 compressGZip(is, os); 348 } 349 finally { 350 IOUtil.closeEL(is,os); 351 } 352 } 353 finally { 354 tmpTarget.delete(); 355 } 356 } 357 358 /** 359 * compress a source file/directory to a tar/bzip2 file 360 * @param sources 361 * @param target 362 * @param mode 363 * @throws IOException 364 */ 365 private static void compressTBZ2(Resource[] sources, Resource target, int mode) throws IOException { 366 //File tmpTarget = File.createTempFile("_temp","tmp"); 367 ByteArrayOutputStream baos=new ByteArrayOutputStream(); 368 compressTar(sources,baos,mode); 369 _compressBZip2(new ByteArrayInputStream(baos.toByteArray()), target.getOutputStream()); 370 //tmpTarget.delete(); 371 } 372 373 /** 374 * compress a source file to a gzip file 375 * @param source 376 * @param target 377 * @throws IOException 378 * @throws IOException 379 */ 380 private static void compressGZip(Resource source, Resource target) throws IOException { 381 if(source.isDirectory()) { 382 throw new IOException("you can only create a GZIP File from a single source file, use TGZ (TAR-GZIP) to first TAR multiple files"); 383 } 384 InputStream is=null; 385 OutputStream os=null; 386 try { 387 is = source.getInputStream(); 388 os = target.getOutputStream(); 389 } catch(IOException ioe) { 390 IOUtil.closeEL(is, os); 391 throw ioe; 392 } 393 compressGZip(is,os); 394 395 } 396 397 public static void compressGZip(InputStream source, OutputStream target) throws IOException { 398 InputStream is = IOUtil.toBufferedInputStream(source); 399 if(!(target instanceof GZIPOutputStream)) target = new GZIPOutputStream(IOUtil.toBufferedOutputStream(target)); 400 IOUtil.copy(is,target,true,true); 401 } 402 403 /** 404 * compress a source file to a bzip2 file 405 * @param source 406 * @param target 407 * @throws IOException 408 */ 409 private static void compressBZip2(Resource source, Resource target) throws IOException { 410 if(source.isDirectory()) { 411 throw new IOException("you can only create a BZIP File from a single source file, use TBZ (TAR-BZIP2) to first TAR multiple files"); 412 } 413 InputStream is=null; 414 OutputStream os=null; 415 try { 416 is=source.getInputStream(); 417 os=target.getOutputStream(); 418 } 419 catch(IOException ioe) { 420 IOUtil.closeEL(is, os); 421 throw ioe; 422 } 423 424 _compressBZip2(is, os); 425 } 426 427 /** 428 * compress a source file to a bzip2 file 429 * @param source 430 * @param target 431 * @throws IOException 432 */ 433 private static void _compressBZip2(InputStream source, OutputStream target) throws IOException { 434 435 InputStream is = IOUtil.toBufferedInputStream(source); 436 OutputStream os = new BZip2CompressorOutputStream(IOUtil.toBufferedOutputStream(target)); 437 IOUtil.copy(is,os,true,true); 438 } 439 440 /** 441 * compress a source file/directory to a zip file 442 * @param sources 443 * @param target 444 * @param filter 445 * @throws IOException 446 */ 447 public static void compressZip(Resource[] sources, Resource target, ResourceFilter filter) throws IOException { 448 ZipOutputStream zos = null; 449 try { 450 zos = new ZipOutputStream(IOUtil.toBufferedOutputStream(target.getOutputStream())); 451 compressZip("",sources, zos, filter); 452 } 453 finally { 454 IOUtil.closeEL(zos); 455 } 456 } 457 458 public static void compressZip( Resource[] sources, ZipOutputStream zos, ResourceFilter filter) throws IOException { 459 compressZip("",sources, zos, filter); 460 } 461 462 463 private static void compressZip(String parent, Resource[] sources, ZipOutputStream zos, ResourceFilter filter) throws IOException { 464 if(parent.length()>0)parent+="/"; 465 for(int i=0;i<sources.length;i++) { 466 compressZip(parent+sources[i].getName(),sources[i],zos,filter); 467 } 468 } 469 470 private static void compressZip(String parent, Resource source, ZipOutputStream zos, ResourceFilter filter) throws IOException { 471 if(source.isFile()) { 472 //if(filter.accept(source)) { 473 ZipEntry ze=new ZipEntry(parent); 474 ze.setTime(source.lastModified()); 475 zos.putNextEntry(ze); 476 try { 477 IOUtil.copy(source,zos,false); 478 } 479 finally { 480 zos.closeEntry(); 481 } 482 //} 483 } 484 else if(source.isDirectory()) { 485 if(!StringUtil.isEmpty(parent)) { 486 ZipEntry ze=new ZipEntry(parent+"/"); 487 ze.setTime(source.lastModified()); 488 try { 489 zos.putNextEntry(ze); 490 } 491 catch(IOException ioe) { 492 if(Caster.toString(ioe.getMessage()).indexOf("duplicate")==-1)throw ioe; 493 } 494 zos.closeEntry(); 495 } 496 compressZip(parent, filter==null?source.listResources():source.listResources(filter),zos,filter); 497 } 498 } 499 500 /** 501 * compress a source file/directory to a tar file 502 * @param sources 503 * @param target 504 * @param mode 505 * @throws IOException 506 */ 507 public static void compressTar(Resource[] sources,Resource target, int mode) throws IOException { 508 compressTar(sources, IOUtil.toBufferedOutputStream(target.getOutputStream()), mode); 509 } 510 511 public static void compressTar(Resource[] sources,OutputStream target, int mode) throws IOException { 512 if(target instanceof TarArchiveOutputStream){ 513 compressTar("",sources,(TarArchiveOutputStream)target,mode); 514 return; 515 } 516 TarArchiveOutputStream tos=new TarArchiveOutputStream(target); 517 tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); 518 try { 519 compressTar("",sources, tos,mode); 520 } 521 finally { 522 IOUtil.closeEL(tos); 523 } 524 } 525 526 public static void compressTar(String parent, Resource[] sources, TarArchiveOutputStream tos, int mode) throws IOException { 527 528 if(parent.length()>0)parent+="/"; 529 for(int i=0;i<sources.length;i++) { 530 compressTar(parent+sources[i].getName(),sources[i],tos,mode); 531 } 532 } 533 534 private static void compressTar(String parent, Resource source,TarArchiveOutputStream tos, int mode) throws IOException { 535 if(source.isFile()) { 536 //TarEntry entry = (source instanceof FileResource)?new TarEntry((FileResource)source):new TarEntry(parent); 537 TarArchiveEntry entry = new TarArchiveEntry(parent); 538 539 entry.setName(parent); 540 541 // mode 542 //100777 TODO ist das so ok? 543 if(mode>0) entry.setMode(mode); 544 else if((mode=source.getMode())>0) entry.setMode(mode); 545 546 entry.setSize(source.length()); 547 entry.setModTime(source.lastModified()); 548 tos.putArchiveEntry(entry); 549 try { 550 IOUtil.copy(source,tos,false); 551 } 552 finally { 553 tos.closeArchiveEntry(); 554 } 555 } 556 else if(source.isDirectory()) { 557 compressTar(parent, source.listResources(),tos,mode); 558 } 559 } 560 561 public static void main(String[] args) throws IOException { 562 ResourceProvider frp = ResourcesImpl.getFileResourceProvider(); 563 Resource src = frp.getResource("/Users/mic/temp/a"); 564 565 Resource tgz = frp.getResource("/Users/mic/temp/b/a.tgz"); 566 tgz.getParentResource().mkdirs(); 567 Resource tar = frp.getResource("/Users/mic/temp/b/a.tar"); 568 tar.getParentResource().mkdirs(); 569 Resource zip = frp.getResource("/Users/mic/temp/b/a.zip"); 570 zip.getParentResource().mkdirs(); 571 572 Resource tgz1 = frp.getResource("/Users/mic/temp/b/tgz"); 573 tgz1.mkdirs(); 574 Resource tar1 = frp.getResource("/Users/mic/temp/b/tar"); 575 tar1.mkdirs(); 576 Resource zip1 = frp.getResource("/Users/mic/temp/b/zip"); 577 zip1.mkdirs(); 578 579 compressTGZ(new Resource[]{src}, tgz, -1); 580 compressTar(new Resource[]{src}, tar, -1); 581 compressZip(new Resource[]{src}, zip, null); 582 583 extractTGZ(tgz, tgz1); 584 extractTar(tar, tar1); 585 extractZip(src, zip1); 586 587 } 588 }