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.ArrayCache;
16 import org.tukaani.xz.CorruptedInputException;
17 
18 public final class LZDecoder {
19     private final byte[] buf;
20     private final int bufSize; // To avoid buf.length with an array-cached buf.
21     private int start = 0;
22     private int pos = 0;
23     private int full = 0;
24     private int limit = 0;
25     private int pendingLen = 0;
26     private int pendingDist = 0;
27 
LZDecoder(int dictSize, byte[] presetDict, ArrayCache arrayCache)28     public LZDecoder(int dictSize, byte[] presetDict, ArrayCache arrayCache) {
29         bufSize = dictSize;
30         buf = arrayCache.getByteArray(bufSize, false);
31 
32         if (presetDict != null) {
33             pos = Math.min(presetDict.length, dictSize);
34             full = pos;
35             start = pos;
36             System.arraycopy(presetDict, presetDict.length - pos, buf, 0, pos);
37         }
38     }
39 
putArraysToCache(ArrayCache arrayCache)40     public void putArraysToCache(ArrayCache arrayCache) {
41         arrayCache.putArray(buf);
42     }
43 
reset()44     public void reset() {
45         start = 0;
46         pos = 0;
47         full = 0;
48         limit = 0;
49         buf[bufSize - 1] = 0x00;
50     }
51 
setLimit(int outMax)52     public void setLimit(int outMax) {
53         if (bufSize - pos <= outMax)
54             limit = bufSize;
55         else
56             limit = pos + outMax;
57     }
58 
hasSpace()59     public boolean hasSpace() {
60         return pos < limit;
61     }
62 
hasPending()63     public boolean hasPending() {
64         return pendingLen > 0;
65     }
66 
getPos()67     public int getPos() {
68         return pos;
69     }
70 
getByte(int dist)71     public int getByte(int dist) {
72         int offset = pos - dist - 1;
73         if (dist >= pos)
74             offset += bufSize;
75 
76         return buf[offset] & 0xFF;
77     }
78 
putByte(byte b)79     public void putByte(byte b) {
80         buf[pos++] = b;
81 
82         if (full < pos)
83             full = pos;
84     }
85 
repeat(int dist, int len)86     public void repeat(int dist, int len) throws IOException {
87         if (dist < 0 || dist >= full)
88             throw new CorruptedInputException();
89 
90         int left = Math.min(limit - pos, len);
91         pendingLen = len - left;
92         pendingDist = dist;
93 
94         int back = pos - dist - 1;
95         if (dist >= pos)
96             back += bufSize;
97 
98         do {
99             buf[pos++] = buf[back++];
100             if (back == bufSize)
101                 back = 0;
102         } while (--left > 0);
103 
104         if (full < pos)
105             full = pos;
106     }
107 
repeatPending()108     public void repeatPending() throws IOException {
109         if (pendingLen > 0)
110             repeat(pendingDist, pendingLen);
111     }
112 
copyUncompressed(DataInputStream inData, int len)113     public void copyUncompressed(DataInputStream inData, int len)
114             throws IOException {
115         int copySize = Math.min(bufSize - pos, len);
116         inData.readFully(buf, pos, copySize);
117         pos += copySize;
118 
119         if (full < pos)
120             full = pos;
121     }
122 
flush(byte[] out, int outOff)123     public int flush(byte[] out, int outOff) {
124         int copySize = pos - start;
125         if (pos == bufSize)
126             pos = 0;
127 
128         System.arraycopy(buf, start, out, outOff, copySize);
129         start = pos;
130 
131         return copySize;
132     }
133 }
134