package net.i2p.util; import java.util.concurrent.LinkedBlockingQueue; /** * Provide a cache of reusable GZIP unzipper streams. * This provides stream output only, and therefore can handle unlimited size. */ public class ReusableGZIPInputStream extends ResettableGZIPInputStream { // Apache Harmony 5.0M13 Deflater doesn't work after reset() // Neither does Android private static final boolean ENABLE_CACHING = !(SystemVersion.isApache() || SystemVersion.isAndroid()); private static final LinkedBlockingQueue<ReusableGZIPInputStream> _available; static { if (ENABLE_CACHING) _available = new LinkedBlockingQueue<ReusableGZIPInputStream>(8); else _available = null; } /** * Pull a cached instance */ public static ReusableGZIPInputStream acquire() { ReusableGZIPInputStream rv = null; // Apache Harmony 5.0M13 Deflater doesn't work after reset() if (ENABLE_CACHING) rv = _available.poll(); if (rv == null) { rv = new ReusableGZIPInputStream(); } return rv; } /** * Release an instance back into the cache (this will reset the * state) */ public static void release(ReusableGZIPInputStream released) { if (ENABLE_CACHING) _available.offer(released); } private ReusableGZIPInputStream() { super(); } /** * Clear the cache. * @since 0.9.21 */ public static void clearCache() { if (_available != null) _available.clear(); } /******* public static void main(String args[]) { for (int i = 0; i < 2; i++) test(); for (int i = 0; i < 64*1024; i++) { if (!test(i)) break; } } private static void test() { byte b[] = "hi, how are you today?".getBytes(); try { java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(64); ResettableGZIPOutputStream o = new ResettableGZIPOutputStream(baos); o.write(b); o.finish(); o.flush(); byte compressed[] = baos.toByteArray(); ReusableGZIPInputStream in = ReusableGZIPInputStream.acquire(); in.initialize(new java.io.ByteArrayInputStream(compressed)); byte rv[] = new byte[128]; int read = in.read(rv); if (!net.i2p.data.DataHelper.eq(rv, 0, b, 0, b.length)) throw new RuntimeException("foo, read=" + read); else System.out.println("match, w00t"); ReusableGZIPInputStream.release(in); } catch (Exception e) { e.printStackTrace(); } } private static boolean test(int size) { byte b[] = new byte[size]; RandomSource.getInstance().nextBytes(b); try { java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(size); ResettableGZIPOutputStream o = new ResettableGZIPOutputStream(baos); o.write(b); o.finish(); o.flush(); byte compressed[] = baos.toByteArray(); ReusableGZIPInputStream in = ReusableGZIPInputStream.acquire(); in.initialize(new java.io.ByteArrayInputStream(compressed)); java.io.ByteArrayOutputStream baos2 = new java.io.ByteArrayOutputStream(size); byte rbuf[] = new byte[128]; try { while (true) { int read = in.read(rbuf); if (read == -1) break; baos2.write(rbuf, 0, read); } } catch (java.io.IOException ioe) { ioe.printStackTrace(); //long crcVal = in.getCurrentCRCVal(); //try { in.verifyFooter(); } catch (IOException ioee) { // ioee.printStackTrace(); //} throw ioe; } catch (RuntimeException re) { re.printStackTrace(); throw re; } ReusableGZIPInputStream.release(in); byte rv[] = baos2.toByteArray(); if (rv.length != b.length) throw new RuntimeException("read length: " + rv.length + " expected: " + b.length); if (!net.i2p.data.DataHelper.eq(rv, 0, b, 0, b.length)) { throw new RuntimeException("foo, read=" + rv.length); } else { System.out.println("match, w00t @ " + size); return true; } } catch (Exception e) { System.out.println("Error dealing with size=" + size + ": " + e.getMessage()); e.printStackTrace(); return false; } } ******/ }