1 /*
2  * LZDecoder
3  *
4  * Authors: Lasse Collin <lasse.collin@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 
LZDecoder(int dictSize, byte[] presetDict)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 
reset()37     public void reset() {
38         start = 0;
39         pos = 0;
40         full = 0;
41         limit = 0;
42         buf[buf.length - 1] = 0x00;
43     }
44 
setLimit(int outMax)45     public void setLimit(int outMax) {
46         if (buf.length - pos <= outMax)
47             limit = buf.length;
48         else
49             limit = pos + outMax;
50     }
51 
hasSpace()52     public boolean hasSpace() {
53         return pos < limit;
54     }
55 
hasPending()56     public boolean hasPending() {
57         return pendingLen > 0;
58     }
59 
getPos()60     public int getPos() {
61         return pos;
62     }
63 
getByte(int dist)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 
putByte(byte b)72     public void putByte(byte b) {
73         buf[pos++] = b;
74 
75         if (full < pos)
76             full = pos;
77     }
78 
repeat(int dist, int len)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 
repeatPending()101     public void repeatPending() throws IOException {
102         if (pendingLen > 0)
103             repeat(pendingDist, pendingLen);
104     }
105 
copyUncompressed(DataInputStream inData, int len)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 
flush(byte[] out, int outOff)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