| /* |
| * LZDecoder |
| * |
| * Authors: Lasse Collin <lasse.collin@tukaani.org> |
| * Igor Pavlov <http://7-zip.org/> |
| * |
| * This file has been put into the public domain. |
| * You can do whatever you want with this file. |
| */ |
| |
| package org.tukaani.xz.lz; |
| |
| import java.io.DataInputStream; |
| import java.io.IOException; |
| import org.tukaani.xz.CorruptedInputException; |
| |
| public final class LZDecoder { |
| private final byte[] buf; |
| private int start = 0; |
| private int pos = 0; |
| private int full = 0; |
| private int limit = 0; |
| private int pendingLen = 0; |
| private int pendingDist = 0; |
| |
| public LZDecoder(int dictSize, byte[] presetDict) { |
| buf = new byte[dictSize]; |
| |
| if (presetDict != null) { |
| pos = Math.min(presetDict.length, dictSize); |
| full = pos; |
| start = pos; |
| System.arraycopy(presetDict, presetDict.length - pos, buf, 0, pos); |
| } |
| } |
| |
| public void reset() { |
| start = 0; |
| pos = 0; |
| full = 0; |
| limit = 0; |
| buf[buf.length - 1] = 0x00; |
| } |
| |
| public void setLimit(int outMax) { |
| if (buf.length - pos <= outMax) |
| limit = buf.length; |
| else |
| limit = pos + outMax; |
| } |
| |
| public boolean hasSpace() { |
| return pos < limit; |
| } |
| |
| public boolean hasPending() { |
| return pendingLen > 0; |
| } |
| |
| public int getPos() { |
| return pos; |
| } |
| |
| public int getByte(int dist) { |
| int offset = pos - dist - 1; |
| if (dist >= pos) |
| offset += buf.length; |
| |
| return buf[offset] & 0xFF; |
| } |
| |
| public void putByte(byte b) { |
| buf[pos++] = b; |
| |
| if (full < pos) |
| full = pos; |
| } |
| |
| public void repeat(int dist, int len) throws IOException { |
| if (dist < 0 || dist >= full) |
| throw new CorruptedInputException(); |
| |
| int left = Math.min(limit - pos, len); |
| pendingLen = len - left; |
| pendingDist = dist; |
| |
| int back = pos - dist - 1; |
| if (dist >= pos) |
| back += buf.length; |
| |
| do { |
| buf[pos++] = buf[back++]; |
| if (back == buf.length) |
| back = 0; |
| } while (--left > 0); |
| |
| if (full < pos) |
| full = pos; |
| } |
| |
| public void repeatPending() throws IOException { |
| if (pendingLen > 0) |
| repeat(pendingDist, pendingLen); |
| } |
| |
| public void copyUncompressed(DataInputStream inData, int len) |
| throws IOException { |
| int copySize = Math.min(buf.length - pos, len); |
| inData.readFully(buf, pos, copySize); |
| pos += copySize; |
| |
| if (full < pos) |
| full = pos; |
| } |
| |
| public int flush(byte[] out, int outOff) { |
| int copySize = pos - start; |
| if (pos == buf.length) |
| pos = 0; |
| |
| System.arraycopy(buf, start, out, outOff, copySize); |
| start = pos; |
| |
| return copySize; |
| } |
| } |