ZLibOutputStream.java

 1package eu.siacs.conversations.utils.zlib;
 2
 3import java.io.IOException;
 4import java.io.OutputStream;
 5import java.lang.reflect.InvocationTargetException;
 6import java.lang.reflect.Method;
 7import java.security.NoSuchAlgorithmException;
 8import java.util.zip.Deflater;
 9import java.util.zip.DeflaterOutputStream;
10
11/**
12 * <p>
13 * Android 2.2 includes Java7 FLUSH_SYNC option, which will be used by this
14 * Implementation, preferable via reflection. The @hide was remove in API level
15 * 19. This class might thus go away in the future.
16 * </p>
17 * <p>
18 * Please use {@link ZLibOutputStream#SUPPORTED} to check for flush
19 * compatibility.
20 * </p>
21 */
22public class ZLibOutputStream extends DeflaterOutputStream {
23
24	/**
25	 * The reflection based flush method.
26	 */
27
28	private final static Method method;
29	/**
30	 * SUPPORTED is true if a flush compatible method exists.
31	 */
32	public final static boolean SUPPORTED;
33
34	/**
35	 * Static block to initialize {@link #SUPPORTED} and {@link #method}.
36	 */
37	static {
38		Method m = null;
39		try {
40			m = Deflater.class.getMethod("deflate", byte[].class, int.class,
41					int.class, int.class);
42		} catch (SecurityException e) {
43		} catch (NoSuchMethodException e) {
44		}
45		method = m;
46		SUPPORTED = (method != null);
47	}
48
49	/**
50	 * Create a new ZLib compatible output stream wrapping the given low level
51	 * stream. ZLib compatiblity means we will send a zlib header.
52	 * 
53	 * @param os
54	 *            OutputStream The underlying stream.
55	 * @throws IOException
56	 *             In case of a lowlevel transfer problem.
57	 * @throws NoSuchAlgorithmException
58	 *             In case of a {@link Deflater} error.
59	 */
60	public ZLibOutputStream(OutputStream os) throws IOException,
61			NoSuchAlgorithmException {
62		super(os, new Deflater(Deflater.BEST_COMPRESSION));
63	}
64
65	/**
66	 * Flush the given stream, preferring Java7 FLUSH_SYNC if available.
67	 * 
68	 * @throws IOException
69	 *             In case of a lowlevel exception.
70	 */
71	@Override
72	public void flush() throws IOException {
73		if (!SUPPORTED) {
74			super.flush();
75			return;
76		}
77		try {
78			int count = 0;
79			do {
80				count = (Integer) method.invoke(def, buf, 0, buf.length, 3);
81				if (count > 0) {
82					out.write(buf, 0, count);
83				}
84			} while (count > 0);
85		} catch (IllegalArgumentException e) {
86			throw new IOException("Can't flush");
87		} catch (IllegalAccessException e) {
88			throw new IOException("Can't flush");
89		} catch (InvocationTargetException e) {
90			throw new IOException("Can't flush");
91		}
92		super.flush();
93	}
94
95}