1 /* 2 * Copyright (c) 1997, 2018, 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 java.util.jar; 27 28 import java.io.DataOutputStream; 29 import java.io.IOException; 30 import java.util.Collection; 31 import java.util.HashMap; 32 import java.util.LinkedHashMap; 33 import java.util.Map; 34 import java.util.Objects; 35 import java.util.Set; 36 37 import jdk.internal.misc.VM; 38 import jdk.internal.vm.annotation.Stable; 39 import sun.util.logging.PlatformLogger; 40 41 /** 42 * The Attributes class maps Manifest attribute names to associated string 43 * values. Valid attribute names are case-insensitive, are restricted to 44 * the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed 70 45 * characters in length. There must be a colon and a SPACE after the name; 46 * the combined length will not exceed 72 characters. 47 * Attribute values can contain any characters and 48 * will be UTF8-encoded when written to the output stream. See the 49 * <a href="{@docRoot}/../specs/jar/jar.html">JAR File Specification</a> 50 * for more information about valid attribute names and values. 51 * 52 * <p>This map and its views have a predictable iteration order, namely the 53 * order that keys were inserted into the map, as with {@link LinkedHashMap}. 54 * 55 * @author David Connelly 56 * @see Manifest 57 * @since 1.2 58 */ 59 public class Attributes implements Map<Object,Object>, Cloneable { 60 /** 61 * The attribute name-value mappings. 62 */ 63 protected Map<Object,Object> map; 64 65 /** 66 * Constructs a new, empty Attributes object with default size. 67 */ 68 public Attributes() { 69 this(11); 70 } 71 72 /** 73 * Constructs a new, empty Attributes object with the specified 74 * initial size. 75 * 76 * @param size the initial number of attributes 77 */ 78 public Attributes(int size) { 79 map = new LinkedHashMap<>(size); 80 } 81 82 /** 83 * Constructs a new Attributes object with the same attribute name-value 84 * mappings as in the specified Attributes. 85 * 86 * @param attr the specified Attributes 87 */ 88 public Attributes(Attributes attr) { 89 map = new LinkedHashMap<>(attr); 90 } 91 92 93 /** 94 * Returns the value of the specified attribute name, or null if the 95 * attribute name was not found. 96 * 97 * @param name the attribute name 98 * @return the value of the specified attribute name, or null if 99 * not found. 100 */ 101 public Object get(Object name) { 102 return map.get(name); 103 } 104 105 /** 106 * Returns the value of the specified attribute name, specified as 107 * a string, or null if the attribute was not found. The attribute 108 * name is case-insensitive. 109 * <p> 110 * This method is defined as: 111 * <pre> 112 * return (String)get(new Attributes.Name((String)name)); 113 * </pre> 114 * 115 * @param name the attribute name as a string 116 * @return the String value of the specified attribute name, or null if 117 * not found. 118 * @throws IllegalArgumentException if the attribute name is invalid 119 */ 120 public String getValue(String name) { 121 return (String)get(Name.of(name)); 122 } 123 124 /** 125 * Returns the value of the specified Attributes.Name, or null if the 126 * attribute was not found. 127 * <p> 128 * This method is defined as: 129 * <pre> 130 * return (String)get(name); 131 * </pre> 132 * 133 * @param name the Attributes.Name object 134 * @return the String value of the specified Attribute.Name, or null if 135 * not found. 136 */ 137 public String getValue(Name name) { 138 return (String)get(name); 139 } 140 141 /** 142 * Associates the specified value with the specified attribute name 143 * (key) in this Map. If the Map previously contained a mapping for 144 * the attribute name, the old value is replaced. 145 * 146 * @param name the attribute name 147 * @param value the attribute value 148 * @return the previous value of the attribute, or null if none 149 * @exception ClassCastException if the name is not a Attributes.Name 150 * or the value is not a String 151 */ 152 public Object put(Object name, Object value) { 153 return map.put((Attributes.Name)name, (String)value); 154 } 155 156 /** 157 * Associates the specified value with the specified attribute name, 158 * specified as a String. The attributes name is case-insensitive. 159 * If the Map previously contained a mapping for the attribute name, 160 * the old value is replaced. 161 * <p> 162 * This method is defined as: 163 * <pre> 164 * return (String)put(new Attributes.Name(name), value); 165 * </pre> 166 * 167 * @param name the attribute name as a string 168 * @param value the attribute value 169 * @return the previous value of the attribute, or null if none 170 * @exception IllegalArgumentException if the attribute name is invalid 171 */ 172 public String putValue(String name, String value) { 173 return (String)put(Name.of(name), value); 174 } 175 176 /** 177 * Removes the attribute with the specified name (key) from this Map. 178 * Returns the previous attribute value, or null if none. 179 * 180 * @param name attribute name 181 * @return the previous value of the attribute, or null if none 182 */ 183 public Object remove(Object name) { 184 return map.remove(name); 185 } 186 187 /** 188 * Returns true if this Map maps one or more attribute names (keys) 189 * to the specified value. 190 * 191 * @param value the attribute value 192 * @return true if this Map maps one or more attribute names to 193 * the specified value 194 */ 195 public boolean containsValue(Object value) { 196 return map.containsValue(value); 197 } 198 199 /** 200 * Returns true if this Map contains the specified attribute name (key). 201 * 202 * @param name the attribute name 203 * @return true if this Map contains the specified attribute name 204 */ 205 public boolean containsKey(Object name) { 206 return map.containsKey(name); 207 } 208 209 /** 210 * Copies all of the attribute name-value mappings from the specified 211 * Attributes to this Map. Duplicate mappings will be replaced. 212 * 213 * @param attr the Attributes to be stored in this map 214 * @exception ClassCastException if attr is not an Attributes 215 */ 216 public void putAll(Map<?,?> attr) { 217 // ## javac bug? 218 if (!Attributes.class.isInstance(attr)) 219 throw new ClassCastException(); 220 for (Map.Entry<?,?> me : (attr).entrySet()) 221 put(me.getKey(), me.getValue()); 222 } 223 224 /** 225 * Removes all attributes from this Map. 226 */ 227 public void clear() { 228 map.clear(); 229 } 230 231 /** 232 * Returns the number of attributes in this Map. 233 */ 234 public int size() { 235 return map.size(); 236 } 237 238 /** 239 * Returns true if this Map contains no attributes. 240 */ 241 public boolean isEmpty() { 242 return map.isEmpty(); 243 } 244 245 /** 246 * Returns a Set view of the attribute names (keys) contained in this Map. 247 */ 248 public Set<Object> keySet() { 249 return map.keySet(); 250 } 251 252 /** 253 * Returns a Collection view of the attribute values contained in this Map. 254 */ 255 public Collection<Object> values() { 256 return map.values(); 257 } 258 259 /** 260 * Returns a Collection view of the attribute name-value mappings 261 * contained in this Map. 262 */ 263 public Set<Map.Entry<Object,Object>> entrySet() { 264 return map.entrySet(); 265 } 266 267 /** 268 * Compares the specified Attributes object with this Map for equality. 269 * Returns true if the given object is also an instance of Attributes 270 * and the two Attributes objects represent the same mappings. 271 * 272 * @param o the Object to be compared 273 * @return true if the specified Object is equal to this Map 274 */ 275 public boolean equals(Object o) { 276 return map.equals(o); 277 } 278 279 /** 280 * Returns the hash code value for this Map. 281 */ 282 public int hashCode() { 283 return map.hashCode(); 284 } 285 286 /** 287 * Returns a copy of the Attributes, implemented as follows: 288 * <pre> 289 * public Object clone() { return new Attributes(this); } 290 * </pre> 291 * Since the attribute names and values are themselves immutable, 292 * the Attributes returned can be safely modified without affecting 293 * the original. 294 */ 295 public Object clone() { 296 return new Attributes(this); 297 } 298 299 /* 300 * Writes the current attributes to the specified data output stream. 301 * XXX Need to handle UTF8 values and break up lines longer than 72 bytes 302 */ 303 @SuppressWarnings("deprecation") 304 void write(DataOutputStream os) throws IOException { 305 for (Entry<Object, Object> e : entrySet()) { 306 StringBuffer buffer = new StringBuffer( 307 ((Name) e.getKey()).toString()); 308 buffer.append(": "); 309 310 String value = (String) e.getValue(); 311 if (value != null) { 312 byte[] vb = value.getBytes("UTF8"); 313 value = new String(vb, 0, 0, vb.length); 314 } 315 buffer.append(value); 316 317 Manifest.make72Safe(buffer); 318 buffer.append("\r\n"); 319 os.writeBytes(buffer.toString()); 320 } 321 os.writeBytes("\r\n"); 322 } 323 324 /* 325 * Writes the current attributes to the specified data output stream, 326 * make sure to write out the MANIFEST_VERSION or SIGNATURE_VERSION 327 * attributes first. 328 * 329 * XXX Need to handle UTF8 values and break up lines longer than 72 bytes 330 */ 331 @SuppressWarnings("deprecation") 332 void writeMain(DataOutputStream out) throws IOException 333 { 334 // write out the *-Version header first, if it exists 335 String vername = Name.MANIFEST_VERSION.toString(); 336 String version = getValue(vername); 337 if (version == null) { 338 vername = Name.SIGNATURE_VERSION.toString(); 339 version = getValue(vername); 340 } 341 342 if (version != null) { 343 out.writeBytes(vername+": "+version+"\r\n"); 344 } 345 346 // write out all attributes except for the version 347 // we wrote out earlier 348 for (Entry<Object, Object> e : entrySet()) { 349 String name = ((Name) e.getKey()).toString(); 350 if ((version != null) && !(name.equalsIgnoreCase(vername))) { 351 352 StringBuffer buffer = new StringBuffer(name); 353 buffer.append(": "); 354 355 String value = (String) e.getValue(); 356 if (value != null) { 357 byte[] vb = value.getBytes("UTF8"); 358 value = new String(vb, 0, 0, vb.length); 359 } 360 buffer.append(value); 361 362 Manifest.make72Safe(buffer); 363 buffer.append("\r\n"); 364 out.writeBytes(buffer.toString()); 365 } 366 } 367 out.writeBytes("\r\n"); 368 } 369 370 /* 371 * Reads attributes from the specified input stream. 372 * XXX Need to handle UTF8 values. 373 */ 374 void read(Manifest.FastInputStream is, byte[] lbuf) throws IOException { 375 read(is, lbuf, null, 0); 376 } 377 378 @SuppressWarnings("deprecation") 379 int read(Manifest.FastInputStream is, byte[] lbuf, String filename, int lineNumber) throws IOException { 380 String name = null, value; 381 byte[] lastline = null; 382 383 int len; 384 while ((len = is.readLine(lbuf)) != -1) { 385 boolean lineContinued = false; 386 byte c = lbuf[--len]; 387 lineNumber++; 388 389 if (c != '\n' && c != '\r') { 390 throw new IOException("line too long (" 391 + Manifest.getErrorPosition(filename, lineNumber) + ")"); 392 } 393 if (len > 0 && lbuf[len-1] == '\r') { 394 --len; 395 } 396 if (len == 0) { 397 break; 398 } 399 int i = 0; 400 if (lbuf[0] == ' ') { 401 // continuation of previous line 402 if (name == null) { 403 throw new IOException("misplaced continuation line (" 404 + Manifest.getErrorPosition(filename, lineNumber) + ")"); 405 } 406 lineContinued = true; 407 byte[] buf = new byte[lastline.length + len - 1]; 408 System.arraycopy(lastline, 0, buf, 0, lastline.length); 409 System.arraycopy(lbuf, 1, buf, lastline.length, len - 1); 410 if (is.peek() == ' ') { 411 lastline = buf; 412 continue; 413 } 414 value = new String(buf, 0, buf.length, "UTF8"); 415 lastline = null; 416 } else { 417 while (lbuf[i++] != ':') { 418 if (i >= len) { 419 throw new IOException("invalid header field (" 420 + Manifest.getErrorPosition(filename, lineNumber) + ")"); 421 } 422 } 423 if (lbuf[i++] != ' ') { 424 throw new IOException("invalid header field (" 425 + Manifest.getErrorPosition(filename, lineNumber) + ")"); 426 } 427 name = new String(lbuf, 0, 0, i - 2); 428 if (is.peek() == ' ') { 429 lastline = new byte[len - i]; 430 System.arraycopy(lbuf, i, lastline, 0, len - i); 431 continue; 432 } 433 value = new String(lbuf, i, len - i, "UTF8"); 434 } 435 try { 436 if ((putValue(name, value) != null) && (!lineContinued)) { 437 PlatformLogger.getLogger("java.util.jar").warning( 438 "Duplicate name in Manifest: " + name 439 + ".\n" 440 + "Ensure that the manifest does not " 441 + "have duplicate entries, and\n" 442 + "that blank lines separate " 443 + "individual sections in both your\n" 444 + "manifest and in the META-INF/MANIFEST.MF " 445 + "entry in the jar file."); 446 } 447 } catch (IllegalArgumentException e) { 448 throw new IOException("invalid header field name: " + name 449 + " (" + Manifest.getErrorPosition(filename, lineNumber) + ")"); 450 } 451 } 452 return lineNumber; 453 } 454 455 /** 456 * The Attributes.Name class represents an attribute name stored in 457 * this Map. Valid attribute names are case-insensitive, are restricted 458 * to the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed 459 * 70 characters in length. Attribute values can contain any characters 460 * and will be UTF8-encoded when written to the output stream. See the 461 * <a href="{@docRoot}/../specs/jar/jar.html">JAR File Specification</a> 462 * for more information about valid attribute names and values. 463 */ 464 public static class Name { 465 private final String name; 466 private final int hashCode; 467 468 /** 469 * Avoid allocation for common Names 470 */ 471 private static @Stable Map<String, Name> KNOWN_NAMES; 472 473 static final Name of(String name) { 474 Name n = KNOWN_NAMES.get(name); 475 if (n != null) { 476 return n; 477 } 478 return new Name(name); 479 } 480 481 /** 482 * Constructs a new attribute name using the given string name. 483 * 484 * @param name the attribute string name 485 * @exception IllegalArgumentException if the attribute name was 486 * invalid 487 * @exception NullPointerException if the attribute name was null 488 */ 489 public Name(String name) { 490 this.hashCode = hash(name); 491 this.name = name.intern(); 492 } 493 494 // Checks the string is valid 495 private final int hash(String name) { 496 Objects.requireNonNull(name, "name"); 497 int len = name.length(); 498 if (len > 70 || len == 0) { 499 throw new IllegalArgumentException(name); 500 } 501 // Calculate hash code case insensitively 502 int h = 0; 503 for (int i = 0; i < len; i++) { 504 char c = name.charAt(i); 505 if (c >= 'a' && c <= 'z') { 506 // hashcode must be identical for upper and lower case 507 h = h * 31 + (c - 0x20); 508 } else if ((c >= 'A' && c <= 'Z' || 509 c >= '0' && c <= '9' || 510 c == '_' || c == '-')) { 511 h = h * 31 + c; 512 } else { 513 throw new IllegalArgumentException(name); 514 } 515 } 516 return h; 517 } 518 519 /** 520 * Compares this attribute name to another for equality. 521 * @param o the object to compare 522 * @return true if this attribute name is equal to the 523 * specified attribute object 524 */ 525 public boolean equals(Object o) { 526 if (this == o) { 527 return true; 528 } 529 if (o instanceof Name) { 530 Name other = (Name)o; 531 return other.name.equalsIgnoreCase(name); 532 } else { 533 return false; 534 } 535 } 536 537 /** 538 * Computes the hash value for this attribute name. 539 */ 540 public int hashCode() { 541 return hashCode; 542 } 543 544 /** 545 * Returns the attribute name as a String. 546 */ 547 public String toString() { 548 return name; 549 } 550 551 /** 552 * {@code Name} object for {@code Manifest-Version} 553 * manifest attribute. This attribute indicates the version number 554 * of the manifest standard to which a JAR file's manifest conforms. 555 * @see <a href="{@docRoot}/../specs/jar/jar.html#jar-manifest"> 556 * Manifest and Signature Specification</a> 557 */ 558 public static final Name MANIFEST_VERSION; 559 560 /** 561 * {@code Name} object for {@code Signature-Version} 562 * manifest attribute used when signing JAR files. 563 * @see <a href="{@docRoot}/../specs/jar/jar.html#jar-manifest"> 564 * Manifest and Signature Specification</a> 565 */ 566 public static final Name SIGNATURE_VERSION; 567 568 /** 569 * {@code Name} object for {@code Content-Type} 570 * manifest attribute. 571 */ 572 public static final Name CONTENT_TYPE; 573 574 /** 575 * {@code Name} object for {@code Class-Path} 576 * manifest attribute. 577 * @see <a href="{@docRoot}/../specs/jar/jar.html#class-path-attribute"> 578 * JAR file specification</a> 579 */ 580 public static final Name CLASS_PATH; 581 582 /** 583 * {@code Name} object for {@code Main-Class} manifest 584 * attribute used for launching applications packaged in JAR files. 585 * The {@code Main-Class} attribute is used in conjunction 586 * with the {@code -jar} command-line option of the 587 * {@code java} application launcher. 588 */ 589 public static final Name MAIN_CLASS; 590 591 /** 592 * {@code Name} object for {@code Sealed} manifest attribute 593 * used for sealing. 594 * @see <a href="{@docRoot}/../specs/jar/jar.html#package-sealing"> 595 * Package Sealing</a> 596 */ 597 public static final Name SEALED; 598 599 /** 600 * {@code Name} object for {@code Extension-List} manifest attribute 601 * used for the extension mechanism that is no longer supported. 602 */ 603 public static final Name EXTENSION_LIST; 604 605 /** 606 * {@code Name} object for {@code Extension-Name} manifest attribute. 607 * used for the extension mechanism that is no longer supported. 608 */ 609 public static final Name EXTENSION_NAME; 610 611 /** 612 * {@code Name} object for {@code Extension-Installation} manifest attribute. 613 * 614 * @deprecated Extension mechanism is no longer supported. 615 */ 616 @Deprecated 617 public static final Name EXTENSION_INSTALLATION; 618 619 /** 620 * {@code Name} object for {@code Implementation-Title} 621 * manifest attribute used for package versioning. 622 */ 623 public static final Name IMPLEMENTATION_TITLE; 624 625 /** 626 * {@code Name} object for {@code Implementation-Version} 627 * manifest attribute used for package versioning. 628 */ 629 public static final Name IMPLEMENTATION_VERSION; 630 631 /** 632 * {@code Name} object for {@code Implementation-Vendor} 633 * manifest attribute used for package versioning. 634 */ 635 public static final Name IMPLEMENTATION_VENDOR; 636 637 /** 638 * {@code Name} object for {@code Implementation-Vendor-Id} 639 * manifest attribute. 640 * 641 * @deprecated Extension mechanism is no longer supported. 642 */ 643 @Deprecated 644 public static final Name IMPLEMENTATION_VENDOR_ID; 645 646 /** 647 * {@code Name} object for {@code Implementation-URL} 648 * manifest attribute. 649 * 650 * @deprecated Extension mechanism is no longer supported. 651 */ 652 @Deprecated 653 public static final Name IMPLEMENTATION_URL; 654 655 /** 656 * {@code Name} object for {@code Specification-Title} 657 * manifest attribute used for package versioning. 658 */ 659 public static final Name SPECIFICATION_TITLE; 660 661 /** 662 * {@code Name} object for {@code Specification-Version} 663 * manifest attribute used for package versioning. 664 */ 665 public static final Name SPECIFICATION_VERSION; 666 667 /** 668 * {@code Name} object for {@code Specification-Vendor} 669 * manifest attribute used for package versioning. 670 */ 671 public static final Name SPECIFICATION_VENDOR; 672 673 /** 674 * {@code Name} object for {@code Multi-Release} 675 * manifest attribute that indicates this is a multi-release JAR file. 676 * 677 * @since 9 678 */ 679 public static final Name MULTI_RELEASE; 680 681 private static void addName(Map<String, Name> names, Name name) { 682 names.put(name.name, name); 683 } 684 685 static { 686 687 VM.initializeFromArchive(Attributes.Name.class); 688 689 if (KNOWN_NAMES == null) { 690 MANIFEST_VERSION = new Name("Manifest-Version"); 691 SIGNATURE_VERSION = new Name("Signature-Version"); 692 CONTENT_TYPE = new Name("Content-Type"); 693 CLASS_PATH = new Name("Class-Path"); 694 MAIN_CLASS = new Name("Main-Class"); 695 SEALED = new Name("Sealed"); 696 EXTENSION_LIST = new Name("Extension-List"); 697 EXTENSION_NAME = new Name("Extension-Name"); 698 EXTENSION_INSTALLATION = new Name("Extension-Installation"); 699 IMPLEMENTATION_TITLE = new Name("Implementation-Title"); 700 IMPLEMENTATION_VERSION = new Name("Implementation-Version"); 701 IMPLEMENTATION_VENDOR = new Name("Implementation-Vendor"); 702 IMPLEMENTATION_VENDOR_ID = new Name("Implementation-Vendor-Id"); 703 IMPLEMENTATION_URL = new Name("Implementation-URL"); 704 SPECIFICATION_TITLE = new Name("Specification-Title"); 705 SPECIFICATION_VERSION = new Name("Specification-Version"); 706 SPECIFICATION_VENDOR = new Name("Specification-Vendor"); 707 MULTI_RELEASE = new Name("Multi-Release"); 708 709 var names = new HashMap<String, Name>(64); 710 addName(names, MANIFEST_VERSION); 711 addName(names, SIGNATURE_VERSION); 712 addName(names, CONTENT_TYPE); 713 addName(names, CLASS_PATH); 714 addName(names, MAIN_CLASS); 715 addName(names, SEALED); 716 addName(names, EXTENSION_LIST); 717 addName(names, EXTENSION_NAME); 718 addName(names, IMPLEMENTATION_TITLE); 719 addName(names, IMPLEMENTATION_VERSION); 720 addName(names, IMPLEMENTATION_VENDOR); 721 addName(names, SPECIFICATION_TITLE); 722 addName(names, SPECIFICATION_VERSION); 723 addName(names, SPECIFICATION_VENDOR); 724 addName(names, MULTI_RELEASE); 725 726 // Common attributes used in MANIFEST.MF et.al; adding these has a 727 // small footprint cost, but is likely to be quickly paid for by 728 // reducing allocation when reading and parsing typical manifests 729 addName(names, new Name("Add-Exports")); 730 addName(names, new Name("Add-Opens")); 731 addName(names, new Name("Ant-Version")); 732 addName(names, new Name("Archiver-Version")); 733 addName(names, new Name("Build-Jdk")); 734 addName(names, new Name("Built-By")); 735 addName(names, new Name("Bnd-LastModified")); 736 addName(names, new Name("Bundle-Description")); 737 addName(names, new Name("Bundle-DocURL")); 738 addName(names, new Name("Bundle-License")); 739 addName(names, new Name("Bundle-ManifestVersion")); 740 addName(names, new Name("Bundle-Name")); 741 addName(names, new Name("Bundle-Vendor")); 742 addName(names, new Name("Bundle-Version")); 743 addName(names, new Name("Bundle-SymbolicName")); 744 addName(names, new Name("Created-By")); 745 addName(names, new Name("Export-Package")); 746 addName(names, new Name("Import-Package")); 747 addName(names, new Name("Name")); 748 addName(names, new Name("SHA1-Digest")); 749 addName(names, new Name("X-Compile-Source-JDK")); 750 addName(names, new Name("X-Compile-Target-JDK")); 751 KNOWN_NAMES = Map.copyOf(names); 752 } else { 753 // Even if KNOWN_NAMES was read from archive, we still need 754 // to initialize the public constants 755 MANIFEST_VERSION = KNOWN_NAMES.get("Manifest-Version"); 756 SIGNATURE_VERSION = KNOWN_NAMES.get("Signature-Version"); 757 CONTENT_TYPE = KNOWN_NAMES.get("Content-Type"); 758 CLASS_PATH = KNOWN_NAMES.get("Class-Path"); 759 MAIN_CLASS = KNOWN_NAMES.get("Main-Class"); 760 SEALED = KNOWN_NAMES.get("Sealed"); 761 EXTENSION_LIST = KNOWN_NAMES.get("Extension-List"); 762 EXTENSION_NAME = KNOWN_NAMES.get("Extension-Name"); 763 EXTENSION_INSTALLATION = KNOWN_NAMES.get("Extension-Installation"); 764 IMPLEMENTATION_TITLE = KNOWN_NAMES.get("Implementation-Title"); 765 IMPLEMENTATION_VERSION = KNOWN_NAMES.get("Implementation-Version"); 766 IMPLEMENTATION_VENDOR = KNOWN_NAMES.get("Implementation-Vendor"); 767 IMPLEMENTATION_VENDOR_ID = KNOWN_NAMES.get("Implementation-Vendor-Id"); 768 IMPLEMENTATION_URL = KNOWN_NAMES.get("Implementation-URL"); 769 SPECIFICATION_TITLE = KNOWN_NAMES.get("Specification-Title"); 770 SPECIFICATION_VERSION = KNOWN_NAMES.get("Specification-Version"); 771 SPECIFICATION_VENDOR = KNOWN_NAMES.get("Specification-Vendor"); 772 MULTI_RELEASE = KNOWN_NAMES.get("Multi-Release"); 773 } 774 } 775 } 776 }