PackingUtils.java
- /*
- * 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.commons.compress.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.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.commons.compress.harmony.pack200.Archive.PackingFile;
- public class PackingUtils {
- private static final class PackingLogger extends Logger {
- private boolean verbose;
- protected PackingLogger(final String name, final String resourceBundleName) {
- super(name, resourceBundleName);
- }
- @Override
- public void log(final LogRecord logRecord) {
- if (verbose) {
- super.log(logRecord);
- }
- }
- private void setVerbose(final boolean isVerbose) {
- verbose = isVerbose;
- }
- }
- private static PackingLogger packingLogger;
- private static FileHandler fileHandler;
- static {
- packingLogger = new PackingLogger("org.harmony.apache.pack200", null);
- LogManager.getLogManager().addLogger(packingLogger);
- }
- public static void config(final PackingOptions options) throws IOException {
- final String logFileName = options != null ? options.getLogFile() : null;
- if (fileHandler != null) {
- fileHandler.close();
- }
- if (logFileName != null) {
- fileHandler = new FileHandler(logFileName, false);
- fileHandler.setFormatter(new SimpleFormatter());
- packingLogger.addHandler(fileHandler);
- packingLogger.setUseParentHandlers(false);
- }
- if (options != null) {
- packingLogger.setVerbose(options.isVerbose());
- }
- }
- /**
- * When effort is 0, the packer copys through the original jar file without compression
- *
- * @param jarFile the input jar file
- * @param outputStream the jar output stream
- * @throws IOException If an I/O error occurs.
- */
- public static void copyThroughJar(final JarFile jarFile, final OutputStream outputStream) throws IOException {
- try (JarOutputStream jarOutputStream = new JarOutputStream(outputStream)) {
- jarOutputStream.setComment("PACK200");
- final byte[] bytes = new byte[16384];
- final Enumeration<JarEntry> entries = jarFile.entries();
- while (entries.hasMoreElements()) {
- final JarEntry jarEntry = entries.nextElement();
- jarOutputStream.putNextEntry(jarEntry);
- try (InputStream inputStream = jarFile.getInputStream(jarEntry)) {
- int bytesRead;
- while ((bytesRead = inputStream.read(bytes)) != -1) {
- jarOutputStream.write(bytes, 0, bytesRead);
- }
- jarOutputStream.closeEntry();
- log("Packed " + jarEntry.getName());
- }
- }
- jarFile.close();
- }
- }
- /**
- * When effort is 0, the packer copies through the original jar input stream without compression
- *
- * @param jarInputStream the jar input stream
- * @param outputStream the jar output stream
- * @throws IOException If an I/O error occurs.
- */
- public static void copyThroughJar(final JarInputStream jarInputStream, final OutputStream outputStream) throws IOException {
- final Manifest manifest = jarInputStream.getManifest();
- try (JarOutputStream jarOutputStream = new JarOutputStream(outputStream, manifest)) {
- jarOutputStream.setComment("PACK200");
- log("Packed " + JarFile.MANIFEST_NAME);
- final 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();
- }
- }
- public static List<PackingFile> getPackingFileListFromJar(final JarFile jarFile, final boolean keepFileOrder) throws IOException {
- final List<PackingFile> packingFileList = new ArrayList<>();
- final Enumeration<JarEntry> jarEntries = jarFile.entries();
- while (jarEntries.hasMoreElements()) {
- final JarEntry jarEntry = jarEntries.nextElement();
- try (InputStream inputStream = jarFile.getInputStream(jarEntry)) {
- final byte[] bytes = readJarEntry(jarEntry, new BufferedInputStream(inputStream));
- packingFileList.add(new PackingFile(bytes, jarEntry));
- }
- }
- // check whether it need reorder packing file list
- if (!keepFileOrder) {
- reorderPackingFiles(packingFileList);
- }
- return packingFileList;
- }
- public static List<PackingFile> getPackingFileListFromJar(final JarInputStream jarInputStream, final boolean keepFileOrder) throws IOException {
- final List<PackingFile> packingFileList = new ArrayList<>();
- // add manifest file
- final Manifest manifest = jarInputStream.getManifest();
- if (manifest != null) {
- final 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 void log(final String message) {
- packingLogger.log(Level.INFO, message);
- }
- private static byte[] readJarEntry(final JarEntry jarEntry, final InputStream inputStream) throws IOException {
- long size = jarEntry.getSize();
- if (size > Integer.MAX_VALUE) {
- // TODO: Should probably allow this
- throw new IllegalArgumentException("Large Class!");
- }
- if (size < 0) {
- size = 0;
- }
- final byte[] bytes = new byte[(int) size];
- if (inputStream.read(bytes) != size) {
- throw new IllegalArgumentException("Error reading from stream");
- }
- return bytes;
- }
- private static void reorderPackingFiles(final List<PackingFile> packingFileList) {
- final Iterator<PackingFile> iterator = packingFileList.iterator();
- while (iterator.hasNext()) {
- final 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
- packingFileList.sort((arg0, arg1) -> {
- final String fileName0 = arg0.getName();
- final String fileName1 = arg1.getName();
- if (fileName0.equals(fileName1)) {
- return 0;
- }
- if (JarFile.MANIFEST_NAME.equals(fileName0)) {
- return -1;
- }
- if (JarFile.MANIFEST_NAME.equals(fileName1)) {
- return 1;
- }
- return fileName0.compareTo(fileName1);
- });
- }
- }