
dorkbox.cabParser.decompress.zip.DecompressZip Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of CabParser Show documentation
Show all versions of CabParser Show documentation
Parse and extract data from inside Microsoft .cab files, specifically those compressed with LZX, for java.
The newest version!
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.decompress.zip;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.CorruptCabException;
import dorkbox.cabParser.decompress.Decompressor;
public final class DecompressZip implements Decompressor {
private static final int[] ar1 = {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,
35,43,51,59, 67,83,99,115,131,163,195,227,258};
private static final int[] ar2 = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,
769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577};
private static final int[] ar3 = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
private byte[] bytes = new byte[320];
private byte[] inputBytes;
private byte[] outputBytes;
private int index;
private int inputPlus4;
int int1;
private int int2;
private int int3;
private int outputLength;
private DecompressZipState state1;
private DecompressZipState state2;
private DecompressZipState state3;
@Override
public void init(int windowBits) {
this.state1 = new DecompressZipState(288, 9, this);
this.state2 = new DecompressZipState(32, 7, this);
this.state3 = new DecompressZipState(19, 7, this);
}
@Override
public void decompress(byte[] inputBytes, byte[] outputBytes, int inputLength, int outputLength) throws CabException {
this.inputBytes = inputBytes;
this.outputBytes = outputBytes;
if (this.inputBytes[0] != 67 || this.inputBytes[1] != 75) {
throw new CorruptCabException();
}
if (outputBytes.length < 33027) {
throw new CabException();
}
if (inputBytes.length < 28) {
throw new CabException();
}
this.index = 2;
this.inputPlus4 = inputLength + 4;
this.outputLength = outputLength;
this.int3 = 0;
maybeDecompress();
while (this.int3 < this.outputLength) {
decompressMore();
}
}
@Override
public int getMaxGrowth() {
return 28;
}
@Override
public void reset(int windowBits) {
}
private void maybeDecompress() throws CabException {
if (this.index + 4 > this.inputPlus4) {
throw new CorruptCabException();
}
this.int1 = readShort() | readShort() << 16;
this.int2 = 16;
}
void add(int paramInt) {
this.int1 >>>= paramInt;
this.int2 -= paramInt;
if (this.int2 <= 0) {
this.int2 += 16;
this.int1 |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << this.int2;
this.index += 2;
}
}
private void check() throws CabException {
if (this.index > this.inputPlus4) {
throw new CorruptCabException();
}
}
@SuppressWarnings({"NumericCastThatLosesPrecision", "Duplicates"})
private void bits() throws CabException {
int i = this.int3;
int j = this.outputLength;
byte[] arrayOfByte1 = this.outputBytes;
int[] arrayOfInt1 = this.state1.intA2;
int[] arrayOfInt2 = this.state1.intA3;
int[] arrayOfInt3 = this.state1.intA4;
byte[] arrayOfByte2 = this.state1.byteA;
int[] arrayOfInt4 = this.state2.intA2;
int[] arrayOfInt5 = this.state2.intA3;
int[] arrayOfInt6 = this.state2.intA4;
byte[] arrayOfByte3 = this.state2.byteA;
int k = this.int1;
int m = this.int2;
do {
if (this.index > this.inputPlus4) {
break;
}
int n = arrayOfInt1[k & 0x1FF];
int i2;
while (n < 0) {
i2 = 512;
do {
n = -n;
if ((k & i2) == 0) {
n = arrayOfInt2[n];
} else {
n = arrayOfInt3[n];
}
i2 <<= 1;
} while (n < 0);
}
int i1 = arrayOfByte2[n];
k >>>= i1;
m -= i1;
if (m <= 0) {
m += 16;
k |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << m;
this.index += 2;
}
if (n < 256) {
arrayOfByte1[i++] = (byte) n;
} else {
n -= 257;
if (n < 0) {
break;
}
if (n < 8) {
n += 3;
} else if (n != 28) {
int i4 = n - 4 >>> 2;
n = ar1[n] + (k & (1 << i4) - 1);
k >>>= i4;
m -= i4;
if (m <= 0) {
m += 16;
k |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << m;
this.index += 2;
}
} else {
n = 258;
}
i2 = arrayOfInt4[k & 0x7F];
while (i2 < 0) {
int i5 = 128;
do {
i2 = -i2;
if ((k & i5) == 0) {
i2 = arrayOfInt5[i2];
} else {
i2 = arrayOfInt6[i2];
}
i5 <<= 1;
} while (i2 < 0);
}
i1 = arrayOfByte3[i2];
k >>>= i1;
m -= i1;
if (m <= 0) {
m += 16;
k |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << m;
this.index += 2;
}
int i4 = i2 - 2 >> 1;
int i3;
if (i4 > 0) {
i3 = ar2[i2] + (k & (1 << i4) - 1);
k >>>= i4;
m -= i4;
if (m <= 0) {
m += 16;
k |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << m;
this.index += 2;
}
} else {
i3 = i2 + 1;
}
do {
arrayOfByte1[i] = arrayOfByte1[i - i3 & 0x7FFF];
i++;
n--;
} while (n != 0);
}
} while (i <= j);
this.int3 = i;
this.int1 = k;
this.int2 = m;
check();
}
private void readStuffcommon() throws CabException {
this.state1.main();
this.state2.main();
}
private void setup() {
int i = 0;
do {
this.state1.byteA[i] = (byte) 8;
i++;
} while (i <= 143);
i = 144;
do {
this.state1.byteA[i] = (byte) 9;
i++;
} while (i <= 255);
i = 256;
do {
this.state1.byteA[i] = (byte) 7;
i++;
} while (i <= 279);
i = 280;
do {
this.state1.byteA[i] = (byte) 8;
i++;
} while (i <= 287);
i = 0;
do {
this.state2.byteA[i] = (byte) 5;
i++;
} while (i < 32);
}
private int makeShort(byte byte1, byte byte2) {
return byte1 & 0xFF | (byte2 & 0xFF) << 8;
}
@SuppressWarnings("NumericCastThatLosesPrecision")
private void expand() throws CabException {
check();
int i = calc(5) + 257;
int j = calc(5) + 1;
int k = calc(4) + 4;
for (int n = 0; n < k; n++) {
this.state3.byteA[ar3[n]] = (byte) calc(3);
check();
}
for (int n = k; n < ar3.length; n++) {
this.state3.byteA[ar3[n]] = (byte) 0;
}
this.state3.main();
int m = i + j;
int n = 0;
while (n < m) {
check();
int i1 = (byte) this.state3.read();
if (i1 <= 15) {
this.bytes[n++] = (byte) i1;
} else {
int i3;
int i2;
if (i1 == 16) {
if (n == 0) {
throw new CorruptCabException();
}
i3 = this.bytes[n - 1];
i2 = calc(2) + 3;
if (n + i2 > m) {
throw new CorruptCabException();
}
for (int i4 = 0; i4 < i2; i4++) {
this.bytes[n++] = (byte) i3;
}
} else if (i1 == 17) {
i2 = calc(3) + 3;
if (n + i2 > m) {
throw new CorruptCabException();
}
for (i3 = 0; i3 < i2; i3++) {
this.bytes[n++] = (byte) 0;
}
} else {
i2 = calc(7) + 11;
if (n + i2 > m) {
throw new CorruptCabException();
}
for (i3 = 0; i3 < i2; i3++) {
this.bytes[n++] = (byte) 0;
}
}
}
}
System.arraycopy(this.bytes, 0, this.state1.byteA, 0, i);
for (n = i; n < 288; n++) {
this.state1.byteA[n] = (byte) 0;
}
for (n = 0; n < j; n++) {
this.state2.byteA[n] = this.bytes[n + i];
}
for (n = j; n < 32; n++) {
this.state2.byteA[n] = (byte) 0;
}
if (this.state1.byteA[256] == 0) {
throw new CorruptCabException();
}
}
private int readShort() {
int i = this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8;
this.index += 2;
return i;
}
private int calc(int paramInt) {
int i = this.int1 & (1 << paramInt) - 1;
add(paramInt);
return i;
}
private void decompressMore() throws CabException {
@SuppressWarnings("unused")
int i = calc(1);
int j = calc(2);
if (j == 2) {
expand();
readStuffcommon();
bits();
return;
}
if (j == 1) {
setup();
readStuffcommon();
bits();
return;
}
if (j == 0) {
verify();
return;
}
throw new CabException();
}
private void verify() throws CabException {
mod();
if (this.index >= this.inputPlus4) {
throw new CorruptCabException();
}
int i = makeShort(this.inputBytes[this.index], this.inputBytes[this.index + 1]);
int j = makeShort(this.inputBytes[this.index + 2], this.inputBytes[this.index + 3]);
//noinspection NumericCastThatLosesPrecision
if ((short) i != (short) (~j)) {
throw new CorruptCabException();
}
if (this.index + i > this.inputPlus4 || this.int3 + i > this.outputLength) {
throw new CorruptCabException();
}
maybeDecompress();
System.arraycopy(this.inputBytes, this.index, this.outputBytes, this.int3, i);
this.int3 += i;
if (this.int3 < this.outputLength) {
maybeDecompress();
}
}
private void mod() {
if (this.int2 == 16) {
this.index -= 4;
} else if (this.int2 >= 8) {
this.index -= 3;
} else {
this.index -= 2;
}
if (this.index < 0) {
this.index = 0;
}
this.int2 = 0;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy