Thanks for the patch Jesse. A specific comment below. On 03/Oct/2009 01:32, Jesse Wilson (JIRA) wrote: > Several archive bugfixes and optimizations > ------------------------------------------ > The attached patch includes several miscellaneous bugfixes, > optimizations and simplifications that we created for Android's copy > of the archive module. Here's an overview of what's changed: > > InflaterInputStream Removes a bogus magic number check. Previously I > submitted a patch to get this check to work; but the whole premise is > flawed. To demonstrate, attempt to inflate data that was deflated > using non-default settings. > > InflaterInputStream, ZipInputStream, GZIPInputStream These now make > sure that available() returns 0 when the end of the stream is > reached. Previously available() could return 1 even if read() was > guaranteed to return -1. > > GZIPOutputStream Slight performance fix: cast from long to int only > once > > JarFile Verifies the entry when the last byte is returned. This is > similar to the available() problem in ZipInputStream etc. Move > getMetaEntriesImpl() from native to Java. > > ZipFile Limit the amount of memory used while reading files. > Previously we would create arbitrarily large buffers. Move several > methods from native to Java. > > MsgHelp Keep resource bundles in memory with soft references Use the > system classloader always. > > Tests New tests to demonstrate problems above, recovery on broken > manifests, verification of empty entries
How about we change this new method in JarFile private byte[] getAllBytesFromStreamAndClose(InputStream is) throws IOException { ByteArrayOutputStream bs = new ByteArrayOutputStream(); try { byte[] buf = new byte[1024]; while (is.available() > 0) { int iRead = is.read(buf, 0, buf.length); if (iRead > 0) bs.write(buf, 0, iRead); } } finally { is.close(); } return bs.toByteArray(); } I know that the InputStream here can only be a RAFStream or InflaterInputStream, and both of them return available() as 1 so long as the stream is not at the end, but in general I guess it is better to read to the -1 eof marker rather than check available(). Then it uses a ByteArrayOutputStream every time, which by default has a 32-byte backing array, that grows aggressively, so putting anything near 1K bytes in will result in a ~2K backing array. So how about we fast track the case (esp. RAFStream) where we get all the bytes in one read...? // Initial read byte[] buffer = new byte[1024]; int count = is.read(buffer); int nextByte = is.read(); // Did we get it all in one read? if (nextByte == -1) { byte[] dest = new byte[count]; System.arraycopy(buffer, 0, dest, 0, count); return dest; } // Requires additional reads ByteArrayOutputStream baos = new ByteArrayOutputStream(count * 2); baos.write(buffer, 0, count); baos.write(nextByte); while (true) { count = is.read(buffer); if (count == -1) { return baos.toByteArray(); } baos.write(buffer, 0, count); } The same holds true for Manifest#readFully(InputStream). Even more so since if we get an eof we don't have to scan for a line ending. WDYT? Regards, Tim