1 /* 2 * Copyright (c) 2003, 2011, 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 com.sun.java.util.jar.pack.ConstantPool.ClassEntry; 29 import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry; 30 import com.sun.java.util.jar.pack.ConstantPool.LiteralEntry; 31 import com.sun.java.util.jar.pack.ConstantPool.MemberEntry; 32 import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry; 33 import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry; 34 import java.io.BufferedInputStream; 35 import java.io.BufferedOutputStream; 36 import java.io.File; 37 import java.io.FilterOutputStream; 38 import java.io.IOException; 39 import java.io.InputStream; 40 import java.io.OutputStream; 41 import java.util.Date; 42 import java.util.Enumeration; 43 import java.util.Map; 44 import java.util.jar.JarEntry; 45 import java.util.jar.JarFile; 46 import java.util.jar.JarInputStream; 47 import java.util.jar.JarOutputStream; 48 import java.util.zip.ZipEntry; 49 import sun.util.logging.PlatformLogger; 50 51 class Utils { 52 static final String COM_PREFIX = "com.sun.java.util.jar.pack."; 53 static final String METAINF = "META-INF"; 54 55 /* 56 * Outputs various diagnostic support information. 57 * If >0, print summary comments (e.g., constant pool info). 58 * If >1, print unit comments (e.g., processing of classes). 59 * If >2, print many comments (e.g., processing of members). 60 * If >3, print tons of comments (e.g., processing of references). 61 * (installer only) 62 */ 63 static final String DEBUG_VERBOSE = Utils.COM_PREFIX+"verbose"; 64 65 /* 66 * Disables use of native code, prefers the Java-coded implementation. 67 * (installer only) 68 */ 69 static final String DEBUG_DISABLE_NATIVE = COM_PREFIX+"disable.native"; 70 71 /* 72 * Use the default working TimeZone instead of UTC. 73 * Note: This has installer unpacker implications. 74 * see: zip.cpp which uses gmtime vs. localtime. 75 */ 76 static final String PACK_DEFAULT_TIMEZONE = COM_PREFIX+"default.timezone"; 77 78 /* 79 * Property indicating that the unpacker should 80 * ignore the transmitted PACK_MODIFICATION_TIME, 81 * replacing it by the given value. The value can 82 * be a numeric string, representing the number of 83 * mSecs since the epoch (UTC), or the special string 84 * {@link #NOW}, meaning the current time (UTC). 85 * The default value is the special string {@link #KEEP}, 86 * which asks the unpacker to preserve all transmitted 87 * modification time information. 88 * (installer only) 89 */ 90 static final String UNPACK_MODIFICATION_TIME = COM_PREFIX+"unpack.modification.time"; 91 92 /* 93 * Property indicating that the unpacker strip the 94 * Debug Attributes, if they are present, in the pack stream. 95 * The default value is false. 96 * (installer only) 97 */ 98 static final String UNPACK_STRIP_DEBUG = COM_PREFIX+"unpack.strip.debug"; 99 100 /* 101 * Remove the input file after unpacking. 102 * (installer only) 103 */ 104 static final String UNPACK_REMOVE_PACKFILE = COM_PREFIX+"unpack.remove.packfile"; 105 106 /* 107 * A possible value for MODIFICATION_TIME 108 */ 109 static final String NOW = "now"; 110 // Other debug options: 111 // com...debug.bands=false add band IDs to pack file, to verify sync 112 // com...dump.bands=false dump band contents to local disk 113 // com...no.vary.codings=false turn off coding variation heuristics 114 // com...no.big.strings=false turn off "big string" feature 115 116 /* 117 * If this property is set to {@link #TRUE}, the packer will preserve 118 * the ordering of class files of the original jar in the output archive. 119 * The ordering is preserved only for class-files; resource files 120 * may be reordered. 121 * <p> 122 * If the packer is allowed to reorder class files, it can marginally 123 * decrease the transmitted size of the archive. 124 */ 125 static final String PACK_KEEP_CLASS_ORDER = COM_PREFIX+"keep.class.order"; 126 /* 127 * This string PACK200 is given as a zip comment on all JAR files 128 * produced by this utility. 129 */ 130 static final String PACK_ZIP_ARCHIVE_MARKER_COMMENT = "PACK200"; 131 132 // Keep a TLS point to the global data and environment. 133 // This makes it simpler to supply environmental options 134 // to the engine code, especially the native code. 135 static final ThreadLocal<TLGlobals> currentInstance = new ThreadLocal<>(); 136 137 // convenience methods to access the TL globals 138 static TLGlobals getTLGlobals() { 139 return currentInstance.get(); 140 } 141 142 static Map<String, Utf8Entry> getUtf8Entries() { 143 return getTLGlobals().getUtf8Entries(); 144 } 145 146 static Map<String, ClassEntry> getClassEntries() { 147 return getTLGlobals().getClassEntries(); 148 } 149 150 static Map<Object, LiteralEntry> getLiteralEntries() { 151 return getTLGlobals().getLiteralEntries(); 152 } 153 154 static Map<String, DescriptorEntry> getDescriptorEntries() { 155 return getTLGlobals().getDescriptorEntries(); 156 } 157 158 static Map<String, SignatureEntry> getSignatureEntries() { 159 return getTLGlobals().getSignatureEntries(); 160 } 161 162 static Map<String, MemberEntry> getMemberEntries() { 163 return getTLGlobals().getMemberEntries(); 164 } 165 166 static PropMap currentPropMap() { 167 Object obj = currentInstance.get(); 168 if (obj instanceof PackerImpl) 169 return ((PackerImpl)obj).props; 170 if (obj instanceof UnpackerImpl) 171 return ((UnpackerImpl)obj).props; 172 return null; 173 } 174 175 static final boolean nolog 176 = Boolean.getBoolean(Utils.COM_PREFIX+"nolog"); 177 178 179 static class Pack200Logger { 180 private final String name; 181 private PlatformLogger log; 182 Pack200Logger(String name) { 183 this.name = name; 184 } 185 186 private synchronized PlatformLogger getLogger() { 187 if (log == null) { 188 log = PlatformLogger.getLogger(name); 189 } 190 return log; 191 } 192 193 public void warning(String msg, Object param) { 194 getLogger().warning(msg, param); 195 } 196 197 public void warning(String msg) { 198 warning(msg, null); 199 } 200 201 public void info(String msg) { 202 int verbose = currentPropMap().getInteger(DEBUG_VERBOSE); 203 if (verbose > 0) { 204 if (nolog) { 205 System.out.println(msg); 206 } else { 207 getLogger().info(msg); 208 } 209 } 210 } 211 212 public void fine(String msg) { 213 int verbose = currentPropMap().getInteger(DEBUG_VERBOSE); 214 if (verbose > 0) { 215 System.out.println(msg); 216 } 217 } 218 } 219 220 static final Pack200Logger log 221 = new Pack200Logger("java.util.jar.Pack200"); 222 223 // Returns the Max Version String of this implementation 224 static String getVersionString() { 225 return "Pack200, Vendor: " + 226 System.getProperty("java.vendor") + 227 ", Version: " + 228 Constants.JAVA6_PACKAGE_MAJOR_VERSION + "." + 229 Constants.JAVA6_PACKAGE_MINOR_VERSION; 230 } 231 232 static void markJarFile(JarOutputStream out) throws IOException { 233 out.setComment(PACK_ZIP_ARCHIVE_MARKER_COMMENT); 234 } 235 236 // -0 mode helper 237 static void copyJarFile(JarInputStream in, JarOutputStream out) throws IOException { 238 if (in.getManifest() != null) { 239 ZipEntry me = new ZipEntry(JarFile.MANIFEST_NAME); 240 out.putNextEntry(me); 241 in.getManifest().write(out); 242 out.closeEntry(); 243 } 244 byte[] buffer = new byte[1 << 14]; 245 for (JarEntry je; (je = in.getNextJarEntry()) != null; ) { 246 out.putNextEntry(je); 247 for (int nr; 0 < (nr = in.read(buffer)); ) { 248 out.write(buffer, 0, nr); 249 } 250 } 251 in.close(); 252 markJarFile(out); // add PACK200 comment 253 } 254 static void copyJarFile(JarFile in, JarOutputStream out) throws IOException { 255 byte[] buffer = new byte[1 << 14]; 256 for (Enumeration e = in.entries(); e.hasMoreElements(); ) { 257 JarEntry je = (JarEntry) e.nextElement(); 258 out.putNextEntry(je); 259 InputStream ein = in.getInputStream(je); 260 for (int nr; 0 < (nr = ein.read(buffer)); ) { 261 out.write(buffer, 0, nr); 262 } 263 } 264 in.close(); 265 markJarFile(out); // add PACK200 comment 266 } 267 static void copyJarFile(JarInputStream in, OutputStream out) throws IOException { 268 // 4947205 : Peformance is slow when using pack-effort=0 269 out = new BufferedOutputStream(out); 270 out = new NonCloser(out); // protect from JarOutputStream.close() 271 try (JarOutputStream jout = new JarOutputStream(out)) { 272 copyJarFile(in, jout); 273 } 274 } 275 static void copyJarFile(JarFile in, OutputStream out) throws IOException { 276 277 // 4947205 : Peformance is slow when using pack-effort=0 278 out = new BufferedOutputStream(out); 279 out = new NonCloser(out); // protect from JarOutputStream.close() 280 try (JarOutputStream jout = new JarOutputStream(out)) { 281 copyJarFile(in, jout); 282 } 283 } 284 // Wrapper to prevent closing of client-supplied stream. 285 static private 286 class NonCloser extends FilterOutputStream { 287 NonCloser(OutputStream out) { super(out); } 288 public void close() throws IOException { flush(); } 289 } 290 static String getJarEntryName(String name) { 291 if (name == null) return null; 292 return name.replace(File.separatorChar, '/'); 293 } 294 295 static String zeString(ZipEntry ze) { 296 int store = (ze.getCompressedSize() > 0) ? 297 (int)( (1.0 - ((double)ze.getCompressedSize()/(double)ze.getSize()))*100 ) 298 : 0 ; 299 // Follow unzip -lv output 300 return ze.getSize() + "\t" + ze.getMethod() 301 + "\t" + ze.getCompressedSize() + "\t" 302 + store + "%\t" 303 + new Date(ze.getTime()) + "\t" 304 + Long.toHexString(ze.getCrc()) + "\t" 305 + ze.getName() ; 306 } 307 308 309 310 static byte[] readMagic(BufferedInputStream in) throws IOException { 311 in.mark(4); 312 byte[] magic = new byte[4]; 313 for (int i = 0; i < magic.length; i++) { 314 // read 1 byte at a time, so we always get 4 315 if (1 != in.read(magic, i, 1)) 316 break; 317 } 318 in.reset(); 319 return magic; 320 } 321 322 // magic number recognizers 323 static boolean isJarMagic(byte[] magic) { 324 return (magic[0] == (byte)'P' && 325 magic[1] == (byte)'K' && 326 magic[2] >= 1 && 327 magic[2] < 8 && 328 magic[3] == magic[2] + 1); 329 } 330 static boolean isPackMagic(byte[] magic) { 331 return (magic[0] == (byte)0xCA && 332 magic[1] == (byte)0xFE && 333 magic[2] == (byte)0xD0 && 334 magic[3] == (byte)0x0D); 335 } 336 static boolean isGZIPMagic(byte[] magic) { 337 return (magic[0] == (byte)0x1F && 338 magic[1] == (byte)0x8B && 339 magic[2] == (byte)0x08); 340 // fourth byte is variable "flg" field 341 } 342 343 private Utils() { } // do not instantiate 344 }