aboutsummaryrefslogtreecommitdiffstats
path: root/src/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java
blob: f2bff9fdabcf978b9d8b5884d272e401697563b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package eu.siacs.conversations.utils.zlib;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.NoSuchAlgorithmException;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;

/**
 * <p>Android 2.2 includes Java7 FLUSH_SYNC option, which will be used by this
 * Implementation, preferable via reflection. The @hide was remove in API level
 * 19. This class might thus go away in the future.</p>
 * <p>Please use {@link ZLibOutputStream#SUPPORTED} to check for flush
 * compatibility.</p> 
 */
public class ZLibOutputStream extends DeflaterOutputStream {

    /**
     * The reflection based flush method.
     */

    private final static Method method;
    /**
     * SUPPORTED is true if a flush compatible method exists.
     */
    public final static boolean SUPPORTED;

    /**
     * Static block to initialize {@link #SUPPORTED} and {@link #method}.
     */
    static {
        Method m = null;
        try {
            m = Deflater.class.getMethod("deflate", byte[].class, int.class, int.class, int.class);
        } catch (SecurityException e) {
        } catch (NoSuchMethodException e) {
        }
        method = m;
        SUPPORTED = (method != null);
    }

    /**
     * Create a new ZLib compatible output stream wrapping the given low level
     * stream. ZLib compatiblity means we will send a zlib header. 
     * @param os OutputStream The underlying stream.
     * @throws IOException In case of a lowlevel transfer problem.
     * @throws NoSuchAlgorithmException In case of a {@link Deflater} error.
     */
    public ZLibOutputStream(OutputStream os) throws IOException,
            NoSuchAlgorithmException {
        super(os, new Deflater(Deflater.BEST_COMPRESSION));
    }

    /**
     * Flush the given stream, preferring Java7 FLUSH_SYNC if available.
     * @throws IOException In case of a lowlevel exception.
     */
    @Override
    public void flush() throws IOException {
        if (!SUPPORTED) {
            super.flush();
            return;
        }
        int count = 0;
        if (!def.needsInput()) {
            do {
                count = def.deflate(buf, 0, buf.length);
                out.write(buf, 0, count);
            } while (count > 0);
            out.flush();
        }
        try {
            do {
                count = (Integer) method.invoke(def, buf, 0, buf.length, 2);
                out.write(buf, 0, count);
            } while (count > 0);
        } catch (IllegalArgumentException e) {
            throw new IOException("Can't flush");
        } catch (IllegalAccessException e) {
            throw new IOException("Can't flush");
        } catch (InvocationTargetException e) {
            throw new IOException("Can't flush");
        }
        super.flush();
    }

}