/* * Copyright (c) 2018, 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. * * 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.
*/
/** * @test * @bug 8066619 * @run testng ValueUtf8Coding * @summary Tests encoding and decoding manifest header values to and from * UTF-8 with the complete Unicode character set.
*/
* see also "../tools/launcher/UnicodeTest.java"for manifest attributes
* parsed during launch
*/ publicclass ValueUtf8Coding {
/** * Maximum number of bytes of UTF-8 encoded characters in one header value. * <p> * There are too many different Unicode code points (more than one million) * to fit all into one manifest value. The specifications state: * <q>Implementations should support 65535-byte (not character) header * values, and 65535 headers per file. They might run out of memory, * but there should not be hard-coded limits below these values.</q> * * @see <a * href="{@docRoot}/../specs/jar/jar.html#Notes_on_Manifest_and_Signature_Files"> * Notes on Manifest and Signature Files</a>
*/ staticfinalint SUPPORTED_VALUE_LENGTH = 65535;
/** * Returns {@code true} if {@code codePoint} is known not to be a supported * character in manifest header values. Explicitly forbidden in manifest * header values are according to a statement from the specifications: * <q>otherchar: any UTF-8 character except NUL, CR and LF</q>. * {@code NUL} ({@code 0x0}), however, works just fine and might have been * used and might still be. * * @see <a href="{@docRoot}/../specs/jar/jar.html#Section-Specification"> * Jar File Specification</a>
*/ staticboolean isUnsupportedManifestValueCharacter(int codePoint) { return codePoint == '\r'/* CR */ || codePoint == '\n' /* LF */;
};
/** * Produces a list of strings with all Unicode characters except those * explicitly invalid in manifest header values. * Each string is filled with as many characters as fit into * {@link #SUPPORTED_VALUE_LENGTH} bytes with UTF-8 encoding except the * last string which contains the remaining characters. Each of those * strings becomes a header value the number of which 65535 should be * supported per file. * * @see <a * href="{@docRoot}/../specs/jar/jar.html#Notes_on_Manifest_and_Signature_Files"> * Notes on Manifest and Signature Files</a>
*/ static List<String> produceValuesWithAllUnicodeCharacters() {
ArrayList<String> values = new ArrayList<>(); byte[] valueBuf = newbyte[SUPPORTED_VALUE_LENGTH]; int pos = 0; for (int codePoint = Character.MIN_CODE_POINT;
codePoint <= Character.MAX_CODE_POINT; codePoint++) { if (isUnsupportedManifestValueCharacter(codePoint)) { continue;
}
byte[] charBuf = Character.toString(codePoint).getBytes(UTF_8); if (pos + charBuf.length > valueBuf.length) {
values.add(new String(valueBuf, 0, pos, UTF_8));
pos = 0;
}
System.arraycopy(charBuf, 0, valueBuf, pos, charBuf.length);
pos += charBuf.length;
} if (pos > 0) {
values.add(new String(valueBuf, 0, pos, UTF_8));
} // minimum number of headers supported is the same as the minimum size // of each header value in bytes
assertTrue(values.size() <= SUPPORTED_VALUE_LENGTH); return values;
}
/** * Returns simple, valid, short, and distinct manifest header names. * The returned name cannot collide with "{@code Manifest-Version}" because * the returned string does not contain "{@code -}".
*/ static Name azName(int seed) {
StringBuffer name = new StringBuffer(); do {
name.insert(0, (char) (seed % 26 + (seed < 26 ? 'A' : 'a')));
seed = seed / 26 - 1;
} while (seed >= 0); returnnew Name(name.toString());
}
/** * Writes and reads a manifest with the complete Unicode character set. * The characters are grouped into manifest header values with about as * many bytes as allowed each, utilizing a single big manifest. * <p> * This test assumes that a manifest is encoded and decoded correctly if * writing and then reading it again results in a manifest with identical * values as the original. The test is not about other aspects of writing * and reading manifests than only that, given the fact and the way it * works for some characters such as the most widely and often used ones, * it also works for the complete Unicode character set just the same. * <p> * Only header values are tested. The set of allowed characters for header * names are much more limited and are a different topic entirely and most * simple ones are used here as necessary just to get valid and different * ones (see {@link #azName}). * <p> * Because the current implementation under test uses different portions * of code depending on where the value occurs to read or write, each * character is tested in each of the three positions:<ul> * <li>main attribute header,</li> * <li>named section name, and</li> * <li>named sections header values</li> * </ul> * Implementation of writing the main section headers in * {@link Attributes#writeMain(java.io.DataOutputStream)} differs from the * one writing named section headers in * {@link Attributes#write(java.io.DataOutputStream)} regarding the special * order of {@link Name#MANIFEST_VERSION} and * {@link Name#SIGNATURE_VERSION} and also * {@link Manifest#read(java.io.InputStream)} at least potentially reads * main sections differently than reading named sections names headers in * {@link Attributes#read(Manifest.FastInputStream, byte[])}.
*/
@Test publicvoid testCompleteUnicodeCharacterSet() throws IOException {
Manifest mf = new Manifest();
mf.getMainAttributes().put(Name.MANIFEST_VERSION, "1.0");
List<String> values = produceValuesWithAllUnicodeCharacters(); for (int i = 0; i < values.size(); i++) {
Name name = azName(i);
String value = values.get(i);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.