Home | History | Annotate | Download | only in util
      1 package com.bumptech.glide.util;
      2 
      3 import com.bumptech.glide.load.resource.bitmap.RecyclableBufferedInputStream;
      4 
      5 import java.io.IOException;
      6 import java.io.InputStream;
      7 import java.util.Queue;
      8 
      9 /**
     10  * An {@link java.io.InputStream} that catches {@link java.io.IOException}s during read and skip calls and stores them
     11  * so they can later be handled or thrown. This class is a workaround for a framework issue where exceptions during
     12  * reads while decoding bitmaps in {@link android.graphics.BitmapFactory} can return partially decoded bitmaps.
     13  *
     14  * See https://github.com/bumptech/glide/issues/126.
     15  */
     16 public class ExceptionCatchingInputStream extends InputStream {
     17 
     18     private static final Queue<ExceptionCatchingInputStream> QUEUE = Util.createQueue(0);
     19 
     20     private RecyclableBufferedInputStream wrapped;
     21     private IOException exception;
     22 
     23     public static ExceptionCatchingInputStream obtain(RecyclableBufferedInputStream toWrap) {
     24         ExceptionCatchingInputStream result;
     25         synchronized (QUEUE) {
     26             result = QUEUE.poll();
     27         }
     28         if (result == null) {
     29             result = new ExceptionCatchingInputStream();
     30         }
     31         result.setInputStream(toWrap);
     32         return result;
     33     }
     34 
     35     // Exposed for testing.
     36     static void clearQueue() {
     37         while (!QUEUE.isEmpty()) {
     38             QUEUE.remove();
     39         }
     40     }
     41 
     42     ExceptionCatchingInputStream() {
     43         // Do nothing.
     44     }
     45 
     46     void setInputStream(RecyclableBufferedInputStream toWrap) {
     47         wrapped = toWrap;
     48     }
     49 
     50     @Override
     51     public int available() throws IOException {
     52         return wrapped.available();
     53     }
     54 
     55     @Override
     56     public void close() throws IOException {
     57         wrapped.close();
     58     }
     59 
     60     @Override
     61     public void mark(int readlimit) {
     62         wrapped.mark(readlimit);
     63     }
     64 
     65     @Override
     66     public boolean markSupported() {
     67         return wrapped.markSupported();
     68     }
     69 
     70     @Override
     71     public int read(byte[] buffer) throws IOException {
     72         int read;
     73         try {
     74             read = wrapped.read(buffer);
     75         } catch (IOException e) {
     76             exception = e;
     77             read = -1;
     78         }
     79         return read;
     80     }
     81 
     82     @Override
     83     public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
     84         int read;
     85         try {
     86             read = wrapped.read(buffer, byteOffset, byteCount);
     87         } catch (IOException e) {
     88             exception = e;
     89             read = -1;
     90         }
     91         return read;
     92     }
     93 
     94     @Override
     95     public synchronized void reset() throws IOException {
     96         wrapped.reset();
     97     }
     98 
     99     @Override
    100     public long skip(long byteCount) throws IOException {
    101         long skipped;
    102         try {
    103             skipped = wrapped.skip(byteCount);
    104         } catch (IOException e) {
    105             exception = e;
    106             skipped = 0;
    107         }
    108         return skipped;
    109     }
    110 
    111     @Override
    112     public int read() throws IOException {
    113         int result;
    114         try {
    115             result = wrapped.read();
    116         } catch (IOException e) {
    117             exception = e;
    118             result = -1;
    119         }
    120         return result;
    121     }
    122 
    123     public void fixMarkLimit() {
    124         wrapped.fixMarkLimit();
    125     }
    126 
    127     public IOException getException() {
    128         return exception;
    129     }
    130 
    131     public void release() {
    132         exception = null;
    133         wrapped = null;
    134         synchronized (QUEUE) {
    135             QUEUE.offer(this);
    136         }
    137     }
    138 }
    139