| /* | |
| * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package java.util.jar; | |
| import java.io.ByteArrayOutputStream; | |
| import java.io.DataOutputStream; | |
| import java.io.IOException; | |
| import java.util.Collection; | |
| import java.util.HashMap; | |
| import java.util.LinkedHashMap; | |
| import java.util.Map; | |
| import java.util.Objects; | |
| import java.util.Set; | |
| import jdk.internal.misc.CDS; | |
| import jdk.internal.vm.annotation.Stable; | |
| import sun.nio.cs.UTF_8; | |
| import sun.util.logging.PlatformLogger; | |
| /** | |
| * The Attributes class maps Manifest attribute names to associated string | |
| * values. Valid attribute names are case-insensitive, are restricted to | |
| * the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed 70 | |
| * characters in length. There must be a colon and a SPACE after the name; | |
| * the combined length will not exceed 72 characters. | |
| * Attribute values can contain any characters and | |
| * will be UTF8-encoded when written to the output stream. See the | |
| * <a href="{@docRoot}/../specs/jar/jar.html">JAR File Specification</a> | |
| * for more information about valid attribute names and values. | |
| * | |
| * <p>This map and its views have a predictable iteration order, namely the | |
| * order that keys were inserted into the map, as with {@link LinkedHashMap}. | |
| * | |
| * @spec jar/jar.html JAR File Specification | |
| * @author David Connelly | |
| * @see Manifest | |
| * @since 1.2 | |
| */ | |
| public class Attributes implements Map<Object,Object>, Cloneable { | |
| /** | |
| * The attribute name-value mappings. | |
| */ | |
| protected Map<Object,Object> map; | |
| /** | |
| * Constructs a new, empty Attributes object with default size. | |
| */ | |
| public Attributes() { | |
| this(16); | |
| } | |
| /** | |
| * Constructs a new, empty Attributes object with the specified | |
| * initial size. | |
| * | |
| * @param size the initial number of attributes | |
| */ | |
| public Attributes(int size) { | |
| map = LinkedHashMap.newLinkedHashMap(size); | |
| } | |
| /** | |
| * Constructs a new Attributes object with the same attribute name-value | |
| * mappings as in the specified Attributes. | |
| * | |
| * @param attr the specified Attributes | |
| */ | |
| public Attributes(Attributes attr) { | |
| map = new LinkedHashMap<>(attr); | |
| } | |
| /** | |
| * Returns the value of the specified attribute name, or null if the | |
| * attribute name was not found. | |
| * | |
| * @param name the attribute name | |
| * @return the value of the specified attribute name, or null if | |
| * not found. | |
| */ | |
| public Object get(Object name) { | |
| return map.get(name); | |
| } | |
| /** | |
| * Returns the value of the specified attribute name, specified as | |
| * a string, or null if the attribute was not found. The attribute | |
| * name is case-insensitive. | |
| * <p> | |
| * This method is defined as: | |
| * <pre> | |
| * return (String)get(new Attributes.Name((String)name)); | |
| * </pre> | |
| * | |
| * @param name the attribute name as a string | |
| * @return the String value of the specified attribute name, or null if | |
| * not found. | |
| * @throws IllegalArgumentException if the attribute name is invalid | |
| */ | |
| public String getValue(String name) { | |
| return (String)get(Name.of(name)); | |
| } | |
| /** | |
| * Returns the value of the specified Attributes.Name, or null if the | |
| * attribute was not found. | |
| * <p> | |
| * This method is defined as: | |
| * <pre> | |
| * return (String)get(name); | |
| * </pre> | |
| * | |
| * @param name the Attributes.Name object | |
| * @return the String value of the specified Attribute.Name, or null if | |
| * not found. | |
| */ | |
| public String getValue(Name name) { | |
| return (String)get(name); | |
| } | |
| /** | |
| * Associates the specified value with the specified attribute name | |
| * (key) in this Map. If the Map previously contained a mapping for | |
| * the attribute name, the old value is replaced. | |
| * | |
| * @param name the attribute name | |
| * @param value the attribute value | |
| * @return the previous value of the attribute, or null if none | |
| * @throws ClassCastException if the name is not a Attributes.Name | |
| * or the value is not a String | |
| */ | |
| public Object put(Object name, Object value) { | |
| return map.put((Attributes.Name)name, (String)value); | |
| } | |
| /** | |
| * Associates the specified value with the specified attribute name, | |
| * specified as a String. The attributes name is case-insensitive. | |
| * If the Map previously contained a mapping for the attribute name, | |
| * the old value is replaced. | |
| * <p> | |
| * This method is defined as: | |
| * <pre> | |
| * return (String)put(new Attributes.Name(name), value); | |
| * </pre> | |
| * | |
| * @param name the attribute name as a string | |
| * @param value the attribute value | |
| * @return the previous value of the attribute, or null if none | |
| * @throws IllegalArgumentException if the attribute name is invalid | |
| */ | |
| public String putValue(String name, String value) { | |
| return (String)put(Name.of(name), value); | |
| } | |
| /** | |
| * Removes the attribute with the specified name (key) from this Map. | |
| * Returns the previous attribute value, or null if none. | |
| * | |
| * @param name attribute name | |
| * @return the previous value of the attribute, or null if none | |
| */ | |
| public Object remove(Object name) { | |
| return map.remove(name); | |
| } | |
| /** | |
| * Returns true if this Map maps one or more attribute names (keys) | |
| * to the specified value. | |
| * | |
| * @param value the attribute value | |
| * @return true if this Map maps one or more attribute names to | |
| * the specified value | |
| */ | |
| public boolean containsValue(Object value) { | |
| return map.containsValue(value); | |
| } | |
| /** | |
| * Returns true if this Map contains the specified attribute name (key). | |
| * | |
| * @param name the attribute name | |
| * @return true if this Map contains the specified attribute name | |
| */ | |
| public boolean containsKey(Object name) { | |
| return map.containsKey(name); | |
| } | |
| /** | |
| * Copies all of the attribute name-value mappings from the specified | |
| * Attributes to this Map. Duplicate mappings will be replaced. | |
| * | |
| * @param attr the Attributes to be stored in this map | |
| * @throws ClassCastException if attr is not an Attributes | |
| */ | |
| public void putAll(Map<?,?> attr) { | |
| // ## javac bug? | |
| if (!Attributes.class.isInstance(attr)) | |
| throw new ClassCastException(); | |
| for (Map.Entry<?,?> me : (attr).entrySet()) | |
| put(me.getKey(), me.getValue()); | |
| } | |
| /** | |
| * Removes all attributes from this Map. | |
| */ | |
| public void clear() { | |
| map.clear(); | |
| } | |
| /** | |
| * Returns the number of attributes in this Map. | |
| */ | |
| public int size() { | |
| return map.size(); | |
| } | |
| /** | |
| * Returns true if this Map contains no attributes. | |
| */ | |
| public boolean isEmpty() { | |
| return map.isEmpty(); | |
| } | |
| /** | |
| * Returns a Set view of the attribute names (keys) contained in this Map. | |
| */ | |
| public Set<Object> keySet() { | |
| return map.keySet(); | |
| } | |
| /** | |
| * Returns a Collection view of the attribute values contained in this Map. | |
| */ | |
| public Collection<Object> values() { | |
| return map.values(); | |
| } | |
| /** | |
| * Returns a Collection view of the attribute name-value mappings | |
| * contained in this Map. | |
| */ | |
| public Set<Map.Entry<Object,Object>> entrySet() { | |
| return map.entrySet(); | |
| } | |
| /** | |
| * Compares the specified object to the underlying | |
| * {@linkplain Attributes#map map} for equality. | |
| * Returns true if the given object is also a Map | |
| * and the two maps represent the same mappings. | |
| * | |
| * @param o the Object to be compared | |
| * @return true if the specified Object is equal to this Map | |
| */ | |
| public boolean equals(Object o) { | |
| return map.equals(o); | |
| } | |
| /** | |
| * Returns the hash code value for this Map. | |
| */ | |
| public int hashCode() { | |
| return map.hashCode(); | |
| } | |
| /** | |
| * Returns a copy of the Attributes, implemented as follows: | |
| * <pre> | |
| * public Object clone() { return new Attributes(this); } | |
| * </pre> | |
| * Since the attribute names and values are themselves immutable, | |
| * the Attributes returned can be safely modified without affecting | |
| * the original. | |
| */ | |
| public Object clone() { | |
| return new Attributes(this); | |
| } | |
| /* | |
| * Writes the current attributes to the specified data output stream. | |
| * XXX Need to handle UTF8 values and break up lines longer than 72 bytes | |
| */ | |
| void write(DataOutputStream out) throws IOException { | |
| StringBuilder buffer = new StringBuilder(72); | |
| for (Entry<Object, Object> e : entrySet()) { | |
| buffer.setLength(0); | |
| buffer.append(e.getKey().toString()); | |
| buffer.append(": "); | |
| buffer.append(e.getValue()); | |
| Manifest.println72(out, buffer.toString()); | |
| } | |
| Manifest.println(out); // empty line after individual section | |
| } | |
| /* | |
| * Writes the current attributes to the specified data output stream, | |
| * make sure to write out the MANIFEST_VERSION or SIGNATURE_VERSION | |
| * attributes first. | |
| * | |
| * XXX Need to handle UTF8 values and break up lines longer than 72 bytes | |
| */ | |
| void writeMain(DataOutputStream out) throws IOException { | |
| StringBuilder buffer = new StringBuilder(72); | |
| // write out the *-Version header first, if it exists | |
| String vername = Name.MANIFEST_VERSION.toString(); | |
| String version = getValue(vername); | |
| if (version == null) { | |
| vername = Name.SIGNATURE_VERSION.toString(); | |
| version = getValue(vername); | |
| } | |
| if (version != null) { | |
| buffer.append(vername); | |
| buffer.append(": "); | |
| buffer.append(version); | |
| out.write(buffer.toString().getBytes(UTF_8.INSTANCE)); | |
| Manifest.println(out); | |
| } | |
| // write out all attributes except for the version | |
| // we wrote out earlier | |
| for (Entry<Object, Object> e : entrySet()) { | |
| String name = ((Name) e.getKey()).toString(); | |
| if ((version != null) && !(name.equalsIgnoreCase(vername))) { | |
| buffer.setLength(0); | |
| buffer.append(name); | |
| buffer.append(": "); | |
| buffer.append(e.getValue()); | |
| Manifest.println72(out, buffer.toString()); | |
| } | |
| } | |
| Manifest.println(out); // empty line after main attributes section | |
| } | |
| /* | |
| * Reads attributes from the specified input stream. | |
| */ | |
| void read(Manifest.FastInputStream is, byte[] lbuf) throws IOException { | |
| read(is, lbuf, null, 0); | |
| } | |
| int read(Manifest.FastInputStream is, byte[] lbuf, String filename, int lineNumber) throws IOException { | |
| String name = null, value; | |
| ByteArrayOutputStream fullLine = new ByteArrayOutputStream(); | |
| int len; | |
| while ((len = is.readLine(lbuf)) != -1) { | |
| boolean lineContinued = false; | |
| byte c = lbuf[--len]; | |
| lineNumber++; | |
| if (c != '\n' && c != '\r') { | |
| throw new IOException("line too long (" | |
| + Manifest.getErrorPosition(filename, lineNumber) + ")"); | |
| } | |
| if (len > 0 && lbuf[len-1] == '\r') { | |
| --len; | |
| } | |
| if (len == 0) { | |
| break; | |
| } | |
| int i = 0; | |
| if (lbuf[0] == ' ') { | |
| // continuation of previous line | |
| if (name == null) { | |
| throw new IOException("misplaced continuation line (" | |
| + Manifest.getErrorPosition(filename, lineNumber) + ")"); | |
| } | |
| lineContinued = true; | |
| fullLine.write(lbuf, 1, len - 1); | |
| if (is.peek() == ' ') { | |
| continue; | |
| } | |
| value = fullLine.toString(UTF_8.INSTANCE); | |
| fullLine.reset(); | |
| } else { | |
| while (lbuf[i++] != ':') { | |
| if (i >= len) { | |
| throw new IOException("invalid header field (" | |
| + Manifest.getErrorPosition(filename, lineNumber) + ")"); | |
| } | |
| } | |
| if (lbuf[i++] != ' ') { | |
| throw new IOException("invalid header field (" | |
| + Manifest.getErrorPosition(filename, lineNumber) + ")"); | |
| } | |
| name = new String(lbuf, 0, i - 2, UTF_8.INSTANCE); | |
| if (is.peek() == ' ') { | |
| fullLine.reset(); | |
| fullLine.write(lbuf, i, len - i); | |
| continue; | |
| } | |
| value = new String(lbuf, i, len - i, UTF_8.INSTANCE); | |
| } | |
| try { | |
| if ((putValue(name, value) != null) && (!lineContinued)) { | |
| PlatformLogger.getLogger("java.util.jar").warning( | |
| "Duplicate name in Manifest: " + name | |
| + ".\n" | |
| + "Ensure that the manifest does not " | |
| + "have duplicate entries, and\n" | |
| + "that blank lines separate " | |
| + "individual sections in both your\n" | |
| + "manifest and in the META-INF/MANIFEST.MF " | |
| + "entry in the jar file."); | |
| } | |
| } catch (IllegalArgumentException e) { | |
| throw new IOException("invalid header field name: " + name | |
| + " (" + Manifest.getErrorPosition(filename, lineNumber) + ")"); | |
| } | |
| } | |
| return lineNumber; | |
| } | |
| /** | |
| * The Attributes.Name class represents an attribute name stored in | |
| * this Map. Valid attribute names are case-insensitive, are restricted | |
| * to the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed | |
| * 70 characters in length. Attribute values can contain any characters | |
| * and will be UTF8-encoded when written to the output stream. See the | |
| * <a href="{@docRoot}/../specs/jar/jar.html">JAR File Specification</a> | |
| * for more information about valid attribute names and values. | |
| * | |
| * @spec jar/jar.html JAR File Specification | |
| */ | |
| public static class Name { | |
| private final String name; | |
| private final int hashCode; | |
| /** | |
| * Avoid allocation for common Names | |
| */ | |
| private static @Stable Map<String, Name> KNOWN_NAMES; | |
| static final Name of(String name) { | |
| Name n = KNOWN_NAMES.get(name); | |
| if (n != null) { | |
| return n; | |
| } | |
| return new Name(name); | |
| } | |
| /** | |
| * Constructs a new attribute name using the given string name. | |
| * | |
| * @param name the attribute string name | |
| * @throws IllegalArgumentException if the attribute name was | |
| * invalid | |
| * @throws NullPointerException if the attribute name was null | |
| */ | |
| public Name(String name) { | |
| this.hashCode = hash(name); | |
| this.name = name.intern(); | |
| } | |
| // Checks the string is valid | |
| private final int hash(String name) { | |
| Objects.requireNonNull(name, "name"); | |
| int len = name.length(); | |
| if (len > 70 || len == 0) { | |
| throw new IllegalArgumentException(name); | |
| } | |
| // Calculate hash code case insensitively | |
| int h = 0; | |
| for (int i = 0; i < len; i++) { | |
| char c = name.charAt(i); | |
| if (c >= 'a' && c <= 'z') { | |
| // hashcode must be identical for upper and lower case | |
| h = h * 31 + (c - 0x20); | |
| } else if ((c >= 'A' && c <= 'Z' || | |
| c >= '0' && c <= '9' || | |
| c == '_' || c == '-')) { | |
| h = h * 31 + c; | |
| } else { | |
| throw new IllegalArgumentException(name); | |
| } | |
| } | |
| return h; | |
| } | |
| /** | |
| * Compares this attribute name to another for equality. | |
| * @param o the object to compare | |
| * @return true if this attribute name is equal to the | |
| * specified attribute object | |
| */ | |
| public boolean equals(Object o) { | |
| if (this == o) { | |
| return true; | |
| } | |
| return o instanceof Name other | |
| && other.name.equalsIgnoreCase(name); | |
| } | |
| /** | |
| * Computes the hash value for this attribute name. | |
| */ | |
| public int hashCode() { | |
| return hashCode; | |
| } | |
| /** | |
| * Returns the attribute name as a String. | |
| */ | |
| public String toString() { | |
| return name; | |
| } | |
| /** | |
| * {@code Name} object for {@code Manifest-Version} | |
| * manifest attribute. This attribute indicates the version number | |
| * of the manifest standard to which a JAR file's manifest conforms. | |
| * @see <a href="{@docRoot}/../specs/jar/jar.html#jar-manifest"> | |
| * Manifest and Signature Specification</a> | |
| */ | |
| public static final Name MANIFEST_VERSION; | |
| /** | |
| * {@code Name} object for {@code Signature-Version} | |
| * manifest attribute used when signing JAR files. | |
| * @see <a href="{@docRoot}/../specs/jar/jar.html#jar-manifest"> | |
| * Manifest and Signature Specification</a> | |
| */ | |
| public static final Name SIGNATURE_VERSION; | |
| /** | |
| * {@code Name} object for {@code Content-Type} | |
| * manifest attribute. | |
| */ | |
| public static final Name CONTENT_TYPE; | |
| /** | |
| * {@code Name} object for {@code Class-Path} | |
| * manifest attribute. | |
| * @see <a href="{@docRoot}/../specs/jar/jar.html#class-path-attribute"> | |
| * JAR file specification</a> | |
| */ | |
| public static final Name CLASS_PATH; | |
| /** | |
| * {@code Name} object for {@code Main-Class} manifest | |
| * attribute used for launching applications packaged in JAR files. | |
| * The {@code Main-Class} attribute is used in conjunction | |
| * with the {@code -jar} command-line option of the | |
| * {@code java} application launcher. | |
| */ | |
| public static final Name MAIN_CLASS; | |
| /** | |
| * {@code Name} object for {@code Sealed} manifest attribute | |
| * used for sealing. | |
| * @see <a href="{@docRoot}/../specs/jar/jar.html#package-sealing"> | |
| * Package Sealing</a> | |
| */ | |
| public static final Name SEALED; | |
| /** | |
| * {@code Name} object for {@code Extension-List} manifest attribute | |
| * used for the extension mechanism that is no longer supported. | |
| */ | |
| public static final Name EXTENSION_LIST; | |
| /** | |
| * {@code Name} object for {@code Extension-Name} manifest attribute | |
| * used for the extension mechanism that is no longer supported. | |
| */ | |
| public static final Name EXTENSION_NAME; | |
| /** | |
| * {@code Name} object for {@code Extension-Installation} manifest attribute. | |
| * | |
| * @deprecated Extension mechanism is no longer supported. | |
| */ | |
| @Deprecated | |
| public static final Name EXTENSION_INSTALLATION; | |
| /** | |
| * {@code Name} object for {@code Implementation-Title} | |
| * manifest attribute used for package versioning. | |
| */ | |
| public static final Name IMPLEMENTATION_TITLE; | |
| /** | |
| * {@code Name} object for {@code Implementation-Version} | |
| * manifest attribute used for package versioning. | |
| */ | |
| public static final Name IMPLEMENTATION_VERSION; | |
| /** | |
| * {@code Name} object for {@code Implementation-Vendor} | |
| * manifest attribute used for package versioning. | |
| */ | |
| public static final Name IMPLEMENTATION_VENDOR; | |
| /** | |
| * {@code Name} object for {@code Implementation-Vendor-Id} | |
| * manifest attribute. | |
| * | |
| * @deprecated Extension mechanism is no longer supported. | |
| */ | |
| @Deprecated | |
| public static final Name IMPLEMENTATION_VENDOR_ID; | |
| /** | |
| * {@code Name} object for {@code Implementation-URL} | |
| * manifest attribute. | |
| * | |
| * @deprecated Extension mechanism is no longer supported. | |
| */ | |
| @Deprecated | |
| public static final Name IMPLEMENTATION_URL; | |
| /** | |
| * {@code Name} object for {@code Specification-Title} | |
| * manifest attribute used for package versioning. | |
| */ | |
| public static final Name SPECIFICATION_TITLE; | |
| /** | |
| * {@code Name} object for {@code Specification-Version} | |
| * manifest attribute used for package versioning. | |
| */ | |
| public static final Name SPECIFICATION_VERSION; | |
| /** | |
| * {@code Name} object for {@code Specification-Vendor} | |
| * manifest attribute used for package versioning. | |
| */ | |
| public static final Name SPECIFICATION_VENDOR; | |
| /** | |
| * {@code Name} object for {@code Multi-Release} | |
| * manifest attribute that indicates this is a multi-release JAR file. | |
| * | |
| * @since 9 | |
| */ | |
| public static final Name MULTI_RELEASE; | |
| private static void addName(Map<String, Name> names, Name name) { | |
| names.put(name.name, name); | |
| } | |
| static { | |
| CDS.initializeFromArchive(Attributes.Name.class); | |
| if (KNOWN_NAMES == null) { | |
| MANIFEST_VERSION = new Name("Manifest-Version"); | |
| SIGNATURE_VERSION = new Name("Signature-Version"); | |
| CONTENT_TYPE = new Name("Content-Type"); | |
| CLASS_PATH = new Name("Class-Path"); | |
| MAIN_CLASS = new Name("Main-Class"); | |
| SEALED = new Name("Sealed"); | |
| EXTENSION_LIST = new Name("Extension-List"); | |
| EXTENSION_NAME = new Name("Extension-Name"); | |
| EXTENSION_INSTALLATION = new Name("Extension-Installation"); | |
| IMPLEMENTATION_TITLE = new Name("Implementation-Title"); | |
| IMPLEMENTATION_VERSION = new Name("Implementation-Version"); | |
| IMPLEMENTATION_VENDOR = new Name("Implementation-Vendor"); | |
| IMPLEMENTATION_VENDOR_ID = new Name("Implementation-Vendor-Id"); | |
| IMPLEMENTATION_URL = new Name("Implementation-URL"); | |
| SPECIFICATION_TITLE = new Name("Specification-Title"); | |
| SPECIFICATION_VERSION = new Name("Specification-Version"); | |
| SPECIFICATION_VENDOR = new Name("Specification-Vendor"); | |
| MULTI_RELEASE = new Name("Multi-Release"); | |
| var names = new HashMap<String, Name>(64); | |
| addName(names, MANIFEST_VERSION); | |
| addName(names, SIGNATURE_VERSION); | |
| addName(names, CONTENT_TYPE); | |
| addName(names, CLASS_PATH); | |
| addName(names, MAIN_CLASS); | |
| addName(names, SEALED); | |
| addName(names, EXTENSION_LIST); | |
| addName(names, EXTENSION_NAME); | |
| addName(names, EXTENSION_INSTALLATION); | |
| addName(names, IMPLEMENTATION_TITLE); | |
| addName(names, IMPLEMENTATION_VERSION); | |
| addName(names, IMPLEMENTATION_VENDOR); | |
| addName(names, IMPLEMENTATION_VENDOR_ID); | |
| addName(names, IMPLEMENTATION_URL); | |
| addName(names, SPECIFICATION_TITLE); | |
| addName(names, SPECIFICATION_VERSION); | |
| addName(names, SPECIFICATION_VENDOR); | |
| addName(names, MULTI_RELEASE); | |
| // Common attributes used in MANIFEST.MF et.al; adding these has a | |
| // small footprint cost, but is likely to be quickly paid for by | |
| // reducing allocation when reading and parsing typical manifests | |
| // JDK specific attributes | |
| addName(names, new Name("Add-Exports")); | |
| addName(names, new Name("Add-Opens")); | |
| addName(names, new Name("Enable-Native-Access")); | |
| // LauncherHelper attributes | |
| addName(names, new Name("Launcher-Agent-Class")); | |
| addName(names, new Name("JavaFX-Application-Class")); | |
| // jarsigner attributes | |
| addName(names, new Name("Name")); | |
| addName(names, new Name("Created-By")); | |
| addName(names, new Name("SHA1-Digest")); | |
| addName(names, new Name("SHA-256-Digest")); | |
| addName(names, new Name("SHA-384-Digest")); | |
| KNOWN_NAMES = Map.copyOf(names); | |
| } else { | |
| // Even if KNOWN_NAMES was read from archive, we still need | |
| // to initialize the public constants | |
| MANIFEST_VERSION = KNOWN_NAMES.get("Manifest-Version"); | |
| SIGNATURE_VERSION = KNOWN_NAMES.get("Signature-Version"); | |
| CONTENT_TYPE = KNOWN_NAMES.get("Content-Type"); | |
| CLASS_PATH = KNOWN_NAMES.get("Class-Path"); | |
| MAIN_CLASS = KNOWN_NAMES.get("Main-Class"); | |
| SEALED = KNOWN_NAMES.get("Sealed"); | |
| EXTENSION_LIST = KNOWN_NAMES.get("Extension-List"); | |
| EXTENSION_NAME = KNOWN_NAMES.get("Extension-Name"); | |
| EXTENSION_INSTALLATION = KNOWN_NAMES.get("Extension-Installation"); | |
| IMPLEMENTATION_TITLE = KNOWN_NAMES.get("Implementation-Title"); | |
| IMPLEMENTATION_VERSION = KNOWN_NAMES.get("Implementation-Version"); | |
| IMPLEMENTATION_VENDOR = KNOWN_NAMES.get("Implementation-Vendor"); | |
| IMPLEMENTATION_VENDOR_ID = KNOWN_NAMES.get("Implementation-Vendor-Id"); | |
| IMPLEMENTATION_URL = KNOWN_NAMES.get("Implementation-URL"); | |
| SPECIFICATION_TITLE = KNOWN_NAMES.get("Specification-Title"); | |
| SPECIFICATION_VERSION = KNOWN_NAMES.get("Specification-Version"); | |
| SPECIFICATION_VENDOR = KNOWN_NAMES.get("Specification-Vendor"); | |
| MULTI_RELEASE = KNOWN_NAMES.get("Multi-Release"); | |
| } | |
| } | |
| } | |
| } |