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