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.
257 lines
9.1 KiB
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();
|
|
}
|
|
});
|
|
}
|
|
|
|
} |