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