harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From telli...@apache.org
Subject 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...
Date Thu, 27 Mar 2008 18:02:39 GMT
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),



Mime
View raw message