1 /* 2 * LZDecoder 3 * 4 * Authors: Lasse Collin <lasse.collin (at) tukaani.org> 5 * Igor Pavlov <http://7-zip.org/> 6 * 7 * This file has been put into the public domain. 8 * You can do whatever you want with this file. 9 */ 10 11 package org.tukaani.xz.lz; 12 13 import java.io.DataInputStream; 14 import java.io.IOException; 15 import org.tukaani.xz.CorruptedInputException; 16 17 public final class LZDecoder { 18 private final byte[] buf; 19 private int start = 0; 20 private int pos = 0; 21 private int full = 0; 22 private int limit = 0; 23 private int pendingLen = 0; 24 private int pendingDist = 0; 25 26 public LZDecoder(int dictSize, byte[] presetDict) { 27 buf = new byte[dictSize]; 28 29 if (presetDict != null) { 30 pos = Math.min(presetDict.length, dictSize); 31 full = pos; 32 start = pos; 33 System.arraycopy(presetDict, presetDict.length - pos, buf, 0, pos); 34 } 35 } 36 37 public void reset() { 38 start = 0; 39 pos = 0; 40 full = 0; 41 limit = 0; 42 buf[buf.length - 1] = 0x00; 43 } 44 45 public void setLimit(int outMax) { 46 if (buf.length - pos <= outMax) 47 limit = buf.length; 48 else 49 limit = pos + outMax; 50 } 51 52 public boolean hasSpace() { 53 return pos < limit; 54 } 55 56 public boolean hasPending() { 57 return pendingLen > 0; 58 } 59 60 public int getPos() { 61 return pos; 62 } 63 64 public int getByte(int dist) { 65 int offset = pos - dist - 1; 66 if (dist >= pos) 67 offset += buf.length; 68 69 return buf[offset] & 0xFF; 70 } 71 72 public void putByte(byte b) { 73 buf[pos++] = b; 74 75 if (full < pos) 76 full = pos; 77 } 78 79 public void repeat(int dist, int len) throws IOException { 80 if (dist < 0 || dist >= full) 81 throw new CorruptedInputException(); 82 83 int left = Math.min(limit - pos, len); 84 pendingLen = len - left; 85 pendingDist = dist; 86 87 int back = pos - dist - 1; 88 if (dist >= pos) 89 back += buf.length; 90 91 do { 92 buf[pos++] = buf[back++]; 93 if (back == buf.length) 94 back = 0; 95 } while (--left > 0); 96 97 if (full < pos) 98 full = pos; 99 } 100 101 public void repeatPending() throws IOException { 102 if (pendingLen > 0) 103 repeat(pendingDist, pendingLen); 104 } 105 106 public void copyUncompressed(DataInputStream inData, int len) 107 throws IOException { 108 int copySize = Math.min(buf.length - pos, len); 109 inData.readFully(buf, pos, copySize); 110 pos += copySize; 111 112 if (full < pos) 113 full = pos; 114 } 115 116 public int flush(byte[] out, int outOff) { 117 int copySize = pos - start; 118 if (pos == buf.length) 119 pos = 0; 120 121 System.arraycopy(buf, start, out, outOff, copySize); 122 start = pos; 123 124 return copySize; 125 } 126 } 127