001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.harmony.pack200;
018:
019: import java.io.BufferedInputStream;
020: import java.io.File;
021: import java.io.FileInputStream;
022: import java.io.FileNotFoundException;
023: import java.io.FileOutputStream;
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.io.OutputStream;
027: import java.util.jar.JarEntry;
028: import java.util.jar.JarInputStream;
029: import java.util.jar.JarOutputStream;
030: import java.util.zip.GZIPInputStream;
031:
032: /**
033: * The Archive class is the main entry point to unpack200. An archive is
034: * constructed with either two file names, a pack file and an output file name
035: * or two input streams corresponding to the input and the output streams. Then
036: * <code>unpack()</code> is called, to unpack the pack200 archive.
037: */
038: public class Archive {
039:
040: private static final int LOG_LEVEL_VERBOSE = 2;
041:
042: private static final int LOG_LEVEL_STANDARD = 1;
043:
044: private static final int LOG_LEVEL_QUIET = 0;
045:
046: private InputStream inputStream;
047:
048: private JarOutputStream outputStream;
049:
050: private boolean removePackFile;
051:
052: private int logLevel = LOG_LEVEL_STANDARD;
053:
054: private FileOutputStream logFile;
055:
056: private boolean overrideDeflateHint;
057:
058: private boolean deflateHint;
059:
060: private String inputFileName;
061:
062: /**
063: * Creates an Archive with the given input and output file names.
064: * @param inputFile
065: * @param outputFile
066: * @throws FileNotFoundException if the input file does not exist
067: * @throws IOException
068: */
069: public Archive(String inputFile, String outputFile)
070: throws FileNotFoundException, IOException {
071: this .inputFileName = inputFile;
072: inputStream = new FileInputStream(inputFile);
073: outputStream = new JarOutputStream(new FileOutputStream(
074: outputFile));
075: }
076:
077: /**
078: * Creates an Archive with streams for the input and output files.
079: * Note: If you use this method then calling {@link #setRemovePackFile(boolean)}
080: * will have no effect.
081: * @param inputStream
082: * @param outputStream
083: * @throws IOException
084: */
085: public Archive(InputStream inputStream, JarOutputStream outputStream)
086: throws IOException {
087: this .inputStream = inputStream;
088: this .outputStream = outputStream;
089: }
090:
091: /**
092: * Unpacks the Archive from the input file to the output file
093: * @throws Pack200Exception
094: * @throws IOException
095: */
096: public void unpack() throws Pack200Exception, IOException {
097: outputStream.setComment("PACK200");
098: try {
099: if (!inputStream.markSupported()) {
100: inputStream = new BufferedInputStream(inputStream);
101: if (!inputStream.markSupported())
102: throw new IllegalStateException();
103: }
104: inputStream.mark(2);
105: if (((inputStream.read() & 0xFF) | (inputStream.read() & 0xFF) << 8) == GZIPInputStream.GZIP_MAGIC) {
106: inputStream.reset();
107: inputStream = new BufferedInputStream(
108: new GZIPInputStream(inputStream));
109: } else {
110: inputStream.reset();
111: }
112: inputStream.mark(4);
113: int[] magic = { 0xCA, 0xFE, 0xD0, 0x0D }; // Magic word for pack200
114: int word[] = new int[4];
115: for (int i = 0; i < word.length; i++) {
116: word[i] = inputStream.read();
117: }
118: boolean compressedWithE0 = false;
119: for (int m = 0; m < magic.length; m++) {
120: if (word[m] != magic[m]) {
121: compressedWithE0 = true;
122: }
123: }
124: inputStream.reset();
125: if (compressedWithE0) { // The original Jar was not packed, so just copy it across
126: JarInputStream jarInputStream = new JarInputStream(
127: inputStream);
128: JarEntry jarEntry;
129: while ((jarEntry = jarInputStream.getNextJarEntry()) != null) {
130: outputStream.putNextEntry(jarEntry);
131: byte[] bytes = new byte[16384];
132: int bytesRead = jarInputStream.read(bytes);
133: while (bytesRead != -1) {
134: outputStream.write(bytes, 0, bytesRead);
135: bytesRead = jarInputStream.read(bytes);
136: }
137: outputStream.closeEntry();
138: }
139: } else {
140: while (available(inputStream)) {
141: Segment segment = new Segment();
142: segment.setLogLevel(logLevel);
143: segment
144: .setLogStream(logFile != null ? (OutputStream) logFile
145: : (OutputStream) System.out);
146: if (overrideDeflateHint) {
147: segment.overrideDeflateHint(deflateHint);
148: }
149: segment.unpack(inputStream, outputStream);
150: outputStream.flush();
151: }
152: }
153: } finally {
154: try {
155: inputStream.close();
156: } catch (Exception e2) {
157: }
158: try {
159: outputStream.close();
160: } catch (Exception e2) {
161: }
162: }
163: if (removePackFile) {
164: File file = new File(inputFileName);
165: file.delete();
166: }
167: }
168:
169: private boolean available(InputStream inputStream)
170: throws IOException {
171: inputStream.mark(1);
172: int check = inputStream.read();
173: inputStream.reset();
174: return check != -1;
175: }
176:
177: /**
178: * If removePackFile is set to true, the input file is deleted after
179: * unpacking
180: *
181: * @param removePackFile
182: */
183: public void setRemovePackFile(boolean removePackFile) {
184: this .removePackFile = removePackFile;
185: }
186:
187: public void setVerbose(boolean verbose) {
188: if (verbose) {
189: logLevel = LOG_LEVEL_VERBOSE;
190: } else if (logLevel == LOG_LEVEL_VERBOSE) {
191: logLevel = LOG_LEVEL_STANDARD;
192: }
193: }
194:
195: public void setQuiet(boolean quiet) {
196: if (quiet) {
197: logLevel = LOG_LEVEL_QUIET;
198: } else if (logLevel == LOG_LEVEL_QUIET) {
199: logLevel = LOG_LEVEL_QUIET;
200: }
201: }
202:
203: public void setLogFile(String logFileName)
204: throws FileNotFoundException {
205: this .logFile = new FileOutputStream(logFileName);
206: }
207:
208: public void setDeflateHint(boolean deflateHint) {
209: overrideDeflateHint = true;
210: this.deflateHint = deflateHint;
211: }
212:
213: }
|