001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020package org.apache.commons.compress.compressors.pack200;
021
022import java.io.File;
023import java.io.IOException;
024import java.io.OutputStream;
025import java.nio.file.Files;
026import java.nio.file.Path;
027import java.util.HashMap;
028import java.util.Map;
029import java.util.jar.JarFile;
030import java.util.jar.JarOutputStream;
031
032import org.apache.commons.compress.java.util.jar.Pack200;
033
034/**
035 * Utility methods for Pack200.
036 *
037 * @ThreadSafe
038 * @since 1.3
039 */
040public class Pack200Utils {
041    /**
042     * Normalizes a JAR archive in-place, so it can be safely signed and packed.
043     *
044     * <p>
045     * As stated in <a href="https://download.oracle.com/javase/1.5.0/docs/api/java/util/jar/Pack200.Packer.html">Pack200.Packer's</a> javadocs applying a
046     * Pack200 compression to a JAR archive will in general make its signatures invalid. In order to prepare a JAR for signing it should be "normalized" by
047     * packing and unpacking it. This is what this method does.
048     * </p>
049     *
050     * <p>
051     * Note this methods implicitly sets the segment length to -1.
052     * </p>
053     *
054     * @param jar the JAR archive to normalize
055     * @throws IOException if reading or writing fails
056     */
057    public static void normalize(final File jar) throws IOException {
058        normalize(jar, jar, null);
059    }
060
061    /**
062     * Normalizes a JAR archive, so it can be safely signed and packed.
063     *
064     * <p>
065     * As stated in <a href="https://download.oracle.com/javase/1.5.0/docs/api/java/util/jar/Pack200.Packer.html">Pack200.Packer's</a> javadocs applying a
066     * Pack200 compression to a JAR archive will in general make its signatures invalid. In order to prepare a JAR for signing it should be "normalized" by
067     * packing and unpacking it. This is what this method does.
068     * </p>
069     *
070     * <p>
071     * This method does not replace the existing archive but creates a new one.
072     * </p>
073     *
074     * <p>
075     * Note this methods implicitly sets the segment length to -1.
076     * </p>
077     *
078     * @param from the JAR archive to normalize
079     * @param to   the normalized archive
080     * @throws IOException if reading or writing fails
081     */
082    public static void normalize(final File from, final File to) throws IOException {
083        normalize(from, to, null);
084    }
085
086    /**
087     * Normalizes a JAR archive, so it can be safely signed and packed.
088     *
089     * <p>
090     * As stated in <a href="https://download.oracle.com/javase/1.5.0/docs/api/java/util/jar/Pack200.Packer.html">Pack200.Packer's</a> javadocs applying a
091     * Pack200 compression to a JAR archive will in general make its signatures invalid. In order to prepare a JAR for signing it should be "normalized" by
092     * packing and unpacking it. This is what this method does.
093     * </p>
094     *
095     * <p>
096     * This method does not replace the existing archive but creates a new one.
097     * </p>
098     *
099     * @param from  the JAR archive to normalize
100     * @param to    the normalized archive
101     * @param props properties to set for the pack operation. This method will implicitly set the segment limit to -1.
102     * @throws IOException if reading or writing fails
103     */
104    public static void normalize(final File from, final File to, Map<String, String> props) throws IOException {
105        if (props == null) {
106            props = new HashMap<>();
107        }
108        props.put(Pack200.Packer.SEGMENT_LIMIT, "-1");
109        final Path tempFile = Files.createTempFile("commons-compress", "pack200normalize");
110        try {
111            try (OutputStream fos = Files.newOutputStream(tempFile);
112                    JarFile jarFile = new JarFile(from)) {
113                final Pack200.Packer packer = Pack200.newPacker();
114                packer.properties().putAll(props);
115                packer.pack(jarFile, fos);
116            }
117            final Pack200.Unpacker unpacker = Pack200.newUnpacker();
118            try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(to.toPath()))) {
119                unpacker.unpack(tempFile.toFile(), jos);
120            }
121        } finally {
122            Files.delete(tempFile);
123        }
124    }
125
126    /**
127     * Normalizes a JAR archive in-place, so it can be safely signed and packed.
128     *
129     * <p>
130     * As stated in <a href="https://download.oracle.com/javase/1.5.0/docs/api/java/util/jar/Pack200.Packer.html">Pack200.Packer's</a> javadocs applying a
131     * Pack200 compression to a JAR archive will in general make its signatures invalid. In order to prepare a JAR for signing it should be "normalized" by
132     * packing and unpacking it. This is what this method does.
133     * </p>
134     *
135     * @param jar   the JAR archive to normalize
136     * @param props properties to set for the pack operation. This method will implicitly set the segment limit to -1.
137     * @throws IOException if reading or writing fails
138     */
139    public static void normalize(final File jar, final Map<String, String> props) throws IOException {
140        normalize(jar, jar, props);
141    }
142
143    private Pack200Utils() {
144    }
145}