< prev index next >

src/java.base/share/classes/java/util/jar/Manifest.java

Print this page
rev 53080 : 8066619: Fix deprecation warnings in java.util.jar
Reviewed-by: rriggs, lancea
Contributed-by: philipp.kunz@paratix.ch


  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.FilterInputStream;
  30 import java.io.IOException;
  31 import java.io.InputStream;
  32 import java.io.OutputStream;
  33 import java.util.HashMap;
  34 import java.util.Map;
  35 
  36 import sun.security.util.SecurityProperties;
  37 


  38 /**
  39  * The Manifest class is used to maintain Manifest entry names and their
  40  * associated Attributes. There are main Manifest Attributes as well as
  41  * per-entry Attributes. For information on the Manifest format, please
  42  * see the
  43  * <a href="{@docRoot}/../specs/jar/jar.html">
  44  * Manifest format specification</a>.
  45  *
  46  * @author  David Connelly
  47  * @see     Attributes
  48  * @since   1.2
  49  */
  50 public class Manifest implements Cloneable {
  51 
  52     // manifest main attributes
  53     private final Attributes attr = new Attributes();
  54 
  55     // manifest entries
  56     private final Map<String, Attributes> entries = new HashMap<>();
  57 


 180         return result;
 181     }
 182 
 183     /**
 184      * Clears the main Attributes as well as the entries in this Manifest.
 185      */
 186     public void clear() {
 187         attr.clear();
 188         entries.clear();
 189     }
 190 
 191     /**
 192      * Writes the Manifest to the specified OutputStream.
 193      * Attributes.Name.MANIFEST_VERSION must be set in
 194      * MainAttributes prior to invoking this method.
 195      *
 196      * @param out the output stream
 197      * @exception IOException if an I/O error has occurred
 198      * @see #getMainAttributes
 199      */
 200     @SuppressWarnings("deprecation")
 201     public void write(OutputStream out) throws IOException {
 202         DataOutputStream dos = new DataOutputStream(out);
 203         // Write out the main attributes for the manifest
 204         attr.writeMain(dos);
 205         // Now write out the per-entry attributes

 206         for (Map.Entry<String, Attributes> e : entries.entrySet()) {
 207             StringBuffer buffer = new StringBuffer("Name: ");
 208             String value = e.getKey();
 209             if (value != null) {
 210                 byte[] vb = value.getBytes("UTF8");
 211                 value = new String(vb, 0, 0, vb.length);
 212             }
 213             buffer.append(value);
 214             make72Safe(buffer);
 215             buffer.append("\r\n");
 216             dos.writeBytes(buffer.toString());
 217             e.getValue().write(dos);
 218         }
 219         dos.flush();
 220     }
 221 
 222     /**
 223      * Adds line breaks to enforce a maximum 72 bytes per line.


 224      */

 225     static void make72Safe(StringBuffer line) {
 226         int length = line.length();
 227         int index = 72;
 228         while (index < length) {
 229             line.insert(index, "\r\n ");
 230             index += 74; // + line width + line break ("\r\n")
 231             length += 3; // + line break ("\r\n") and space
 232         }
 233         return;































 234     }
 235 
 236     static String getErrorPosition(String filename, final int lineNumber) {
 237         if (filename == null ||
 238                 !SecurityProperties.INCLUDE_JAR_NAME_IN_EXCEPTIONS) {
 239             return "line " + lineNumber;
 240         }
 241         return "manifest of " + filename + ":" + lineNumber;
 242     }
 243 
 244     /**
 245      * Reads the Manifest from the specified InputStream. The entry
 246      * names and attributes read will be merged in with the current
 247      * manifest entries.
 248      *
 249      * @param is the input stream
 250      * @exception IOException if an I/O error has occurred
 251      */
 252     public void read(InputStream is) throws IOException {
 253         // Buffered input stream for reading manifest data


 287                 if (name == null) {
 288                     throw new IOException("invalid manifest format"
 289                               + getErrorPosition(jarFilename, lineNumber) + ")");
 290                 }
 291                 if (fis.peek() == ' ') {
 292                     // name is wrapped
 293                     lastline = new byte[len - 6];
 294                     System.arraycopy(lbuf, 6, lastline, 0, len - 6);
 295                     continue;
 296                 }
 297             } else {
 298                 // continuation line
 299                 byte[] buf = new byte[lastline.length + len - 1];
 300                 System.arraycopy(lastline, 0, buf, 0, lastline.length);
 301                 System.arraycopy(lbuf, 1, buf, lastline.length, len - 1);
 302                 if (fis.peek() == ' ') {
 303                     // name is wrapped
 304                     lastline = buf;
 305                     continue;
 306                 }
 307                 name = new String(buf, 0, buf.length, "UTF8");
 308                 lastline = null;
 309             }
 310             Attributes attr = getAttributes(name);
 311             if (attr == null) {
 312                 attr = new Attributes(asize);
 313                 entries.put(name, attr);
 314             }
 315             lineNumber = attr.read(fis, lbuf, jarFilename, lineNumber);
 316             ecount++;
 317             acount += attr.size();
 318             //XXX: Fix for when the average is 0. When it is 0,
 319             // you get an Attributes object with an initial
 320             // capacity of 0, which tickles a bug in HashMap.
 321             asize = Math.max(2, acount / ecount);
 322 
 323             name = null;
 324             skipEmptyLines = true;
 325         }
 326     }
 327 
 328     private String parseName(byte[] lbuf, int len) {
 329         if (toLower(lbuf[0]) == 'n' && toLower(lbuf[1]) == 'a' &&
 330             toLower(lbuf[2]) == 'm' && toLower(lbuf[3]) == 'e' &&
 331             lbuf[4] == ':' && lbuf[5] == ' ') {
 332             try {
 333                 return new String(lbuf, 6, len - 6, "UTF8");
 334             }
 335             catch (Exception e) {
 336             }
 337         }
 338         return null;
 339     }
 340 
 341     private int toLower(int c) {
 342         return (c >= 'A' && c <= 'Z') ? 'a' + (c - 'A') : c;
 343     }
 344 
 345     /**
 346      * Returns true if the specified Object is also a Manifest and has
 347      * the same main Attributes and entries.
 348      *
 349      * @param o the object to be compared
 350      * @return true if the specified Object is also a Manifest and has
 351      * the same main Attributes and entries
 352      */
 353     public boolean equals(Object o) {




  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.FilterInputStream;
  30 import java.io.IOException;
  31 import java.io.InputStream;
  32 import java.io.OutputStream;
  33 import java.util.HashMap;
  34 import java.util.Map;
  35 
  36 import sun.security.util.SecurityProperties;
  37 
  38 import static java.nio.charset.StandardCharsets.UTF_8;
  39 
  40 /**
  41  * The Manifest class is used to maintain Manifest entry names and their
  42  * associated Attributes. There are main Manifest Attributes as well as
  43  * per-entry Attributes. For information on the Manifest format, please
  44  * see the
  45  * <a href="{@docRoot}/../specs/jar/jar.html">
  46  * Manifest format specification</a>.
  47  *
  48  * @author  David Connelly
  49  * @see     Attributes
  50  * @since   1.2
  51  */
  52 public class Manifest implements Cloneable {
  53 
  54     // manifest main attributes
  55     private final Attributes attr = new Attributes();
  56 
  57     // manifest entries
  58     private final Map<String, Attributes> entries = new HashMap<>();
  59 


 182         return result;
 183     }
 184 
 185     /**
 186      * Clears the main Attributes as well as the entries in this Manifest.
 187      */
 188     public void clear() {
 189         attr.clear();
 190         entries.clear();
 191     }
 192 
 193     /**
 194      * Writes the Manifest to the specified OutputStream.
 195      * Attributes.Name.MANIFEST_VERSION must be set in
 196      * MainAttributes prior to invoking this method.
 197      *
 198      * @param out the output stream
 199      * @exception IOException if an I/O error has occurred
 200      * @see #getMainAttributes
 201      */

 202     public void write(OutputStream out) throws IOException {
 203         DataOutputStream dos = new DataOutputStream(out);
 204         // Write out the main attributes for the manifest
 205         attr.writeMain(dos);
 206         // Now write out the per-entry attributes
 207         StringBuilder buffer = entries.isEmpty() ? null : new StringBuilder(72);
 208         for (Map.Entry<String, Attributes> e : entries.entrySet()) {
 209             buffer.setLength(0);
 210             buffer.append("Name: ");
 211             buffer.append(e.getKey());
 212             println72(dos, buffer.toString());






 213             e.getValue().write(dos);
 214         }
 215         dos.flush();
 216     }
 217 
 218     /**
 219      * Adds line breaks to enforce a maximum of 72 bytes per line.
 220      *
 221      * @deprecation Replaced with {@link #println72}.
 222      */
 223     @Deprecated(since = "13")
 224     static void make72Safe(StringBuffer line) {
 225         int length = line.length();
 226         int index = 72;
 227         while (index < length) {
 228             line.insert(index, "\r\n ");
 229             index += 74; // + line width + line break ("\r\n")
 230             length += 3; // + line break ("\r\n") and space
 231         }
 232     }
 233 
 234     /**
 235      * Writes {@code line} to {@code out} with line breaks and continuation
 236      * spaces within the limits of 72 bytes of contents per line followed
 237      * by a line break.
 238      */
 239     static void println72(OutputStream out, String line) throws IOException {
 240         if (!line.isEmpty()) {
 241             byte[] lineBytes = line.getBytes(UTF_8);
 242             int length = lineBytes.length;
 243             // first line can hold one byte more than subsequent lines which
 244             // start with a continuation line break space
 245             out.write(lineBytes[0]);
 246             int pos = 1;
 247             while (length - pos > 71) {
 248                 out.write(lineBytes, pos, 71);
 249                 pos += 71;
 250                 println(out);
 251                 out.write(' ');
 252             }
 253             out.write(lineBytes, pos, length - pos);
 254         }
 255         println(out);
 256     }
 257 
 258     /**
 259      * Writes a line break to {@code out}.
 260      */
 261     static void println(OutputStream out) throws IOException {
 262         out.write('\r');
 263         out.write('\n');
 264     }
 265 
 266     static String getErrorPosition(String filename, final int lineNumber) {
 267         if (filename == null ||
 268                 !SecurityProperties.INCLUDE_JAR_NAME_IN_EXCEPTIONS) {
 269             return "line " + lineNumber;
 270         }
 271         return "manifest of " + filename + ":" + lineNumber;
 272     }
 273 
 274     /**
 275      * Reads the Manifest from the specified InputStream. The entry
 276      * names and attributes read will be merged in with the current
 277      * manifest entries.
 278      *
 279      * @param is the input stream
 280      * @exception IOException if an I/O error has occurred
 281      */
 282     public void read(InputStream is) throws IOException {
 283         // Buffered input stream for reading manifest data


 317                 if (name == null) {
 318                     throw new IOException("invalid manifest format"
 319                               + getErrorPosition(jarFilename, lineNumber) + ")");
 320                 }
 321                 if (fis.peek() == ' ') {
 322                     // name is wrapped
 323                     lastline = new byte[len - 6];
 324                     System.arraycopy(lbuf, 6, lastline, 0, len - 6);
 325                     continue;
 326                 }
 327             } else {
 328                 // continuation line
 329                 byte[] buf = new byte[lastline.length + len - 1];
 330                 System.arraycopy(lastline, 0, buf, 0, lastline.length);
 331                 System.arraycopy(lbuf, 1, buf, lastline.length, len - 1);
 332                 if (fis.peek() == ' ') {
 333                     // name is wrapped
 334                     lastline = buf;
 335                     continue;
 336                 }
 337                 name = new String(buf, 0, buf.length, UTF_8);
 338                 lastline = null;
 339             }
 340             Attributes attr = getAttributes(name);
 341             if (attr == null) {
 342                 attr = new Attributes(asize);
 343                 entries.put(name, attr);
 344             }
 345             lineNumber = attr.read(fis, lbuf, jarFilename, lineNumber);
 346             ecount++;
 347             acount += attr.size();
 348             //XXX: Fix for when the average is 0. When it is 0,
 349             // you get an Attributes object with an initial
 350             // capacity of 0, which tickles a bug in HashMap.
 351             asize = Math.max(2, acount / ecount);
 352 
 353             name = null;
 354             skipEmptyLines = true;
 355         }
 356     }
 357 
 358     private String parseName(byte[] lbuf, int len) {
 359         if (toLower(lbuf[0]) == 'n' && toLower(lbuf[1]) == 'a' &&
 360             toLower(lbuf[2]) == 'm' && toLower(lbuf[3]) == 'e' &&
 361             lbuf[4] == ':' && lbuf[5] == ' ') {
 362             try {
 363                 return new String(lbuf, 6, len - 6, UTF_8);
 364             }
 365             catch (Exception e) {
 366             }
 367         }
 368         return null;
 369     }
 370 
 371     private int toLower(int c) {
 372         return (c >= 'A' && c <= 'Z') ? 'a' + (c - 'A') : c;
 373     }
 374 
 375     /**
 376      * Returns true if the specified Object is also a Manifest and has
 377      * the same main Attributes and entries.
 378      *
 379      * @param o the object to be compared
 380      * @return true if the specified Object is also a Manifest and has
 381      * the same main Attributes and entries
 382      */
 383     public boolean equals(Object o) {


< prev index next >