Merge
This commit is contained in:
commit
87d92f70f4
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2017, 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
|
||||
@ -471,7 +471,7 @@ class Properties extends Hashtable<Object,Object> {
|
||||
if (inStream != null) {
|
||||
//The line below is equivalent to calling a
|
||||
//ISO8859-1 decoder.
|
||||
c = (char) (0xff & inByteBuf[inOff++]);
|
||||
c = (char)(inByteBuf[inOff++] & 0xFF);
|
||||
} else {
|
||||
c = inCharBuf[inOff++];
|
||||
}
|
||||
@ -494,8 +494,25 @@ class Properties extends Hashtable<Object,Object> {
|
||||
if (isNewLine) {
|
||||
isNewLine = false;
|
||||
if (c == '#' || c == '!') {
|
||||
// Comment, quickly consume the rest of the line,
|
||||
// resume on line-break and backslash.
|
||||
if (inStream != null) {
|
||||
while (inOff < inLimit) {
|
||||
byte b = inByteBuf[inOff++];
|
||||
if (b == '\n' || b == '\r' || b == '\\') {
|
||||
c = (char)(b & 0xFF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (inOff < inLimit) {
|
||||
c = inCharBuf[inOff++];
|
||||
if (c == '\n' || c == '\r' || c == '\\') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
isCommentLine = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,27 +249,20 @@ public class BasicImageReader implements AutoCloseable {
|
||||
return stringsReader;
|
||||
}
|
||||
|
||||
public ImageLocation findLocation(String mn, String rn) {
|
||||
Objects.requireNonNull(mn);
|
||||
Objects.requireNonNull(rn);
|
||||
|
||||
return findLocation("/" + mn + "/" + rn);
|
||||
}
|
||||
|
||||
public synchronized ImageLocation findLocation(String name) {
|
||||
public synchronized ImageLocation findLocation(String module, String name) {
|
||||
Objects.requireNonNull(module);
|
||||
Objects.requireNonNull(name);
|
||||
// Details of the algorithm used here can be found in
|
||||
// jdk.tools.jlink.internal.PerfectHashBuilder.
|
||||
byte[] bytes = ImageStringsReader.mutf8FromString(name);
|
||||
int count = header.getTableLength();
|
||||
int index = redirect.get(ImageStringsReader.hashCode(bytes) % count);
|
||||
int index = redirect.get(ImageStringsReader.hashCode(module, name) % count);
|
||||
|
||||
if (index < 0) {
|
||||
// index is twos complement of location attributes index.
|
||||
index = -index - 1;
|
||||
} else if (index > 0) {
|
||||
// index is hash seed needed to compute location attributes index.
|
||||
index = ImageStringsReader.hashCode(bytes, index) % count;
|
||||
index = ImageStringsReader.hashCode(module, name, index) % count;
|
||||
} else {
|
||||
// No entry.
|
||||
return null;
|
||||
@ -277,13 +270,36 @@ public class BasicImageReader implements AutoCloseable {
|
||||
|
||||
long[] attributes = getAttributes(offsets.get(index));
|
||||
|
||||
ImageLocation imageLocation = new ImageLocation(attributes, stringsReader);
|
||||
if (!ImageLocation.verify(module, name, attributes, stringsReader)) {
|
||||
return null;
|
||||
}
|
||||
return new ImageLocation(attributes, stringsReader);
|
||||
}
|
||||
|
||||
if (!imageLocation.verify(name)) {
|
||||
public synchronized ImageLocation findLocation(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
// Details of the algorithm used here can be found in
|
||||
// jdk.tools.jlink.internal.PerfectHashBuilder.
|
||||
int count = header.getTableLength();
|
||||
int index = redirect.get(ImageStringsReader.hashCode(name) % count);
|
||||
|
||||
if (index < 0) {
|
||||
// index is twos complement of location attributes index.
|
||||
index = -index - 1;
|
||||
} else if (index > 0) {
|
||||
// index is hash seed needed to compute location attributes index.
|
||||
index = ImageStringsReader.hashCode(name, index) % count;
|
||||
} else {
|
||||
// No entry.
|
||||
return null;
|
||||
}
|
||||
|
||||
return imageLocation;
|
||||
long[] attributes = getAttributes(offsets.get(index));
|
||||
|
||||
if (!ImageLocation.verify(name, attributes, stringsReader)) {
|
||||
return null;
|
||||
}
|
||||
return new ImageLocation(attributes, stringsReader);
|
||||
}
|
||||
|
||||
public String[] getEntryNames() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2017, 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
|
||||
@ -59,14 +59,6 @@ public class ImageLocation {
|
||||
return strings;
|
||||
}
|
||||
|
||||
private static int attributeLength(int data) {
|
||||
return (data & 0x7) + 1;
|
||||
}
|
||||
|
||||
private static int attributeKind(int data) {
|
||||
return data >>> 3;
|
||||
}
|
||||
|
||||
static long[] decompress(ByteBuffer bytes) {
|
||||
Objects.requireNonNull(bytes);
|
||||
long[] attributes = new long[ATTRIBUTE_COUNT];
|
||||
@ -74,7 +66,7 @@ public class ImageLocation {
|
||||
if (bytes != null) {
|
||||
while (bytes.hasRemaining()) {
|
||||
int data = bytes.get() & 0xFF;
|
||||
int kind = attributeKind(data);
|
||||
int kind = data >>> 3;
|
||||
|
||||
if (kind == ATTRIBUTE_END) {
|
||||
break;
|
||||
@ -85,7 +77,7 @@ public class ImageLocation {
|
||||
"Invalid jimage attribute kind: " + kind);
|
||||
}
|
||||
|
||||
int length = attributeLength(data);
|
||||
int length = (data & 0x7) + 1;
|
||||
long value = 0;
|
||||
|
||||
for (int j = 0; j < length; j++) {
|
||||
@ -128,9 +120,82 @@ public class ImageLocation {
|
||||
}
|
||||
|
||||
public boolean verify(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
return verify(name, attributes, strings);
|
||||
}
|
||||
|
||||
return name.equals(getFullName());
|
||||
/**
|
||||
* A simpler verification would be {@code name.equals(getFullName())}, but
|
||||
* by not creating the full name and enabling early returns we allocate
|
||||
* fewer objects. Could possibly be made allocation free by extending
|
||||
* ImageStrings to test if strings at an offset match the name region.
|
||||
*/
|
||||
static boolean verify(String name, long[] attributes, ImageStrings strings) {
|
||||
Objects.requireNonNull(name);
|
||||
final int length = name.length();
|
||||
int index = 0;
|
||||
int moduleOffset = (int)attributes[ATTRIBUTE_MODULE];
|
||||
if (moduleOffset != 0) {
|
||||
String module = strings.get(moduleOffset);
|
||||
final int moduleLen = module.length();
|
||||
index = moduleLen + 1;
|
||||
if (length <= index
|
||||
|| name.charAt(0) != '/'
|
||||
|| !name.regionMatches(1, module, 0, moduleLen)
|
||||
|| name.charAt(index++) != '/') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return verifyName(name, index, length, attributes, strings);
|
||||
}
|
||||
|
||||
static boolean verify(String module, String name, long[] attributes,
|
||||
ImageStrings strings) {
|
||||
Objects.requireNonNull(module);
|
||||
Objects.requireNonNull(name);
|
||||
int moduleOffset = (int)attributes[ATTRIBUTE_MODULE];
|
||||
if (moduleOffset != 0) {
|
||||
if (!module.equals(strings.get(moduleOffset))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return verifyName(name, 0, name.length(), attributes, strings);
|
||||
}
|
||||
|
||||
private static boolean verifyName(String name, int index, int length,
|
||||
long[] attributes, ImageStrings strings) {
|
||||
|
||||
int parentOffset = (int) attributes[ATTRIBUTE_PARENT];
|
||||
if (parentOffset != 0) {
|
||||
String parent = strings.get(parentOffset);
|
||||
final int parentLen = parent.length();
|
||||
if (!name.regionMatches(index, parent, 0, parentLen)) {
|
||||
return false;
|
||||
}
|
||||
index += parentLen;
|
||||
if (length <= index || name.charAt(index++) != '/') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
String base = strings.get((int) attributes[ATTRIBUTE_BASE]);
|
||||
final int baseLen = base.length();
|
||||
if (!name.regionMatches(index, base, 0, baseLen)) {
|
||||
return false;
|
||||
}
|
||||
index += baseLen;
|
||||
int extOffset = (int) attributes[ATTRIBUTE_EXTENSION];
|
||||
if (extOffset != 0) {
|
||||
String extension = strings.get(extOffset);
|
||||
int extLen = extension.length();
|
||||
if (length <= index
|
||||
|| name.charAt(index++) != '.'
|
||||
|| !name.regionMatches(index, extension, 0, extLen)) {
|
||||
return false;
|
||||
}
|
||||
index += extLen;
|
||||
}
|
||||
return length == index;
|
||||
}
|
||||
|
||||
long getAttribute(int kind) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2017, 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
|
||||
@ -38,6 +38,8 @@ import java.util.Objects;
|
||||
*/
|
||||
public class ImageStringsReader implements ImageStrings {
|
||||
public static final int HASH_MULTIPLIER = 0x01000193;
|
||||
public static final int POSITIVE_MASK = 0x7FFFFFFF;
|
||||
|
||||
private final BasicImageReader reader;
|
||||
|
||||
ImageStringsReader(BasicImageReader reader) {
|
||||
@ -54,40 +56,60 @@ public class ImageStringsReader implements ImageStrings {
|
||||
throw new InternalError("Can not add strings at runtime");
|
||||
}
|
||||
|
||||
private static int hashCode(byte[] bytes, int offset, int count, int seed) {
|
||||
Objects.requireNonNull(bytes);
|
||||
public static int hashCode(String s) {
|
||||
return hashCode(s, HASH_MULTIPLIER);
|
||||
}
|
||||
|
||||
if (offset < 0 || count < 0 || offset > bytes.length - count) {
|
||||
throw new IndexOutOfBoundsException("offset=" + offset + ", count=" + count);
|
||||
public static int hashCode(String s, int seed) {
|
||||
return unmaskedHashCode(s, seed) & POSITIVE_MASK;
|
||||
}
|
||||
|
||||
public static int hashCode(String module, String name) {
|
||||
return hashCode(module, name, HASH_MULTIPLIER);
|
||||
}
|
||||
|
||||
public static int hashCode(String module, String name, int seed) {
|
||||
seed = unmaskedHashCode("/", seed);
|
||||
seed = unmaskedHashCode(module, seed);
|
||||
seed = unmaskedHashCode("/", seed);
|
||||
seed = unmaskedHashCode(name, seed);
|
||||
return seed & POSITIVE_MASK;
|
||||
}
|
||||
|
||||
public static int unmaskedHashCode(String s, int seed) {
|
||||
int slen = s.length();
|
||||
byte[] buffer = null;
|
||||
|
||||
for (int i = 0; i < slen; i++) {
|
||||
char ch = s.charAt(i);
|
||||
int uch = ch & 0xFFFF;
|
||||
|
||||
if ((uch & ~0x7F) != 0) {
|
||||
if (buffer == null) {
|
||||
buffer = new byte[8];
|
||||
}
|
||||
int mask = ~0x3F;
|
||||
int n = 0;
|
||||
|
||||
do {
|
||||
buffer[n++] = (byte)(0x80 | (uch & 0x3F));
|
||||
uch >>= 6;
|
||||
mask >>= 1;
|
||||
} while ((uch & mask) != 0);
|
||||
|
||||
buffer[n] = (byte)((mask << 1) | uch);
|
||||
|
||||
do {
|
||||
seed = (seed * HASH_MULTIPLIER) ^ (buffer[n--] & 0xFF);
|
||||
} while (0 <= n);
|
||||
} else if (uch == 0) {
|
||||
seed = (seed * HASH_MULTIPLIER) ^ (0xC0);
|
||||
seed = (seed * HASH_MULTIPLIER) ^ (0x80);
|
||||
} else {
|
||||
seed = (seed * HASH_MULTIPLIER) ^ (uch);
|
||||
}
|
||||
}
|
||||
|
||||
int limit = offset + count;
|
||||
|
||||
if (limit < 0 || limit > bytes.length) {
|
||||
throw new IndexOutOfBoundsException("limit=" + limit);
|
||||
}
|
||||
|
||||
for (int i = offset; i < limit; i++) {
|
||||
seed = (seed * HASH_MULTIPLIER) ^ (bytes[i] & 0xFF);
|
||||
}
|
||||
|
||||
return seed & 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
public static int hashCode(byte[] bytes, int seed) {
|
||||
return hashCode(bytes, 0, bytes.length, seed);
|
||||
}
|
||||
|
||||
public static int hashCode(byte[] bytes) {
|
||||
return hashCode(bytes, 0, bytes.length, HASH_MULTIPLIER);
|
||||
}
|
||||
|
||||
public static int hashCode(String string, int seed) {
|
||||
return hashCode(mutf8FromString(string), seed);
|
||||
}
|
||||
|
||||
public static int hashCode(String string) {
|
||||
return hashCode(mutf8FromString(string), HASH_MULTIPLIER);
|
||||
return seed;
|
||||
}
|
||||
|
||||
static int charsFromMUTF8Length(byte[] bytes, int offset, int count) {
|
||||
@ -179,7 +201,7 @@ public class ImageStringsReader implements ImageStrings {
|
||||
throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence");
|
||||
}
|
||||
|
||||
static void charsFromByteBuffer(char chars[], ByteBuffer buffer) {
|
||||
static void charsFromByteBuffer(char[] chars, ByteBuffer buffer) {
|
||||
int j = 0;
|
||||
|
||||
while(buffer.hasRemaining()) {
|
||||
@ -228,10 +250,12 @@ public class ImageStringsReader implements ImageStrings {
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
static int mutf8FromCharsLength(char chars[]) {
|
||||
static int mutf8FromStringLength(String s) {
|
||||
int length = 0;
|
||||
int slen = s.length();
|
||||
|
||||
for (char ch : chars) {
|
||||
for (int i = 0; i < slen; i++) {
|
||||
char ch = s.charAt(i);
|
||||
int uch = ch & 0xFFFF;
|
||||
|
||||
if ((uch & ~0x7F) != 0) {
|
||||
@ -255,14 +279,19 @@ public class ImageStringsReader implements ImageStrings {
|
||||
return length;
|
||||
}
|
||||
|
||||
static void mutf8FromChars(byte[] bytes, int offset, char chars[]) {
|
||||
static void mutf8FromString(byte[] bytes, int offset, String s) {
|
||||
int j = offset;
|
||||
byte[] buffer = new byte[8];
|
||||
byte[] buffer = null;
|
||||
int slen = s.length();
|
||||
|
||||
for (char ch : chars) {
|
||||
for (int i = 0; i < slen; i++) {
|
||||
char ch = s.charAt(i);
|
||||
int uch = ch & 0xFFFF;
|
||||
|
||||
if ((uch & ~0x7F) != 0) {
|
||||
if (buffer == null) {
|
||||
buffer = new byte[8];
|
||||
}
|
||||
int mask = ~0x3F;
|
||||
int n = 0;
|
||||
|
||||
@ -287,10 +316,9 @@ public class ImageStringsReader implements ImageStrings {
|
||||
}
|
||||
|
||||
public static byte[] mutf8FromString(String string) {
|
||||
char[] chars = string.toCharArray();
|
||||
int length = mutf8FromCharsLength(chars);
|
||||
int length = mutf8FromStringLength(string);
|
||||
byte[] bytes = new byte[length];
|
||||
mutf8FromChars(bytes, 0, chars);
|
||||
mutf8FromString(bytes, 0, string);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
@ -237,6 +237,7 @@ public class Main {
|
||||
if (!parseArgs(args)) {
|
||||
return false;
|
||||
}
|
||||
File tmpFile = null;
|
||||
try {
|
||||
if (cflag || uflag) {
|
||||
if (fname != null) {
|
||||
@ -303,8 +304,8 @@ public class Main {
|
||||
? "tmpjar"
|
||||
: fname.substring(fname.indexOf(File.separatorChar) + 1);
|
||||
|
||||
File tmpfile = createTemporaryFile(tmpbase, ".jar");
|
||||
try (OutputStream out = new FileOutputStream(tmpfile)) {
|
||||
tmpFile = createTemporaryFile(tmpbase, ".jar");
|
||||
try (OutputStream out = new FileOutputStream(tmpFile)) {
|
||||
create(new BufferedOutputStream(out, 4096), manifest);
|
||||
}
|
||||
if (nflag) {
|
||||
@ -313,16 +314,16 @@ public class Main {
|
||||
Packer packer = Pack200.newPacker();
|
||||
Map<String, String> p = packer.properties();
|
||||
p.put(Packer.EFFORT, "1"); // Minimal effort to conserve CPU
|
||||
try (JarFile jarFile = new JarFile(tmpfile.getCanonicalPath());
|
||||
try (JarFile jarFile = new JarFile(tmpFile.getCanonicalPath());
|
||||
OutputStream pack = new FileOutputStream(packFile))
|
||||
{
|
||||
packer.pack(jarFile, pack);
|
||||
}
|
||||
if (tmpfile.exists()) {
|
||||
tmpfile.delete();
|
||||
if (tmpFile.exists()) {
|
||||
tmpFile.delete();
|
||||
}
|
||||
tmpfile = createTemporaryFile(tmpbase, ".jar");
|
||||
try (OutputStream out = new FileOutputStream(tmpfile);
|
||||
tmpFile = createTemporaryFile(tmpbase, ".jar");
|
||||
try (OutputStream out = new FileOutputStream(tmpFile);
|
||||
JarOutputStream jos = new JarOutputStream(out))
|
||||
{
|
||||
Unpacker unpacker = Pack200.newUnpacker();
|
||||
@ -332,9 +333,9 @@ public class Main {
|
||||
Files.deleteIfExists(packFile.toPath());
|
||||
}
|
||||
}
|
||||
validateAndClose(tmpfile);
|
||||
validateAndClose(tmpFile);
|
||||
} else if (uflag) {
|
||||
File inputFile = null, tmpFile = null;
|
||||
File inputFile = null;
|
||||
if (fname != null) {
|
||||
inputFile = new File(fname);
|
||||
tmpFile = createTempFileInSameDirectoryAs(inputFile);
|
||||
@ -425,6 +426,9 @@ public class Main {
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
ok = false;
|
||||
} finally {
|
||||
if (tmpFile != null && tmpFile.exists())
|
||||
tmpFile.delete();
|
||||
}
|
||||
out.flush();
|
||||
err.flush();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2017, 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
|
||||
@ -108,24 +108,24 @@ public final class ImageLocationWriter extends ImageLocation {
|
||||
int hash = seed;
|
||||
|
||||
if (getModuleOffset() != 0) {
|
||||
hash = ImageStringsReader.hashCode("/", hash);
|
||||
hash = ImageStringsReader.hashCode(getModule(), hash);
|
||||
hash = ImageStringsReader.hashCode("/", hash);
|
||||
hash = ImageStringsReader.unmaskedHashCode("/", hash);
|
||||
hash = ImageStringsReader.unmaskedHashCode(getModule(), hash);
|
||||
hash = ImageStringsReader.unmaskedHashCode("/", hash);
|
||||
}
|
||||
|
||||
if (getParentOffset() != 0) {
|
||||
hash = ImageStringsReader.hashCode(getParent(), hash);
|
||||
hash = ImageStringsReader.hashCode("/", hash);
|
||||
hash = ImageStringsReader.unmaskedHashCode(getParent(), hash);
|
||||
hash = ImageStringsReader.unmaskedHashCode("/", hash);
|
||||
}
|
||||
|
||||
hash = ImageStringsReader.hashCode(getBase(), hash);
|
||||
hash = ImageStringsReader.unmaskedHashCode(getBase(), hash);
|
||||
|
||||
if (getExtensionOffset() != 0) {
|
||||
hash = ImageStringsReader.hashCode(".", hash);
|
||||
hash = ImageStringsReader.hashCode(getExtension(), hash);
|
||||
hash = ImageStringsReader.unmaskedHashCode(".", hash);
|
||||
hash = ImageStringsReader.unmaskedHashCode(getExtension(), hash);
|
||||
}
|
||||
|
||||
return hash;
|
||||
return hash & ImageStringsReader.POSITIVE_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user