You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by te...@apache.org on 2008/03/27 19:02:39 UTC
svn commit: r641928 [1/2] - in /harmony/enhanced/classlib/trunk/modules:
archive/src/main/java/java/util/jar/
archive/src/main/java/org/apache/harmony/archive/internal/nls/
archive/src/main/java/org/apache/harmony/archive/util/
archive/src/test/java/or...
Author: tellison
Date: Thu Mar 27 11:02:32 2008
New Revision: 641928
URL: http://svn.apache.org/viewvc?rev=641928&view=rev
Log:
Apply patch HARMONY-4569 ([classlib][performance] Ineffecient manifest parsing results in slowdown when debugging java code)
Added:
harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/util/ByteBuffer.java (with props)
harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/util/ExposedByteArrayInputStream.java (with props)
harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/util/ThreadLocalCache.java (with props)
Modified:
harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/Attributes.java
harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/InitManifest.java
harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarFile.java
harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarInputStream.java
harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarVerifier.java
harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/Manifest.java
harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties
harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/util/Util.java
harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesNameTest.java
harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java
harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java
harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/util/UtilTest.java
Modified: harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/Attributes.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/Attributes.java?rev=641928&r1=641927&r2=641928&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/Attributes.java (original)
+++ harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/Attributes.java Thu Mar 27 11:02:32 2008
@@ -17,6 +17,7 @@
package java.util.jar;
+import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -34,7 +35,7 @@
protected Map<Object, Object> map;
public static class Name {
- private final String name;
+ private final byte[] name;
private int hashCode;
@@ -82,42 +83,70 @@
public static final Name IMPLEMENTATION_URL = new Name(
"Implementation-URL"); //$NON-NLS-1$
+ static final Name NAME = new Name("Name");
+
public Name(String s) {
int i = s.length();
- if (i == 0 || i > 70) {
+ if (i == 0 || i > Manifest.LINE_LENGTH_LIMIT - 2) {
throw new IllegalArgumentException();
}
+
+ name = new byte[i];
+
for (; --i >= 0;) {
char ch = s.charAt(i);
if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|| ch == '_' || ch == '-' || (ch >= '0' && ch <= '9'))) {
throw new IllegalArgumentException(s);
}
+ name[i] = (byte) ch;
}
- name = s;
+ }
+
+ /**
+ * A private constructor for a trusted attribute name.
+ */
+ Name(byte[] buf) {
+ name = buf;
+ }
+
+ public byte[] getBytes() {
+ return name;
}
@Override
public String toString() {
- return name;
+ try {
+ return new String(name, "ISO-8859-1");
+ } catch (UnsupportedEncodingException iee) {
+ throw new InternalError(iee.getLocalizedMessage());
+ }
}
@Override
- public boolean equals(Object an) {
- if (an == null) {
+ public boolean equals(Object object) {
+ if (object == null || object.getClass() != getClass()
+ || object.hashCode() != hashCode()) {
return false;
}
- return an.getClass() == this.getClass()
- && Util.equalsIgnoreCase(name, ((Name) an).name);
+
+ return Util.equalsIgnoreCase(name, ((Name) object).name);
}
@Override
public int hashCode() {
if (hashCode == 0) {
- hashCode = Util.toASCIILowerCase(name).hashCode();
+ int hash = 0, multiplier = 1;
+ for (int i = name.length - 1; i >= 0; i--) {
+ hash += Util.toASCIIUpperCase(name[i]) * multiplier;
+ int shifted = multiplier << 5;
+ multiplier = shifted - multiplier;
+ }
+ hashCode = hash;
}
return hashCode;
}
+
}
/**
Modified: harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/InitManifest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/InitManifest.java?rev=641928&r1=641927&r2=641928&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/InitManifest.java (original)
+++ harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/InitManifest.java Thu Mar 27 11:02:32 2008
@@ -17,274 +17,210 @@
package java.util.jar;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.UTFDataFormatException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
import java.util.Map;
import org.apache.harmony.archive.internal.nls.Messages;
-import org.apache.harmony.luni.util.Util;
+import org.apache.harmony.luni.util.ThreadLocalCache;
class InitManifest {
- private final byte[] inbuf = new byte[1024];
- private int inbufCount = 0, inbufPos = 0;
+ private byte[] buf;
- private byte[] buffer = new byte[5];
+ private int pos;
- private char[] charbuf = new char[0];
+ Attributes.Name name;
- private final ByteArrayOutputStream out = new ByteArrayOutputStream(256);
+ String value;
- private final Map<String, Attributes.Name> attributeNames = new HashMap<String, Attributes.Name>();
+ CharsetDecoder decoder = ThreadLocalCache.utf8Decoder.get();
+ CharBuffer cBuf = ThreadLocalCache.charBuffer.get();
- private final byte[] mainAttributesChunk;
-
- InitManifest(InputStream is, Attributes main,
- Map<String, Attributes> entries, Map<String, byte[]> chunks,
- String verString) throws IOException {
- Attributes current = main;
- ArrayList<String> list = new ArrayList<String>();
+ InitManifest(byte[] buf, Attributes main, Attributes.Name ver)
+ throws IOException {
- // Return the chunk of main attributes in the manifest.
- mainAttributesChunk = nextChunk(is, list);
+ this.buf = buf;
- Iterator<String> it = list.iterator();
- while (it.hasNext()) {
- addAttribute(it.next(), current);
+ // check a version attribute
+ if (!readHeader() || !name.equals(ver)) {
+ throw new IOException(Messages.getString(
+ "archive.missingVersionAttribute", ver)); //$NON-NLS-1$
}
- // Check for version attribute
- if (verString != null && main.getValue(verString) == null) {
- throw new IOException(Messages.getString("archive.2D", verString)); //$NON-NLS-1$
+ main.put(name, value);
+ while (readHeader()) {
+ main.put(name, value);
}
+ }
- list.clear();
- byte[] chunk = null;
- while (chunks == null ? readLines(is, list) : (chunk = nextChunk(is,
- list)) != null) {
- if (list.size() == 0) {
- continue;
+ void initEntries(Map<String, Attributes> entries,
+ Map<String, Manifest.Chunk> chunks) throws IOException {
+
+ int mark = pos;
+ while (readHeader()) {
+ if (!Attributes.Name.NAME.equals(name)) {
+ throw new IOException(Messages
+ .getString("archive.entryIsNotNamed")); //$NON-NLS-1$
}
- it = list.iterator();
- String line = it.next();
- if (line.length() < 6
- || !Util.toASCIILowerCase(line.substring(0, 5)).equals(
- "name:")) { //$NON-NLS-1$
- throw new IOException(Messages.getString("archive.23")); //$NON-NLS-1$
+ String entryNameValue = value;
+
+ Attributes entry = entries.get(entryNameValue);
+ if (entry == null) {
+ entry = new Attributes(12);
}
- // Name: length required space char
- String name = line.substring(6, line.length());
- current = new Attributes(12);
- if (chunks != null) {
- chunks.put(name, chunk);
+
+ while (readHeader()) {
+ entry.put(name, value);
}
- entries.put(name, current);
- while (it.hasNext()) {
- addAttribute(it.next(), current);
+
+ if (chunks != null) {
+ if (chunks.get(entryNameValue) != null) {
+ // TODO A bug: there might be several verification chunks for
+ // the same name. I believe they should be used to update
+ // signature in order of appearance; there are two ways to fix
+ // this: either use a list of chunks, or decide on used
+ // signature algorithm in advance and reread the chunks while
+ // updating the signature; for now a defensive error is thrown
+ throw new IOException(Messages
+ .getString("archive.verifiableEntryRepeated"));
+ }
+ chunks.put(entryNameValue, new Manifest.Chunk(mark, pos));
+ mark = pos;
}
- list.clear();
- }
+ entries.put(entryNameValue, entry);
+ }
}
- byte[] getMainAttributesChunk() {
- return mainAttributesChunk;
+ int getPos() {
+ return pos;
}
- private void addLine(int length, List<String> lines) throws IOException {
- try {
- if (charbuf.length < length) {
- charbuf = new char[length];
- }
- int start = skipFirstEmptyLines(0, buffer);
- lines.add(Util.convertUTF8WithBuf(buffer, charbuf, Math.min(Math
- .max(length - 1, 0), start), length));
- } catch (UTFDataFormatException e) {
- throw new IOException(e.getLocalizedMessage());
+ /**
+ * Number of subsequent line breaks.
+ */
+ int linebreak = 0;
+
+ /**
+ * Read a single line from the manifest buffer.
+ */
+ private boolean readHeader() throws IOException {
+ if (linebreak > 1) {
+ // break a section on an empty line
+ linebreak = 0;
+ return false;
}
+ readName();
+ linebreak = 0;
+ readValue();
+ // if the last line break is missed, the line
+ // is ignored by the reference implementation
+ return linebreak > 0;
}
- private int skipFirstEmptyLines(int start, byte[] buf) {
- int res = start;
- if (buf.length > start) {
- if ((char) buf[res] == '\r') {
- res++;
- if ((res < buf.length) && ((char) buf[res] == '\n')) {
- res++;
- return skipFirstEmptyLines(res, buf);
- }
- return res;
- } else if ((char) buf[res] == '\n') {
- res++;
- return skipFirstEmptyLines(res, buf);
- } else {
- return res;
- }
- }
- return res;
+ private byte[] wrap(int mark, int pos) {
+ byte[] buffer = new byte[pos - mark];
+ System.arraycopy(buf, mark, buffer, 0, pos - mark);
+ return buffer;
}
- private byte[] nextChunk(InputStream in, List<String> lines)
- throws IOException {
- if (inbufCount == -1) {
- return null;
- }
- byte next;
- int pos = 0;
- boolean blankline = false, lastCr = false;
- out.reset();
- while (true) {
- if (inbufPos == inbufCount) {
- if ((inbufCount = in.read(inbuf)) == -1) {
- if (out.size() == 0) {
- return null;
- }
- if (blankline) {
- addLine(pos, lines);
- }
- return out.toByteArray();
- }
- if (inbufCount == inbuf.length && in.available() == 0) {
- /* archive.2E = "line too long" */
- throw new IOException(Messages.getString("archive.2E")); //$NON-NLS-1$
- }
- inbufPos = 0;
- }
- next = inbuf[inbufPos++];
- if (lastCr) {
- if (next != '\n') {
- inbufPos--;
- next = '\r';
- } else {
- if (out.size() == 0) {
- continue;
- }
- out.write('\r');
- }
- lastCr = false;
- } else if (next == '\r') {
- lastCr = true;
- continue;
- }
- if (blankline) {
- if (next == ' ') {
- out.write(next);
- blankline = false;
- continue;
- }
- addLine(pos, lines);
- if (next == '\n') {
- out.write(next);
- return out.toByteArray();
- }
- pos = 0;
- } else if (next == '\n') {
- if (out.size() == 0) {
- continue;
+ private void readName() throws IOException {
+ int i = 0;
+ int mark = pos;
+
+ while (pos < buf.length) {
+ byte b = buf[pos++];
+
+ if (b == ':') {
+ byte[] nameBuffer = wrap(mark, pos - 1);
+
+ if (buf[pos++] != ' ') {
+ throw new IOException(Messages.getString(
+ "archive.invalidAttribute", nameBuffer));
}
- out.write(next);
- blankline = true;
- continue;
+
+ name = new Attributes.Name(nameBuffer);
+ return;
}
- blankline = false;
- out.write(next);
- if (pos == buffer.length) {
- byte[] newBuf = new byte[buffer.length * 2];
- System.arraycopy(buffer, 0, newBuf, 0, buffer.length);
- buffer = newBuf;
+
+ if (!((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_'
+ || b == '-' || (b >= '0' && b <= '9'))) {
+ throw new IOException(Messages.getString(
+ "archive.invalidAttribute", b));
}
- buffer[pos++] = next;
+ }
+ if (i > 0) {
+ throw new IOException(Messages.getString(
+ "archive.invalidAttribute", wrap(mark, buf.length)));
}
}
- private boolean readLines(InputStream in, List<String> lines)
- throws IOException {
- if (inbufCount == -1) {
- return false;
- }
+ private void readValue() throws IOException {
byte next;
- int pos = 0;
- boolean blankline = false, lastCr = false;
- while (true) {
- if (inbufPos == inbufCount) {
- if ((inbufCount = in.read(inbuf)) == -1) {
- if (blankline) {
- addLine(pos, lines);
- }
- return lines.size() != 0;
- }
- if (inbufCount == inbuf.length && in.available() == 0) {
- /* archive.2E = "line too long" */
- throw new IOException(Messages.getString("archive.2E")); //$NON-NLS-1$
- }
- inbufPos = 0;
- }
- next = inbuf[inbufPos++];
- if (lastCr) {
- if (next != '\n') {
- inbufPos--;
- next = '\r';
+ boolean lastCr = false;
+ int mark = pos;
+ int last = pos;
+
+ decoder.reset();
+ cBuf.clear();
+
+ while (pos < buf.length) {
+ next = buf[pos++];
+
+ switch (next) {
+ case 0:
+ throw new IOException(Messages
+ .getString("archive.nulCharInManifest")); // $NON-NLS-1$
+ case '\n':
+ if (lastCr) {
+ lastCr = false;
+ } else {
+ linebreak++;
}
- lastCr = false;
- } else if (next == '\r') {
+ continue;
+ case '\r':
lastCr = true;
+ linebreak++;
continue;
- }
- if (blankline) {
- if (next == ' ') {
- blankline = false;
- continue;
- }
- addLine(pos, lines);
- if (next == '\n') {
- return true;
- }
- pos = 0;
- } else if (next == '\n') {
- if (pos == 0 && lines.size() == 0) {
+ case ' ':
+ if (linebreak == 1) {
+ decode(mark, last, false);
+ mark = pos;
+ linebreak = 0;
continue;
}
- blankline = true;
- continue;
}
- blankline = false;
- if (pos == buffer.length) {
- byte[] newBuf = new byte[buffer.length * 2];
- System.arraycopy(buffer, 0, newBuf, 0, buffer.length);
- buffer = newBuf;
+
+ if (linebreak >= 1) {
+ pos--;
+ break;
}
- buffer[pos++] = next;
+ last = pos;
}
+
+ decode(mark, last, true);
+ while (CoderResult.OVERFLOW == decoder.flush(cBuf)) {
+ enlargeBuffer();
+ }
+ value = new String(cBuf.array(), cBuf.arrayOffset(), cBuf.position());
}
- /* Get the next attribute and add it */
- private void addAttribute(String line, Attributes current)
+ private void decode(int mark, int pos, boolean endOfInput)
throws IOException {
- String header;
- int hdrIdx = line.indexOf(':');
- if (hdrIdx < 1) {
- throw new IOException(Messages.getString("archive.2F", line)); //$NON-NLS-1$
- }
- header = line.substring(0, hdrIdx);
- Attributes.Name name = attributeNames.get(header);
- if (name == null) {
- try {
- name = new Attributes.Name(header);
- } catch (IllegalArgumentException e) {
- throw new IOException(e.toString());
- }
- attributeNames.put(header, name);
+ ByteBuffer bBuf = ByteBuffer.wrap(buf, mark, pos - mark);
+ while (CoderResult.OVERFLOW == decoder.decode(bBuf, cBuf, endOfInput)) {
+ enlargeBuffer();
}
- if (hdrIdx + 1 >= line.length() || line.charAt(hdrIdx + 1) != ' ') {
- throw new IOException(Messages.getString("archive.2F", line)); //$NON-NLS-1$
- }
- // +2 due to required SPACE char
- current.put(name, line.substring(hdrIdx + 2, line.length()));
+ }
+
+ private void enlargeBuffer() {
+ CharBuffer newBuf = CharBuffer.allocate(cBuf.capacity() * 2);
+ newBuf.put(cBuf.array(), cBuf.arrayOffset(), cBuf.position());
+ cBuf = newBuf;
+ ThreadLocalCache.charBuffer.set(cBuf);
}
}
Modified: harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarFile.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarFile.java?rev=641928&r1=641927&r2=641928&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarFile.java (original)
+++ harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarFile.java Thu Mar 27 11:02:32 2008
@@ -22,7 +22,6 @@
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.security.MessageDigest;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -52,61 +51,56 @@
private ZipEntry zipEntry;
- private JarVerifier verifier;
-
private JarVerifier.VerifierEntry entry;
- private MessageDigest digest;
-
- JarFileInputStream(InputStream is, ZipEntry ze, JarVerifier ver) {
+ JarFileInputStream(InputStream is, ZipEntry ze,
+ JarVerifier.VerifierEntry e) {
super(is);
- if (ver != null) {
- zipEntry = ze;
- verifier = ver;
- count = zipEntry.getSize();
- entry = verifier.initEntry(ze.getName());
- if (entry != null) {
- digest = entry.digest;
- }
- }
+ zipEntry = ze;
+ count = zipEntry.getSize();
+ entry = e;
}
@Override
public int read() throws IOException {
- int r = super.read();
- if (entry != null) {
+ if (count > 0) {
+ int r = super.read();
if (r != -1) {
- digest.update((byte) r);
+ entry.write(r);
count--;
+ } else {
+ count = 0;
}
- if (r == -1 || count <= 0) {
- JarVerifier.VerifierEntry temp = entry;
- entry = null;
- verifier.verifySignatures(temp, zipEntry);
+ if (count == 0) {
+ entry.verify();
}
+ return r;
+ } else {
+ return -1;
}
- return r;
}
@Override
public int read(byte[] buf, int off, int nbytes) throws IOException {
- int r = super.read(buf, off, nbytes);
- if (entry != null) {
+ if (count > 0) {
+ int r = super.read(buf, off, nbytes);
if (r != -1) {
int size = r;
if (count < size) {
size = (int) count;
}
- digest.update(buf, off, size);
- count -= r;
+ entry.write(buf, off, size);
+ count -= size;
+ } else {
+ count = 0;
}
- if (r == -1 || count <= 0) {
- JarVerifier.VerifierEntry temp = entry;
- entry = null;
- verifier.verifySignatures(temp, zipEntry);
+ if (count == 0) {
+ entry.verify();
}
+ return r;
+ } else {
+ return -1;
}
- return r;
}
@Override
@@ -332,7 +326,7 @@
* the ZipEntry to read from
* @return java.io.InputStream
* @exception java.io.IOException
- * If an error occured while creating the InputStream.
+ * If an error occurred while creating the InputStream.
*/
@Override
public InputStream getInputStream(ZipEntry ze) throws IOException {
@@ -342,8 +336,7 @@
if (verifier != null) {
verifier.setManifest(getManifest());
if (manifest != null) {
- verifier.mainAttributesChunk = manifest
- .getMainAttributesChunk();
+ verifier.mainAttributesEnd = manifest.getMainAttributesEnd();
}
if (verifier.readCertificates()) {
verifier.removeMetaEntries();
@@ -359,8 +352,14 @@
if (in == null) {
return null;
}
- return new JarFileInputStream(in, ze, ze.getSize() >= 0 ? verifier
- : null);
+ if (verifier == null || ze.getSize() == -1) {
+ return in;
+ }
+ JarVerifier.VerifierEntry entry = verifier.initEntry(ze.getName());
+ if (entry == null) {
+ return in;
+ }
+ return new JarFileInputStream(in, ze, entry);
}
/**
Modified: harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarInputStream.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarInputStream.java?rev=641928&r1=641927&r2=641928&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarInputStream.java (original)
+++ harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarInputStream.java Thu Mar 27 11:02:32 2008
@@ -24,7 +24,7 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
-import org.apache.harmony.archive.util.Util;
+import org.apache.harmony.luni.util.Util;
public class JarInputStream extends ZipInputStream {
@@ -68,8 +68,8 @@
if (verify) {
verifier.setManifest(manifest);
if (manifest != null) {
- verifier.mainAttributesChunk = manifest
- .getMainAttributesChunk();
+ verifier.mainAttributesEnd = manifest
+ .getMainAttributesEnd();
}
}
@@ -132,10 +132,7 @@
throw e;
}
} else {
- verifier
- .verifySignatures(
- (JarVerifier.VerifierEntry) verStream,
- jarEntry);
+ ((JarVerifier.VerifierEntry) verStream).verify();
}
}
} else {
Modified: harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarVerifier.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarVerifier.java?rev=641928&r1=641927&r2=641928&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarVerifier.java (original)
+++ harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/JarVerifier.java Thu Mar 27 11:02:32 2008
@@ -31,14 +31,12 @@
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Vector;
-import java.util.zip.ZipEntry;
import org.apache.harmony.archive.internal.nls.Messages;
+import org.apache.harmony.luni.util.Util;
import org.apache.harmony.luni.util.Base64;
import org.apache.harmony.security.utils.JarUtils;
-import org.apache.harmony.archive.util.Util;
-
/**
* Non-public class used by {@link JarFile} and {@link JarInputStream} to manage
* the verification of signed jars. <code>JarFile</code> and
@@ -71,45 +69,68 @@
private final Hashtable<String, Certificate[]> verifiedEntries = new Hashtable<String, Certificate[]>();
- byte[] mainAttributesChunk;
+ int mainAttributesEnd;
/**
- * TODO Type description
+ * Stores and a hash and a message digest and verifies that massage digest
+ * matches the hash.
*/
- static class VerifierEntry extends OutputStream {
+ class VerifierEntry extends OutputStream {
+
+ private String name;
- MessageDigest digest;
+ private MessageDigest digest;
- byte[] hash;
+ private byte[] hash;
- Certificate[] certificates;
+ private Certificate[] certificates;
- VerifierEntry(MessageDigest digest, byte[] hash,
+ VerifierEntry(String name, MessageDigest digest, byte[] hash,
Certificate[] certificates) {
+ this.name = name;
this.digest = digest;
this.hash = hash;
this.certificates = certificates;
}
- /*
- * (non-Javadoc)
- *
- * @see java.io.OutputStream#write(int)
+ /**
+ * Updates a digest with one byte.
*/
@Override
public void write(int value) {
digest.update((byte) value);
}
- /*
- * (non-Javadoc)
- *
- * @see java.io.OutputStream#write(byte[], int, int)
+ /**
+ * Updates a digest with byte array.
*/
@Override
public void write(byte[] buf, int off, int nbytes) {
digest.update(buf, off, nbytes);
}
+
+ /**
+ * Verifies that the digests stored in the manifest match the decrypted
+ * digests from the .SF file. This indicates the validity of the
+ * signing, not the integrity of the file, as it's digest must be
+ * calculated and verified when its contents are read.
+ *
+ * @throws SecurityException
+ * if the digest value stored in the manifest does <i>not</i>
+ * agree with the decrypted digest as recovered from the
+ * <code>.SF</code> file.
+ * @see #initEntry(String)
+ */
+ void verify() {
+ byte[] d = digest.digest();
+ if (!MessageDigest.isEqual(d, Base64.decode(hash))) {
+ throw new SecurityException(Messages.getString(
+ "archive.invalidDigest", new Object[] { //$NON-NLS-1$
+ JarFile.MANIFEST_NAME, name, jarName }));
+ }
+ verifiedEntries.put(name, certificates);
+ }
+
}
/**
@@ -187,16 +208,16 @@
}
byte[] hashBytes;
try {
- hashBytes = hash.getBytes("ISO8859_1"); //$NON-NLS-1$
+ hashBytes = hash.getBytes("ISO-8859-1"); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.toString());
}
try {
- return new VerifierEntry(MessageDigest.getInstance(algorithm),
- hashBytes, certificatesArray);
+ return new VerifierEntry(name, MessageDigest
+ .getInstance(algorithm), hashBytes, certificatesArray);
} catch (NoSuchAlgorithmException e) {
- // Ignored
+ // ignored
}
}
return null;
@@ -267,6 +288,12 @@
return;
}
+ byte[] manifest = metaEntries.get(JarFile.MANIFEST_NAME);
+ // Manifest entry is required for any verifications.
+ if (manifest == null) {
+ return;
+ }
+
byte[] sBlockBytes = metaEntries.get(certFile);
try {
Certificate[] signerCertChain = JarUtils.verifySignature(
@@ -292,66 +319,58 @@
// Verify manifest hash in .sf file
Attributes attributes = new Attributes();
- HashMap<String, Attributes> hm = new HashMap<String, Attributes>();
+ HashMap<String, Attributes> entries = new HashMap<String, Attributes>();
try {
- new InitManifest(new ByteArrayInputStream(sfBytes), attributes, hm,
- null, "Signature-Version"); //$NON-NLS-1$
+ InitManifest im = new InitManifest(sfBytes, attributes, Attributes.Name.SIGNATURE_VERSION); //$NON-NLS-1$
+ im.initEntries(entries, null); //$NON-NLS-1$
} catch (IOException e) {
return;
}
boolean createdBySigntool = false;
- String createdByValue = attributes.getValue("Created-By"); //$NON-NLS-1$
- if (createdByValue != null) {
- createdBySigntool = createdByValue.indexOf("signtool") != -1; //$NON-NLS-1$
+ String createdBy = attributes.getValue("Created-By"); //$NON-NLS-1$
+ if (createdBy != null) {
+ createdBySigntool = createdBy.indexOf("signtool") != -1; //$NON-NLS-1$
}
// Use .SF to verify the mainAttributes of the manifest
// If there is no -Digest-Manifest-Main-Attributes entry in .SF
// file, such as those created before java 1.5, then we ignore
// such verification.
- // FIXME: The meaning of createdBySigntool
- if (mainAttributesChunk != null && !createdBySigntool) {
+ if (mainAttributesEnd > 0 && !createdBySigntool) {
String digestAttribute = "-Digest-Manifest-Main-Attributes"; //$NON-NLS-1$
- if (!verify(attributes, digestAttribute, mainAttributesChunk,
- false, true)) {
+ if (!verify(attributes, digestAttribute, manifest, 0,
+ mainAttributesEnd, false, true)) {
/* [MSG "archive.30", "{0} failed verification of {1}"] */
throw new SecurityException(Messages.getString(
"archive.30", jarName, signatureFile)); //$NON-NLS-1$
}
}
- byte[] manifest = metaEntries.get(JarFile.MANIFEST_NAME);
- if (manifest == null) {
- return;
- }
- // Use .SF to verify the whole manifest
+ // Use .SF to verify the whole manifest.
String digestAttribute = createdBySigntool ? "-Digest" //$NON-NLS-1$
: "-Digest-Manifest"; //$NON-NLS-1$
- if (!verify(attributes, digestAttribute, manifest, false, false)) {
- Iterator<Map.Entry<String, Attributes>> it = hm.entrySet()
+ if (!verify(attributes, digestAttribute, manifest, 0, manifest.length,
+ false, false)) {
+ Iterator<Map.Entry<String, Attributes>> it = entries.entrySet()
.iterator();
while (it.hasNext()) {
Map.Entry<String, Attributes> entry = it.next();
- byte[] chunk = man.getChunk(entry.getKey());
+ Manifest.Chunk chunk = man.getChunk(entry.getKey());
if (chunk == null) {
return;
}
- if (!verify(entry.getValue(), "-Digest", chunk, //$NON-NLS-1$
- createdBySigntool, false)) {
- /*
- * [MSG "archive.31", "{0} has invalid digest for {1} in
- * {2}"]
- */
+ if (!verify(entry.getValue(), "-Digest", manifest, //$NON-NLS-1$
+ chunk.start, chunk.end, createdBySigntool, false)) {
throw new SecurityException(Messages.getString(
- "archive.31", //$NON-NLS-1$
+ "archive.invalidDigest", //$NON-NLS-1$
new Object[] { signatureFile, entry.getKey(),
jarName }));
}
}
}
metaEntries.put(signatureFile, null);
- signatures.put(signatureFile, hm);
+ signatures.put(signatureFile, entries);
}
/**
@@ -365,34 +384,6 @@
}
/**
- * Verifies that the digests stored in the manifest match the decrypted
- * digests from the .SF file. This indicates the validity of the signing,
- * not the integrity of the file, as it's digest must be calculated and
- * verified when its contents are read.
- *
- * @param entry
- * the {@link VerifierEntry} associated with the specified
- * <code>zipEntry</code>.
- * @param zipEntry
- * an entry in the jar file
- * @throws SecurityException
- * if the digest value stored in the manifest does <i>not</i>
- * agree with the decrypted digest as recovered from the
- * <code>.SF</code> file.
- * @see #initEntry(String)
- */
- void verifySignatures(VerifierEntry entry, ZipEntry zipEntry) {
- byte[] digest = entry.digest.digest();
- if (!MessageDigest.isEqual(digest, Base64.decode(entry.hash))) {
- /* [MSG "archive.31", "{0} has invalid digest for {1} in {2}"] */
- throw new SecurityException(Messages.getString(
- "archive.31", new Object[] { //$NON-NLS-1$
- JarFile.MANIFEST_NAME, zipEntry.getName(), jarName }));
- }
- verifiedEntries.put(zipEntry.getName(), entry.certificates);
- }
-
- /**
* Returns a <code>boolean</code> indication of whether or not the
* associated jar file is signed.
*
@@ -404,7 +395,7 @@
}
private boolean verify(Attributes attributes, String entry, byte[] data,
- boolean ignoreSecondEndline, boolean ignorable) {
+ int start, int end, boolean ignoreSecondEndline, boolean ignorable) {
String algorithms = attributes.getValue("Digest-Algorithms"); //$NON-NLS-1$
if (algorithms == null) {
algorithms = "SHA SHA1"; //$NON-NLS-1$
@@ -423,16 +414,16 @@
} catch (NoSuchAlgorithmException e) {
continue;
}
- if (ignoreSecondEndline && data[data.length - 1] == '\n'
- && data[data.length - 2] == '\n') {
- md.update(data, 0, data.length - 1);
+ if (ignoreSecondEndline && data[end - 1] == '\n'
+ && data[end - 2] == '\n') {
+ md.update(data, start, end - 1 - start);
} else {
- md.update(data, 0, data.length);
+ md.update(data, start, end - start);
}
byte[] b = md.digest();
byte[] hashBytes;
try {
- hashBytes = hash.getBytes("ISO8859_1"); //$NON-NLS-1$
+ hashBytes = hash.getBytes("ISO-8859-1"); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.toString());
}
Modified: harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/Manifest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/Manifest.java?rev=641928&r1=641927&r2=641928&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/Manifest.java (original)
+++ harmony/enhanced/classlib/trunk/modules/archive/src/main/java/java/util/jar/Manifest.java Thu Mar 27 11:02:32 2008
@@ -20,35 +20,57 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.ByteBuffer;
import java.nio.CharBuffer;
-import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import org.apache.harmony.archive.internal.nls.Messages;
+import org.apache.harmony.luni.util.ThreadLocalCache;
+
/**
* The Manifest class is used to obtain attribute information for a JarFile and
* its entries.
*/
public class Manifest implements Cloneable {
- private static final int LINE_LENGTH_LIMIT = 70;
+ static final int LINE_LENGTH_LIMIT = 72;
private static final byte[] LINE_SEPARATOR = new byte[] { '\r', '\n' };
+ private static final byte[] VALUE_SEPARATOR = new byte[] { ':', ' ' };
+
private static final Attributes.Name NAME_ATTRIBUTE = new Attributes.Name(
"Name"); //$NON-NLS-1$
private Attributes mainAttributes = new Attributes();
- private HashMap<String, Attributes> entryAttributes = new HashMap<String, Attributes>();
+ private HashMap<String, Attributes> entries = new HashMap<String, Attributes>();
- private HashMap<String, byte[]> chunks;
+ static class Chunk {
+ int start;
+ int end;
+
+ Chunk(int start, int end) {
+ this.start = start;
+ this.end = end;
+ }
+ }
+
+ private HashMap<String, Chunk> chunks;
/**
- * The data chunk of Main Attributes in the manifest is needed in
+ * Manifest bytes are used for delayed entry parsing.
+ */
+ private InitManifest im;
+
+ /**
+ * The end of the main attributes section in the manifest is needed in
* verification.
*/
- private byte[] mainAttributesChunk;
+ private int mainEnd;
/**
* Constructs a new Manifest instance.
@@ -82,13 +104,13 @@
@SuppressWarnings("unchecked")
public Manifest(Manifest man) {
mainAttributes = (Attributes) man.mainAttributes.clone();
- entryAttributes = (HashMap<String, Attributes>) man.entryAttributes
- .clone();
+ entries = (HashMap<String, Attributes>) ((HashMap<String, Attributes>) man
+ .getEntries()).clone();
}
Manifest(InputStream is, boolean readChunks) throws IOException {
if (readChunks) {
- chunks = new HashMap<String, byte[]>();
+ chunks = new HashMap<String, Chunk>();
}
read(is);
}
@@ -98,7 +120,8 @@
* associated with this Manifest.
*/
public void clear() {
- entryAttributes.clear();
+ im = null;
+ entries.clear();
mainAttributes.clear();
}
@@ -119,7 +142,20 @@
* @return A Map of entry attributes
*/
public Map<String, Attributes> getEntries() {
- return entryAttributes;
+ initEntries();
+ return entries;
+ }
+
+ private void initEntries() {
+ if (im == null) {
+ return;
+ }
+ // try {
+ // im.initEntries(entries, chunks);
+ // } catch (IOException ioe) {
+ // throw new RuntimeException(ioe);
+ // }
+ // im = null;
}
/**
@@ -166,9 +202,18 @@
* If an error occurs reading the Manifest.
*/
public void read(InputStream is) throws IOException {
- InitManifest initManifest = new InitManifest(is, mainAttributes,
- entryAttributes, chunks, null);
- mainAttributesChunk = initManifest.getMainAttributesChunk();
+ byte[] buf;
+ try {
+ buf = org.apache.harmony.luni.util.ByteBuffer.wrap(is);
+ } catch (OutOfMemoryError oome) {
+ throw new IOException(Messages.getString("archive.manifestTooLong")); // $NON-NLS-1$
+ }
+ im = new InitManifest(buf, mainAttributes,
+ Attributes.Name.MANIFEST_VERSION);
+ mainEnd = im.getPos();
+ // FIXME
+ im.initEntries(entries, chunks);
+ im = null;
}
/**
@@ -178,7 +223,7 @@
*/
@Override
public int hashCode() {
- return mainAttributes.hashCode() ^ entryAttributes.hashCode();
+ return mainAttributes.hashCode() ^ getEntries().hashCode();
}
/**
@@ -202,10 +247,10 @@
if (!mainAttributes.equals(((Manifest) o).mainAttributes)) {
return false;
}
- return entryAttributes.equals(((Manifest) o).entryAttributes);
+ return getEntries().equals(((Manifest) o).getEntries());
}
- byte[] getChunk(String name) {
+ Chunk getChunk(String name) {
return chunks.get(name);
}
@@ -213,8 +258,8 @@
chunks = null;
}
- byte[] getMainAttributesChunk() {
- return mainAttributesChunk;
+ int getMainAttributesEnd() {
+ return mainEnd;
}
/**
@@ -230,91 +275,68 @@
* If an error occurs writing the Manifest
*/
static void write(Manifest manifest, OutputStream out) throws IOException {
- Charset charset = null;
+ CharsetEncoder encoder = ThreadLocalCache.utf8Encoder.get();
+ ByteBuffer buffer = ThreadLocalCache.byteBuffer.get();
+
String version = manifest.mainAttributes
.getValue(Attributes.Name.MANIFEST_VERSION);
if (version != null) {
- writeEntry(out, charset, Attributes.Name.MANIFEST_VERSION, version);
+ writeEntry(out, Attributes.Name.MANIFEST_VERSION, version, encoder,
+ buffer);
Iterator<?> entries = manifest.mainAttributes.keySet().iterator();
while (entries.hasNext()) {
Attributes.Name name = (Attributes.Name) entries.next();
if (!name.equals(Attributes.Name.MANIFEST_VERSION)) {
- writeEntry(out, charset, name, manifest.mainAttributes
- .getValue(name));
+ writeEntry(out, name, manifest.mainAttributes
+ .getValue(name), encoder, buffer);
}
}
}
out.write(LINE_SEPARATOR);
- Iterator<String> i = manifest.entryAttributes.keySet().iterator();
+ Iterator<String> i = manifest.getEntries().keySet().iterator();
while (i.hasNext()) {
String key = i.next();
- writeEntry(out, charset, NAME_ATTRIBUTE, key);
- Attributes attrib = manifest.entryAttributes.get(key);
+ writeEntry(out, NAME_ATTRIBUTE, key, encoder, buffer);
+ Attributes attrib = manifest.entries.get(key);
Iterator<?> entries = attrib.keySet().iterator();
while (entries.hasNext()) {
Attributes.Name name = (Attributes.Name) entries.next();
- writeEntry(out, charset, name, attrib.getValue(name));
+ writeEntry(out, name, attrib.getValue(name), encoder, buffer);
}
out.write(LINE_SEPARATOR);
}
}
- private static void writeEntry(OutputStream os, Charset charset,
- Attributes.Name name, String value) throws IOException {
- int offset = 0;
- int limit = LINE_LENGTH_LIMIT;
- byte[] out = (name.toString() + ": ").getBytes("UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$
- if (out.length > limit) {
- while (out.length - offset >= limit) {
- int len = out.length - offset;
- if (len > limit) {
- len = limit;
- }
- if (offset > 0) {
- os.write(' ');
- }
- os.write(out, offset, len);
- os.write(LINE_SEPARATOR);
- offset += len;
- limit = LINE_LENGTH_LIMIT - 1;
- }
+ private static void writeEntry(OutputStream os, Attributes.Name name,
+ String value, CharsetEncoder encoder, ByteBuffer bBuf)
+ throws IOException {
+ byte[] out = name.getBytes();
+ if (out.length > LINE_LENGTH_LIMIT) {
+ throw new IOException(Messages.getString(
+ "archive.headerNameTooLong", name, LINE_LENGTH_LIMIT));
}
- int size = out.length - offset;
- final byte[] outBuf = new byte[LINE_LENGTH_LIMIT];
- System.arraycopy(out, offset, outBuf, 0, size);
- for (int i = 0; i < value.length(); i++) {
- char[] oneChar = new char[1];
- oneChar[0] = value.charAt(i);
- byte[] buf;
- if (oneChar[0] < 128 || charset == null) {
- byte[] oneByte = new byte[1];
- oneByte[0] = (byte) oneChar[0];
- buf = oneByte;
- } else {
- buf = charset.encode(CharBuffer.wrap(oneChar, 0, 1)).array();
- }
- if (size + buf.length > limit) {
- if (limit != LINE_LENGTH_LIMIT) {
- os.write(' ');
- }
- os.write(outBuf, 0, size);
- os.write(LINE_SEPARATOR);
- limit = LINE_LENGTH_LIMIT - 1;
- size = 0;
- }
- if (buf.length == 1) {
- outBuf[size] = buf[0];
- } else {
- System.arraycopy(buf, 0, outBuf, size, buf.length);
- }
- size += buf.length;
- }
- if (size > 0) {
- if (limit != LINE_LENGTH_LIMIT) {
- os.write(' ');
+
+ os.write(out);
+ os.write(VALUE_SEPARATOR);
+
+ encoder.reset();
+ bBuf.clear().limit(LINE_LENGTH_LIMIT - out.length - 2);
+
+ CharBuffer cBuf = CharBuffer.wrap(value);
+ CoderResult r;
+
+ while (true) {
+ r = encoder.encode(cBuf, bBuf, true);
+ if (CoderResult.UNDERFLOW == r) {
+ r = encoder.flush(bBuf);
}
- os.write(outBuf, 0, size);
+ os.write(bBuf.array(), bBuf.arrayOffset(), bBuf.position());
os.write(LINE_SEPARATOR);
+ if (CoderResult.UNDERFLOW == r) {
+ break;
+ }
+ os.write(' ');
+ bBuf.clear().limit(LINE_LENGTH_LIMIT - 1);
}
}
}
Modified: harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties?rev=641928&r1=641927&r2=641928&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties (original)
+++ harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties Thu Mar 27 11:02:32 2008
@@ -50,7 +50,7 @@
archive.20=Crc mismatch
archive.21=Size mismatch
archive.22=Cannot read version
-archive.23=Entry is not named
+archive.entryIsNotNamed=Entry is not named
archive.24=Unable to open\: {0}
archive.25=Invalid zip file\: {0}
archive.26=attempt to write after finish
@@ -60,8 +60,11 @@
archive.2A=Name too long: {0}
archive.2B=String is too long
archive.2C=No active entry
-archive.2D=Missing version string\: {0}
-archive.2E=Line too long
-archive.2F=Invalid attribute {0}
+archive.missingVersionAttribute=Missing version attribute\: {0}
+archive.manifestTooLong=Manifest is too long
+archive.nulCharInManifest=NUL character in a manifest
+archive.invalidAttribute=Invalid attribute {0}
archive.30={0} failed verification of {1}
-archive.31={0} has invalid digest for {1} in {2}
+archive.invalidDigest={0} has invalid digest for {1} in {2}
+archive.headerNameTooLong=A length of the encoded header name "{1}" exceeded maximum length {2}
+archive.verifiableEntryRepeated=A jar verifier does not support more than one entry with the same name
Modified: harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/util/Util.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/util/Util.java?rev=641928&r1=641927&r2=641928&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/util/Util.java (original)
+++ harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/util/Util.java Thu Mar 27 11:02:32 2008
@@ -30,40 +30,30 @@
return false;
}
- s1 = s1.substring(start1, start1 + length);
- s2 = s2.substring(start2, start2 + length);
-
- return toASCIILowerCase(s1).equals(toASCIILowerCase(s2));
- }
- throw new NullPointerException();
- }
-
- public static String toASCIILowerCase(String s) {
- int len = s.length();
- StringBuilder buffer = new StringBuilder(len);
- for (int i = 0; i < len; i++) {
- char c = s.charAt(i);
- if ('A' <= c && c <= 'Z') {
- buffer.append((char) (c + ('a' - 'A')));
- } else {
- buffer.append(c);
+ char c1, c2;
+ for (int i = 0; i < length; i++) {
+ if ((c1 = s1.charAt(start1++)) != (c2 = s2.charAt(start2++))
+ && toASCIIUpperCase(c1) != toASCIIUpperCase(c2)) {
+ return false;
+ }
}
+ return true;
}
- return buffer.toString();
+ throw new NullPointerException();
}
- public static String toASCIIUpperCase(String s) {
- int len = s.length();
- StringBuilder buffer = new StringBuilder(len);
+ public static byte[] toASCIILowerCase(byte[] buf) {
+ int len = buf.length;
+ byte[] buffer = new byte[len];
for (int i = 0; i < len; i++) {
- char c = s.charAt(i);
- if ('a' <= c && c <= 'z') {
- buffer.append((char) (c - ('a' - 'A')));
+ byte b = buf[i];
+ if ('A' <= b && b <= 'Z') {
+ buffer[i] = (byte) (b + ('a' - 'A'));
} else {
- buffer.append(c);
+ buffer[i] = b;
}
}
- return buffer.toString();
+ return buffer;
}
public static final boolean equalsIgnoreCase(String s1, String s2) {
@@ -86,6 +76,26 @@
return true;
}
+ public static final boolean equalsIgnoreCase(byte[] buf1, byte[] buf2) {
+ if (buf1 == buf2) {
+ return true;
+ }
+
+ if (buf1 == null || buf2 == null || buf1.length != buf2.length) {
+ return false;
+ }
+
+ byte b1, b2;
+
+ for (int i = 0; i < buf1.length; i++) {
+ if ((b1 = buf1[i]) != (b2 = buf2[i])
+ && toASCIIUpperCase(b1) != toASCIIUpperCase(b2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static final char toASCIILowerCase(char c) {
if ('A' <= c && c <= 'Z') {
return (char) (c + ('a' - 'A'));
@@ -98,5 +108,12 @@
return (char) (c - ('a' - 'A'));
}
return c;
+ }
+
+ public static final byte toASCIIUpperCase(byte b) {
+ if ('a' <= b && b <= 'z') {
+ return (byte) (b - ('a' - 'A'));
+ }
+ return b;
}
}
Modified: harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesNameTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesNameTest.java?rev=641928&r1=641927&r2=641928&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesNameTest.java (original)
+++ harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesNameTest.java Thu Mar 27 11:02:32 2008
@@ -26,12 +26,12 @@
/**
* @tests java.util.jar.Attributes.Name#Name(java.lang.String)
*/
- public void test_AttributesName_Constructor() {
+ public void testAttributesNameConstructor() {
// Regression for HARMONY-85
try {
new Attributes.Name(
"01234567890123456789012345678901234567890123456789012345678901234567890");
- fail("Assert 0: should have thrown IllegalArgumentException");
+ fail("Should throw IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
Modified: harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java?rev=641928&r1=641927&r2=641928&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java (original)
+++ harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java Thu Mar 27 11:02:32 2008
@@ -62,7 +62,7 @@
jarFile.close();
}
}
-
+
/**
* @throws IOException
* @tests java.util.jar.JarEntry#JarEntry(java.util.jar.JarEntry)
@@ -89,8 +89,10 @@
assertNotNull("Zip entry is null", zipEntry);
jarEntry = new JarEntry(zipEntry);
assertNotNull("Jar entry is null", jarEntry);
- assertEquals("Wrong entry constructed--wrong name", entryName, jarEntry.getName());
- assertEquals("Wrong entry constructed--wrong size", 311, jarEntry.getSize());
+ assertEquals("Wrong entry constructed--wrong name", entryName, jarEntry
+ .getName());
+ assertEquals("Wrong entry constructed--wrong size", 311, jarEntry
+ .getSize());
}
/**
@@ -105,22 +107,24 @@
attrJar = new JarFile(file);
jarEntry = attrJar.getJarEntry(attEntryName);
- assertNotNull("Should have Manifest attributes", jarEntry.getAttributes());
+ assertNotNull("Should have Manifest attributes", jarEntry
+ .getAttributes());
jarEntry = attrJar.getJarEntry(attEntryName2);
- assertNull("Shouldn't have any Manifest attributes", jarEntry.getAttributes());
+ assertNull("Shouldn't have any Manifest attributes", jarEntry
+ .getAttributes());
attrJar.close();
}
/**
* @tests java.util.jar.JarEntry#getCertificates()
*/
- public void test_getCertificates() throws Exception{
+ public void test_getCertificates() throws Exception {
zipEntry = jarFile.getEntry(entryName2);
jarEntry = new JarEntry(zipEntry);
- assertNull("Shouldn't have any Certificates", jarEntry.getCertificates());
-
- //Regression Test for HARMONY-3424
+ assertNull(jarEntry.getCertificates());
+
+ // Regression Test for HARMONY-3424
String jarFileName = "TestCodeSigners.jar";
Support_Resources.copyFile(resources, null, jarFileName);
File file = new File(resources, jarFileName);
@@ -129,10 +133,16 @@
JarEntry jarEntry2 = jarFile.getJarEntry("Test.class");
InputStream in = jarFile.getInputStream(jarEntry1);
byte[] buffer = new byte[1024];
- while(in.read(buffer)>=0);
- in.close();
+ while (in.available() > 0) {
+ assertNull("getCertificates() should be null until the entry is read",
+ jarEntry1.getCertificates());
+ assertNull(jarEntry2.getCertificates());
+ in.read(buffer);
+ }
+ assertEquals("the file is fully read", -1, in.read());
assertNotNull(jarEntry1.getCertificates());
assertNotNull(jarEntry2.getCertificates());
+ in.close();
}
/**
@@ -147,12 +157,17 @@
InputStream in = jarFile.getInputStream(jarEntry);
byte[] buffer = new byte[1024];
while (in.available() > 0) {
+ assertNull("getCodeSigners() should be null until the entry is read",
+ jarEntry.getCodeSigners());
in.read(buffer);
}
+ assertEquals("the file is fully read", -1, in.read());
CodeSigner[] codeSigners = jarEntry.getCodeSigners();
assertEquals(2, codeSigners.length);
- List<?> certs_bob = codeSigners[0].getSignerCertPath().getCertificates();
- List<?> certs_alice = codeSigners[1].getSignerCertPath().getCertificates();
+ List<?> certs_bob = codeSigners[0].getSignerCertPath()
+ .getCertificates();
+ List<?> certs_alice = codeSigners[1].getSignerCertPath()
+ .getCertificates();
if (1 == certs_bob.size()) {
List<?> temp = certs_bob;
certs_bob = certs_alice;
@@ -160,7 +175,8 @@
}
assertEquals(2, certs_bob.size());
assertEquals(1, certs_alice.size());
- assertNull("getCodeSigners() of a primitive JarEntry should return null", new JarEntry(
- "aaa").getCodeSigners());
+ assertNull(
+ "getCodeSigners() should be null for a primitive JarEntry",
+ new JarEntry("aaa").getCodeSigners());
}
}
Modified: harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java?rev=641928&r1=641927&r2=641928&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java (original)
+++ harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java Thu Mar 27 11:02:32 2008
@@ -38,308 +38,304 @@
public class JarFileTest extends TestCase {
- private final String jarName = "hyts_patch.jar"; // a 'normal' jar file
+ /**
+ * The file contains the following entries:
+ *
+ * <pre>
+ * META-INF/ META-INF/MANIFEST.MF
+ * foo/ foo/bar/ foo/bar/A.class
+ * Blah.txt
+ * </pre>
+ */
+ private final String JAR1 = "hyts_patch.jar";
+
+ private final String JAR2 = "hyts_patch2.jar";
- private final String jarName2 = "hyts_patch2.jar";
+ private final String JAR3 = "hyts_manifest1.jar";
- private final String jarName3 = "hyts_manifest1.jar";
+ private final String JAR4 = "hyts_signed.jar";
- private final String jarName4 = "hyts_signed.jar";
+ private final String JAR5 = "Integrate.jar";
- private final String entryName = "foo/bar/A.class";
+ private final String JAR1_ENTRY1 = "foo/bar/A.class";
- private final String entryName3 = "coucou/FileAccess.class";
+ private final String JAR5_SIGNED_ENTRY = "Test.class";
+
+ private final String JAR4_SIGNED_ENTRY = "coucou/FileAccess.class";
private File resources;
-
+
@Override
protected void setUp() {
resources = Support_Resources.createTempFolder();
}
- /**
- * @tests java.util.jar.JarFile#JarFile(java.io.File)
- */
- public void test_ConstructorLjava_io_File() {
- // Test for method java.util.jar.JarFile(java.io.File)
- /*
- * try { assertTrue("Error in created file", new JarFile(new
- * java.io.File(jarName)).getEntry(entryName).getName().equals(entryName)); }
- * catch (Exception e) { fail("Exception during test: " +
- * e.toString()); }
- */
- }
-
- /**
- * @tests java.util.jar.JarFile#JarFile(java.lang.String)
- */
- public void test_ConstructorLjava_lang_String() {
- // Test for method java.util.jar.JarFile(java.lang.String)
- /*
- * try { assertTrue("Error in created file", new
- * JarFile(jarName).getEntry(entryName).getName().equals(entryName)); }
- * catch (Exception e) { fail("Exception during test: " +
- * e.toString()); }
- */
- }
-
- /**
- * @tests java.util.jar.JarFile#entries()
- */
- public void test_entries() throws Exception {
- /*
- * Note only (and all of) the following should be contained in the file
- * META-INF/ META-INF/MANIFEST.MF foo/ foo/bar/ foo/bar/A.class Blah.txt
- */
- Support_Resources.copyFile(resources, null, jarName);
- JarFile jarFile = new JarFile(new File(resources, jarName));
+ /**
+ * Constructs JarFile object.
+ *
+ * @tests java.util.jar.JarFile#JarFile(java.io.File)
+ * @tests java.util.jar.JarFile#JarFile(java.lang.String)
+ */
+ public void testConstructor() throws IOException {
+ File f = new File(resources, JAR1);
+ Support_Resources.copyFile(resources, null, JAR1);
+ assertTrue(new JarFile(f).getEntry(JAR1_ENTRY1).getName().equals(
+ JAR1_ENTRY1));
+ assertTrue(new JarFile(f.getPath()).getEntry(JAR1_ENTRY1).getName()
+ .equals(JAR1_ENTRY1));
+ }
+
+ /**
+ * @tests java.util.jar.JarFile#entries()
+ */
+ public void testEntries() throws Exception {
+ Support_Resources.copyFile(resources, null, JAR1);
+ JarFile jarFile = new JarFile(new File(resources, JAR1));
Enumeration<JarEntry> e = jarFile.entries();
- int i = 0;
- while (e.hasMoreElements()) {
- i++;
+ int i;
+ for (i = 0; e.hasMoreElements(); i++) {
e.nextElement();
}
+ assertEquals(jarFile.size(), i);
jarFile.close();
assertEquals(6, i);
}
-
- public void test_entries2() throws Exception {
- Support_Resources.copyFile(resources, null, jarName);
- JarFile jarFile = new JarFile(new File(resources, jarName));
+
+ public void testEntriesIterator() throws Exception {
+ Support_Resources.copyFile(resources, null, JAR1);
+ JarFile jarFile = new JarFile(new File(resources, JAR1));
Enumeration<JarEntry> enumeration = jarFile.entries();
jarFile.close();
- boolean pass = false;
try {
enumeration.hasMoreElements();
+ fail("hasMoreElements() did not detect a closed jar file");
} catch (IllegalStateException e) {
- pass = true;
}
- assertTrue("hasMoreElements did not detect closed jar file", pass);
- Support_Resources.copyFile(resources, null, jarName);
- jarFile = new JarFile(new File(resources, jarName));
+ Support_Resources.copyFile(resources, null, JAR1);
+ jarFile = new JarFile(new File(resources, JAR1));
enumeration = jarFile.entries();
jarFile.close();
- pass = false;
try {
enumeration.nextElement();
+ fail("nextElement() did not detect closed jar file");
} catch (IllegalStateException e) {
- pass = true;
}
- assertTrue("nextElement did not detect closed jar file", pass);
}
- /**
- * @tests java.util.jar.JarFile#getJarEntry(java.lang.String)
- */
- public void test_getJarEntryLjava_lang_String() throws Exception {
- Support_Resources.copyFile(resources, null, jarName);
- JarFile jarFile = new JarFile(new File(resources, jarName));
- assertEquals("Error in returned entry", 311, jarFile.getEntry(entryName)
- .getSize());
- jarFile.close();
-
- // tests for signed jars
- // test all signed jars in the /Testres/Internal/SignedJars directory
- String jarDirUrl = Support_Resources
- .getResourceURL("/../internalres/signedjars");
- Vector<String> signedJars = new Vector<String>();
- try {
- InputStream is = new URL(jarDirUrl + "/jarlist.txt").openStream();
- while (is.available() > 0) {
- StringBuffer linebuff = new StringBuffer(80); // Typical line
- // length
- done: while (true) {
- int nextByte = is.read();
- switch (nextByte) {
- case -1:
- break done;
- case (byte) '\r':
- if (linebuff.length() == 0) {
- // ignore
- }
- break done;
- case (byte) '\n':
- if (linebuff.length() == 0) {
- // ignore
- }
- break done;
- default:
- linebuff.append((char) nextByte);
- }
- }
- if (linebuff.length() == 0) {
- break;
- }
- String line = linebuff.toString();
- signedJars.add(line);
- }
- is.close();
- } catch (IOException e) {
- // no list of jars found
- }
-
- for (int i = 0; i < signedJars.size(); i++) {
- String jarName = signedJars.get(i);
- try {
- File file = Support_Resources.getExternalLocalFile(jarDirUrl
- + "/" + jarName);
- jarFile = new JarFile(file, true);
- boolean foundCerts = false;
- Enumeration<JarEntry> e = jarFile.entries();
- while (e.hasMoreElements()) {
- JarEntry entry = e.nextElement();
- InputStream is = jarFile.getInputStream(entry);
- is.skip(100000);
- is.close();
- Certificate[] certs = entry.getCertificates();
- if (certs != null && certs.length > 0) {
- foundCerts = true;
- break;
- }
- }
- assertTrue(
- "No certificates found during signed jar test for jar \""
- + jarName + "\"", foundCerts);
- } catch (IOException e) {
- fail("Exception during signed jar test for jar \""
- + jarName + "\": " + e.toString());
- }
- }
- }
-
- /**
- * @tests java.util.jar.JarFile#getManifest()
- */
- public void test_getManifest() throws Exception {
- // Test for method java.util.jar.Manifest
- // java.util.jar.JarFile.getManifest()
- Support_Resources.copyFile(resources, null, jarName);
- JarFile jarFile = new JarFile(new File(resources, jarName));
- assertNotNull("Error--Manifest not returned",
- jarFile.getManifest());
- jarFile.close();
-
- Support_Resources.copyFile(resources, null, jarName2);
- jarFile = new JarFile(new File(resources, jarName2));
- assertNull("Error--should have returned null", jarFile
- .getManifest());
- jarFile.close();
-
- // jarName3 was created using the following test
- Support_Resources.copyFile(resources, null, jarName3);
- jarFile = new JarFile(new File(resources, jarName3));
- assertNotNull("Should find manifest without verifying", jarFile
- .getManifest());
- jarFile.close();
-
- // this is used to create jarName3 used in the previous test
- Manifest manifest = new Manifest();
- Attributes attributes = manifest.getMainAttributes();
- attributes.put(new Attributes.Name("Manifest-Version"), "1.0");
- ByteArrayOutputStream manOut = new ByteArrayOutputStream();
- manifest.write(manOut);
- byte[] manBytes = manOut.toByteArray();
- File file = new File(Support_PlatformFile.getNewPlatformFile(
- "hyts_manifest1", ".jar"));
- JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(
- file.getAbsolutePath()));
- ZipEntry entry = new ZipEntry("META-INF/");
- entry.setSize(0);
- jarOut.putNextEntry(entry);
- entry = new ZipEntry(JarFile.MANIFEST_NAME);
- entry.setSize(manBytes.length);
- jarOut.putNextEntry(entry);
- jarOut.write(manBytes);
- entry = new ZipEntry("myfile");
- entry.setSize(1);
- jarOut.putNextEntry(entry);
- jarOut.write(65);
- jarOut.close();
- JarFile jar = new JarFile(file.getAbsolutePath(), false);
- assertNotNull("Should find manifest without verifying", jar
- .getManifest());
- jar.close();
- file.delete();
-
- try {
- Support_Resources.copyFile(resources, null, jarName2);
- JarFile jF = new JarFile(new File(resources, jarName2));
- jF.close();
- jF.getManifest();
- fail("FAILED: expected IllegalStateException" );
- } catch (IllegalStateException ise) {
- //expected;
- }
- }
-
- /**
- * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
- */
- public void test_getInputStreamLjava_util_jar_JarEntry() throws Exception {
+ /**
+ * @tests java.util.jar.JarFile#getJarEntry(java.lang.String)
+ */
+ public void testGetJarEntry() throws Exception {
+ Support_Resources.copyFile(resources, null, JAR1);
+ JarFile jarFile = new JarFile(new File(resources, JAR1));
+ assertEquals("Error in returned entry", 311, jarFile.getEntry(
+ JAR1_ENTRY1).getSize());
+ jarFile.close();
+
+ // tests for signed jars
+ // test all signed jars in the /Testres/Internal/SignedJars directory
+ String jarDirUrl = Support_Resources
+ .getResourceURL("/../internalres/signedjars");
+ Vector<String> signedJars = new Vector<String>();
+ try {
+ InputStream is = new URL(jarDirUrl + "/jarlist.txt").openStream();
+ while (is.available() > 0) {
+ StringBuffer linebuff = new StringBuffer(80); // Typical line
+ // length
+ done: while (true) {
+ int nextByte = is.read();
+ switch (nextByte) {
+ case -1:
+ break done;
+ case (byte) '\r':
+ if (linebuff.length() == 0) {
+ // ignore
+ }
+ break done;
+ case (byte) '\n':
+ if (linebuff.length() == 0) {
+ // ignore
+ }
+ break done;
+ default:
+ linebuff.append((char) nextByte);
+ }
+ }
+ if (linebuff.length() == 0) {
+ break;
+ }
+ String line = linebuff.toString();
+ signedJars.add(line);
+ }
+ is.close();
+ } catch (IOException e) {
+ // no list of jars found
+ }
+
+ for (int i = 0; i < signedJars.size(); i++) {
+ String jarName = signedJars.get(i);
+ try {
+ File file = Support_Resources.getExternalLocalFile(jarDirUrl
+ + "/" + jarName);
+ jarFile = new JarFile(file, true);
+ boolean foundCerts = false;
+ Enumeration<JarEntry> e = jarFile.entries();
+ while (e.hasMoreElements()) {
+ JarEntry entry = e.nextElement();
+ InputStream is = jarFile.getInputStream(entry);
+ is.skip(100000);
+ is.close();
+ Certificate[] certs = entry.getCertificates();
+ if (certs != null && certs.length > 0) {
+ foundCerts = true;
+ break;
+ }
+ }
+ assertTrue(
+ "No certificates found during signed jar test for jar \""
+ + jarName + "\"", foundCerts);
+ } catch (IOException e) {
+ fail("Exception during signed jar test for jar \"" + jarName
+ + "\": " + e.toString());
+ }
+ }
+ }
+
+ /**
+ * @tests java.util.jar.JarFile#getManifest()
+ */
+ public void testGetManifest() throws Exception {
+ // Test for method java.util.jar.Manifest
+ // java.util.jar.JarFile.getManifest()
+ Support_Resources.copyFile(resources, null, JAR1);
+ JarFile jarFile = new JarFile(new File(resources, JAR1));
+ assertNotNull("Error--Manifest not returned", jarFile.getManifest());
+ jarFile.close();
+
+ Support_Resources.copyFile(resources, null, JAR2);
+ jarFile = new JarFile(new File(resources, JAR2));
+ assertNull("Error--should have returned null", jarFile.getManifest());
+ jarFile.close();
+
+ // jarName3 was created using the following test
+ Support_Resources.copyFile(resources, null, JAR3);
+ jarFile = new JarFile(new File(resources, JAR3));
+ assertNotNull("Should find manifest without verifying", jarFile
+ .getManifest());
+ jarFile.close();
+
+ // this is used to create jarName3 used in the previous test
+ Manifest manifest = new Manifest();
+ Attributes attributes = manifest.getMainAttributes();
+ attributes.put(new Attributes.Name("Manifest-Version"), "1.0");
+ ByteArrayOutputStream manOut = new ByteArrayOutputStream();
+ manifest.write(manOut);
+ byte[] manBytes = manOut.toByteArray();
+ File file = new File(Support_PlatformFile.getNewPlatformFile(
+ "hyts_manifest1", ".jar"));
+ JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(file
+ .getAbsolutePath()));
+ ZipEntry entry = new ZipEntry("META-INF/");
+ entry.setSize(0);
+ jarOut.putNextEntry(entry);
+ entry = new ZipEntry(JarFile.MANIFEST_NAME);
+ entry.setSize(manBytes.length);
+ jarOut.putNextEntry(entry);
+ jarOut.write(manBytes);
+ entry = new ZipEntry("myfile");
+ entry.setSize(1);
+ jarOut.putNextEntry(entry);
+ jarOut.write(65);
+ jarOut.close();
+ JarFile jar = new JarFile(file.getAbsolutePath(), false);
+ assertNotNull("Should find manifest without verifying", jar
+ .getManifest());
+ jar.close();
+ file.delete();
+
+ try {
+ Support_Resources.copyFile(resources, null, JAR2);
+ JarFile jF = new JarFile(new File(resources, JAR2));
+ jF.close();
+ jF.getManifest();
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException ise) {
+ // expected;
+ }
+ }
+
+ /**
+ * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
+ */
+ public void testGetInputStream() throws Exception {
File localFile;
byte[] b = new byte[1024];
JarFile jf;
InputStream is;
- Support_Resources.copyFile(resources, null, jarName);
- localFile = new File(resources, jarName);
+ Support_Resources.copyFile(resources, null, JAR1);
+ localFile = new File(resources, JAR1);
jf = new JarFile(localFile);
is = jf.getInputStream(new JarEntry("invalid"));
assertNull("Got stream for non-existent entry", is);
- is = jf.getInputStream(jf.getEntry(entryName));
+ is = jf.getInputStream(jf.getEntry(JAR1_ENTRY1));
assertTrue("Returned invalid stream", is.available() > 0);
// try to read class file header
is.read(b, 0, 1024);
jf.close();
- assertTrue("Invalid bytes were red",
- b[0] == (byte) 0xCA &&
- b[1] == (byte) 0xFE &&
- b[2] == (byte) 0xBA &&
- b[3] == (byte) 0xBE);
- }
-
- /**
- * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
- */
- public void test_getInputStreamLjava_util_jar_JarEntry_subtest0() throws Exception {
- File signedFile = null;
- Support_Resources.copyFile(resources, null, jarName4);
- signedFile = new File(resources, jarName4);
-
- JarFile jar = new JarFile(signedFile);
- JarEntry entry = new JarEntry(entryName3);
- InputStream in = jar.getInputStream(entry);
- in.read();
-
- jar = new JarFile(signedFile);
- entry = new JarEntry(entryName3);
- in = jar.getInputStream(entry);
- in.read(new byte[1077]);
- assertNull("found certificates", entry.getCertificates());
-
- boolean exception = false;
- try {
- jar = new JarFile(signedFile);
- entry = new JarEntry(entryName3);
- entry.setSize(1076);
- in = jar.getInputStream(entry);
- in.read(new byte[2048]);
- } catch (SecurityException e) {
- exception = true;
- }
+ assertTrue("Invalid bytes were red", b[0] == (byte) 0xCA
+ && b[1] == (byte) 0xFE && b[2] == (byte) 0xBA
+ && b[3] == (byte) 0xBE);
+ }
- assertTrue("Failed to throw SecurityException", exception);
- }
+ /**
+ * Signed file is verified by default.
+ *
+ * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
+ */
+ public void testInputStreamOperations() throws Exception {
+ Support_Resources.copyFile(resources, null, JAR4);
+ File signedFile = new File(resources, JAR4);
+
+ JarFile jar = new JarFile(signedFile);
+ JarEntry entry = new JarEntry(JAR4_SIGNED_ENTRY);
+ InputStream in = jar.getInputStream(entry);
+ in.read();
+
+ // RI verifies only entries which appear via getJarEntry method
+ jar = new JarFile(signedFile);
+ entry = jar.getJarEntry(JAR4_SIGNED_ENTRY);
+ in = jar.getInputStream(entry);
+ in.read(new byte[(int) entry.getSize() - 1]);
+ assertNull(entry.getCertificates());
+ in.read();
+ assertNotNull(entry.getCertificates());
+ assertEquals(-1, in.read());
+
+ jar = new JarFile(signedFile);
+ entry = jar.getJarEntry(JAR4_SIGNED_ENTRY);
+ entry.setSize(entry.getSize() - 1);
+ in = jar.getInputStream(entry);
+ in.read(new byte[(int) entry.getSize() - 1]);
+ assertNull(entry.getCertificates());
+ try {
+ in.read();
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // desired
+ }
+ assertEquals(-1, in.read());
+ }
/*
* The jar created by 1.4 which does not provide a
* algorithm-Digest-Manifest-Main-Attributes entry in .SF file.
*/
- public void test_Jar_created_before_java_5() throws IOException {
+ public void testJar14() throws IOException {
String modifiedJarName = "Created_by_1_4.jar";
Support_Resources.copyFile(resources, null, modifiedJarName);
JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
@@ -351,16 +347,40 @@
}
}
- /* The jar is intact, then everything is all right. */
- public void test_JarFile_Integrate_Jar() throws IOException {
- String modifiedJarName = "Integrate.jar";
- Support_Resources.copyFile(resources, null, modifiedJarName);
- JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
- true);
+ /**
+ * The jar is intact, then everything is all right.
+ */
+ public void testJarVerification() throws IOException {
+ Support_Resources.copyFile(resources, null, JAR5);
+ JarFile jarFile = new JarFile(new File(resources, JAR5), true);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
ZipEntry zipEntry = entries.nextElement();
- jarFile.getInputStream(zipEntry);
+ jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
+ }
+ }
+
+ /**
+ * The jar is intact, but the entry object is modified.
+ */
+ public void testJarVerificationModifiedEntry() throws IOException {
+ Support_Resources.copyFile(resources, null, JAR5);
+ File f = new File(resources, JAR5);
+
+ JarFile jarFile = new JarFile(f);
+ ZipEntry zipEntry = jarFile.getJarEntry(JAR5_SIGNED_ENTRY);
+ zipEntry.setSize(zipEntry.getSize() + 1);
+ jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
+
+ jarFile = new JarFile(f);
+ zipEntry = jarFile.getJarEntry(JAR5_SIGNED_ENTRY);
+ zipEntry.setSize(zipEntry.getSize() - 1);
+ try {
+ //jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
+ jarFile.getInputStream(zipEntry).read(new byte[5000], 0, 5000);
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // desired
}
}
@@ -368,7 +388,7 @@
* If another entry is inserted into Manifest, no security exception will be
* thrown out.
*/
- public void test_JarFile_InsertEntry_in_Manifest_Jar() throws IOException {
+ public void testJarFileInsertEntryInManifestJar() throws IOException {
String modifiedJarName = "Inserted_Entry_Manifest.jar";
Support_Resources.copyFile(resources, null, modifiedJarName);
JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
@@ -388,8 +408,7 @@
* If another entry is inserted into Manifest, no security exception will be
* thrown out.
*/
- public void test_Inserted_Entry_Manifest_with_DigestCode()
- throws IOException {
+ public void testInsertedEntryManifestWithDigestCode() throws IOException {
String modifiedJarName = "Inserted_Entry_Manifest_with_DigestCode.jar";
Support_Resources.copyFile(resources, null, modifiedJarName);
JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
@@ -397,7 +416,6 @@
Enumeration<JarEntry> entries = jarFile.entries();
int count = 0;
while (entries.hasMoreElements()) {
-
ZipEntry zipEntry = entries.nextElement();
jarFile.getInputStream(zipEntry);
count++;
@@ -410,7 +428,7 @@
* throw security Exception, but it will anytime before the inputStream got
* from getInputStream method has been read to end.
*/
- public void test_JarFile_Modified_Class() throws IOException {
+ public void testJarFileModifiedClass() throws IOException {
String modifiedJarName = "Modified_Class.jar";
Support_Resources.copyFile(resources, null, modifiedJarName);
JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
@@ -428,7 +446,7 @@
while (in.available() > 0) {
in.read(buffer);
}
- fail("should throw Security Exception");
+ fail("SecurityException expected");
} catch (SecurityException e) {
// desired
}
@@ -437,10 +455,9 @@
/*
* In the Modified.jar, the main attributes of META-INF/MANIFEST.MF is
* tampered manually. Hence the RI 5.0 JarFile.getInputStream of any
- * JarEntry will throw security exception, but the apache harmony will not.
+ * JarEntry will throw security exception.
*/
- public void test_JarFile_Modified_Manifest_MainAttributes()
- throws IOException {
+ public void testJarFileModifiedManifestMainAttributes() throws IOException {
String modifiedJarName = "Modified_Manifest_MainAttributes.jar";
Support_Resources.copyFile(resources, null, modifiedJarName);
JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
@@ -450,7 +467,7 @@
ZipEntry zipEntry = entries.nextElement();
try {
jarFile.getInputStream(zipEntry);
- fail("should throw Security Exception");
+ fail("SecurityException expected");
} catch (SecurityException e) {
// desired
}
@@ -462,8 +479,7 @@
* example Test.class in our jar, the jarFile.getInputStream will throw
* Security Exception.
*/
- public void test_JarFile_Modified_Manifest_EntryAttributes()
- throws IOException {
+ public void testJarFileModifiedManifestEntryAttributes() throws IOException {
String modifiedJarName = "Modified_Manifest_EntryAttributes.jar";
Support_Resources.copyFile(resources, null, modifiedJarName);
JarFile jarFile = new JarFile(new File(resources, modifiedJarName),
@@ -484,7 +500,7 @@
* If the content of the .SA file is modified, no matter what it resides,
* JarFile.getInputStream of any JarEntry will throw Security Exception.
*/
- public void test_JarFile_Modified_SF_EntryAttributes() throws IOException {
+ public void testJarFileModifiedSfEntryAttributes() throws IOException {
String modifiedJarName = "Modified_SF_EntryAttributes.jar";
Support_Resources.copyFile(resources, null, modifiedJarName);
JarFile jarFile = new JarFile(new File(resources, modifiedJarName),