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