This commit is contained in:
Yuri Nesterenko 2022-07-20 10:12:57 +03:00
commit bae72014c6
17 changed files with 610 additions and 203 deletions

View File

@ -596,7 +596,6 @@ ciKlass* ciEnv::get_klass_by_index(const constantPoolHandle& cpool,
ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool,
int pool_index, int cache_index,
ciInstanceKlass* accessor) {
bool ignore_will_link;
EXCEPTION_CONTEXT;
int index = pool_index;
if (cache_index >= 0) {
@ -668,8 +667,8 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool,
return ciConstant(T_OBJECT, constant);
}
} else if (tag.is_klass() || tag.is_unresolved_klass()) {
// 4881222: allow ldc to take a class type
ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore_will_link, accessor);
bool will_link;
ciKlass* klass = get_klass_by_index_impl(cpool, index, will_link, accessor);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
record_out_of_memory_failure();
@ -677,7 +676,8 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool,
}
assert (klass->is_instance_klass() || klass->is_array_klass(),
"must be an instance or array klass ");
return ciConstant(T_OBJECT, klass->java_mirror());
ciInstance* mirror = (will_link ? klass->java_mirror() : get_unloaded_klass_mirror(klass));
return ciConstant(T_OBJECT, mirror);
} else if (tag.is_method_type()) {
// must execute Java code to link this CP entry into cache[i].f1
ciSymbol* signature = get_symbol(cpool->method_type_signature_at(index));
@ -685,6 +685,7 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool,
return ciConstant(T_OBJECT, ciobj);
} else if (tag.is_method_handle()) {
// must execute Java code to link this CP entry into cache[i].f1
bool ignore_will_link;
int ref_kind = cpool->method_handle_ref_kind_at(index);
int callee_index = cpool->method_handle_klass_index_at(index);
ciKlass* callee = get_klass_by_index_impl(cpool, callee_index, ignore_will_link, accessor);

View File

@ -1716,9 +1716,32 @@ void LinkResolver::resolve_handle_call(CallInfo& result,
assert(resolved_klass == SystemDictionary::MethodHandle_klass() ||
resolved_klass == SystemDictionary::VarHandle_klass(), "");
assert(MethodHandles::is_signature_polymorphic_name(link_info.name()), "");
Handle resolved_appendix;
Method* resolved_method = lookup_polymorphic_method(link_info, &resolved_appendix, CHECK);
result.set_handle(resolved_klass, methodHandle(THREAD, resolved_method), resolved_appendix, CHECK);
Handle resolved_appendix;
Method* m = lookup_polymorphic_method(link_info, &resolved_appendix, CHECK);
methodHandle resolved_method(THREAD, m);
if (link_info.check_access()) {
Symbol* name = link_info.name();
vmIntrinsics::ID iid = MethodHandles::signature_polymorphic_name_id(name);
if (MethodHandles::is_signature_polymorphic_intrinsic(iid)) {
// Check if method can be accessed by the referring class.
// MH.linkTo* invocations are not rewritten to invokehandle.
assert(iid == vmIntrinsicID::_invokeBasic, "%s", vmIntrinsics::name_at(iid));
Klass* current_klass = link_info.current_klass();
assert(current_klass != NULL , "current_klass should not be null");
check_method_accessability(current_klass,
resolved_klass,
resolved_method->method_holder(),
resolved_method,
CHECK);
} else {
// Java code is free to arbitrarily link signature-polymorphic invokers.
assert(iid == vmIntrinsics::_invokeGeneric, "not an invoker: %s", vmIntrinsics::name_at(iid));
assert(MethodHandles::is_signature_polymorphic_public_name(resolved_klass, name), "not public");
}
}
result.set_handle(resolved_klass, resolved_method, resolved_appendix, CHECK);
}
void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHandle& pool, int indy_index, TRAPS) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2022, 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
@ -137,7 +137,7 @@ class HostPortrange {
}
this.ipv4 = this.literal = ipv4;
if (ipv4) {
byte[] ip = IPAddressUtil.textToNumericFormatV4(hoststr);
byte[] ip = IPAddressUtil.validateNumericFormatV4(hoststr);
if (ip == null) {
throw new IllegalArgumentException("illegal IPv4 address");
}

View File

@ -1103,7 +1103,11 @@ public class InetAddress implements java.io.Serializable {
private byte [] createAddressByteArray(String addrStr) {
byte[] addrArray;
// check if IPV4 address - most likely
addrArray = IPAddressUtil.textToNumericFormatV4(addrStr);
try {
addrArray = IPAddressUtil.validateNumericFormatV4(addrStr);
} catch (IllegalArgumentException iae) {
return null;
}
if (addrArray == null) {
addrArray = IPAddressUtil.textToNumericFormatV6(addrStr);
}
@ -1322,13 +1326,19 @@ public class InetAddress implements java.io.Serializable {
}
// if host is an IP address, we won't do further lookup
if (Character.digit(host.charAt(0), 16) != -1
if (IPAddressUtil.digit(host.charAt(0), 16) != -1
|| (host.charAt(0) == ':')) {
byte[] addr = null;
byte[] addr;
int numericZone = -1;
String ifname = null;
// see if it is IPv4 address
addr = IPAddressUtil.textToNumericFormatV4(host);
try {
addr = IPAddressUtil.validateNumericFormatV4(host);
} catch (IllegalArgumentException iae) {
var uhe = new UnknownHostException(host);
uhe.initCause(iae);
throw uhe;
}
if (addr == null) {
// This is supposed to be an IPv6 literal
// Check if a numeric or string zone id is present

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
@ -469,7 +469,7 @@ public final class SocketPermission extends Permission
if (!host.isEmpty()) {
// see if we are being initialized with an IP address.
char ch = host.charAt(0);
if (ch == ':' || Character.digit(ch, 16) != -1) {
if (ch == ':' || IPAddressUtil.digit(ch, 16) != -1) {
byte ip[] = IPAddressUtil.textToNumericFormatV4(host);
if (ip == null) {
ip = IPAddressUtil.textToNumericFormatV6(host);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022, 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
@ -30,6 +30,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import jdk.internal.org.xml.sax.InputSource;
@ -42,7 +43,11 @@ public abstract class Parser {
public static final String FAULT = "";
protected static final int BUFFSIZE_READER = 512;
// Initial buffer (mBuff) size
protected static final int BUFFSIZE_PARSER = 128;
// Max buffer size
private static final int MAX_ARRAY_SIZE = 1024 << 16;
/**
* The end of stream character.
*/
@ -525,6 +530,10 @@ public abstract class Parser {
mPh = PH_DTD; // DTD
for (short st = 0; st >= 0;) {
ch = getch();
// report error if EOS is reached while parsing the DTD
if (ch == EOS) {
panic(FAULT);
}
switch (st) {
case 0: // read the document type name
if (chtyp(ch) != ' ') {
@ -1664,6 +1673,10 @@ public abstract class Parser {
mBuffIdx = -1;
for (short st = 0; st >= 0;) {
ch = getch();
// report error if EOS is reached while parsing the DTD
if (ch == EOS) {
panic(FAULT);
}
switch (st) {
case 0: // the first '[' of the CDATA open
if (ch == '[') {
@ -1871,7 +1884,7 @@ public abstract class Parser {
}
/**
* Resoves an entity.
* Resolves an entity.
*
* This method resolves built-in and character entity references. It is also
* reports external entities to the application.
@ -2529,7 +2542,7 @@ public abstract class Parser {
}
/**
* Reads a single or double quotted string in to the buffer.
* Reads a single or double quoted string into the buffer.
*
* This method resolves entities inside a string unless the parser parses
* DTD.
@ -2664,7 +2677,7 @@ public abstract class Parser {
* @param ch The character to append to the buffer.
* @param mode The normalization mode.
*/
private void bappend(char ch, char mode) {
private void bappend(char ch, char mode) throws Exception {
// This implements attribute value normalization as
// described in the XML specification [#3.3.3].
switch (mode) {
@ -2714,16 +2727,9 @@ public abstract class Parser {
*
* @param ch The character to append to the buffer.
*/
private void bappend(char ch) {
try {
mBuff[++mBuffIdx] = ch;
} catch (Exception exp) {
// Double the buffer size
char buff[] = new char[mBuff.length << 1];
System.arraycopy(mBuff, 0, buff, 0, mBuff.length);
mBuff = buff;
mBuff[mBuffIdx] = ch;
}
private void bappend(char ch) throws Exception {
ensureCapacity(++mBuffIdx);
mBuff[mBuffIdx] = ch;
}
/**
@ -2733,14 +2739,9 @@ public abstract class Parser {
* @param cidx The character buffer (mChars) start index.
* @param bidx The parser buffer (mBuff) start index.
*/
private void bcopy(int cidx, int bidx) {
private void bcopy(int cidx, int bidx) throws Exception {
int length = mChIdx - cidx;
if ((bidx + length + 1) >= mBuff.length) {
// Expand the buffer
char buff[] = new char[mBuff.length + length];
System.arraycopy(mBuff, 0, buff, 0, mBuff.length);
mBuff = buff;
}
ensureCapacity(bidx + length + 1);
System.arraycopy(mChars, cidx, mBuff, bidx, length);
mBuffIdx += length;
}
@ -3327,7 +3328,7 @@ public abstract class Parser {
}
/**
* Retrives the next character in the document.
* Retrieves the next character in the document.
*
* @return The next character in the document.
*/
@ -3433,4 +3434,23 @@ public abstract class Parser {
return next;
}
private void ensureCapacity(int minCapacity) throws Exception {
if (mBuff == null) {
int newCapacity = minCapacity > BUFFSIZE_PARSER ?
minCapacity + BUFFSIZE_PARSER : BUFFSIZE_PARSER;
mBuff = new char[newCapacity];
return;
}
if (mBuff.length <= minCapacity) {
int size = mBuff.length << 1;
int newCapacity = size > minCapacity ? size : minCapacity + BUFFSIZE_PARSER;
if (newCapacity < 0 || newCapacity > MAX_ARRAY_SIZE) {
panic(FAULT);
}
mBuff = Arrays.copyOf(mBuff, newCapacity);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2022, 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
@ -25,7 +25,8 @@
package sun.net.util;
import java.io.IOException;
import sun.security.action.GetPropertyAction;
import java.io.UncheckedIOException;
import java.net.Inet6Address;
import java.net.InetAddress;
@ -33,6 +34,7 @@ import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.nio.CharBuffer;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
@ -101,7 +103,7 @@ public class IPAddressUtil {
tmpValue = 0;
newOctet = true;
} else {
int digit = Character.digit(c, 10);
int digit = digit(c, 10);
if (digit < 0) {
return null;
}
@ -126,6 +128,29 @@ public class IPAddressUtil {
return res;
}
/**
* Validates if input string is a valid IPv4 address literal.
* If the "jdk.net.allowAmbiguousIPAddressLiterals" system property is set
* to {@code false}, or is not set then validation of the address string is performed as follows:
* If string can't be parsed by following IETF IPv4 address string literals
* formatting style rules (default one), but can be parsed by following BSD formatting
* style rules, the IPv4 address string content is treated as ambiguous and
* {@code IllegalArgumentException} is thrown.
*
* @param src input string
* @return bytes array if string is a valid IPv4 address string
* @throws IllegalArgumentException if "jdk.net.allowAmbiguousIPAddressLiterals" SP is set to
* "false" and IPv4 address string {@code "src"} is ambiguous
*/
public static byte[] validateNumericFormatV4(String src) {
byte[] parsedBytes = textToNumericFormatV4(src);
if (!ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE
&& parsedBytes == null && isBsdParsableV4(src)) {
throw new IllegalArgumentException("Invalid IP address literal: " + src);
}
return parsedBytes;
}
/*
* Convert IPv6 presentation level address to network order binary form.
* credit:
@ -171,7 +196,7 @@ public class IPAddressUtil {
val = 0;
while (i < srcb_length) {
ch = srcb[i++];
int chval = Character.digit(ch, 16);
int chval = digit(ch, 16);
if (chval != -1) {
val <<= 4;
val |= chval;
@ -551,4 +576,245 @@ public class IPAddressUtil {
}
return null;
}
/**
* Returns the numeric value of the character {@code ch} in the
* specified radix.
*
* @param ch the character to be converted.
* @param radix the radix.
* @return the numeric value represented by the character in the
* specified radix.
*/
public static int digit(char ch, int radix) {
if (ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE) {
return Character.digit(ch, radix);
} else {
return parseAsciiDigit(ch, radix);
}
}
/**
* Try to parse String as IPv4 address literal by following
* BSD-style formatting rules.
*
* @param input input string
* @return {@code true} if input string is parsable as IPv4 address literal,
* {@code false} otherwise.
*/
public static boolean isBsdParsableV4(String input) {
char firstSymbol = input.charAt(0);
// Check if first digit is not a decimal digit
if (parseAsciiDigit(firstSymbol, DECIMAL) == -1) {
return false;
}
// Last character is dot OR is not a supported digit: [0-9,A-F,a-f]
char lastSymbol = input.charAt(input.length() - 1);
if (lastSymbol == '.' || parseAsciiHexDigit(lastSymbol) == -1) {
return false;
}
// Parse IP address fields
CharBuffer charBuffer = CharBuffer.wrap(input);
int fieldNumber = 0;
while (charBuffer.hasRemaining()) {
long fieldValue = -1L;
// Try to parse fields in all supported radixes
for (int radix : SUPPORTED_RADIXES) {
fieldValue = parseV4FieldBsd(radix, charBuffer, fieldNumber);
if (fieldValue >= 0) {
fieldNumber++;
break;
} else if (fieldValue == TERMINAL_PARSE_ERROR) {
return false;
}
}
// If field can't be parsed as one of supported radixes stop
// parsing
if (fieldValue < 0) {
return false;
}
}
return true;
}
/**
* Method tries to parse IP address field that starts from {@linkplain CharBuffer#position()
* current position} of the provided character buffer.
* <p>
* This method supports three {@code "radix"} values to decode field values in
* {@code "HEXADECIMAL (radix=16)"}, {@code "DECIMAL (radix=10)"} and
* {@code "OCTAL (radix=8)"} radixes.
* <p>
* If {@code -1} value is returned the char buffer position is reset to the value
* it was before it was called.
* <p>
* Method returns {@code -2} if formatting illegal for all supported {@code radix}
* values is observed, and there is no point in checking other radix values.
* That includes the following cases:<ul>
* <li>Two subsequent dots are observer
* <li>Number of dots more than 3
* <li>Field value exceeds max allowed
* <li>Character is not a valid digit for the requested {@code radix} value, given
* that a field has the radix specific prefix
* </ul>
*
* @param radix digits encoding radix to use for parsing. Valid values: 8, 10, 16.
* @param buffer {@code CharBuffer} with position set to the field's fist character
* @param fieldNumber parsed field number
* @return {@code CANT_PARSE_IN_RADIX} if field can not be parsed in requested {@code radix}.
* {@code TERMINAL_PARSE_ERROR} if field can't be parsed and the whole parse process should be terminated.
* Parsed field value otherwise.
*/
private static long parseV4FieldBsd(int radix, CharBuffer buffer, int fieldNumber) {
int initialPos = buffer.position();
long val = 0;
int digitsCount = 0;
if (!checkPrefix(buffer, radix)) {
val = CANT_PARSE_IN_RADIX;
}
boolean dotSeen = false;
while (buffer.hasRemaining() && val != CANT_PARSE_IN_RADIX && !dotSeen) {
char c = buffer.get();
if (c == '.') {
dotSeen = true;
// Fail if 4 dots in IP address string.
// fieldNumber counter starts from 0, therefore 3
if (fieldNumber == 3) {
// Terminal state, can stop parsing: too many fields
return TERMINAL_PARSE_ERROR;
}
// Check for literals with two dots, like '1.2..3', '1.2.3..'
if (digitsCount == 0) {
// Terminal state, can stop parsing: dot with no digits
return TERMINAL_PARSE_ERROR;
}
if (val > 255) {
// Terminal state, can stop parsing: too big value for an octet
return TERMINAL_PARSE_ERROR;
}
} else {
int dv = parseAsciiDigit(c, radix);
if (dv >= 0) {
digitsCount++;
val *= radix;
val += dv;
} else {
// Spotted digit can't be parsed in the requested 'radix'.
// The order in which radixes are checked - hex, octal, decimal:
// - if symbol is not a valid digit in hex radix - terminal
// - if symbol is not a valid digit in octal radix, and given
// that octal prefix was observed before - terminal
// - if symbol is not a valid digit in decimal radix - terminal
return TERMINAL_PARSE_ERROR;
}
}
}
if (val == CANT_PARSE_IN_RADIX) {
buffer.position(initialPos);
} else if (!dotSeen) {
// It is the last field - check its value
// This check will ensure that address strings with less
// than 4 fields, i.e. A, A.B and A.B.C address types
// contain value less then the allowed maximum for the last field.
long maxValue = (1L << ((4 - fieldNumber) * 8)) - 1;
if (val > maxValue) {
// Terminal state, can stop parsing: last field value exceeds its
// allowed value
return TERMINAL_PARSE_ERROR;
}
}
return val;
}
// This method moves the position of the supplied CharBuffer by analysing the digit prefix
// symbols if any.
// The caller should reset the position when method returns false.
private static boolean checkPrefix(CharBuffer buffer, int radix) {
return switch (radix) {
case OCTAL -> isOctalFieldStart(buffer);
case DECIMAL -> isDecimalFieldStart(buffer);
case HEXADECIMAL -> isHexFieldStart(buffer);
default -> throw new AssertionError("Not supported radix");
};
}
// This method always moves the position of the supplied CharBuffer
// removing the octal prefix symbols '0'.
// The caller should reset the position when method returns false.
private static boolean isOctalFieldStart(CharBuffer cb) {
// .0<EOS> is not treated as octal field
if (cb.remaining() < 2) {
return false;
}
// Fetch two first characters
int position = cb.position();
char first = cb.get();
char second = cb.get();
// Return false if the first char is not octal prefix '0' or second is a
// field separator - parseV4FieldBsd will reset position to start of the field.
// '.0.' fields will be successfully parsed in decimal radix.
boolean isOctalPrefix = first == '0' && second != '.';
// If the prefix looks like octal - consume '0', otherwise 'false' is returned
// and caller will reset the buffer position.
if (isOctalPrefix) {
cb.position(position + 1);
}
return isOctalPrefix;
}
// This method doesn't move the position of the supplied CharBuffer
private static boolean isDecimalFieldStart(CharBuffer cb) {
return cb.hasRemaining();
}
// This method always moves the position of the supplied CharBuffer
// removing the hexadecimal prefix symbols '0x'.
// The caller should reset the position when method returns false.
private static boolean isHexFieldStart(CharBuffer cb) {
if (cb.remaining() < 2) {
return false;
}
char first = cb.get();
char second = cb.get();
return first == '0' && (second == 'x' || second == 'X');
}
// Parse ASCII digit in given radix
private static int parseAsciiDigit(char c, int radix) {
assert radix == OCTAL || radix == DECIMAL || radix == HEXADECIMAL;
if (radix == HEXADECIMAL) {
return parseAsciiHexDigit(c);
}
int val = c - '0';
return (val < 0 || val >= radix) ? -1 : val;
}
// Parse ASCII digit in hexadecimal radix
private static int parseAsciiHexDigit(char digit) {
char c = Character.toLowerCase(digit);
if (c >= 'a' && c <= 'f') {
return c - 'a' + 10;
}
return parseAsciiDigit(c, DECIMAL);
}
// Supported radixes
private static final int HEXADECIMAL = 16;
private static final int DECIMAL = 10;
private static final int OCTAL = 8;
// Order in which field formats are exercised to parse one IP address textual field
private static final int[] SUPPORTED_RADIXES = new int[]{HEXADECIMAL, OCTAL, DECIMAL};
// BSD parser's return values
private final static long CANT_PARSE_IN_RADIX = -1L;
private final static long TERMINAL_PARSE_ERROR = -2L;
private static final String ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP = "jdk.net.allowAmbiguousIPAddressLiterals";
private static final boolean ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE = Boolean.valueOf(
GetPropertyAction.privilegedGetProperty(ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP, "false"));
}

View File

@ -63,22 +63,32 @@ public class BitArray {
repn = new byte[(length + BITS_PER_UNIT - 1)/BITS_PER_UNIT];
}
/**
* Creates a BitArray of the specified size, initialized from the
* specified byte array. The most significant bit of {@code a[0]} gets
* index zero in the BitArray. The array must be large enough to specify
* a value for every bit of the BitArray. i.e. {@code 8*a.length <= length}.
*/
public BitArray(int length, byte[] a) throws IllegalArgumentException {
this(length, a, 0);
}
/**
* Creates a BitArray of the specified size, initialized from the
* specified byte array. The most significant bit of {@code a[0]} gets
* index zero in the BitArray. The array a must be large enough
* to specify a value for every bit in the BitArray. In other words,
* {@code 8*a.length <= length}.
* specified byte array starting at the specified offset. The most
* significant bit of {@code a[ofs]} gets index zero in the BitArray.
* The array must be large enough to specify a value for every bit of
* the BitArray, i.e. {@code 8*(a.length - ofs) <= length}.
*/
public BitArray(int length, byte[] a) throws IllegalArgumentException {
public BitArray(int length, byte[] a, int ofs)
throws IllegalArgumentException {
if (length < 0) {
throw new IllegalArgumentException("Negative length for BitArray");
}
if (a.length * BITS_PER_UNIT < length) {
throw new IllegalArgumentException("Byte array too short to represent " +
"bit array of given length");
if ((a.length - ofs) * BITS_PER_UNIT < length) {
throw new IllegalArgumentException
("Byte array too short to represent " + length + "-bit array");
}
this.length = length;
@ -93,7 +103,7 @@ public class BitArray {
2. zero out extra bits in the last byte
*/
repn = new byte[repLength];
System.arraycopy(a, 0, repn, 0, repLength);
System.arraycopy(a, ofs, repn, 0, repLength);
if (repLength > 0) {
repn[repLength - 1] &= bitMask;
}
@ -270,7 +280,7 @@ public class BitArray {
public BitArray truncate() {
for (int i=length-1; i>=0; i--) {
if (get(i)) {
return new BitArray(i+1, Arrays.copyOf(repn, (i + BITS_PER_UNIT)/BITS_PER_UNIT));
return new BitArray(i+1, repn, 0);
}
}
return new BitArray(1);

View File

@ -189,6 +189,28 @@ class DerInputBuffer extends ByteArrayInputStream implements Cloneable {
return result.intValue();
}
// check the number of pad bits, validate the pad bits in the bytes
// if enforcing DER (i.e. allowBER == false), and return the number of
// bits of the resulting BitString
private static int checkPaddedBits(int numOfPadBits, byte[] data, int start,
int end, boolean allowBER) throws IOException {
// number of pad bits should be from 0(min) to 7(max).
if ((numOfPadBits < 0) || (numOfPadBits > 7)) {
throw new IOException("Invalid number of padding bits");
}
int lenInBits = ((end - start) << 3) - numOfPadBits;
if (lenInBits < 0) {
throw new IOException("Not enough bytes in BitString");
}
// padding bits should be all zeros for DER
if (!allowBER && numOfPadBits != 0 &&
(data[end - 1] & (0xff >>> (8 - numOfPadBits))) != 0) {
throw new IOException("Invalid value of padding bits");
}
return lenInBits;
}
/**
* Returns the bit string which takes up the specified
* number of bytes in this buffer.
@ -201,18 +223,20 @@ class DerInputBuffer extends ByteArrayInputStream implements Cloneable {
throw new IOException("Invalid encoding: zero length bit string");
}
int numOfPadBits = buf[pos];
if ((numOfPadBits < 0) || (numOfPadBits > 7)) {
throw new IOException("Invalid number of padding bits");
}
int start = pos;
int end = start + len;
skip(len); // Compatibility.
int numOfPadBits = buf[start++];
checkPaddedBits(numOfPadBits, buf, start, end, allowBER);
// minus the first byte which indicates the number of padding bits
byte[] retval = new byte[len - 1];
System.arraycopy(buf, pos + 1, retval, 0, len - 1);
if (numOfPadBits != 0) {
// get rid of the padding bits
retval[len - 2] &= (0xff << numOfPadBits);
System.arraycopy(buf, start, retval, 0, len - 1);
if (allowBER && numOfPadBits != 0) {
// fix the potential non-zero padding bits
retval[retval.length - 1] &= (0xff << numOfPadBits);
}
skip(len);
return retval;
}
@ -228,26 +252,35 @@ class DerInputBuffer extends ByteArrayInputStream implements Cloneable {
* The bit string need not be byte-aligned.
*/
BitArray getUnalignedBitString() throws IOException {
return getUnalignedBitString(available());
}
/**
* Returns the bit string which takes up the specified
* number of bytes in this buffer.
* The bit string need not be byte-aligned.
*/
BitArray getUnalignedBitString(int len) throws IOException {
if (len > available())
throw new IOException("short read of bit string");
if (len == 0) {
throw new IOException("Invalid encoding: zero length bit string");
}
if (pos >= count)
return null;
/*
* Just copy the data into an aligned, padded octet buffer,
* and consume the rest of the buffer.
*/
int len = available();
int unusedBits = buf[pos] & 0xff;
if (unusedBits > 7 ) {
throw new IOException("Invalid value for unused bits: " + unusedBits);
}
byte[] bits = new byte[len - 1];
// number of valid bits
int length = (bits.length == 0) ? 0 : bits.length * 8 - unusedBits;
System.arraycopy(buf, pos + 1, bits, 0, len - 1);
BitArray bitArray = new BitArray(length, bits);
pos = count;
return bitArray;
int start = pos;
int end = start + len;
pos = count; // Compatibility.
int numOfPadBits = buf[start++];
int lenInBits = checkPaddedBits(numOfPadBits, buf, start,
end, allowBER);
return new BitArray(lenInBits, buf, start);
}
/**

View File

@ -264,27 +264,7 @@ public class DerInputStream {
return new BitArray(0);
}
/*
* First byte = number of excess bits in the last octet of the
* representation.
*/
length--;
int excessBits = buffer.read();
if (excessBits < 0) {
throw new IOException("Unused bits of bit string invalid");
}
int validBits = length*8 - excessBits;
if (validBits < 0) {
throw new IOException("Valid bits of bit string invalid");
}
byte[] repn = new byte[length];
if ((length != 0) && (buffer.read(repn) != length)) {
throw new IOException("Short read of DER bit string");
}
return new BitArray(validBits, repn);
return buffer.getUnalignedBitString(length);
}
/**

View File

@ -276,11 +276,6 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
int wrap = 1;
static const char my_version[] = ZLIB_VERSION;
ushf *overlay;
/* We overlay pending_buf and d_buf+l_buf. This works since the average
* output size for (length,distance) codes is <= 24 bits.
*/
if (version == Z_NULL || version[0] != my_version[0] ||
stream_size != sizeof(z_stream)) {
return Z_VERSION_ERROR;
@ -350,9 +345,47 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
s->pending_buf = (uchf *) overlay;
s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
/* We overlay pending_buf and sym_buf. This works since the average size
* for length/distance pairs over any compressed block is assured to be 31
* bits or less.
*
* Analysis: The longest fixed codes are a length code of 8 bits plus 5
* extra bits, for lengths 131 to 257. The longest fixed distance codes are
* 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest
* possible fixed-codes length/distance pair is then 31 bits total.
*
* sym_buf starts one-fourth of the way into pending_buf. So there are
* three bytes in sym_buf for every four bytes in pending_buf. Each symbol
* in sym_buf is three bytes -- two for the distance and one for the
* literal/length. As each symbol is consumed, the pointer to the next
* sym_buf value to read moves forward three bytes. From that symbol, up to
* 31 bits are written to pending_buf. The closest the written pending_buf
* bits gets to the next sym_buf symbol to read is just before the last
* code is written. At that time, 31*(n-2) bits have been written, just
* after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at
* 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1
* symbols are written.) The closest the writing gets to what is unread is
* then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and
* can range from 128 to 32768.
*
* Therefore, at a minimum, there are 142 bits of space between what is
* written and what is read in the overlain buffers, so the symbols cannot
* be overwritten by the compressed data. That space is actually 139 bits,
* due to the three-bit fixed-code block header.
*
* That covers the case where either Z_FIXED is specified, forcing fixed
* codes, or when the use of fixed codes is chosen, because that choice
* results in a smaller compressed block than dynamic codes. That latter
* condition then assures that the above analysis also covers all dynamic
* blocks. A dynamic-code block will only be chosen to be emitted if it has
* fewer bits than a fixed-code block would for the same set of symbols.
* Therefore its average symbol length is assured to be less than 31. So
* the compressed data for a dynamic block also cannot overwrite the
* symbols from which it is being constructed.
*/
s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4);
s->pending_buf_size = (ulg)s->lit_bufsize * 4;
if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
s->pending_buf == Z_NULL) {
@ -361,8 +394,12 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
deflateEnd (strm);
return Z_MEM_ERROR;
}
s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
s->sym_buf = s->pending_buf + s->lit_bufsize;
s->sym_end = (s->lit_bufsize - 1) * 3;
/* We avoid equality with lit_bufsize*3 because of wraparound at 64K
* on 16 bit machines and because stored blocks are restricted to
* 64K-1 bytes.
*/
s->level = level;
s->strategy = strategy;
@ -573,7 +610,8 @@ int ZEXPORT deflatePrime (strm, bits, value)
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
s = strm->state;
if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))
if (bits < 0 || bits > 16 ||
s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3))
return Z_BUF_ERROR;
do {
put = Buf_size - s->bi_valid;
@ -1132,7 +1170,6 @@ int ZEXPORT deflateCopy (dest, source)
#else
deflate_state *ds;
deflate_state *ss;
ushf *overlay;
if (deflateStateCheck(source) || dest == Z_NULL) {
@ -1152,8 +1189,7 @@ int ZEXPORT deflateCopy (dest, source)
ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
ds->pending_buf = (uchf *) overlay;
ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4);
if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
ds->pending_buf == Z_NULL) {
@ -1167,8 +1203,7 @@ int ZEXPORT deflateCopy (dest, source)
zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
ds->sym_buf = ds->pending_buf + ds->lit_bufsize;
ds->l_desc.dyn_tree = ds->dyn_ltree;
ds->d_desc.dyn_tree = ds->dyn_dtree;
@ -1936,7 +1971,7 @@ local block_state deflate_fast(s, flush)
FLUSH_BLOCK(s, 1);
return finish_done;
}
if (s->last_lit)
if (s->sym_next)
FLUSH_BLOCK(s, 0);
return block_done;
}
@ -2067,7 +2102,7 @@ local block_state deflate_slow(s, flush)
FLUSH_BLOCK(s, 1);
return finish_done;
}
if (s->last_lit)
if (s->sym_next)
FLUSH_BLOCK(s, 0);
return block_done;
}
@ -2142,7 +2177,7 @@ local block_state deflate_rle(s, flush)
FLUSH_BLOCK(s, 1);
return finish_done;
}
if (s->last_lit)
if (s->sym_next)
FLUSH_BLOCK(s, 0);
return block_done;
}
@ -2181,7 +2216,7 @@ local block_state deflate_huff(s, flush)
FLUSH_BLOCK(s, 1);
return finish_done;
}
if (s->last_lit)
if (s->sym_next)
FLUSH_BLOCK(s, 0);
return block_done;
}

View File

@ -241,7 +241,7 @@ typedef struct internal_state {
/* Depth of each subtree used as tie breaker for trees of equal frequency
*/
uchf *l_buf; /* buffer for literals or lengths */
uchf *sym_buf; /* buffer for distances and literals/lengths */
uInt lit_bufsize;
/* Size of match buffer for literals/lengths. There are 4 reasons for
@ -263,13 +263,8 @@ typedef struct internal_state {
* - I can't count above 4
*/
uInt last_lit; /* running index in l_buf */
ushf *d_buf;
/* Buffer for distances. To simplify the code, d_buf and l_buf have
* the same number of elements. To use different lengths, an extra flag
* array would be necessary.
*/
uInt sym_next; /* running index in sym_buf */
uInt sym_end; /* symbol table full when sym_next reaches this */
ulg opt_len; /* bit length of current block with optimal trees */
ulg static_len; /* bit length of current block with static trees */
@ -349,20 +344,22 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
# define _tr_tally_lit(s, c, flush) \
{ uch cc = (c); \
s->d_buf[s->last_lit] = 0; \
s->l_buf[s->last_lit++] = cc; \
s->sym_buf[s->sym_next++] = 0; \
s->sym_buf[s->sym_next++] = 0; \
s->sym_buf[s->sym_next++] = cc; \
s->dyn_ltree[cc].Freq++; \
flush = (s->last_lit == s->lit_bufsize-1); \
flush = (s->sym_next == s->sym_end); \
}
# define _tr_tally_dist(s, distance, length, flush) \
{ uch len = (uch)(length); \
ush dist = (ush)(distance); \
s->d_buf[s->last_lit] = dist; \
s->l_buf[s->last_lit++] = len; \
s->sym_buf[s->sym_next++] = (uch)dist; \
s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \
s->sym_buf[s->sym_next++] = len; \
dist--; \
s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
s->dyn_dtree[d_code(dist)].Freq++; \
flush = (s->last_lit == s->lit_bufsize-1); \
flush = (s->sym_next == s->sym_end); \
}
#else
# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)

View File

@ -440,7 +440,7 @@ local void init_block(s)
s->dyn_ltree[END_BLOCK].Freq = 1;
s->opt_len = s->static_len = 0L;
s->last_lit = s->matches = 0;
s->sym_next = s->matches = 0;
}
#define SMALLEST 1
@ -971,7 +971,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
s->last_lit));
s->sym_next / 3));
if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
@ -1040,8 +1040,9 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc)
unsigned dist; /* distance of matched string */
unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
{
s->d_buf[s->last_lit] = (ush)dist;
s->l_buf[s->last_lit++] = (uch)lc;
s->sym_buf[s->sym_next++] = (uch)dist;
s->sym_buf[s->sym_next++] = (uch)(dist >> 8);
s->sym_buf[s->sym_next++] = (uch)lc;
if (dist == 0) {
/* lc is the unmatched char */
s->dyn_ltree[lc].Freq++;
@ -1056,30 +1057,7 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc)
s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
s->dyn_dtree[d_code(dist)].Freq++;
}
#ifdef TRUNCATE_BLOCK
/* Try to guess if it is profitable to stop the current block here */
if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
/* Compute an upper bound for the compressed length */
ulg out_length = (ulg)s->last_lit*8L;
ulg in_length = (ulg)((long)s->strstart - s->block_start);
int dcode;
for (dcode = 0; dcode < D_CODES; dcode++) {
out_length += (ulg)s->dyn_dtree[dcode].Freq *
(5L+extra_dbits[dcode]);
}
out_length >>= 3;
Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
s->last_lit, in_length, out_length,
100L - out_length*100L/in_length));
if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
}
#endif
return (s->last_lit == s->lit_bufsize-1);
/* We avoid equality with lit_bufsize because of wraparound at 64K
* on 16 bit machines and because stored blocks are restricted to
* 64K-1 bytes.
*/
return (s->sym_next == s->sym_end);
}
/* ===========================================================================
@ -1092,13 +1070,14 @@ local void compress_block(s, ltree, dtree)
{
unsigned dist; /* distance of matched string */
int lc; /* match length or unmatched char (if dist == 0) */
unsigned lx = 0; /* running index in l_buf */
unsigned sx = 0; /* running index in sym_buf */
unsigned code; /* the code to send */
int extra; /* number of extra bits to send */
if (s->last_lit != 0) do {
dist = s->d_buf[lx];
lc = s->l_buf[lx++];
if (s->sym_next != 0) do {
dist = s->sym_buf[sx++] & 0xff;
dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8;
lc = s->sym_buf[sx++];
if (dist == 0) {
send_code(s, lc, ltree); /* send a literal byte */
Tracecv(isgraph(lc), (stderr," '%c' ", lc));
@ -1123,11 +1102,10 @@ local void compress_block(s, ltree, dtree)
}
} /* literal or match pair ? */
/* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
"pendingBuf overflow");
/* Check that the overlay between pending_buf and sym_buf is ok: */
Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");
} while (lx < s->last_lit);
} while (sx < s->sym_next);
send_code(s, END_BLOCK, ltree);
}

View File

@ -380,6 +380,11 @@ final class SMFParser {
case 0xF7:
// sys ex
int sysexLength = (int) readVarInt();
if (sysexLength < 0 || sysexLength > trackLength - pos) {
throw new InvalidMidiDataException("Message length is out of bounds: "
+ sysexLength);
}
byte[] sysexData = new byte[sysexLength];
read(sysexData);
@ -392,8 +397,8 @@ final class SMFParser {
// meta
int metaType = readUnsigned();
int metaLength = (int) readVarInt();
if (metaLength < 0) {
throw new InvalidMidiDataException("length out of bounds: "
if (metaLength < 0 || metaLength > trackLength - pos) {
throw new InvalidMidiDataException("Message length is out of bounds: "
+ metaLength);
}
final byte[] metaData;

View File

@ -1,6 +1,5 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -26,6 +25,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
/**
* This class represents the constant pool, i.e., a table of constants, of
@ -37,6 +37,7 @@ import com.sun.org.apache.bcel.internal.Const;
* @see Constant
* @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen
* @LastModified: May 2022
*/
public class ConstantPool implements Cloneable, Node {
@ -222,8 +223,16 @@ public class ConstantPool implements Cloneable, Node {
* @throws IOException
*/
public void dump( final DataOutputStream file ) throws IOException {
file.writeShort(constantPool.length);
for (int i = 1; i < constantPool.length; i++) {
/*
* Constants over the size of the constant pool shall not be written out.
* This is a redundant measure as the ConstantPoolGen should have already
* reported an error back in the situation.
*/
int size = constantPool.length < ConstantPoolGen.CONSTANT_POOL_SIZE - 1 ?
constantPool.length : ConstantPoolGen.CONSTANT_POOL_SIZE - 1;
file.writeShort(size);
for (int i = 1; i < size; i++) {
if (constantPool[i] != null) {
constantPool[i].dump(file);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -50,10 +50,10 @@ import com.sun.org.apache.bcel.internal.classfile.ConstantUtf8;
* JVM and that Double and Long constants need two slots.
*
* @see Constant
* @LastModified: May 2021
* @LastModified: May 2022
*/
public class ConstantPoolGen {
public static final int CONSTANT_POOL_SIZE = 65536;
private static final int DEFAULT_BUFFER_SIZE = 256;
private int size;
private Constant[] constants;
@ -83,7 +83,7 @@ public class ConstantPoolGen {
public ConstantPoolGen(final Constant[] cs) {
final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_SIZE);
size = Math.max(DEFAULT_BUFFER_SIZE, cs.length + 64);
size = Math.min(Math.max(DEFAULT_BUFFER_SIZE, cs.length + 64), CONSTANT_POOL_SIZE);
constants = new Constant[size];
System.arraycopy(cs, 0, constants, 0, cs.length);
@ -212,9 +212,18 @@ public class ConstantPoolGen {
/** Resize internal array of constants.
*/
protected void adjustSize() {
// 3 extra spaces are needed as some entries may take 3 slots
if (index + 3 >= CONSTANT_POOL_SIZE) {
throw new RuntimeException("The number of constants " + (index + 3)
+ " is over the size of the constant pool: "
+ (CONSTANT_POOL_SIZE - 1));
}
if (index + 3 >= size) {
final Constant[] cs = constants;
size *= 2;
// the constant array shall not exceed the size of the constant pool
size = Math.min(size, CONSTANT_POOL_SIZE);
constants = new Constant[size];
System.arraycopy(cs, 0, constants, 0, index);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2021, 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
@ -26,52 +26,83 @@
* @bug 4511556
* @summary Verify BitString value containing padding bits is accepted.
* @modules java.base/sun.security.util
* @library /test/lib
*/
import java.io.*;
import java.util.Arrays;
import java.math.BigInteger;
import java.util.Arrays;
import jdk.test.lib.Asserts;
import jdk.test.lib.Utils;
import jdk.test.lib.hexdump.HexPrinter;
import sun.security.util.BitArray;
import sun.security.util.DerInputStream;
public class PaddedBitString {
// Relaxed the BitString parsing routine to accept bit strings
// with padding bits, ex. treat DER_BITSTRING_PAD6 as the same
// bit string as DER_BITSTRING_NOPAD.
// with padding bits, ex. treat DER_BITSTRING_PAD6_b as the same
// bit string as DER_BITSTRING_PAD6_0/DER_BITSTRING_NOPAD.
// Note:
// 1. the number of padding bits has to be in [0...7]
// 2. value of the padding bits is ignored
// bit string (01011101 11000000)
// With 6 padding bits (01011101 11001011)
private final static byte[] DER_BITSTRING_PAD6 = { 3, 3, 6,
(byte)0x5d, (byte)0xcb };
// With no padding bits
private final static byte[] DER_BITSTRING_NOPAD = { 3, 3, 0,
(byte)0x5d, (byte)0xc0 };
// With 6 zero padding bits (01011101 11000000)
private final static byte[] DER_BITSTRING_PAD6_0 = { 3, 3, 6,
(byte)0x5d, (byte)0xc0 };
// With 6 nonzero padding bits (01011101 11001011)
private final static byte[] DER_BITSTRING_PAD6_b = { 3, 3, 6,
(byte)0x5d, (byte)0xcb };
// With 8 padding bits
private final static byte[] DER_BITSTRING_PAD8_0 = { 3, 3, 8,
(byte)0x5d, (byte)0xc0 };
private final static byte[] BITS = { (byte)0x5d, (byte)0xc0 };
static enum Type {
BIT_STRING,
UNALIGNED_BIT_STRING;
}
public static void main(String args[]) throws Exception {
byte[] ba0, ba1;
try {
DerInputStream derin = new DerInputStream(DER_BITSTRING_PAD6);
ba1 = derin.getBitString();
} catch( IOException e ) {
e.printStackTrace();
throw new Exception("Unable to parse BitString with 6 padding bits");
}
test(DER_BITSTRING_NOPAD, new BitArray(16, BITS));
test(DER_BITSTRING_PAD6_0, new BitArray(10, BITS));
test(DER_BITSTRING_PAD6_b, new BitArray(10, BITS));
test(DER_BITSTRING_PAD8_0, null);
System.out.println("Tests Passed");
}
try {
DerInputStream derin = new DerInputStream(DER_BITSTRING_NOPAD);
ba0 = derin.getBitString();
} catch( IOException e ) {
e.printStackTrace();
throw new Exception("Unable to parse BitString with no padding");
}
if (Arrays.equals(ba1, ba0) == false ) {
throw new Exception("BitString comparison check failed");
private static void test(byte[] in, BitArray ans) throws IOException {
System.out.println("Testing " +
HexPrinter.minimal().toString(in));
for (Type t : Type.values()) {
DerInputStream derin = new DerInputStream(in);
boolean shouldPass = (ans != null);
switch (t) {
case BIT_STRING:
if (shouldPass) {
Asserts.assertTrue(Arrays.equals(ans.toByteArray(),
derin.getBitString()));
} else {
Utils.runAndCheckException(() -> derin.getBitString(),
IOException.class);
}
break;
case UNALIGNED_BIT_STRING:
if (shouldPass) {
Asserts.assertEQ(ans, derin.getUnalignedBitString());
} else {
Utils.runAndCheckException(() ->
derin.getUnalignedBitString(), IOException.class);
}
break;
}
}
}
}