1 /* 2 * Copyright (c) 2003, 2014, 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 package java.util.jar; 26 27 import java.util.SortedMap; 28 import java.io.InputStream; 29 import java.io.OutputStream; 30 import java.io.File; 31 import java.io.IOException; 32 import sun.security.action.GetPropertyAction; 33 34 35 /** 36 * Transforms a JAR file to or from a packed stream in Pack200 format. 37 * Please refer to Network Transfer Format JSR 200 Specification at 38 * <a href=http://jcp.org/aboutJava/communityprocess/review/jsr200/index.html>http://jcp.org/aboutJava/communityprocess/review/jsr200/index.html</a> 39 * <p> 40 * Typically the packer engine is used by application developers 41 * to deploy or host JAR files on a website. 42 * The unpacker engine is used by deployment applications to 43 * transform the byte-stream back to JAR format. 44 * <p> 45 * Here is an example using packer and unpacker: 46 * <pre>{@code 47 * import java.util.jar.Pack200; 48 * import java.util.jar.Pack200.*; 49 * ... 50 * // Create the Packer object 51 * Packer packer = Pack200.newPacker(); 52 * 53 * // Initialize the state by setting the desired properties 54 * Map p = packer.properties(); 55 * // take more time choosing codings for better compression 56 * p.put(Packer.EFFORT, "7"); // default is "5" 57 * // use largest-possible archive segments (>10% better compression). 58 * p.put(Packer.SEGMENT_LIMIT, "-1"); 59 * // reorder files for better compression. 60 * p.put(Packer.KEEP_FILE_ORDER, Packer.FALSE); 61 * // smear modification times to a single value. 62 * p.put(Packer.MODIFICATION_TIME, Packer.LATEST); 63 * // ignore all JAR deflation requests, 64 * // transmitting a single request to use "store" mode. 65 * p.put(Packer.DEFLATE_HINT, Packer.FALSE); 66 * // discard debug attributes 67 * p.put(Packer.CODE_ATTRIBUTE_PFX+"LineNumberTable", Packer.STRIP); 68 * // throw an error if an attribute is unrecognized 69 * p.put(Packer.UNKNOWN_ATTRIBUTE, Packer.ERROR); 70 * // pass one class file uncompressed: 71 * p.put(Packer.PASS_FILE_PFX+0, "mutants/Rogue.class"); 72 * try { 73 * JarFile jarFile = new JarFile("/tmp/testref.jar"); 74 * FileOutputStream fos = new FileOutputStream("/tmp/test.pack"); 75 * // Call the packer 76 * packer.pack(jarFile, fos); 77 * jarFile.close(); 78 * fos.close(); 79 * 80 * File f = new File("/tmp/test.pack"); 81 * FileOutputStream fostream = new FileOutputStream("/tmp/test.jar"); 82 * JarOutputStream jostream = new JarOutputStream(fostream); 83 * Unpacker unpacker = Pack200.newUnpacker(); 84 * // Call the unpacker 85 * unpacker.unpack(f, jostream); 86 * // Must explicitly close the output. 87 * jostream.close(); 88 * } catch (IOException ioe) { 89 * ioe.printStackTrace(); 90 * } 91 * }</pre> 92 * <p> 93 * A Pack200 file compressed with gzip can be hosted on HTTP/1.1 web servers. 94 * The deployment applications can use "Accept-Encoding=pack200-gzip". This 95 * indicates to the server that the client application desires a version of 96 * the file encoded with Pack200 and further compressed with gzip. Please 97 * refer to the Java Deployment Guide for techniques and details. 98 * <p> 99 * Unless otherwise noted, passing a {@code null} argument to a constructor or 100 * method in this class will cause a {@link NullPointerException} to be thrown. 101 * 102 * @author John Rose 103 * @author Kumar Srinivasan 104 * @since 1.5 105 */ 106 public abstract class Pack200 { 107 private Pack200() {} //prevent instantiation 108 109 // Static methods of the Pack200 class. 110 /** 111 * Obtain new instance of a class that implements Packer. 112 * <ul> 113 * <li><p>If the system property {@code java.util.jar.Pack200.Packer} 114 * is defined, then the value is taken to be the fully-qualified name 115 * of a concrete implementation class, which must implement Packer. 116 * This class is loaded and instantiated. If this process fails 117 * then an unspecified error is thrown.</p></li> 118 * 119 * <li><p>If an implementation has not been specified with the system 120 * property, then the system-default implementation class is instantiated, 121 * and the result is returned.</p></li> 122 * </ul> 123 * 124 * <p>Note: The returned object is not guaranteed to operate 125 * correctly if multiple threads use it at the same time. 126 * A multi-threaded application should either allocate multiple 127 * packer engines, or else serialize use of one engine with a lock. 128 * 129 * @return A newly allocated Packer engine. 130 */ 131 public static synchronized Packer newPacker() { 132 return (Packer) newInstance(PACK_PROVIDER); 133 } 134 135 136 /** 137 * Obtain new instance of a class that implements Unpacker. 138 * <ul> 139 * <li><p>If the system property {@code java.util.jar.Pack200.Unpacker} 140 * is defined, then the value is taken to be the fully-qualified 141 * name of a concrete implementation class, which must implement Unpacker. 142 * The class is loaded and instantiated. If this process fails 143 * then an unspecified error is thrown.</p></li> 144 * 145 * <li><p>If an implementation has not been specified with the 146 * system property, then the system-default implementation class 147 * is instantiated, and the result is returned.</p></li> 148 * </ul> 149 * 150 * <p>Note: The returned object is not guaranteed to operate 151 * correctly if multiple threads use it at the same time. 152 * A multi-threaded application should either allocate multiple 153 * unpacker engines, or else serialize use of one engine with a lock. 154 * 155 * @return A newly allocated Unpacker engine. 156 */ 157 158 public static Unpacker newUnpacker() { 159 return (Unpacker) newInstance(UNPACK_PROVIDER); 160 } 161 162 // Interfaces 163 /** 164 * The packer engine applies various transformations to the input JAR file, 165 * making the pack stream highly compressible by a compressor such as 166 * gzip or zip. An instance of the engine can be obtained 167 * using {@link #newPacker}. 168 169 * The high degree of compression is achieved 170 * by using a number of techniques described in the JSR 200 specification. 171 * Some of the techniques are sorting, re-ordering and co-location of the 172 * constant pool. 173 * <p> 174 * The pack engine is initialized to an initial state as described 175 * by their properties below. 176 * The initial state can be manipulated by getting the 177 * engine properties (using {@link #properties}) and storing 178 * the modified properties on the map. 179 * The resource files will be passed through with no changes at all. 180 * The class files will not contain identical bytes, since the unpacker 181 * is free to change minor class file features such as constant pool order. 182 * However, the class files will be semantically identical, 183 * as specified in 184 * <cite>The Java™ Virtual Machine Specification</cite>. 185 * <p> 186 * By default, the packer does not change the order of JAR elements. 187 * Also, the modification time and deflation hint of each 188 * JAR element is passed unchanged. 189 * (Any other ZIP-archive information, such as extra attributes 190 * giving Unix file permissions, are lost.) 191 * <p> 192 * Note that packing and unpacking a JAR will in general alter the 193 * bytewise contents of classfiles in the JAR. This means that packing 194 * and unpacking will in general invalidate any digital signatures 195 * which rely on bytewise images of JAR elements. In order both to sign 196 * and to pack a JAR, you must first pack and unpack the JAR to 197 * "normalize" it, then compute signatures on the unpacked JAR elements, 198 * and finally repack the signed JAR. 199 * Both packing steps should 200 * use precisely the same options, and the segment limit may also 201 * need to be set to "-1", to prevent accidental variation of segment 202 * boundaries as class file sizes change slightly. 203 * <p> 204 * (Here's why this works: Any reordering the packer does 205 * of any classfile structures is idempotent, so the second packing 206 * does not change the orderings produced by the first packing. 207 * Also, the unpacker is guaranteed by the JSR 200 specification 208 * to produce a specific bytewise image for any given transmission 209 * ordering of archive elements.) 210 * <p> 211 * In order to maintain backward compatibility, the pack file's version is 212 * set to accommodate the class files present in the input JAR file. In 213 * other words, the pack file version will be the latest, if the class files 214 * are the latest and conversely the pack file version will be the oldest 215 * if the class file versions are also the oldest. For intermediate class 216 * file versions the corresponding pack file version will be used. 217 * For example: 218 * If the input JAR-files are solely comprised of 1.5 (or lesser) 219 * class files, a 1.5 compatible pack file is produced. This will also be 220 * the case for archives that have no class files. 221 * If the input JAR-files contains a 1.6 class file, then the pack file 222 * version will be set to 1.6. 223 * <p> 224 * Note: Unless otherwise noted, passing a {@code null} argument to a 225 * constructor or method in this class will cause a {@link NullPointerException} 226 * to be thrown. 227 * 228 * @since 1.5 229 */ 230 public interface Packer { 231 /** 232 * This property is a numeral giving the estimated target size N 233 * (in bytes) of each archive segment. 234 * If a single input file requires more than N bytes, 235 * it will be given its own archive segment. 236 * <p> 237 * As a special case, a value of -1 will produce a single large 238 * segment with all input files, while a value of 0 will 239 * produce one segment for each class. 240 * Larger archive segments result in less fragmentation and 241 * better compression, but processing them requires more memory. 242 * <p> 243 * The size of each segment is estimated by counting the size of each 244 * input file to be transmitted in the segment, along with the size 245 * of its name and other transmitted properties. 246 * <p> 247 * The default is -1, which means the packer will always create a single 248 * segment output file. In cases where extremely large output files are 249 * generated, users are strongly encouraged to use segmenting or break 250 * up the input file into smaller JARs. 251 * <p> 252 * A 10Mb JAR packed without this limit will 253 * typically pack about 10% smaller, but the packer may require 254 * a larger Java heap (about ten times the segment limit). 255 */ 256 String SEGMENT_LIMIT = "pack.segment.limit"; 257 258 /** 259 * If this property is set to {@link #TRUE}, the packer will transmit 260 * all elements in their original order within the source archive. 261 * <p> 262 * If it is set to {@link #FALSE}, the packer may reorder elements, 263 * and also remove JAR directory entries, which carry no useful 264 * information for Java applications. 265 * (Typically this enables better compression.) 266 * <p> 267 * The default is {@link #TRUE}, which preserves the input information, 268 * but may cause the transmitted archive to be larger than necessary. 269 */ 270 String KEEP_FILE_ORDER = "pack.keep.file.order"; 271 272 273 /** 274 * If this property is set to a single decimal digit, the packer will 275 * use the indicated amount of effort in compressing the archive. 276 * Level 1 may produce somewhat larger size and faster compression speed, 277 * while level 9 will take much longer but may produce better compression. 278 * <p> 279 * The special value 0 instructs the packer to copy through the 280 * original JAR file directly, with no compression. The JSR 200 281 * standard requires any unpacker to understand this special case 282 * as a pass-through of the entire archive. 283 * <p> 284 * The default is 5, investing a modest amount of time to 285 * produce reasonable compression. 286 */ 287 String EFFORT = "pack.effort"; 288 289 /** 290 * If this property is set to {@link #TRUE} or {@link #FALSE}, the packer 291 * will set the deflation hint accordingly in the output archive, and 292 * will not transmit the individual deflation hints of archive elements. 293 * <p> 294 * If this property is set to the special string {@link #KEEP}, the packer 295 * will attempt to determine an independent deflation hint for each 296 * available element of the input archive, and transmit this hint separately. 297 * <p> 298 * The default is {@link #KEEP}, which preserves the input information, 299 * but may cause the transmitted archive to be larger than necessary. 300 * <p> 301 * It is up to the unpacker implementation 302 * to take action upon the hint to suitably compress the elements of 303 * the resulting unpacked jar. 304 * <p> 305 * The deflation hint of a ZIP or JAR element indicates 306 * whether the element was deflated or stored directly. 307 */ 308 String DEFLATE_HINT = "pack.deflate.hint"; 309 310 /** 311 * If this property is set to the special string {@link #LATEST}, 312 * the packer will attempt to determine the latest modification time, 313 * among all the available entries in the original archive or the latest 314 * modification time of all the available entries in each segment. 315 * This single value will be transmitted as part of the segment and applied 316 * to all the entries in each segment, {@link #SEGMENT_LIMIT}. 317 * <p> 318 * This can marginally decrease the transmitted size of the 319 * archive, at the expense of setting all installed files to a single 320 * date. 321 * <p> 322 * If this property is set to the special string {@link #KEEP}, 323 * the packer transmits a separate modification time for each input 324 * element. 325 * <p> 326 * The default is {@link #KEEP}, which preserves the input information, 327 * but may cause the transmitted archive to be larger than necessary. 328 * <p> 329 * It is up to the unpacker implementation to take action to suitably 330 * set the modification time of each element of its output file. 331 * @see #SEGMENT_LIMIT 332 */ 333 String MODIFICATION_TIME = "pack.modification.time"; 334 335 /** 336 * Indicates that a file should be passed through bytewise, with no 337 * compression. Multiple files may be specified by specifying 338 * additional properties with distinct strings appended, to 339 * make a family of properties with the common prefix. 340 * <p> 341 * There is no pathname transformation, except 342 * that the system file separator is replaced by the JAR file 343 * separator '/'. 344 * <p> 345 * The resulting file names must match exactly as strings with their 346 * occurrences in the JAR file. 347 * <p> 348 * If a property value is a directory name, all files under that 349 * directory will be passed also. 350 * <p> 351 * Examples: 352 * <pre>{@code 353 * Map p = packer.properties(); 354 * p.put(PASS_FILE_PFX+0, "mutants/Rogue.class"); 355 * p.put(PASS_FILE_PFX+1, "mutants/Wolverine.class"); 356 * p.put(PASS_FILE_PFX+2, "mutants/Storm.class"); 357 * # Pass all files in an entire directory hierarchy: 358 * p.put(PASS_FILE_PFX+3, "police/"); 359 * }</pre> 360 */ 361 String PASS_FILE_PFX = "pack.pass.file."; 362 363 /// Attribute control. 364 365 /** 366 * Indicates the action to take when a class-file containing an unknown 367 * attribute is encountered. Possible values are the strings {@link #ERROR}, 368 * {@link #STRIP}, and {@link #PASS}. 369 * <p> 370 * The string {@link #ERROR} means that the pack operation 371 * as a whole will fail, with an exception of type {@code IOException}. 372 * The string 373 * {@link #STRIP} means that the attribute will be dropped. 374 * The string 375 * {@link #PASS} means that the whole class-file will be passed through 376 * (as if it were a resource file) without compression, with a suitable warning. 377 * This is the default value for this property. 378 * <p> 379 * Examples: 380 * <pre>{@code 381 * Map p = pack200.getProperties(); 382 * p.put(UNKNOWN_ATTRIBUTE, ERROR); 383 * p.put(UNKNOWN_ATTRIBUTE, STRIP); 384 * p.put(UNKNOWN_ATTRIBUTE, PASS); 385 * }</pre> 386 */ 387 String UNKNOWN_ATTRIBUTE = "pack.unknown.attribute"; 388 389 /** 390 * When concatenated with a class attribute name, 391 * indicates the format of that attribute, 392 * using the layout language specified in the JSR 200 specification. 393 * <p> 394 * For example, the effect of this option is built in: 395 * {@code pack.class.attribute.SourceFile=RUH}. 396 * <p> 397 * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS} are 398 * also allowed, with the same meaning as {@link #UNKNOWN_ATTRIBUTE}. 399 * This provides a way for users to request that specific attributes be 400 * refused, stripped, or passed bitwise (with no class compression). 401 * <p> 402 * Code like this might be used to support attributes for JCOV: 403 * <pre>{@code 404 * Map p = packer.properties(); 405 * p.put(CODE_ATTRIBUTE_PFX+"CoverageTable", "NH[PHHII]"); 406 * p.put(CODE_ATTRIBUTE_PFX+"CharacterRangeTable", "NH[PHPOHIIH]"); 407 * p.put(CLASS_ATTRIBUTE_PFX+"SourceID", "RUH"); 408 * p.put(CLASS_ATTRIBUTE_PFX+"CompilationID", "RUH"); 409 * }</pre> 410 * <p> 411 * Code like this might be used to strip debugging attributes: 412 * <pre>{@code 413 * Map p = packer.properties(); 414 * p.put(CODE_ATTRIBUTE_PFX+"LineNumberTable", STRIP); 415 * p.put(CODE_ATTRIBUTE_PFX+"LocalVariableTable", STRIP); 416 * p.put(CLASS_ATTRIBUTE_PFX+"SourceFile", STRIP); 417 * }</pre> 418 */ 419 String CLASS_ATTRIBUTE_PFX = "pack.class.attribute."; 420 421 /** 422 * When concatenated with a field attribute name, 423 * indicates the format of that attribute. 424 * For example, the effect of this option is built in: 425 * {@code pack.field.attribute.Deprecated=}. 426 * The special strings {@link #ERROR}, {@link #STRIP}, and 427 * {@link #PASS} are also allowed. 428 * @see #CLASS_ATTRIBUTE_PFX 429 */ 430 String FIELD_ATTRIBUTE_PFX = "pack.field.attribute."; 431 432 /** 433 * When concatenated with a method attribute name, 434 * indicates the format of that attribute. 435 * For example, the effect of this option is built in: 436 * {@code pack.method.attribute.Exceptions=NH[RCH]}. 437 * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS} 438 * are also allowed. 439 * @see #CLASS_ATTRIBUTE_PFX 440 */ 441 String METHOD_ATTRIBUTE_PFX = "pack.method.attribute."; 442 443 /** 444 * When concatenated with a code attribute name, 445 * indicates the format of that attribute. 446 * For example, the effect of this option is built in: 447 * {@code pack.code.attribute.LocalVariableTable=NH[PHOHRUHRSHH]}. 448 * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS} 449 * are also allowed. 450 * @see #CLASS_ATTRIBUTE_PFX 451 */ 452 String CODE_ATTRIBUTE_PFX = "pack.code.attribute."; 453 454 /** 455 * The unpacker's progress as a percentage, as periodically 456 * updated by the unpacker. 457 * Values of 0 - 100 are normal, and -1 indicates a stall. 458 * Progress can be monitored by polling the value of this 459 * property. 460 * <p> 461 * At a minimum, the unpacker must set progress to 0 462 * at the beginning of a packing operation, and to 100 463 * at the end. 464 */ 465 String PROGRESS = "pack.progress"; 466 467 /** The string "keep", a possible value for certain properties. 468 * @see #DEFLATE_HINT 469 * @see #MODIFICATION_TIME 470 */ 471 String KEEP = "keep"; 472 473 /** The string "pass", a possible value for certain properties. 474 * @see #UNKNOWN_ATTRIBUTE 475 * @see #CLASS_ATTRIBUTE_PFX 476 * @see #FIELD_ATTRIBUTE_PFX 477 * @see #METHOD_ATTRIBUTE_PFX 478 * @see #CODE_ATTRIBUTE_PFX 479 */ 480 String PASS = "pass"; 481 482 /** The string "strip", a possible value for certain properties. 483 * @see #UNKNOWN_ATTRIBUTE 484 * @see #CLASS_ATTRIBUTE_PFX 485 * @see #FIELD_ATTRIBUTE_PFX 486 * @see #METHOD_ATTRIBUTE_PFX 487 * @see #CODE_ATTRIBUTE_PFX 488 */ 489 String STRIP = "strip"; 490 491 /** The string "error", a possible value for certain properties. 492 * @see #UNKNOWN_ATTRIBUTE 493 * @see #CLASS_ATTRIBUTE_PFX 494 * @see #FIELD_ATTRIBUTE_PFX 495 * @see #METHOD_ATTRIBUTE_PFX 496 * @see #CODE_ATTRIBUTE_PFX 497 */ 498 String ERROR = "error"; 499 500 /** The string "true", a possible value for certain properties. 501 * @see #KEEP_FILE_ORDER 502 * @see #DEFLATE_HINT 503 */ 504 String TRUE = "true"; 505 506 /** The string "false", a possible value for certain properties. 507 * @see #KEEP_FILE_ORDER 508 * @see #DEFLATE_HINT 509 */ 510 String FALSE = "false"; 511 512 /** The string "latest", a possible value for certain properties. 513 * @see #MODIFICATION_TIME 514 */ 515 String LATEST = "latest"; 516 517 /** 518 * Get the set of this engine's properties. 519 * This set is a "live view", so that changing its 520 * contents immediately affects the Packer engine, and 521 * changes from the engine (such as progress indications) 522 * are immediately visible in the map. 523 * 524 * <p>The property map may contain pre-defined implementation 525 * specific and default properties. Users are encouraged to 526 * read the information and fully understand the implications, 527 * before modifying pre-existing properties. 528 * <p> 529 * Implementation specific properties are prefixed with a 530 * package name associated with the implementor, beginning 531 * with {@code com.} or a similar prefix. 532 * All property names beginning with {@code pack.} and 533 * {@code unpack.} are reserved for use by this API. 534 * <p> 535 * Unknown properties may be ignored or rejected with an 536 * unspecified error, and invalid entries may cause an 537 * unspecified error to be thrown. 538 * 539 * <p> 540 * The returned map implements all optional {@link SortedMap} operations 541 * @return A sorted association of property key strings to property 542 * values. 543 */ 544 SortedMap<String,String> properties(); 545 546 /** 547 * Takes a JarFile and converts it into a Pack200 archive. 548 * <p> 549 * Closes its input but not its output. (Pack200 archives are appendable.) 550 * @param in a JarFile 551 * @param out an OutputStream 552 * @exception IOException if an error is encountered. 553 */ 554 void pack(JarFile in, OutputStream out) throws IOException ; 555 556 /** 557 * Takes a JarInputStream and converts it into a Pack200 archive. 558 * <p> 559 * Closes its input but not its output. (Pack200 archives are appendable.) 560 * <p> 561 * The modification time and deflation hint attributes are not available, 562 * for the JAR manifest file and its containing directory. 563 * 564 * @see #MODIFICATION_TIME 565 * @see #DEFLATE_HINT 566 * @param in a JarInputStream 567 * @param out an OutputStream 568 * @exception IOException if an error is encountered. 569 */ 570 void pack(JarInputStream in, OutputStream out) throws IOException ; 571 } 572 573 /** 574 * The unpacker engine converts the packed stream to a JAR file. 575 * An instance of the engine can be obtained 576 * using {@link #newUnpacker}. 577 * <p> 578 * Every JAR file produced by this engine will include the string 579 * "{@code PACK200}" as a zip file comment. 580 * This allows a deployer to detect if a JAR archive was packed and unpacked. 581 * <p> 582 * Note: Unless otherwise noted, passing a {@code null} argument to a 583 * constructor or method in this class will cause a {@link NullPointerException} 584 * to be thrown. 585 * <p> 586 * This version of the unpacker is compatible with all previous versions. 587 * @since 1.5 588 */ 589 public interface Unpacker { 590 591 /** The string "keep", a possible value for certain properties. 592 * @see #DEFLATE_HINT 593 */ 594 String KEEP = "keep"; 595 596 /** The string "true", a possible value for certain properties. 597 * @see #DEFLATE_HINT 598 */ 599 String TRUE = "true"; 600 601 /** The string "false", a possible value for certain properties. 602 * @see #DEFLATE_HINT 603 */ 604 String FALSE = "false"; 605 606 /** 607 * Property indicating that the unpacker should 608 * ignore all transmitted values for DEFLATE_HINT, 609 * replacing them by the given value, {@link #TRUE} or {@link #FALSE}. 610 * The default value is the special string {@link #KEEP}, 611 * which asks the unpacker to preserve all transmitted 612 * deflation hints. 613 */ 614 String DEFLATE_HINT = "unpack.deflate.hint"; 615 616 617 618 /** 619 * The unpacker's progress as a percentage, as periodically 620 * updated by the unpacker. 621 * Values of 0 - 100 are normal, and -1 indicates a stall. 622 * Progress can be monitored by polling the value of this 623 * property. 624 * <p> 625 * At a minimum, the unpacker must set progress to 0 626 * at the beginning of a packing operation, and to 100 627 * at the end. 628 */ 629 String PROGRESS = "unpack.progress"; 630 631 /** 632 * Get the set of this engine's properties. This set is 633 * a "live view", so that changing its 634 * contents immediately affects the Packer engine, and 635 * changes from the engine (such as progress indications) 636 * are immediately visible in the map. 637 * 638 * <p>The property map may contain pre-defined implementation 639 * specific and default properties. Users are encouraged to 640 * read the information and fully understand the implications, 641 * before modifying pre-existing properties. 642 * <p> 643 * Implementation specific properties are prefixed with a 644 * package name associated with the implementor, beginning 645 * with {@code com.} or a similar prefix. 646 * All property names beginning with {@code pack.} and 647 * {@code unpack.} are reserved for use by this API. 648 * <p> 649 * Unknown properties may be ignored or rejected with an 650 * unspecified error, and invalid entries may cause an 651 * unspecified error to be thrown. 652 * 653 * @return A sorted association of option key strings to option values. 654 */ 655 SortedMap<String,String> properties(); 656 657 /** 658 * Read a Pack200 archive, and write the encoded JAR to 659 * a JarOutputStream. 660 * The entire contents of the input stream will be read. 661 * It may be more efficient to read the Pack200 archive 662 * to a file and pass the File object, using the alternate 663 * method described below. 664 * <p> 665 * Closes its input but not its output. (The output can accumulate more elements.) 666 * @param in an InputStream. 667 * @param out a JarOutputStream. 668 * @exception IOException if an error is encountered. 669 */ 670 void unpack(InputStream in, JarOutputStream out) throws IOException; 671 672 /** 673 * Read a Pack200 archive, and write the encoded JAR to 674 * a JarOutputStream. 675 * <p> 676 * Does not close its output. (The output can accumulate more elements.) 677 * @param in a File. 678 * @param out a JarOutputStream. 679 * @exception IOException if an error is encountered. 680 */ 681 void unpack(File in, JarOutputStream out) throws IOException; 682 } 683 684 // Private stuff.... 685 686 private static final String PACK_PROVIDER = "java.util.jar.Pack200.Packer"; 687 private static final String UNPACK_PROVIDER = "java.util.jar.Pack200.Unpacker"; 688 689 private static Class<?> packerImpl; 690 private static Class<?> unpackerImpl; 691 692 private static synchronized Object newInstance(String prop) { 693 String implName = "(unknown)"; 694 try { 695 Class<?> impl = (PACK_PROVIDER.equals(prop))? packerImpl: unpackerImpl; 696 if (impl == null) { 697 // The first time, we must decide which class to use. 698 implName = GetPropertyAction.getProperty(prop,""); 699 if (implName != null && !implName.equals("")) 700 impl = Class.forName(implName); 701 else if (PACK_PROVIDER.equals(prop)) 702 impl = com.sun.java.util.jar.pack.PackerImpl.class; 703 else 704 impl = com.sun.java.util.jar.pack.UnpackerImpl.class; 705 } 706 // We have a class. Now instantiate it. 707 return impl.newInstance(); 708 } catch (ClassNotFoundException e) { 709 throw new Error("Class not found: " + implName + 710 ":\ncheck property " + prop + 711 " in your properties file.", e); 712 } catch (InstantiationException e) { 713 throw new Error("Could not instantiate: " + implName + 714 ":\ncheck property " + prop + 715 " in your properties file.", e); 716 } catch (IllegalAccessException e) { 717 throw new Error("Cannot access class: " + implName + 718 ":\ncheck property " + prop + 719 " in your properties file.", e); 720 } 721 } 722 723 }