1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.commons.compress.harmony.unpack200;
20  
21  import java.io.BufferedInputStream;
22  import java.io.BufferedOutputStream;
23  import java.io.FileInputStream;
24  import java.io.FileNotFoundException;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.nio.file.Files;
29  import java.nio.file.Path;
30  import java.nio.file.Paths;
31  import java.util.jar.JarEntry;
32  import java.util.jar.JarInputStream;
33  import java.util.jar.JarOutputStream;
34  import java.util.zip.GZIPInputStream;
35  
36  import org.apache.commons.compress.harmony.pack200.Pack200Exception;
37  import org.apache.commons.io.IOUtils;
38  import org.apache.commons.io.input.BoundedInputStream;
39  
40  
41  
42  
43  
44  public class Archive {
45  
46      private static final int[] MAGIC = { 0xCA, 0xFE, 0xD0, 0x0D };
47  
48      private BoundedInputStream inputStream;
49  
50      private final JarOutputStream outputStream;
51  
52      private boolean removePackFile;
53  
54      private int logLevel = Segment.LOG_LEVEL_STANDARD;
55  
56      private FileOutputStream logFile;
57  
58      private boolean overrideDeflateHint;
59  
60      private boolean deflateHint;
61  
62      private final Path inputPath;
63  
64      private final long inputSize;
65  
66      private final String outputFileName;
67  
68      private final boolean closeStreams;
69  
70      
71  
72  
73  
74  
75  
76  
77  
78      public Archive(final InputStream inputStream, final JarOutputStream outputStream) throws IOException {
79          this.inputStream = Pack200UnpackerAdapter.newBoundedInputStream(inputStream);
80          this.outputStream = outputStream;
81          if (inputStream instanceof FileInputStream) {
82              inputPath = Paths.get(Pack200UnpackerAdapter.readPathString((FileInputStream) inputStream));
83          } else {
84              inputPath = null;
85          }
86          this.outputFileName = null;
87          this.inputSize = -1;
88          this.closeStreams = false;
89      }
90  
91      
92  
93  
94  
95  
96  
97  
98  
99      @SuppressWarnings("resource")
100     public Archive(final String inputFileName, final String outputFileName) throws FileNotFoundException, IOException {
101         this.inputPath = Paths.get(inputFileName);
102         this.inputSize = Files.size(this.inputPath);
103         this.inputStream = BoundedInputStream.builder().setPath(inputPath).setMaxCount(inputSize).get();
104         this.outputStream = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(outputFileName)));
105         this.outputFileName = outputFileName;
106         this.closeStreams = true;
107     }
108 
109     private boolean available(final InputStream inputStream) throws IOException {
110         inputStream.mark(1);
111         final int check = inputStream.read();
112         inputStream.reset();
113         return check != -1;
114     }
115 
116     
117 
118 
119 
120 
121     public void setDeflateHint(final boolean deflateHint) {
122         overrideDeflateHint = true;
123         this.deflateHint = deflateHint;
124     }
125 
126     
127 
128 
129 
130 
131 
132 
133     public void setLogFile(final String logFileName) throws FileNotFoundException {
134         logFile = new FileOutputStream(logFileName);
135     }
136 
137     
138 
139 
140 
141 
142 
143 
144 
145     public void setLogFile(final String logFileName, final boolean append) throws FileNotFoundException {
146         logFile = new FileOutputStream(logFileName, append);
147     }
148 
149     
150 
151 
152 
153 
154     public void setQuiet(final boolean quiet) {
155         if (quiet || logLevel == Segment.LOG_LEVEL_QUIET) {
156             logLevel = Segment.LOG_LEVEL_QUIET;
157         }
158     }
159 
160     
161 
162 
163 
164 
165     public void setRemovePackFile(final boolean removePackFile) {
166         this.removePackFile = removePackFile;
167     }
168 
169     
170 
171 
172 
173 
174     public void setVerbose(final boolean verbose) {
175         if (verbose) {
176             logLevel = Segment.LOG_LEVEL_VERBOSE;
177         } else if (logLevel == Segment.LOG_LEVEL_VERBOSE) {
178             logLevel = Segment.LOG_LEVEL_STANDARD;
179         }
180     }
181 
182     
183 
184 
185 
186 
187 
188     public void unpack() throws Pack200Exception, IOException {
189         outputStream.setComment("PACK200");
190         try {
191             if (!inputStream.markSupported()) {
192                 inputStream = new BoundedInputStream(new BufferedInputStream(inputStream));
193                 if (!inputStream.markSupported()) {
194                     throw new IllegalStateException();
195                 }
196             }
197             inputStream.mark(2);
198             if ((inputStream.read() & 0xFF | (inputStream.read() & 0xFF) << 8) == GZIPInputStream.GZIP_MAGIC) {
199                 inputStream.reset();
200                 inputStream = new BoundedInputStream(new BufferedInputStream(new GZIPInputStream(inputStream)));
201             } else {
202                 inputStream.reset();
203             }
204             inputStream.mark(MAGIC.length);
205             
206             final int[] word = new int[MAGIC.length];
207             for (int i = 0; i < word.length; i++) {
208                 word[i] = inputStream.read();
209             }
210             boolean compressedWithE0 = false;
211             for (int m = 0; m < MAGIC.length; m++) {
212                 if (word[m] != MAGIC[m]) {
213                     compressedWithE0 = true;
214                     break;
215                 }
216             }
217             inputStream.reset();
218             if (compressedWithE0) { 
219                 final JarInputStream jarInputStream = new JarInputStream(inputStream);
220                 JarEntry jarEntry;
221                 while ((jarEntry = jarInputStream.getNextJarEntry()) != null) {
222                     outputStream.putNextEntry(jarEntry);
223                     IOUtils.copy(jarInputStream, outputStream, 16_384);
224                     outputStream.closeEntry();
225                 }
226             } else {
227                 int i = 0;
228                 while (available(inputStream)) {
229                     i++;
230                     final Segment segment = new Segment();
231                     segment.setLogLevel(logLevel);
232                     segment.setLogStream(logFile);
233                     segment.setPreRead(false);
234                     if (i == 1) {
235                         segment.log(Segment.LOG_LEVEL_VERBOSE, "Unpacking from " + inputPath + " to " + outputFileName);
236                     }
237                     segment.log(Segment.LOG_LEVEL_VERBOSE, "Reading segment " + i);
238                     if (overrideDeflateHint) {
239                         segment.overrideDeflateHint(deflateHint);
240                     }
241                     segment.unpack(inputStream, outputStream);
242                     outputStream.flush();
243                 }
244             }
245         } finally {
246             if (closeStreams) {
247                 IOUtils.closeQuietly(inputStream);
248                 IOUtils.closeQuietly(outputStream);
249             }
250             IOUtils.closeQuietly(logFile);
251         }
252         if (removePackFile && inputPath != null) {
253             Files.delete(inputPath);
254         }
255     }
256 
257 }