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 
  26 package com.sun.java.util.jar.pack;
  27 
  28 import java.io.BufferedInputStream;
  29 import java.io.BufferedOutputStream;
  30 import java.io.File;
  31 import java.io.FilterOutputStream;
  32 import java.io.IOException;
  33 import java.io.InputStream;
  34 import java.io.OutputStream;
  35 import java.util.Collections;
  36 import java.util.Date;
  37 import java.util.jar.JarEntry;
  38 import java.util.jar.JarFile;
  39 import java.util.jar.JarInputStream;
  40 import java.util.jar.JarOutputStream;
  41 import java.util.zip.ZipEntry;
  42 import sun.util.logging.PlatformLogger;
  43 
  44 class 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     static private
 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 }