1526ae88675e01956aa14415b0cba527cf4f1cb0aSam Juddpackage com.bumptech.glide.util;
2526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
32007440c380df454db15f83b019a5b4c55ca4b72Sam Juddimport com.bumptech.glide.load.resource.bitmap.RecyclableBufferedInputStream;
42007440c380df454db15f83b019a5b4c55ca4b72Sam Judd
5526ae88675e01956aa14415b0cba527cf4f1cb0aSam Juddimport java.io.IOException;
6526ae88675e01956aa14415b0cba527cf4f1cb0aSam Juddimport java.io.InputStream;
7526ae88675e01956aa14415b0cba527cf4f1cb0aSam Juddimport java.util.Queue;
8526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
9526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd/**
10526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd * An {@link java.io.InputStream} that catches {@link java.io.IOException}s during read and skip calls and stores them
11526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd * so they can later be handled or thrown. This class is a workaround for a framework issue where exceptions during
12526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd * reads while decoding bitmaps in {@link android.graphics.BitmapFactory} can return partially decoded bitmaps.
13526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd *
14526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd * See https://github.com/bumptech/glide/issues/126.
15526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd */
16526ae88675e01956aa14415b0cba527cf4f1cb0aSam Juddpublic class ExceptionCatchingInputStream extends InputStream {
17526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
18526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    private static final Queue<ExceptionCatchingInputStream> QUEUE = Util.createQueue(0);
19526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
202007440c380df454db15f83b019a5b4c55ca4b72Sam Judd    private RecyclableBufferedInputStream wrapped;
215ba19a0e69ad3a651b8f13ba45de48a56b56ce36Sam Judd    private IOException exception;
225ba19a0e69ad3a651b8f13ba45de48a56b56ce36Sam Judd
232007440c380df454db15f83b019a5b4c55ca4b72Sam Judd    public static ExceptionCatchingInputStream obtain(RecyclableBufferedInputStream toWrap) {
24526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        ExceptionCatchingInputStream result;
25526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        synchronized (QUEUE) {
26526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            result = QUEUE.poll();
27526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        }
28526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        if (result == null) {
29526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            result = new ExceptionCatchingInputStream();
30526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        }
31526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        result.setInputStream(toWrap);
32526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        return result;
33526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
34526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
35526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    // Exposed for testing.
36526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    static void clearQueue() {
375ba19a0e69ad3a651b8f13ba45de48a56b56ce36Sam Judd        while (!QUEUE.isEmpty()) {
385ba19a0e69ad3a651b8f13ba45de48a56b56ce36Sam Judd            QUEUE.remove();
395ba19a0e69ad3a651b8f13ba45de48a56b56ce36Sam Judd        }
40526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
41526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
42526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    ExceptionCatchingInputStream() {
43526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        // Do nothing.
44526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
45526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
462007440c380df454db15f83b019a5b4c55ca4b72Sam Judd    void setInputStream(RecyclableBufferedInputStream toWrap) {
47526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        wrapped = toWrap;
48526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
49526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
50526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    @Override
51526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    public int available() throws IOException {
52526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        return wrapped.available();
53526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
54526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
55526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    @Override
56526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    public void close() throws IOException {
57526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        wrapped.close();
58526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
59526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
60526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    @Override
61526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    public void mark(int readlimit) {
62526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        wrapped.mark(readlimit);
63526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
64526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
65526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    @Override
66526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    public boolean markSupported() {
67526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        return wrapped.markSupported();
68526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
69526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
70526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    @Override
71526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    public int read(byte[] buffer) throws IOException {
72526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        int read;
73526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        try {
74526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            read = wrapped.read(buffer);
75526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        } catch (IOException e) {
76526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            exception = e;
77526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            read = -1;
78526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        }
79526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        return read;
80526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
81526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
82526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    @Override
83526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
84526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        int read;
85526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        try {
86526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            read = wrapped.read(buffer, byteOffset, byteCount);
87526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        } catch (IOException e) {
88526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            exception = e;
89526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            read = -1;
90526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        }
91526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        return read;
92526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
93526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
94526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    @Override
95526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    public synchronized void reset() throws IOException {
96526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        wrapped.reset();
97526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
98526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
99526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    @Override
100526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    public long skip(long byteCount) throws IOException {
101526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        long skipped;
102526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        try {
103526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            skipped = wrapped.skip(byteCount);
104526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        } catch (IOException e) {
105526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            exception = e;
106526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            skipped = 0;
107526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        }
108526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        return skipped;
109526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
110526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
111526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    @Override
112526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    public int read() throws IOException {
113526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        int result;
114526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        try {
115526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            result = wrapped.read();
116526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        } catch (IOException e) {
117526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            exception = e;
118526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            result = -1;
119526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        }
120526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        return result;
121526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
122526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
1232007440c380df454db15f83b019a5b4c55ca4b72Sam Judd    public void fixMarkLimit() {
1242007440c380df454db15f83b019a5b4c55ca4b72Sam Judd        wrapped.fixMarkLimit();
1252007440c380df454db15f83b019a5b4c55ca4b72Sam Judd    }
1262007440c380df454db15f83b019a5b4c55ca4b72Sam Judd
127526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    public IOException getException() {
128526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        return exception;
129526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
130526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd
131526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    public void release() {
132526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        exception = null;
133526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        wrapped = null;
134526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        synchronized (QUEUE) {
135526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd            QUEUE.offer(this);
136526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd        }
137526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd    }
138526ae88675e01956aa14415b0cba527cf4f1cb0aSam Judd}
139