Index: src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java
===================================================================
--- src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java	(revision 759456)
+++ src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java	(working copy)
@@ -35,22 +35,47 @@
     private final InputStream input;
     private long offset = 0;
 
-    public ArArchiveInputStream( final InputStream pInput ) {
+    /*
+     * If getNextEnxtry has been called, the entry metadata is stored in
+     * currentEntry.
+     */
+    private ArArchiveEntry currentEntry = null;
+    /*
+     * The offset where the current entry started. -1 if no entry has been
+     * called
+     */
+    private long entryOffset = -1;
+
+    public ArArchiveInputStream(final InputStream pInput) {
         input = pInput;
     }
 
+    /**
+     * Returns the next AR entry in this stream.
+     * 
+     * @return the next AR entry.
+     * @throws IOException
+     *             if the entry could not be read
+     */
     public ArArchiveEntry getNextArEntry() throws IOException {
+        if (this.currentEntry != null) {
+            long entryEnd = entryOffset + currentEntry.getLength();
+            while (offset < entryEnd) {
+                this.read();
+            }
+        }
 
         if (offset == 0) {
             final byte[] expected = "!<arch>\n".getBytes();
-            final byte[] realized = new byte[expected.length]; 
+            final byte[] realized = new byte[expected.length];
             final int read = read(realized);
             if (read != expected.length) {
                 throw new IOException("failed to read header");
             }
             for (int i = 0; i < expected.length; i++) {
                 if (expected[i] != realized[i]) {
-                    throw new IOException("invalid header " + new String(realized));
+                    throw new IOException("invalid header "
+                            + new String(realized));
                 }
             }
         }
@@ -79,48 +104,119 @@
 
         {
             final byte[] expected = "`\012".getBytes();
-            final byte[] realized = new byte[expected.length]; 
+            final byte[] realized = new byte[expected.length];
             final int read = read(realized);
             if (read != expected.length) {
                 throw new IOException("failed to read entry header");
             }
             for (int i = 0; i < expected.length; i++) {
                 if (expected[i] != realized[i]) {
-                    throw new IOException("invalid entry header. not read the content?");
+                    throw new IOException(
+                            "invalid entry header. not read the content?");
                 }
             }
         }
 
-        return new ArArchiveEntry(new String(name).trim(), Long.parseLong(new String(length).trim()));
-
+        entryOffset = offset;
+        currentEntry = new ArArchiveEntry(new String(name).trim(), Long
+                .parseLong(new String(length).trim()));
+        return currentEntry;
     }
 
-
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * org.apache.commons.compress.archivers.ArchiveInputStream#getNextEntry()
+     */
     public ArchiveEntry getNextEntry() throws IOException {
         return getNextArEntry();
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.io.InputStream#read()
+     */
     public int read() throws IOException {
         final int ret = input.read();
         offset++;
         return ret;
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.io.InputStream#read(byte[])
+     */
     public int read(byte b[]) throws IOException {
-        final int ret = read(b, 0, b.length);
-        offset = offset + b.length;
-        return ret;
+        return read(b, 0, b.length);
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.io.InputStream#read(byte[], int, int)
+     */
     public int read(byte[] b, int off, int len) throws IOException {
-        final int ret = this.input.read(b, off, len);
-        offset = offset + off;
+        int maxread = calculateReadableBytes(len);
+        if (maxread == -1) {
+            return maxread;
+        }
+
+        final int ret = this.input.read(b, off, maxread);
+        if (ret != -1) {
+            offset = offset + ret;
+        }
         return ret;
     }
 
-    public static boolean matches(byte[] signature, int length) {
-        // 3c21 7261 6863 0a3e
+    /**
+     * Calculates the maximum number of bytes which can be read before the next
+     * entry starts.
+     * 
+     * @param maxread
+     *            the number of bytes the client would like to read
+     * @return the actual number of bytes which can be read
+     */
+    private int calculateReadableBytes(int maxread) {
+        if (currentEntry == null) {
+            return maxread;
+        }
+
+        long endoffset = entryOffset + currentEntry.getLength();
+        if (endoffset == offset) {
+            currentEntry = null;
+            return -1;
+        } else if (currentEntry.getLength() < maxread) {
+            // FIXME: better option than this cast?
+            return (int) currentEntry.getLength();
+        } else {
+            if (offset >= endoffset) {
+                return -1;
+            } else if (offset < endoffset) {
+                int left = (int) (endoffset - offset);
+                if (left < maxread) {
+                    return left;
+                }
+            }
+        }
+        return maxread;
+    }
 
+    /**
+     * Checks if the referenced signature is the header of an AR archive. The
+     * byte signature of an ar archive is the following: 3c21 7261 6863 0a3e
+     * 
+     * The ASCII representation is: !<arch> (followed by a line feed)
+     * 
+     * @param signature
+     *            the header bytes to check
+     * @param length
+     *            the length to to check
+     * @return true, if this signature matches this stream, false otherwise
+     */
+    public static boolean matches(byte[] signature, int length) {
         if (length < 8) {
             return false;
         }
