Fork of Apache Harmony's Pack200 implementation
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pack200/src/main/java/org/apache/harmony/pack200/PackingUtils.java

257 lines
9.1 KiB

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.harmony.pack200;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import org.apache.harmony.pack200.Archive.PackingFile;
public class PackingUtils {
private static PackingLogger packingLogger;
static {
packingLogger = new PackingLogger("org.harmony.apache.pack200", null);
LogManager.getLogManager().addLogger(packingLogger);
}
private static class PackingLogger extends Logger {
private boolean verbose = false;
protected PackingLogger(String name, String resourceBundleName) {
super(name, resourceBundleName);
}
public void log(LogRecord logRecord) {
if (verbose) {
super.log(logRecord);
}
}
public void setVerbose(boolean isVerbose) {
verbose = isVerbose;
}
}
public static void config(PackingOptions options) throws IOException {
String logFileName = options.getLogFile();
if (logFileName != null) {
FileHandler fileHandler = new FileHandler(logFileName, false);
fileHandler.setFormatter(new SimpleFormatter());
packingLogger.addHandler(fileHandler);
packingLogger.setUseParentHandlers(false);
}
packingLogger.setVerbose(options.isVerbose());
}
public static void log(String message) {
packingLogger.log(Level.INFO, message);
}
/**
* When effort is 0, the packer copies through the original jar input stream
* without compression
*
* @param jarInputStream
* the jar input stream
* @param jarOutputStream
* the jar output stream
* @throws IOException
*/
public static void copyThroughJar(JarInputStream jarInputStream,
OutputStream outputStream) throws IOException {
Manifest manifest = jarInputStream.getManifest();
JarOutputStream jarOutputStream = new JarOutputStream(outputStream,
manifest);
jarOutputStream.setComment("PACK200");
log("Packed " + JarFile.MANIFEST_NAME);
byte[] bytes = new byte[16384];
JarEntry jarEntry;
int bytesRead;
while ((jarEntry = jarInputStream.getNextJarEntry()) != null) {
jarOutputStream.putNextEntry(jarEntry);
while ((bytesRead = jarInputStream.read(bytes)) != -1) {
jarOutputStream.write(bytes, 0, bytesRead);
}
log("Packed " + jarEntry.getName());
}
jarInputStream.close();
jarOutputStream.close();
}
/**
* When effort is 0, the packer copys through the original jar file without
* compression
*
* @param jarFile
* the input jar file
* @param jarOutputStream
* the jar output stream
* @throws IOException
*/
public static void copyThroughJar(JarFile jarFile, OutputStream outputStream)
throws IOException {
JarOutputStream jarOutputStream = new JarOutputStream(outputStream);
jarOutputStream.setComment("PACK200");
byte[] bytes = new byte[16384];
Enumeration entries = jarFile.entries();
InputStream inputStream;
JarEntry jarEntry;
int bytesRead;
while (entries.hasMoreElements()) {
jarEntry = (JarEntry) entries.nextElement();
jarOutputStream.putNextEntry(jarEntry);
inputStream = jarFile.getInputStream(jarEntry);
while ((bytesRead = inputStream.read(bytes)) != -1) {
jarOutputStream.write(bytes, 0, bytesRead);
}
jarOutputStream.closeEntry();
log("Packed " + jarEntry.getName());
}
jarFile.close();
jarOutputStream.close();
}
public static List getPackingFileListFromJar(JarInputStream jarInputStream,
boolean keepFileOrder) throws IOException {
List packingFileList = new ArrayList();
// add manifest file
Manifest manifest = jarInputStream.getManifest();
if (manifest != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
manifest.write(baos);
packingFileList.add(new PackingFile(JarFile.MANIFEST_NAME, baos
.toByteArray(), 0));
}
// add rest of entries in the jar
JarEntry jarEntry;
byte[] bytes;
while ((jarEntry = jarInputStream.getNextJarEntry()) != null) {
bytes = readJarEntry(jarEntry, new BufferedInputStream(
jarInputStream));
packingFileList.add(new PackingFile(bytes, jarEntry));
}
// check whether it need reorder packing file list
if (!keepFileOrder) {
reorderPackingFiles(packingFileList);
}
return packingFileList;
}
public static List getPackingFileListFromJar(JarFile jarFile,
boolean keepFileOrder) throws IOException {
List packingFileList = new ArrayList();
Enumeration jarEntries = jarFile.entries();
JarEntry jarEntry;
byte[] bytes;
while (jarEntries.hasMoreElements()) {
jarEntry = (JarEntry) jarEntries.nextElement();
bytes = readJarEntry(jarEntry, new BufferedInputStream(jarFile
.getInputStream(jarEntry)));
packingFileList.add(new PackingFile(bytes, jarEntry));
}
// check whether it need reorder packing file list
if (!keepFileOrder) {
reorderPackingFiles(packingFileList);
}
return packingFileList;
}
private static byte[] readJarEntry(JarEntry jarEntry,
InputStream inputStream) throws IOException {
long size = jarEntry.getSize();
if (size > Integer.MAX_VALUE) {
// TODO: Should probably allow this
throw new RuntimeException("Large Class!");
} else if (size < 0) {
byte[] temp = new byte[4096];
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
int len;
while ((len = inputStream.read(temp, 0, temp.length)) != -1) {
out.write(temp, 0, len);
}
return out.toByteArray();
}
}
byte[] bytes = new byte[(int) size];
if (inputStream.read(bytes) != size) {
throw new RuntimeException("Error reading from stream");
}
return bytes;
}
private static void reorderPackingFiles(List packingFileList) {
Iterator iterator = packingFileList.iterator();
PackingFile packingFile;
while (iterator.hasNext()) {
packingFile = (PackingFile) iterator.next();
if (packingFile.isDirectory()) {
// remove directory entries
iterator.remove();
}
}
// Sort files by name, "META-INF/MANIFEST.MF" should be put in the 1st
// position
Collections.sort(packingFileList, new Comparator() {
public int compare(Object arg0, Object arg1) {
if (arg0 instanceof PackingFile && arg1 instanceof PackingFile) {
String fileName0 = ((PackingFile) arg0).getName();
String fileName1 = ((PackingFile) arg1).getName();
if (fileName0.equals(fileName1)) {
return 0;
} else if (JarFile.MANIFEST_NAME.equals(fileName0)) {
return -1;
} else if (JarFile.MANIFEST_NAME.equals(fileName1)) {
return 1;
}
return fileName0.compareTo(fileName1);
}
throw new IllegalArgumentException();
}
});
}
}