Utils.java revision 12745:f068a4ffddd2
1/*
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.java.util.jar.pack;
27
28import java.io.BufferedInputStream;
29import java.io.BufferedOutputStream;
30import java.io.File;
31import java.io.FilterOutputStream;
32import java.io.IOException;
33import java.io.InputStream;
34import java.io.OutputStream;
35import java.util.Collections;
36import java.util.Date;
37import java.util.jar.JarEntry;
38import java.util.jar.JarFile;
39import java.util.jar.JarInputStream;
40import java.util.jar.JarOutputStream;
41import java.util.zip.ZipEntry;
42import sun.util.logging.PlatformLogger;
43
44class Utils {
45    static final String COM_PREFIX = "com.sun.java.util.jar.pack.";
46    static final String METAINF    = "META-INF";
47
48    /*
49     * Outputs various diagnostic support information.
50     * If >0, print summary comments (e.g., constant pool info).
51     * If >1, print unit comments (e.g., processing of classes).
52     * If >2, print many comments (e.g., processing of members).
53     * If >3, print tons of comments (e.g., processing of references).
54     * (installer only)
55     */
56    static final String DEBUG_VERBOSE = COM_PREFIX+"verbose";
57
58    /*
59     * Disables use of native code, prefers the Java-coded implementation.
60     * (installer only)
61     */
62    static final String DEBUG_DISABLE_NATIVE = COM_PREFIX+"disable.native";
63
64    /*
65     * Use the default working TimeZone instead of UTC.
66     * Note: This has installer unpacker implications.
67     * see: zip.cpp which uses gmtime vs. localtime.
68     */
69    static final String PACK_DEFAULT_TIMEZONE = COM_PREFIX+"default.timezone";
70
71    /*
72     * Property indicating that the unpacker should
73     * ignore the transmitted PACK_MODIFICATION_TIME,
74     * replacing it by the given value. The value can
75     * be a numeric string, representing the number of
76     * mSecs since the epoch (UTC), or the special string
77     * {@link #NOW}, meaning the current time (UTC).
78     * The default value is the special string {@link #KEEP},
79     * which asks the unpacker to preserve all transmitted
80     * modification time information.
81     * (installer only)
82     */
83    static final String UNPACK_MODIFICATION_TIME = COM_PREFIX+"unpack.modification.time";
84
85    /*
86     * Property indicating that the unpacker strip the
87     * Debug Attributes, if they are present, in the pack stream.
88     * The default value is false.
89     * (installer only)
90     */
91    static final String UNPACK_STRIP_DEBUG = COM_PREFIX+"unpack.strip.debug";
92
93    /*
94     * Remove the input file after unpacking.
95     * (installer only)
96     */
97    static final String UNPACK_REMOVE_PACKFILE = COM_PREFIX+"unpack.remove.packfile";
98
99    /*
100     * A possible value for MODIFICATION_TIME
101     */
102    static final String NOW                             = "now";
103    // Other debug options:
104    //   com...debug.bands=false      add band IDs to pack file, to verify sync
105    //   com...dump.bands=false       dump band contents to local disk
106    //   com...no.vary.codings=false  turn off coding variation heuristics
107    //   com...no.big.strings=false   turn off "big string" feature
108
109    /*
110     * If this property is set to {@link #TRUE}, the packer will preserve
111     * the ordering of class files of the original jar in the output archive.
112     * The ordering is preserved only for class-files; resource files
113     * may be reordered.
114     * <p>
115     * If the packer is allowed to reorder class files, it can marginally
116     * decrease the transmitted size of the archive.
117     */
118    static final String PACK_KEEP_CLASS_ORDER = COM_PREFIX+"keep.class.order";
119    /*
120     * This string PACK200 is given as a zip comment on all JAR files
121     * produced by this utility.
122     */
123    static final String PACK_ZIP_ARCHIVE_MARKER_COMMENT = "PACK200";
124
125    /*
126     * behaviour when we hit a class format error, but not necessarily
127     * an unknown attribute, by default it is allowed to PASS.
128     */
129    static final String CLASS_FORMAT_ERROR = COM_PREFIX+"class.format.error";
130
131    // Keep a TLS point to the global data and environment.
132    // This makes it simpler to supply environmental options
133    // to the engine code, especially the native code.
134    static final ThreadLocal<TLGlobals> currentInstance = new ThreadLocal<>();
135
136    // convenience method to access the TL globals
137    static TLGlobals getTLGlobals() {
138        return currentInstance.get();
139    }
140
141    static PropMap currentPropMap() {
142        Object obj = currentInstance.get();
143        if (obj instanceof PackerImpl)
144            return ((PackerImpl)obj).props;
145        if (obj instanceof UnpackerImpl)
146            return ((UnpackerImpl)obj).props;
147        return null;
148    }
149
150    static final boolean nolog
151        = Boolean.getBoolean(COM_PREFIX+"nolog");
152
153    static final boolean SORT_MEMBERS_DESCR_MAJOR
154        = Boolean.getBoolean(COM_PREFIX+"sort.members.descr.major");
155
156    static final boolean SORT_HANDLES_KIND_MAJOR
157        = Boolean.getBoolean(COM_PREFIX+"sort.handles.kind.major");
158
159    static final boolean SORT_INDY_BSS_MAJOR
160        = Boolean.getBoolean(COM_PREFIX+"sort.indy.bss.major");
161
162    static final boolean SORT_BSS_BSM_MAJOR
163        = Boolean.getBoolean(COM_PREFIX+"sort.bss.bsm.major");
164
165    static class Pack200Logger {
166        private final String name;
167        private PlatformLogger log;
168        Pack200Logger(String name) {
169            this.name = name;
170        }
171
172        private synchronized PlatformLogger getLogger() {
173            if (log == null) {
174                log = PlatformLogger.getLogger(name);
175            }
176            return log;
177        }
178
179        public void warning(String msg, Object param) {
180                getLogger().warning(msg, param);
181            }
182
183        public void warning(String msg) {
184            warning(msg, null);
185        }
186
187        public void info(String msg) {
188            int verbose = currentPropMap().getInteger(DEBUG_VERBOSE);
189            if (verbose > 0) {
190                if (nolog) {
191                    System.out.println(msg);
192                } else {
193                    getLogger().info(msg);
194                }
195            }
196        }
197
198        public void fine(String msg) {
199            int verbose = currentPropMap().getInteger(DEBUG_VERBOSE);
200            if (verbose > 0) {
201                    System.out.println(msg);
202            }
203        }
204    }
205
206    static final Pack200Logger log
207        = new Pack200Logger("java.util.jar.Pack200");
208
209    // Returns the Max Version String of this implementation
210    static String getVersionString() {
211        return "Pack200, Vendor: " +
212            System.getProperty("java.vendor") +
213            ", Version: " + Constants.MAX_PACKAGE_VERSION;
214    }
215
216    static void markJarFile(JarOutputStream out) throws IOException {
217        out.setComment(PACK_ZIP_ARCHIVE_MARKER_COMMENT);
218    }
219
220    // -0 mode helper
221    static void copyJarFile(JarInputStream in, JarOutputStream out) throws IOException {
222        if (in.getManifest() != null) {
223            ZipEntry me = new ZipEntry(JarFile.MANIFEST_NAME);
224            out.putNextEntry(me);
225            in.getManifest().write(out);
226            out.closeEntry();
227        }
228        byte[] buffer = new byte[1 << 14];
229        for (JarEntry je; (je = in.getNextJarEntry()) != null; ) {
230            out.putNextEntry(je);
231            for (int nr; 0 < (nr = in.read(buffer)); ) {
232                out.write(buffer, 0, nr);
233            }
234        }
235        in.close();
236        markJarFile(out);  // add PACK200 comment
237    }
238    static void copyJarFile(JarFile in, JarOutputStream out) throws IOException {
239        byte[] buffer = new byte[1 << 14];
240        for (JarEntry je : Collections.list(in.entries())) {
241            out.putNextEntry(je);
242            InputStream ein = in.getInputStream(je);
243            for (int nr; 0 < (nr = ein.read(buffer)); ) {
244                out.write(buffer, 0, nr);
245            }
246        }
247        in.close();
248        markJarFile(out);  // add PACK200 comment
249    }
250    static void copyJarFile(JarInputStream in, OutputStream out) throws IOException {
251        // 4947205 : Peformance is slow when using pack-effort=0
252        out = new BufferedOutputStream(out);
253        out = new NonCloser(out); // protect from JarOutputStream.close()
254        try (JarOutputStream jout = new JarOutputStream(out)) {
255            copyJarFile(in, jout);
256        }
257    }
258    static void copyJarFile(JarFile in, OutputStream out) throws IOException {
259
260        // 4947205 : Peformance is slow when using pack-effort=0
261        out = new BufferedOutputStream(out);
262        out = new NonCloser(out); // protect from JarOutputStream.close()
263        try (JarOutputStream jout = new JarOutputStream(out)) {
264            copyJarFile(in, jout);
265        }
266    }
267        // Wrapper to prevent closing of client-supplied stream.
268    private static
269    class NonCloser extends FilterOutputStream {
270        NonCloser(OutputStream out) { super(out); }
271        public void close() throws IOException { flush(); }
272    }
273   static String getJarEntryName(String name) {
274        if (name == null)  return null;
275        return name.replace(File.separatorChar, '/');
276    }
277
278    static String zeString(ZipEntry ze) {
279        int store = (ze.getCompressedSize() > 0) ?
280            (int)( (1.0 - ((double)ze.getCompressedSize()/(double)ze.getSize()))*100 )
281            : 0 ;
282        // Follow unzip -lv output
283        return ze.getSize() + "\t" + ze.getMethod()
284            + "\t" + ze.getCompressedSize() + "\t"
285            + store + "%\t"
286            + new Date(ze.getTime()) + "\t"
287            + Long.toHexString(ze.getCrc()) + "\t"
288            + ze.getName() ;
289    }
290
291
292
293    static byte[] readMagic(BufferedInputStream in) throws IOException {
294        in.mark(4);
295        byte[] magic = new byte[4];
296        for (int i = 0; i < magic.length; i++) {
297            // read 1 byte at a time, so we always get 4
298            if (1 != in.read(magic, i, 1))
299                break;
300        }
301        in.reset();
302        return magic;
303    }
304
305    // magic number recognizers
306    static boolean isJarMagic(byte[] magic) {
307        return (magic[0] == (byte)'P' &&
308                magic[1] == (byte)'K' &&
309                magic[2] >= 1 &&
310                magic[2] <  8 &&
311                magic[3] == magic[2] + 1);
312    }
313    static boolean isPackMagic(byte[] magic) {
314        return (magic[0] == (byte)0xCA &&
315                magic[1] == (byte)0xFE &&
316                magic[2] == (byte)0xD0 &&
317                magic[3] == (byte)0x0D);
318    }
319    static boolean isGZIPMagic(byte[] magic) {
320        return (magic[0] == (byte)0x1F &&
321                magic[1] == (byte)0x8B &&
322                magic[2] == (byte)0x08);
323        // fourth byte is variable "flg" field
324    }
325
326    private Utils() { } // do not instantiate
327}
328