/* * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved. * Original author: Edmund Wagner * Creation date: 21.06.2007 * * Source: $HeadURL$ * Last changed: $LastChangedDate$ * * the unrar licence applies to all junrar source and binary distributions * you are not allowed to use this source to re-create the RAR compression algorithm * * Here some html entities which can be used for escaping javadoc tags: * "&": "&" or "&" * "<": "<" or "<" * ">": ">" or ">" * "@": "@" */ package com.github.junrar.unpack; import java.io.IOException; import java.util.Arrays; import com.github.junrar.exception.RarException; import com.github.junrar.unpack.decode.Compress; import com.github.junrar.unpack.vm.BitInput; /** * DOCUMENT ME * * @author $LastChangedBy$ * @version $LastChangedRevision$ */ public abstract class Unpack15 extends BitInput { protected int readBorder; protected boolean suspended; protected boolean unpAllBuf; protected ComprDataIO unpIO; protected boolean unpSomeRead; protected int readTop; protected long destUnpSize; protected byte[] window; protected int[] oldDist = new int[4]; protected int unpPtr, wrPtr; protected int oldDistPtr; protected int[] ChSet = new int[256], ChSetA = new int[256], ChSetB = new int[256], ChSetC = new int[256]; protected int[] Place = new int[256], PlaceA = new int[256], PlaceB = new int[256], PlaceC = new int[256]; protected int[] NToPl = new int[256], NToPlB = new int[256], NToPlC = new int[256]; protected int FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3; protected int Buf60, NumHuf, StMode, LCount, FlagsCnt; protected int Nhfb, Nlzb, MaxDist3; protected int lastDist, lastLength; private static final int STARTL1 = 2; private static int DecL1[] = { 0x8000, 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, 0xee00, 0xf000, 0xf200, 0xf200, 0xffff }; private static int PosL1[] = { 0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32 }; private static final int STARTL2 = 3; private static int DecL2[] = { 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, 0xee00, 0xf000, 0xf200, 0xf240, 0xffff }; private static int PosL2[] = { 0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36 }; private static final int STARTHF0 = 4; private static int DecHf0[] = { 0x8000, 0xc000, 0xe000, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xffff }; private static int PosHf0[] = { 0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, 33 }; private static final int STARTHF1 = 5; private static int DecHf1[] = { 0x2000, 0xc000, 0xe000, 0xf000, 0xf200, 0xf200, 0xf7e0, 0xffff }; private static int PosHf1[] = { 0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, 127 }; private static final int STARTHF2 = 5; private static int DecHf2[] = { 0x1000, 0x2400, 0x8000, 0xc000, 0xfa00, 0xffff, 0xffff, 0xffff }; private static int PosHf2[] = { 0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0 }; private static final int STARTHF3 = 6; private static int DecHf3[] = { 0x800, 0x2400, 0xee00, 0xfe80, 0xffff, 0xffff, 0xffff }; private static int PosHf3[] = { 0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0 }; private static final int STARTHF4 = 8; private static int DecHf4[] = { 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }; private static int PosHf4[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0 }; static int ShortLen1[] = { 1, 3, 4, 4, 5, 6, 7, 8, 8, 4, 4, 5, 6, 6, 4, 0 }; static int ShortXor1[] = { 0, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xc0, 0x80, 0x90, 0x98, 0x9c, 0xb0 }; static int ShortLen2[] = { 2, 3, 3, 3, 4, 4, 5, 6, 6, 4, 4, 5, 6, 6, 4, 0 }; static int ShortXor2[] = { 0, 0x40, 0x60, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xc0, 0x80, 0x90, 0x98, 0x9c, 0xb0 }; protected abstract void unpInitData(boolean solid); protected void unpack15(boolean solid) throws IOException, RarException { if (suspended) { unpPtr = wrPtr; } else { unpInitData(solid); oldUnpInitData(solid); unpReadBuf(); if (!solid) { initHuff(); unpPtr = 0; } else { unpPtr = wrPtr; } --destUnpSize; } if (destUnpSize >= 0) { getFlagsBuf(); FlagsCnt = 8; } while (destUnpSize >= 0) { unpPtr &= Compress.MAXWINMASK; if (inAddr > readTop - 30 && !unpReadBuf()) { break; } if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 270 && wrPtr != unpPtr) { oldUnpWriteBuf(); if (suspended) { return; } } if (StMode != 0) { huffDecode(); continue; } if (--FlagsCnt < 0) { getFlagsBuf(); FlagsCnt = 7; } if ((FlagBuf & 0x80) != 0) { FlagBuf <<= 1; if (Nlzb > Nhfb) { longLZ(); } else { huffDecode(); } } else { FlagBuf <<= 1; if (--FlagsCnt < 0) { getFlagsBuf(); FlagsCnt = 7; } if ((FlagBuf & 0x80) != 0) { FlagBuf <<= 1; if (Nlzb > Nhfb) { huffDecode(); } else { longLZ(); } } else { FlagBuf <<= 1; shortLZ(); } } } oldUnpWriteBuf(); } protected boolean unpReadBuf() throws IOException, RarException { int dataSize=readTop-inAddr; if (dataSize<0){ return(false); } if (inAddr>BitInput.MAX_SIZE/2) { if (dataSize>0){ //memmove(InBuf,InBuf+InAddr,DataSize); // for (int i = 0; i < dataSize; i++) { // inBuf[i] = inBuf[inAddr + i]; // } System.arraycopy(inBuf, inAddr, inBuf, 0, dataSize); } inAddr=0; readTop=dataSize; } else{ dataSize=readTop; } //int readCode=UnpIO->UnpRead(InBuf+DataSize,(BitInput::MAX_SIZE-DataSize)&~0xf); int readCode=unpIO.unpRead(inBuf, dataSize, (BitInput.MAX_SIZE-dataSize)&~0xf); if (readCode>0){ readTop+=readCode; } readBorder=readTop-30; return(readCode!=-1); } private int getShortLen1(int pos) { return pos == 1 ? Buf60 + 3 : ShortLen1[pos]; } private int getShortLen2(int pos) { return pos == 3 ? Buf60 + 3 : ShortLen2[pos]; } protected void shortLZ() { int Length, SaveLength; int LastDistance; int Distance; int DistancePlace; NumHuf = 0; int BitField = fgetbits(); if (LCount == 2) { faddbits(1); if (BitField >= 0x8000) { oldCopyString(lastDist, lastLength); return; } BitField <<= 1; LCount = 0; } BitField >>>= 8; if (AvrLn1 < 37) { for (Length = 0;; Length++) { if (((BitField ^ ShortXor1[Length]) & (~(0xff >>> getShortLen1(Length)))) == 0) { break; } } faddbits(getShortLen1(Length)); } else { for (Length = 0;; Length++) { if (((BitField ^ ShortXor2[Length]) & (~(0xff >> getShortLen2(Length)))) == 0) { break; } } faddbits(getShortLen2(Length)); } if (Length >= 9) { if (Length == 9) { LCount++; oldCopyString(lastDist, lastLength); return; } if (Length == 14) { LCount = 0; Length = decodeNum(fgetbits(), STARTL2, DecL2, PosL2) + 5; Distance = (fgetbits() >> 1) | 0x8000; faddbits(15); lastLength = Length; lastDist = Distance; oldCopyString(Distance, Length); return; } LCount = 0; SaveLength = Length; Distance = oldDist[(oldDistPtr - (Length - 9)) & 3]; Length = decodeNum(fgetbits(), STARTL1, DecL1, PosL1) + 2; if (Length == 0x101 && SaveLength == 10) { Buf60 ^= 1; return; } if (Distance > 256) Length++; if (Distance >= MaxDist3) Length++; oldDist[oldDistPtr++] = Distance; oldDistPtr = oldDistPtr & 3; lastLength = Length; lastDist = Distance; oldCopyString(Distance, Length); return; } LCount = 0; AvrLn1 += Length; AvrLn1 -= AvrLn1 >> 4; DistancePlace = decodeNum(fgetbits(), STARTHF2, DecHf2, PosHf2) & 0xff; Distance = ChSetA[DistancePlace]; if (--DistancePlace != -1) { PlaceA[Distance]--; LastDistance = ChSetA[DistancePlace]; PlaceA[LastDistance]++; ChSetA[DistancePlace + 1] = LastDistance; ChSetA[DistancePlace] = Distance; } Length += 2; oldDist[oldDistPtr++] = ++Distance; oldDistPtr = oldDistPtr & 3; lastLength = Length; lastDist = Distance; oldCopyString(Distance, Length); } protected void longLZ() { int Length; int Distance; int DistancePlace, NewDistancePlace; int OldAvr2, OldAvr3; NumHuf = 0; Nlzb += 16; if (Nlzb > 0xff) { Nlzb = 0x90; Nhfb >>>= 1; } OldAvr2 = AvrLn2; int BitField = fgetbits(); if (AvrLn2 >= 122) { Length = decodeNum(BitField, STARTL2, DecL2, PosL2); } else { if (AvrLn2 >= 64) { Length = decodeNum(BitField, STARTL1, DecL1, PosL1); } else { if (BitField < 0x100) { Length = BitField; faddbits(16); } else { for (Length = 0; ((BitField << Length) & 0x8000) == 0; Length++) { ; } faddbits(Length + 1); } } } AvrLn2 += Length; AvrLn2 -= AvrLn2 >>> 5; BitField = fgetbits(); if (AvrPlcB > 0x28ff) { DistancePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); } else { if (AvrPlcB > 0x6ff) { DistancePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1); } else { DistancePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0); } } AvrPlcB += DistancePlace; AvrPlcB -= AvrPlcB >> 8; while (true) { Distance = ChSetB[DistancePlace & 0xff]; NewDistancePlace = NToPlB[Distance++ & 0xff]++; if ((Distance & 0xff) == 0) { corrHuff(ChSetB, NToPlB); } else { break; } } ChSetB[DistancePlace] = ChSetB[NewDistancePlace]; ChSetB[NewDistancePlace] = Distance; Distance = ((Distance & 0xff00) | (fgetbits() >>> 8)) >>> 1; faddbits(7); OldAvr3 = AvrLn3; if (Length != 1 && Length != 4) { if (Length == 0 && Distance <= MaxDist3) { AvrLn3++; AvrLn3 -= AvrLn3 >> 8; } else { if (AvrLn3 > 0) { AvrLn3--; } } } Length += 3; if (Distance >= MaxDist3) { Length++; } if (Distance <= 256) { Length += 8; } if (OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40) { MaxDist3 = 0x7f00; } else { MaxDist3 = 0x2001; } oldDist[oldDistPtr++] = Distance; oldDistPtr = oldDistPtr & 3; lastLength = Length; lastDist = Distance; oldCopyString(Distance, Length); } protected void huffDecode() { int CurByte, NewBytePlace; int Length; int Distance; int BytePlace; int BitField = fgetbits(); if (AvrPlc > 0x75ff) { BytePlace = decodeNum(BitField, STARTHF4, DecHf4, PosHf4); } else { if (AvrPlc > 0x5dff) { BytePlace = decodeNum(BitField, STARTHF3, DecHf3, PosHf3); } else { if (AvrPlc > 0x35ff) { BytePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2); } else { if (AvrPlc > 0x0dff) { BytePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1); } else { BytePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0); } } } } BytePlace &= 0xff; if (StMode != 0) { if (BytePlace == 0 && BitField > 0xfff) { BytePlace = 0x100; } if (--BytePlace == -1) { BitField = fgetbits(); faddbits(1); if ((BitField & 0x8000) != 0) { NumHuf = StMode = 0; return; } else { Length = (BitField & 0x4000) != 0 ? 4 : 3; faddbits(1); Distance = decodeNum(fgetbits(), STARTHF2, DecHf2, PosHf2); Distance = (Distance << 5) | (fgetbits() >>> 11); faddbits(5); oldCopyString(Distance, Length); return; } } } else { if (NumHuf++ >= 16 && FlagsCnt == 0) { StMode = 1; } } AvrPlc += BytePlace; AvrPlc -= AvrPlc >>> 8; Nhfb += 16; if (Nhfb > 0xff) { Nhfb = 0x90; Nlzb >>>= 1; } window[unpPtr++] = (byte) (ChSet[BytePlace] >>> 8); --destUnpSize; while (true) { CurByte = ChSet[BytePlace]; NewBytePlace = NToPl[CurByte++ & 0xff]++; if ((CurByte & 0xff) > 0xa1) { corrHuff(ChSet, NToPl); } else { break; } } ChSet[BytePlace] = ChSet[NewBytePlace]; ChSet[NewBytePlace] = CurByte; } protected void getFlagsBuf() { int Flags, NewFlagsPlace; int FlagsPlace = decodeNum(fgetbits(), STARTHF2, DecHf2, PosHf2); while (true) { Flags = ChSetC[FlagsPlace]; FlagBuf = Flags >>> 8; NewFlagsPlace = NToPlC[Flags++ & 0xff]++; if ((Flags & 0xff) != 0) { break; } corrHuff(ChSetC, NToPlC); } ChSetC[FlagsPlace] = ChSetC[NewFlagsPlace]; ChSetC[NewFlagsPlace] = Flags; } protected void oldUnpInitData(boolean Solid) { if (!Solid ) { AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0; AvrPlc = 0x3500; MaxDist3 = 0x2001; Nhfb = Nlzb = 0x80; } FlagsCnt = 0; FlagBuf = 0; StMode = 0; LCount = 0; readTop = 0; } protected void initHuff() { for (int I = 0; I < 256; I++) { Place[I] = PlaceA[I] = PlaceB[I] = I; PlaceC[I] = (~I + 1) & 0xff; ChSet[I] = ChSetB[I] = I << 8; ChSetA[I] = I; ChSetC[I] = ((~I + 1) & 0xff) << 8; } Arrays.fill(NToPl, 0);// memset(NToPl,0,sizeof(NToPl)); Arrays.fill(NToPlB, 0); // memset(NToPlB,0,sizeof(NToPlB)); Arrays.fill(NToPlC, 0); // memset(NToPlC,0,sizeof(NToPlC)); corrHuff(ChSetB, NToPlB); } protected void corrHuff(int[] CharSet, int[] NumToPlace) { int I, J, pos = 0; for (I = 7; I >= 0; I--) { for (J = 0; J < 32; J++, pos++) { CharSet[pos] = ((CharSet[pos] & ~0xff) | I);// *CharSet=(*CharSet // & ~0xff) | I; } } Arrays.fill(NumToPlace, 0);// memset(NumToPlace,0,sizeof(NToPl)); for (I = 6; I >= 0; I--) { NumToPlace[I] = (7 - I) * 32; } } protected void oldCopyString(int Distance, int Length) { destUnpSize -= Length; while ((Length--) != 0) { window[unpPtr] = window[(unpPtr - Distance) & Compress.MAXWINMASK]; unpPtr = (unpPtr + 1) & Compress.MAXWINMASK; } } protected int decodeNum(int Num, int StartPos, int[] DecTab, int[] PosTab) { int I; for (Num &= 0xfff0, I = 0; DecTab[I] <= Num; I++) { StartPos++; } faddbits(StartPos); return (((Num - (I != 0 ? DecTab[I - 1] : 0)) >>> (16 - StartPos)) + PosTab[StartPos]); } protected void oldUnpWriteBuf() throws IOException { if (unpPtr != wrPtr) { unpSomeRead = true; } if (unpPtr < wrPtr) { unpIO.unpWrite(window, wrPtr, -wrPtr & Compress.MAXWINMASK); unpIO.unpWrite(window, 0, unpPtr); unpAllBuf = true; } else { unpIO.unpWrite(window, wrPtr, unpPtr - wrPtr); } wrPtr = unpPtr; } }