package com.bumptech.glide.util;
import android.text.TextUtils;
import android.util.Log;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Uses the content length as the basis for the return value of {@link #available()} and verifies
* that at least content length bytes are returned from the various read methods.
*/
public final class ContentLengthInputStream extends FilterInputStream {
private static final String TAG = "ContentLengthStream";
private static final int UNKNOWN = -1;
private final long contentLength;
private int readSoFar;
public static InputStream obtain(InputStream other, String contentLengthHeader) {
return obtain(other, parseContentLength(contentLengthHeader));
}
public static InputStream obtain(InputStream other, long contentLength) {
return new ContentLengthInputStream(other, contentLength);
}
private static int parseContentLength(String contentLengthHeader) {
int result = UNKNOWN;
if (!TextUtils.isEmpty(contentLengthHeader)) {
try {
result = Integer.parseInt(contentLengthHeader);
} catch (NumberFormatException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "failed to parse content length header: " + contentLengthHeader, e);
}
}
}
return result;
}
ContentLengthInputStream(InputStream in, long contentLength) {
super(in);
this.contentLength = contentLength;
}
@Override
public synchronized int available() throws IOException {
return (int) Math.max(contentLength - readSoFar, in.available());
}
@Override
public synchronized int read() throws IOException {
int value = super.read();
checkReadSoFarOrThrow(value >= 0 ? 1 : -1);
return value;
}
@Override
public int read(byte[] buffer) throws IOException {
return read(buffer, 0 /*byteOffset*/, buffer.length /*byteCount*/);
}
@Override
public synchronized int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
return checkReadSoFarOrThrow(super.read(buffer, byteOffset, byteCount));
}
private int checkReadSoFarOrThrow(int read) throws IOException {
if (read >= 0) {
readSoFar += read;
} else if (contentLength - readSoFar > 0) {
throw new IOException("Failed to read all expected data"
+ ", expected: " + contentLength
+ ", but read: " + readSoFar);
}
return read;
}
}