package mwt.wow.mpq;
import java.io.EOFException;
import java.io.IOException;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
class DeflateReader extends Reader {
private Reader reader;
private Inflater inflater;
private int compressedRemaining;
private byte[] buffer = new byte[4096];
public DeflateReader(Reader reader, int compressedLength)
throws IOException {
this.reader = reader;
this.compressedRemaining = compressedLength;
inflater = new Inflater();
}
@Override
protected int readByte() throws IOException {
if (inflater == null) {
return -1;
}
try {
while (inflater.inflate(buffer, 0, 1) == 0) {
if (inflater.finished()) {
inflater.end();
inflater = null;
return -1;
} else if (inflater.needsDictionary()) {
inflater.end();
inflater = null;
throw new IOException(
"zlib preset dictionary not supported");
} else if (inflater.needsInput()) {
int toRead = compressedRemaining < buffer.length ? compressedRemaining
: buffer.length;
toRead = reader.readBlock(buffer, 0, toRead);
if (toRead <= 0) {
throw new EOFException("end of compressed data");
}
compressedRemaining -= toRead;
inflater.setInput(buffer, 0, toRead);
} else {
inflater.end();
inflater = null;
throw new IOException("Inflater error");
}
}
return buffer[0] & 0xff;
} catch (DataFormatException e) {
throw new IOException("inflate error: " + e.getMessage());
}
}
@Override
public int readBlock(byte[] b, int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
if (inflater == null) {
return -1;
}
try {
int bytesRead = 0;
while (bytesRead < len) {
int inflated = inflater.inflate(b, off + bytesRead, len
- bytesRead);
if (inflated == 0) {
if (inflater.finished()) {
inflater.end();
inflater = null;
return bytesRead == 0 ? -1 : bytesRead;
} else if (inflater.needsDictionary()) {
inflater.end();
inflater = null;
throw new IOException(
"zlib preset dictionary not supported");
} else if (inflater.needsInput()) {
int toRead = compressedRemaining < buffer.length ? compressedRemaining
: buffer.length;
toRead = reader.readBlock(buffer, 0, toRead);
if (toRead <= 0) {
if (bytesRead == 0) {
throw new EOFException("end of compressed data");
}
return bytesRead;
}
compressedRemaining -= toRead;
inflater.setInput(buffer, 0, toRead);
} else {
inflater.end();
inflater = null;
throw new IOException("Inflater error");
}
} else {
bytesRead += inflated;
}
}
return bytesRead;
} catch (DataFormatException e) {
throw new IOException("inflate error: " + e.getMessage());
}
}
@Override
public void seek(long position) throws IOException {
throw new IOException("Cannot seek in a compressed stream");
}
@Override
public void close() throws IOException {
if (inflater != null) {
inflater.end();
inflater = null;
}
}
}