📄 manifest.java
字号:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */package org.apache.tools.ant.taskdefs;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.io.Reader;import java.io.StringWriter;import java.io.UnsupportedEncodingException;import java.util.Enumeration;import java.util.Hashtable;import java.util.Vector;import org.apache.tools.ant.BuildException;import org.apache.tools.ant.util.FileUtils;/** * Holds the data of a jar manifest. * * Manifests are processed according to the * {@link <a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html">Jar * file specification.</a>}. * Specifically, a manifest element consists of * a set of attributes and sections. These sections in turn may contain * attributes. Note in particular that this may result in manifest lines * greater than 72 bytes being wrapped and continued on the next * line. If an application can not handle the continuation mechanism, it * is a defect in the application, not this task. * * * @since Ant 1.4 */public class Manifest { /** The standard manifest version header */ public static final String ATTRIBUTE_MANIFEST_VERSION = "Manifest-Version"; /** The standard Signature Version header */ public static final String ATTRIBUTE_SIGNATURE_VERSION = "Signature-Version"; /** The Name Attribute is the first in a named section */ public static final String ATTRIBUTE_NAME = "Name"; /** The From Header is disallowed in a Manifest */ public static final String ATTRIBUTE_FROM = "From"; /** The Class-Path Header is special - it can be duplicated */ public static final String ATTRIBUTE_CLASSPATH = "Class-Path"; /** Default Manifest version if one is not specified */ public static final String DEFAULT_MANIFEST_VERSION = "1.0"; /** The max length of a line in a Manifest */ public static final int MAX_LINE_LENGTH = 72; /** * Max length of a line section which is continued. Need to allow * for the CRLF. */ public static final int MAX_SECTION_LENGTH = MAX_LINE_LENGTH - 2; /** The End-Of-Line marker in manifests */ public static final String EOL = "\r\n"; /** Error for attributes */ public static final String ERROR_FROM_FORBIDDEN = "Manifest attributes should not start " + "with \"" + ATTRIBUTE_FROM + "\" in \""; /** Encoding to be used for JAR files. */ public static final String JAR_ENCODING = "UTF-8"; /** * An attribute for the manifest. * Those attributes that are not nested into a section will be added to the "Main" section. */ public static class Attribute { /** * Maximum length of the name to have the value starting on the same * line as the name. This to stay under 72 bytes total line length * (including CRLF). */ private static final int MAX_NAME_VALUE_LENGTH = 68; /** * Maximum length of the name according to the jar specification. * In this case the first line will have 74 bytes total line length * (including CRLF). This conflicts with the 72 bytes total line length * max, but is the only possible conclusion from the manifest specification, if * names with 70 bytes length are allowed, have to be on the first line, and * have to be followed by ": ". */ private static final int MAX_NAME_LENGTH = 70; /** The attribute's name */ private String name = null; /** The attribute's value */ private Vector values = new Vector(); /** * For multivalued attributes, this is the index of the attribute * currently being defined. */ private int currentIndex = 0; /** * Construct an empty attribute */ public Attribute() { } /** * Construct an attribute by parsing a line from the Manifest * * @param line the line containing the attribute name and value * * @throws ManifestException if the line is not valid */ public Attribute(String line) throws ManifestException { parse(line); } /** * Construct a manifest by specifying its name and value * * @param name the attribute's name * @param value the Attribute's value */ public Attribute(String name, String value) { this.name = name; setValue(value); } /** * @see java.lang.Object#hashCode * @return a hashcode based on the key and values. */ public int hashCode() { int hashCode = 0; if (name != null) { hashCode += getKey().hashCode(); } hashCode += values.hashCode(); return hashCode; } /** * @param rhs the object to check for equality. * @see java.lang.Object#equals * @return true if the key and values are the same. */ public boolean equals(Object rhs) { if (rhs == null || rhs.getClass() != getClass()) { return false; } if (rhs == this) { return true; } Attribute rhsAttribute = (Attribute) rhs; String lhsKey = getKey(); String rhsKey = rhsAttribute.getKey(); if ((lhsKey == null && rhsKey != null) || (lhsKey != null && !lhsKey.equals(rhsKey))) { return false; } return values.equals(rhsAttribute.values); } /** * Parse a line into name and value pairs * * @param line the line to be parsed * * @throws ManifestException if the line does not contain a colon * separating the name and value */ public void parse(String line) throws ManifestException { int index = line.indexOf(": "); if (index == -1) { throw new ManifestException("Manifest line \"" + line + "\" is not valid as it does not " + "contain a name and a value separated by ': ' "); } name = line.substring(0, index); setValue(line.substring(index + 2)); } /** * Set the Attribute's name; required * * @param name the attribute's name */ public void setName(String name) { this.name = name; } /** * Get the Attribute's name * * @return the attribute's name. */ public String getName() { return name; } /** * Get the attribute's Key - its name in lower case. * * @return the attribute's key. */ public String getKey() { if (name == null) { return null; } return name.toLowerCase(); } /** * Set the Attribute's value; required * * @param value the attribute's value */ public void setValue(String value) { if (currentIndex >= values.size()) { values.addElement(value); currentIndex = values.size() - 1; } else { values.setElementAt(value, currentIndex); } } /** * Get the Attribute's value. * * @return the attribute's value. */ public String getValue() { if (values.size() == 0) { return null; } String fullValue = ""; for (Enumeration e = getValues(); e.hasMoreElements();) { String value = (String) e.nextElement(); fullValue += value + " "; } return fullValue.trim(); } /** * Add a new value to this attribute - making it multivalued. * * @param value the attribute's additional value */ public void addValue(String value) { currentIndex++; setValue(value); } /** * Get all the attribute's values. * * @return an enumeration of the attributes values */ public Enumeration getValues() { return values.elements(); } /** * Add a continuation line from the Manifest file. * * When lines are too long in a manifest, they are continued on the * next line by starting with a space. This method adds the continuation * data to the attribute value by skipping the first character. * * @param line the continuation line. */ public void addContinuation(String line) { String currentValue = (String) values.elementAt(currentIndex); setValue(currentValue + line.substring(1)); } /** * Write the attribute out to a print writer. * * @param writer the Writer to which the attribute is written * * @throws IOException if the attribute value cannot be written */ public void write(PrintWriter writer) throws IOException { for (Enumeration e = getValues(); e.hasMoreElements();) { writeValue(writer, (String) e.nextElement()); } } /** * Write a single attribute value out * * @param writer the Writer to which the attribute is written * @param value the attribute value * * @throws IOException if the attribute value cannot be written */ private void writeValue(PrintWriter writer, String value) throws IOException { String line = null; int nameLength = name.getBytes(JAR_ENCODING).length; if (nameLength > MAX_NAME_VALUE_LENGTH) { if (nameLength > MAX_NAME_LENGTH) { throw new IOException("Unable to write manifest line " + name + ": " + value); } writer.print(name + ": " + EOL); line = " " + value; } else { line = name + ": " + value; } while (line.getBytes(JAR_ENCODING).length > MAX_SECTION_LENGTH) { // try to find a MAX_LINE_LENGTH byte section int breakIndex = MAX_SECTION_LENGTH; if (breakIndex >= line.length()) { breakIndex = line.length() - 1; } String section = line.substring(0, breakIndex); while (section.getBytes(JAR_ENCODING).length > MAX_SECTION_LENGTH && breakIndex > 0) { breakIndex--; section = line.substring(0, breakIndex); } if (breakIndex == 0) { throw new IOException("Unable to write manifest line " + name + ": " + value); } writer.print(section + EOL); line = " " + line.substring(breakIndex); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -