001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 package org.apache.commons.compress.archivers; 020 021 import java.io.IOException; 022 import java.io.InputStream; 023 import java.io.OutputStream; 024 025 import org.apache.commons.compress.archivers.ar.ArArchiveInputStream; 026 import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream; 027 import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream; 028 import org.apache.commons.compress.archivers.cpio.CpioArchiveOutputStream; 029 import org.apache.commons.compress.archivers.jar.JarArchiveInputStream; 030 import org.apache.commons.compress.archivers.jar.JarArchiveOutputStream; 031 import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; 032 import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; 033 import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; 034 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; 035 036 /** 037 * <p>Factory to create Archive[In|Out]putStreams from names or the first bytes of 038 * the InputStream. In order add other implementations you should extend 039 * ArchiveStreamFactory and override the appropriate methods (and call their 040 * implementation from super of course).</p> 041 * 042 * Compressing a ZIP-File: 043 * 044 * <pre> 045 * final OutputStream out = new FileOutputStream(output); 046 * ArchiveOutputStream os = new ArchiveStreamFactory().createArchiveOutputStream(ArchiveStreamFactory.ZIP, out); 047 * 048 * os.putArchiveEntry(new ZipArchiveEntry("testdata/test1.xml")); 049 * IOUtils.copy(new FileInputStream(file1), os); 050 * os.closeArchiveEntry(); 051 * 052 * os.putArchiveEntry(new ZipArchiveEntry("testdata/test2.xml")); 053 * IOUtils.copy(new FileInputStream(file2), os); 054 * os.closeArchiveEntry(); 055 * os.close(); 056 * </pre> 057 * 058 * Decompressing a ZIP-File: 059 * 060 * <pre> 061 * final InputStream is = new FileInputStream(input); 062 * ArchiveInputStream in = new ArchiveStreamFactory().createArchiveInputStream(ArchiveStreamFactory.ZIP, is); 063 * ZipArchiveEntry entry = (ZipArchiveEntry)in.getNextEntry(); 064 * OutputStream out = new FileOutputStream(new File(dir, entry.getName())); 065 * IOUtils.copy(in, out); 066 * out.close(); 067 * in.close(); 068 * </pre> 069 * 070 * @Immutable 071 */ 072 public class ArchiveStreamFactory { 073 074 /** 075 * Constant used to identify the AR archive format. 076 * @since Commons Compress 1.1 077 */ 078 public static final String AR = "ar"; 079 /** 080 * Constant used to identify the CPIO archive format. 081 * @since Commons Compress 1.1 082 */ 083 public static final String CPIO = "cpio"; 084 /** 085 * Constant used to identify the JAR archive format. 086 * @since Commons Compress 1.1 087 */ 088 public static final String JAR = "jar"; 089 /** 090 * Constant used to identify the TAR archive format. 091 * @since Commons Compress 1.1 092 */ 093 public static final String TAR = "tar"; 094 /** 095 * Constant used to identify the ZIP archive format. 096 * @since Commons Compress 1.1 097 */ 098 public static final String ZIP = "zip"; 099 100 /** 101 * Create an archive input stream from an archiver name and an input stream. 102 * 103 * @param archiverName the archive name, i.e. "ar", "zip", "tar", "jar" or "cpio" 104 * @param in the input stream 105 * @return the archive input stream 106 * @throws ArchiveException if the archiver name is not known 107 * @throws IllegalArgumentException if the archiver name or stream is null 108 */ 109 public ArchiveInputStream createArchiveInputStream( 110 final String archiverName, final InputStream in) 111 throws ArchiveException { 112 113 if (archiverName == null) { 114 throw new IllegalArgumentException("Archivername must not be null."); 115 } 116 117 if (in == null) { 118 throw new IllegalArgumentException("InputStream must not be null."); 119 } 120 121 if (AR.equalsIgnoreCase(archiverName)) { 122 return new ArArchiveInputStream(in); 123 } 124 if (ZIP.equalsIgnoreCase(archiverName)) { 125 return new ZipArchiveInputStream(in); 126 } 127 if (TAR.equalsIgnoreCase(archiverName)) { 128 return new TarArchiveInputStream(in); 129 } 130 if (JAR.equalsIgnoreCase(archiverName)) { 131 return new JarArchiveInputStream(in); 132 } 133 if (CPIO.equalsIgnoreCase(archiverName)) { 134 return new CpioArchiveInputStream(in); 135 } 136 137 throw new ArchiveException("Archiver: " + archiverName + " not found."); 138 } 139 140 /** 141 * Create an archive output stream from an archiver name and an input stream. 142 * 143 * @param archiverName the archive name, i.e. "ar", "zip", "tar", "jar" or "cpio" 144 * @param out the output stream 145 * @return the archive output stream 146 * @throws ArchiveException if the archiver name is not known 147 * @throws IllegalArgumentException if the archiver name or stream is null 148 */ 149 public ArchiveOutputStream createArchiveOutputStream( 150 final String archiverName, final OutputStream out) 151 throws ArchiveException { 152 if (archiverName == null) { 153 throw new IllegalArgumentException("Archivername must not be null."); 154 } 155 if (out == null) { 156 throw new IllegalArgumentException("OutputStream must not be null."); 157 } 158 159 if (AR.equalsIgnoreCase(archiverName)) { 160 return new ArArchiveOutputStream(out); 161 } 162 if (ZIP.equalsIgnoreCase(archiverName)) { 163 return new ZipArchiveOutputStream(out); 164 } 165 if (TAR.equalsIgnoreCase(archiverName)) { 166 return new TarArchiveOutputStream(out); 167 } 168 if (JAR.equalsIgnoreCase(archiverName)) { 169 return new JarArchiveOutputStream(out); 170 } 171 if (CPIO.equalsIgnoreCase(archiverName)) { 172 return new CpioArchiveOutputStream(out); 173 } 174 throw new ArchiveException("Archiver: " + archiverName + " not found."); 175 } 176 177 /** 178 * Create an archive input stream from an input stream, autodetecting 179 * the archive type from the first few bytes of the stream. The InputStream 180 * must support marks, like BufferedInputStream. 181 * 182 * @param in the input stream 183 * @return the archive input stream 184 * @throws ArchiveException if the archiver name is not known 185 * @throws IllegalArgumentException if the stream is null or does not support mark 186 */ 187 public ArchiveInputStream createArchiveInputStream(final InputStream in) 188 throws ArchiveException { 189 if (in == null) { 190 throw new IllegalArgumentException("Stream must not be null."); 191 } 192 193 if (!in.markSupported()) { 194 throw new IllegalArgumentException("Mark is not supported."); 195 } 196 197 final byte[] signature = new byte[12]; 198 in.mark(signature.length); 199 try { 200 int signatureLength = in.read(signature); 201 in.reset(); 202 if (ZipArchiveInputStream.matches(signature, signatureLength)) { 203 return new ZipArchiveInputStream(in); 204 } else if (JarArchiveInputStream.matches(signature, signatureLength)) { 205 return new JarArchiveInputStream(in); 206 } else if (ArArchiveInputStream.matches(signature, signatureLength)) { 207 return new ArArchiveInputStream(in); 208 } else if (CpioArchiveInputStream.matches(signature, signatureLength)) { 209 return new CpioArchiveInputStream(in); 210 } 211 // Tar needs a bigger buffer to check the signature; read the first block 212 final byte[] tarheader = new byte[512]; 213 in.mark(tarheader.length); 214 signatureLength = in.read(tarheader); 215 in.reset(); 216 if (TarArchiveInputStream.matches(tarheader, signatureLength)) { 217 return new TarArchiveInputStream(in); 218 } 219 } catch (IOException e) { 220 throw new ArchiveException("Could not use reset and mark operations.", e); 221 } 222 223 throw new ArchiveException("No Archiver found for the stream signature"); 224 } 225 }