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