1/*
2 * Copyright (c) 2003, 2015, 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     * Property indicating that the unpacker should
66     * ignore the transmitted PACK_MODIFICATION_TIME,
67     * replacing it by the given value. The value can
68     * be a numeric string, representing the number of
69     * mSecs since the epoch (UTC), or the special string
70     * {@link #NOW}, meaning the current time (UTC).
71     * The default value is the special string {@link #KEEP},
72     * which asks the unpacker to preserve all transmitted
73     * modification time information.
74     * (installer only)
75     */
76    static final String UNPACK_MODIFICATION_TIME = COM_PREFIX+"unpack.modification.time";
77
78    /*
79     * Property indicating that the unpacker strip the
80     * Debug Attributes, if they are present, in the pack stream.
81     * The default value is false.
82     * (installer only)
83     */
84    static final String UNPACK_STRIP_DEBUG = COM_PREFIX+"unpack.strip.debug";
85
86    /*
87     * Remove the input file after unpacking.
88     * (installer only)
89     */
90    static final String UNPACK_REMOVE_PACKFILE = COM_PREFIX+"unpack.remove.packfile";
91
92    /*
93     * A possible value for MODIFICATION_TIME
94     */
95    static final String NOW                             = "now";
96    // Other debug options:
97    //   com...debug.bands=false      add band IDs to pack file, to verify sync
98    //   com...dump.bands=false       dump band contents to local disk
99    //   com...no.vary.codings=false  turn off coding variation heuristics
100    //   com...no.big.strings=false   turn off "big string" feature
101
102    /*
103     * If this property is set to {@link #TRUE}, the packer will preserve
104     * the ordering of class files of the original jar in the output archive.
105     * The ordering is preserved only for class-files; resource files
106     * may be reordered.
107     * <p>
108     * If the packer is allowed to reorder class files, it can marginally
109     * decrease the transmitted size of the archive.
110     */
111    static final String PACK_KEEP_CLASS_ORDER = COM_PREFIX+"keep.class.order";
112    /*
113     * This string PACK200 is given as a zip comment on all JAR files
114     * produced by this utility.
115     */
116    static final String PACK_ZIP_ARCHIVE_MARKER_COMMENT = "PACK200";
117
118    /*
119     * behaviour when we hit a class format error, but not necessarily
120     * an unknown attribute, by default it is allowed to PASS.
121     */
122    static final String CLASS_FORMAT_ERROR = COM_PREFIX+"class.format.error";
123
124    // Keep a TLS point to the global data and environment.
125    // This makes it simpler to supply environmental options
126    // to the engine code, especially the native code.
127    static final ThreadLocal<TLGlobals> currentInstance = new ThreadLocal<>();
128
129    // convenience method to access the TL globals
130    static TLGlobals getTLGlobals() {
131        return currentInstance.get();
132    }
133
134    static PropMap currentPropMap() {
135        Object obj = currentInstance.get();
136        if (obj instanceof PackerImpl)
137            return ((PackerImpl)obj).props;
138        if (obj instanceof UnpackerImpl)
139            return ((UnpackerImpl)obj).props;
140        return null;
141    }
142
143    static final boolean nolog
144        = Boolean.getBoolean(COM_PREFIX+"nolog");
145
146    static final boolean SORT_MEMBERS_DESCR_MAJOR
147        = Boolean.getBoolean(COM_PREFIX+"sort.members.descr.major");
148
149    static final boolean SORT_HANDLES_KIND_MAJOR
150        = Boolean.getBoolean(COM_PREFIX+"sort.handles.kind.major");
151
152    static final boolean SORT_INDY_BSS_MAJOR
153        = Boolean.getBoolean(COM_PREFIX+"sort.indy.bss.major");
154
155    static final boolean SORT_BSS_BSM_MAJOR
156        = Boolean.getBoolean(COM_PREFIX+"sort.bss.bsm.major");
157
158    static class Pack200Logger {
159        private final String name;
160        private PlatformLogger log;
161        Pack200Logger(String name) {
162            this.name = name;
163        }
164
165        private synchronized PlatformLogger getLogger() {
166            if (log == null) {
167                log = PlatformLogger.getLogger(name);
168            }
169            return log;
170        }
171
172        public void warning(String msg, Object param) {
173                getLogger().warning(msg, param);
174            }
175
176        public void warning(String msg) {
177            warning(msg, null);
178        }
179
180        public void info(String msg) {
181            int verbose = currentPropMap().getInteger(DEBUG_VERBOSE);
182            if (verbose > 0) {
183                if (nolog) {
184                    System.out.println(msg);
185                } else {
186                    getLogger().info(msg);
187                }
188            }
189        }
190
191        public void fine(String msg) {
192            int verbose = currentPropMap().getInteger(DEBUG_VERBOSE);
193            if (verbose > 0) {
194                    System.out.println(msg);
195            }
196        }
197    }
198
199    static final Pack200Logger log
200        = new Pack200Logger("java.util.jar.Pack200");
201
202    // Returns the Max Version String of this implementation
203    static String getVersionString() {
204        return "Pack200, Vendor: " +
205            System.getProperty("java.vendor") +
206            ", Version: " + Constants.MAX_PACKAGE_VERSION;
207    }
208
209    static void markJarFile(JarOutputStream out) throws IOException {
210        out.setComment(PACK_ZIP_ARCHIVE_MARKER_COMMENT);
211    }
212
213    // -0 mode helper
214    static void copyJarFile(JarInputStream in, JarOutputStream out) throws IOException {
215        if (in.getManifest() != null) {
216            ZipEntry me = new ZipEntry(JarFile.MANIFEST_NAME);
217            out.putNextEntry(me);
218            in.getManifest().write(out);
219            out.closeEntry();
220        }
221        byte[] buffer = new byte[1 << 14];
222        for (JarEntry je; (je = in.getNextJarEntry()) != null; ) {
223            out.putNextEntry(je);
224            for (int nr; 0 < (nr = in.read(buffer)); ) {
225                out.write(buffer, 0, nr);
226            }
227        }
228        in.close();
229        markJarFile(out);  // add PACK200 comment
230    }
231    static void copyJarFile(JarFile in, JarOutputStream out) throws IOException {
232        byte[] buffer = new byte[1 << 14];
233        for (JarEntry je : Collections.list(in.entries())) {
234            out.putNextEntry(je);
235            InputStream ein = in.getInputStream(je);
236            for (int nr; 0 < (nr = ein.read(buffer)); ) {
237                out.write(buffer, 0, nr);
238            }
239        }
240        in.close();
241        markJarFile(out);  // add PACK200 comment
242    }
243    static void copyJarFile(JarInputStream in, OutputStream out) throws IOException {
244        // 4947205 : Peformance is slow when using pack-effort=0
245        out = new BufferedOutputStream(out);
246        out = new NonCloser(out); // protect from JarOutputStream.close()
247        try (JarOutputStream jout = new JarOutputStream(out)) {
248            copyJarFile(in, jout);
249        }
250    }
251    static void copyJarFile(JarFile in, OutputStream out) throws IOException {
252
253        // 4947205 : Peformance is slow when using pack-effort=0
254        out = new BufferedOutputStream(out);
255        out = new NonCloser(out); // protect from JarOutputStream.close()
256        try (JarOutputStream jout = new JarOutputStream(out)) {
257            copyJarFile(in, jout);
258        }
259    }
260        // Wrapper to prevent closing of client-supplied stream.
261    private static
262    class NonCloser extends FilterOutputStream {
263        NonCloser(OutputStream out) { super(out); }
264        public void close() throws IOException { flush(); }
265    }
266   static String getJarEntryName(String name) {
267        if (name == null)  return null;
268        return name.replace(File.separatorChar, '/');
269    }
270
271    static String zeString(ZipEntry ze) {
272        int store = (ze.getCompressedSize() > 0) ?
273            (int)( (1.0 - ((double)ze.getCompressedSize()/(double)ze.getSize()))*100 )
274            : 0 ;
275        // Follow unzip -lv output
276        return ze.getSize() + "\t" + ze.getMethod()
277            + "\t" + ze.getCompressedSize() + "\t"
278            + store + "%\t"
279            + new Date(ze.getTime()) + "\t"
280            + Long.toHexString(ze.getCrc()) + "\t"
281            + ze.getName() ;
282    }
283
284
285
286    static byte[] readMagic(BufferedInputStream in) throws IOException {
287        in.mark(4);
288        byte[] magic = new byte[4];
289        for (int i = 0; i < magic.length; i++) {
290            // read 1 byte at a time, so we always get 4
291            if (1 != in.read(magic, i, 1))
292                break;
293        }
294        in.reset();
295        return magic;
296    }
297
298    // magic number recognizers
299    static boolean isJarMagic(byte[] magic) {
300        return (magic[0] == (byte)'P' &&
301                magic[1] == (byte)'K' &&
302                magic[2] >= 1 &&
303                magic[2] <  8 &&
304                magic[3] == magic[2] + 1);
305    }
306    static boolean isPackMagic(byte[] magic) {
307        return (magic[0] == (byte)0xCA &&
308                magic[1] == (byte)0xFE &&
309                magic[2] == (byte)0xD0 &&
310                magic[3] == (byte)0x0D);
311    }
312    static boolean isGZIPMagic(byte[] magic) {
313        return (magic[0] == (byte)0x1F &&
314                magic[1] == (byte)0x8B &&
315                magic[2] == (byte)0x08);
316        // fourth byte is variable "flg" field
317    }
318
319    private Utils() { } // do not instantiate
320}
321