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