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