From 354cef3a9c4e020aef9afeee12f846e4554ec7b7 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Fri, 19 Oct 2012 10:53:02 +0400 Subject: add rarlib stuff --- src/org/catacombae/rarx/DecompressionCode.java | 1715 ++++++++++++++++++++++++ 1 file changed, 1715 insertions(+) create mode 100644 src/org/catacombae/rarx/DecompressionCode.java (limited to 'src/org/catacombae/rarx/DecompressionCode.java') diff --git a/src/org/catacombae/rarx/DecompressionCode.java b/src/org/catacombae/rarx/DecompressionCode.java new file mode 100644 index 0000000..20f79f2 --- /dev/null +++ b/src/org/catacombae/rarx/DecompressionCode.java @@ -0,0 +1,1715 @@ +/*- + * Copyright (C) 2006 Erik Larsson + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +package org.catacombae.rarx; + +//import org.catacombae.rarx.*; +import java.math.BigInteger; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.util.zip.CRC32; + +public class DecompressionCode { + private static final int MAXWINSIZE = 0x100000; + private static final int MAXWINMASK = (MAXWINSIZE-1); + private static final int UNP_MEMORY = MAXWINSIZE; + + public static final short NC = 298; /* alphabet = {0,1,2, .,NC - 1} */ + public static final short DC = 48; + public static final short RC = 28; + public static final short BC = 19; + public static final short MC = 257; + + public static final int CODE_HUFFMAN = 0; + public static final int CODE_LZ = 1; + public static final int CODE_LZ2 = 2; + public static final int CODE_REPEATLZ = 3; + public static final int CODE_CACHELZ = 4; + public static final int CODE_STARTFILE = 5; + public static final int CODE_ENDFILE = 6; + public static final int CODE_ENDMM = 7; + public static final int CODE_STARTMM = 8; + public static final int CODE_MMDELTA = 9; + + public static final int LHD_SPLIT_BEFORE = 1; //flag bit 0 + public static final int LHD_SPLIT_AFTER = 2; //flag bit 1 + public static final int LHD_PASSWORD = 4; //flag bit 2 + public static final int LHD_COMMENT = 8; //flag bit 3 + public static final int LHD_SOLID = 16; //flag bit 4 + + public static final int LHD_WINDOWMASK = 0x00e0; + public static final int LHD_WINDOW64 = 0; + public static final int LHD_WINDOW128 = 32; + public static final int LHD_WINDOW256 = 64; + public static final int LHD_WINDOW512 = 96; + public static final int LHD_WINDOW1024 = 128; + public static final int LHD_DIRECTORY = 0x00e0; + + public static final int NROUNDS = 32; + + /* Static variables belonging to the function Unpack. */ + private static final short[] LDecode = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, + 24, 28, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224}; //unsigned char[14] + private static final byte[] LBits = {0,0,0,0,0,0,0,0,1,1,1,1,2,2, //unsigned char[14] + 2,2,3,3,3,3,4,4,4,4,5,5,5,5}; + private static final int[] DDecode = {0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, + 32768, 49152, 65536, 98304, 131072,196608,262144,327680,393216,458752, + 524288,589824,655360,720896,786432,851968,917504,983040}; //int[48] + private static final byte[] DBits = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10,10,11,11,12,12,13,13,14,14, + 15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,16}; //unsigned char[48] + private static final short[] SDDecode = {0,4,8,16,32,64,128,192}; //unsigned char[8] + private static final byte[] SDBits = {2,2,3,4,5,6,6,6}; //unsigned char[8] + + public static final /*UBYTE*/ short[] InitSubstTable = { + 215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42 + ,232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137 + ,255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6 + , 71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235 + ,107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36 + ,158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251 + , 97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11 + ,164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51 + ,207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7 + ,122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80 + ,131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129 + ,224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10 + ,118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108 + ,161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225 + , 0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52 + ,116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84 + }; // UBYTE[256] + public static final /*UDWORD*/ int[] CRCTab = new int[256]; // Initialized in static constructor + + static { + // Perform initialization of static structures and variables. + //CRCTab = new int[256]; + InitCRC(CRCTab); + } + + private CRC32 crc = new CRC32(); + + public final /*UBYTE*/ short[] SubstTable = new short[256]; + + private /*unsigned*/ byte PN1, PN2, PN3; + + /* Note: temp_output_buffer is allocated when a file is about to be + extracted. It is allocated to NewLhd.UnpSize, which can be quite + large. The assumption that the unpacked file can be stored in + memory is awkward and must immediately be replaced with an output + stream. */ + private /* unsigned char* */ byte[] temp_output_buffer; /* extract files to this pointer*/ + private /* unsigned long* */ int temp_output_buffer_offset; /* size of temp. extract buffer */ + //private /*unsigned int*/ int UnpPtr,WrPtr; + private final /*unsigned short*/ short[] OldKey = new short[4]; + + private static class Decode { + public int MaxNum; // unsigned int + public final int[] DecodeLen = new int[16]; // unsigned int[16] + public final int[] DecodePos = new int[16]; // unsigned int[16] + public final int[] DecodeNum; // unsigned int[] + + public Decode() { + this(2); + } + + protected Decode(int decodeNumSize) { DecodeNum = new int[decodeNumSize]; } + } + private static class LitDecode extends Decode { + public LitDecode() { super(NC); } + } + private static class DistDecode extends Decode { + public DistDecode() { super(DC); } + } + private static class RepDecode extends Decode { + public RepDecode() { super(RC); } + } + private static class MultDecode extends Decode { + public MultDecode() { super(MC); } + } + private static class BitDecode extends Decode { + public BitDecode() { super(BC); } + } + + private final LitDecode LD = new LitDecode(); + private final DistDecode DD = new DistDecode(); + private final RepDecode RD = new RepDecode(); + private final MultDecode[] MD = { new MultDecode(), new MultDecode(), + new MultDecode(), new MultDecode() }; //new MultDecode[4]; + private final BitDecode BD = new BitDecode(); + + private final MultDecode[] MDPtr = { MD[0], MD[1], MD[2], MD[3] }; + + + /* ***************************** + * ** unpack stored RAR files ** + * *****************************/ + +// BOOL UnstoreFile(void) +// { +// if ((long)(*temp_output_buffer_offset=UnpRead(temp_output_buffer, +// NewLhd.UnpSize))==-1) +// { +// debug_log("Read error of stored file!"); +// return FALSE; +// } +// return TRUE; +// } + + + + + /* **************************************** + * ** RAR decompression code starts here ** + * ****************************************/ + + /* #define statements */ + public static class AudioVariables { + public int K1,K2,K3,K4,K5; // Should be short...? + public int D1,D2,D3,D4; + public int LastDelta; + public final int[] Dif = new int[11]; //unsigned + public int ByteCount; //unsigned + public int LastChar; + + public void zero() { + K1 = 0; + K2 = 0; + K3 = 0; + K4 = 0; + K5 = 0; + D1 = 0; + D2 = 0; + D3 = 0; + D4 = 0; + LastDelta = 0; + Util.zero(Dif); + ByteCount = 0; + LastChar = 0; + } + } + + public AudioVariables[] AudV = { new AudioVariables(), new AudioVariables(), + new AudioVariables(), new AudioVariables() }; + + /* +#define GetBits() \ + BitField = ( ( ( (UDWORD)InBuf[InAddr] << 16 ) | \ + ( (UWORD) InBuf[InAddr+1] << 8 ) | \ + ( InBuf[InAddr+2] ) ) \ + >> (8-InBit) ) & 0xffff; + */ + private static int GetBits(byte[] inBuf, int inAddr, int inBit) { + return ( ( ( (int) (inBuf[inAddr]&0xFF) << 16 ) | + ( (short) (inBuf[inAddr+1]&0xFF) << 8 ) | + ( (inBuf[inAddr+2]&0xFF) ) ) + >>> (8-unsign(inBit)) ) & 0xffff; + } + + /* +#define AddBits(Bits) \ + InAddr += ( InBit + (Bits) ) >> 3; \ + InBit = ( InBit + (Bits) ) & 7; + */ + + /** + * Adds Bits to the address specifiers. + * InAddr is the high 32 bits of the 35-bit address (?) while InBit is the low 3 bits (?). + * Modifies: InAddr, InBit + * @param Bits the bits to add (interpreted as unsigned int) + */ + private void AddBits(int Bits) { + InAddr += (int)(( unsign(InBit) + unsign(Bits) ) >>> 3); // (InBit + Bits) / 8 + InBit = (int)(( unsign(InBit) + unsign(Bits) ) & 7); + } + + public static int unsign(byte i) { + return i & 0xFF; + } + public static int unsign(short i) { + return i & 0xFFFF; + } + public static long unsign(int i) { + return i & 0xFFFFFFFFL; + } + public static BigInteger unsign(long i) { + return new BigInteger(1, Util.toByteArrayBE(i)); + } + + private static class Struct_NewFileHeader { + short HeadCRC; + byte HeadType; + short Flags; + short HeadSize; + int PackSize; + int UnpSize; + byte HostOS; + int FileCRC; + int FileTime; + byte UnpVer; + byte Method; + short NameSize; + int FileAttr; + }; + private NewFileHeader NewLhd;// = new NewFileHeader(); + + private RARFileEntryStream ArcPtr = null; + private int Encryption; + private long UnpPackedSize; + private /*unsigned long*/ int CurUnpRead, CurUnpWrite; + + //private byte[] UnpBuf; + private int BitField; //unsigned int + //private int Number; //unsigned int + + public final byte[] InBuf = new byte[8192]; /* input read buffer */ + + public final byte[] UnpOldTable = new byte[MC*4]; + + public int InAddr,InBit,ReadTop; //unsigned int + + //public int LastDist,LastLength; //unsigned int + //private int Length,Distance; //unsigned int + + //public final int[] OldDist = new int[4]; //unsigned int + //public int OldDistPtr; //unsigned int + + + public int UnpAudioBlock; + public int UnpChannels; + public int CurChannel; + public int ChannelDelta; + private boolean FileFound; + + + /* *** 38.3% of all CPU time is spent within this function!!! */ + /** + * Unpacks stuff.

+ * + *

+     * Global read set (constants):
+     *       DBits                      (final byte[48])
+     *       DDecode                    (final int[48])
+     *       LBits                      (final byte[14])
+     *       LDecode                    (final short[14])
+     *       LHD_SOLID                  (final int)
+     *       MAXWINMASK                 (final int)
+     *       MDPtr                      (final {@link MultDecode}[4])
+     *       SDBits                     (final byte[8])
+     *       SDDecode                   (final short[8])
+     *
+     * Global read set (variables):
+     *       FileFound                  (boolean)
+     *       NewLhd                     ({@link Struct_NewFileHeader})
+     *
+     * Global modify set:
+     *       BitField                   (int)
+     *       CurChannel                 (int)
+     *       DD                         (final {@link DistDecode})
+     *       InAddr                     (int)
+     *       InBit                      (int)
+     *       InBuf                      (final byte[8192])
+     *       LD                         (final {@link LitDecode})
+     *       temp_output_buffer         (byte[])
+     *       temp_output_buffer_offset  (int)
+     *       UnpAudioBlock              (int)
+     *       UnpChannels                (int)
+     *
+     * Local use set:
+     *       Bits                       (int)
+     * (in)  DestUnpSize                (long)
+     *       Distance                   (int)
+     *       LastDist                   (int)
+     *       LastLength                 (int)
+     *       Length                     (int)
+     *       Number                     (int)
+     *       OldDist                    (final int[4])
+     *       OldDistPtr                 (int)
+     * (in)  UnpAddr                    (byte[])
+     *       UnpBuf                     (byte[])
+     *       UnpPtr                     (int)
+     *       WrPtr                      (int)
+     *
+     * Call set:
+     *       {@link #UnpInitData}
+     *       {@link #UnpReadBuf}
+     *       {@link #ReadTables}
+     *       {@link #debug_log}
+     *       {@link System#arraycopy}
+     *       {@link #DecodeNumber}
+     *       {@link #DecodeAudio}
+     *       {@link #GetBits}
+     *       {@link #AddBits}
+     *       {@link #ReadLastTables}
+     * 
+ */ + public void Unpack(/*unsigned char*/ byte[] UnpAddr, /*long DestUnpSize, */RARFileEntryStream i_ArcPtr, OutputStream dataOut, NewFileHeader i_NewLhd) throws IOException { + // catacombae + ArcPtr = i_ArcPtr; + NewLhd = i_NewLhd; + long DestUnpSize = NewLhd.getUnpSize(); + UnpPackedSize = NewLhd.getPackSize(); + FileFound = true; //Otherwise no data will be written, just uncompressed and skipped (for the purpose of extracting solid archives). + Encryption = 0; + CurUnpRead = CurUnpWrite = 0; + // /catacombae + + int Bits; // unsigned int + + byte[] UnpBuf=UnpAddr; /* UnpAddr is a pointer to the unpack buffer */ + int UnpPtr = 0; // Pointer to where in the buffer we are at present + int WrPtr = 0; // Pointer to where in the buffer UnpBuf we were at the last write + int Length = 0; + int Distance = 0; + int LastDist = 0; + int LastLength = 0; + int Number = 0; + final int[] OldDist = new int[4]; + int OldDistPtr = 0; + + System.out.println("UnpInitData"); + UnpInitData(UnpBuf); + System.out.println("UnpReadBuf"); + UnpReadBuf(true); + if((NewLhd.getFlags() & LHD_SOLID) == 0) { + System.out.println("ReadTables"); + ReadTables(); + } + + DestUnpSize--; + + int l256 = 0, g269 = 0, e269 = 0, e256 = 0, l261 = 0, l270 = 0; // debug / understanding + while(DestUnpSize>=0) { + System.out.println("Looping (DestUnpSize=" + DestUnpSize + ")"); + UnpPtr &= MAXWINMASK; + + if(unsign(InAddr) > InBuf.length-30) + UnpReadBuf(false); + if(((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr) { + System.out.println("YO"); + if(FileFound) { + // Flush extracted data to file + if(!writeData(UnpBuf, UnpPtr, WrPtr, dataOut)) + DestUnpSize = -1; + } + WrPtr=UnpPtr; + } + else { + //System.out.println("((" + WrPtr + "-" + UnpPtr + ") & MAXWINMASK) >= 270"); + //System.out.println(((WrPtr-UnpPtr) & MAXWINMASK) + "<270"); + } + + if(UnpAudioBlock != 0) { + Number = DecodeNumber(MDPtr[CurChannel]); + if (Number==256) { + ReadTables(); + } + else { + UnpBuf[UnpPtr++]=DecodeAudio(Number); + if (++CurChannel==UnpChannels) + CurChannel=0; + DestUnpSize--; + } + //continue; + } + else { + Number = DecodeNumber(LD); + if(Number<256) { // stored + System.out.println(Number); + ++l256; + UnpBuf[UnpPtr++]=(byte)Number; + DestUnpSize--; + //continue; + } + else if(Number>269) { + ++g269; + Length = LDecode[Number-=270]+3; + if ((Bits=LBits[Number])>0) { + BitField = GetBits(InBuf, InAddr, InBit); + Length+=BitField>>>(16-Bits); + AddBits(Bits); + } + + Number = DecodeNumber(DD); + Distance = DDecode[Number]+1; + if ((Bits=DBits[Number])>0) { + BitField = GetBits(InBuf, InAddr, InBit); + Distance += BitField >>> (16-Bits); + AddBits(Bits); + } + + if (Distance>=0x40000) + Length++; + + if (Distance>=0x2000) + Length++; + + LastDist=OldDist[OldDistPtr++ & 3]=Distance; + DestUnpSize-=(LastLength=Length); + while (Length-- != 0) { + UnpBuf[UnpPtr]=UnpBuf[(UnpPtr-Distance) & MAXWINMASK]; + UnpPtr=(UnpPtr+1) & MAXWINMASK; + } + + //continue; + } + else if(Number==269) { + ++e269; + ReadTables(); + //continue; + } + else if(Number==256) { + ++e256; + Length = LastLength; + Distance = LastDist; + LastDist = OldDist[OldDistPtr++ & 3] = Distance; + DestUnpSize -= (LastLength=Length); + while(Length-- != 0) { + UnpBuf[UnpPtr] = UnpBuf[(UnpPtr-Distance) & MAXWINMASK]; + UnpPtr = (UnpPtr+1) & MAXWINMASK; + } + //continue; + } + else if(Number<261) { + ++l261; + Distance=OldDist[(OldDistPtr-(Number-256)) & 3]; + Number = DecodeNumber(RD); + Length=LDecode[Number]+2; + if ((Bits=LBits[Number])>0) { + BitField = GetBits(InBuf, InAddr, InBit); + Length+=BitField>>>(16-Bits); + AddBits(Bits); + } + if (Distance>=0x40000) + Length++; + if (Distance>=0x2000) + Length++; + if (Distance>=0x101) + Length++; + LastDist=OldDist[OldDistPtr++ & 3]=Distance; + DestUnpSize-=(LastLength=Length); + while (Length-- != 0) { + UnpBuf[UnpPtr]=UnpBuf[(UnpPtr-Distance) & MAXWINMASK]; + UnpPtr=(UnpPtr+1) & MAXWINMASK; + } + //continue; + } + else if(Number<270) { + ++l270; + Distance=SDDecode[Number-=261]+1; + if ((Bits=SDBits[Number])>0) { + BitField = GetBits(InBuf, InAddr, InBit); + Distance+=BitField>>>(16-Bits); + AddBits(Bits); + } + Length=2; + LastDist=OldDist[OldDistPtr++ & 3]=Distance; + DestUnpSize-=(LastLength=Length); + while (Length-- != 0) { + UnpBuf[UnpPtr]=UnpBuf[(UnpPtr-Distance) & MAXWINMASK]; + UnpPtr=(UnpPtr+1) & MAXWINMASK; + } + //continue; + } + else + debug_log("This message will NEVER be printed. If it is printed anyway, kick the programmer."); + } + } + System.out.println("x < 256: " + l256); + System.out.println("x > 269: " + g269); + System.out.println("x = 269: " + e269); + System.out.println("x = 256: " + e256); + System.out.println("x < 261: " + l261); + System.out.println("x < 270: " + l270); + System.out.println("Total: " + (l256+g269+e269+e256+l261+l270)); + System.out.println("LD.DecodeLen: 0x" + Util.toHexStringBE(LD.DecodeLen)); + System.out.println("LD.DecodeNum: 0x" + Util.toHexStringBE(LD.DecodeNum)); + System.out.println("LD.DecodePos: 0x" + Util.toHexStringBE(LD.DecodePos)); + System.out.println("LD.MaxNum: 0x" + Util.toHexStringBE(LD.MaxNum)); + ReadLastTables(); + + if (FileFound) { /* flush buffer */ + // Flush extracted data to file + if(!writeData(UnpBuf, UnpPtr, WrPtr, dataOut)) + DestUnpSize = -1; + } + + WrPtr=UnpPtr; + } + + /** + * Writes the data in UnpBuf to dataOut according to some rules.

+ *

+     * Global read set:
+     *       {@link #NewLhd}            ({@link NewFileHeader})
+     *
+     * Global modify set:
+     *      *temp_output_buffer         (byte[])
+     *       temp_output_buffer_offset  (int)
+     *
+     * Local use set:
+     * (in)  UnpBuf                     (byte[])
+     * 
+ */ + private boolean writeData(byte[] UnpBuf, int UnpPtr, int WrPtr, OutputStream dataOut) throws IOException { + if (UnpPtr NewLhd.getUnpSize()) { + debug_log("Fatal! Buffer overrun during decompression!"); + return false; //DestUnpSize=-1; + } else if(true) { + int firstOutLengthOld = (0-WrPtr) & MAXWINMASK; // Don't understand... + int firstOutLength = (UnpBuf.length-1) - WrPtr; //This should be equivalent to the above + if(firstOutLengthOld != firstOutLength) + debug_log("Assumption broken for firstOutLength :("); + + dataOut.write(UnpBuf, WrPtr, firstOutLength); + dataOut.write(UnpBuf, 0, UnpPtr); + temp_output_buffer_offset += firstOutLength+UnpPtr; + } else { + int firstOutLength = (0-WrPtr) & MAXWINMASK; // Don't understand... + /* copy extracted data to output buffer */ + System.arraycopy(UnpBuf, WrPtr, temp_output_buffer, temp_output_buffer_offset, firstOutLength); + /* update offset within buffer */ + temp_output_buffer_offset += firstOutLength; + /* copy extracted data to output buffer */ + System.arraycopy(UnpBuf, 0, temp_output_buffer, temp_output_buffer_offset, UnpPtr); + /* update offset within buffer */ + temp_output_buffer_offset += UnpPtr; + } + } else { + debug_log("UnpPtr>WrPtr (" + UnpPtr + ">" + WrPtr + ")"); + + if((temp_output_buffer_offset + (UnpPtr-WrPtr)) > NewLhd.getUnpSize()) { + debug_log("Fatal! Buffer overrun during decompression!"); + //DestUnpSize=-1; + return false; + } else if(true) { + dataOut.write(UnpBuf, WrPtr, UnpPtr-WrPtr); + temp_output_buffer_offset += UnpPtr-WrPtr; + } else { + /* copy extracted data to output buffer */ + System.arraycopy(UnpBuf, WrPtr, temp_output_buffer, temp_output_buffer_offset, UnpPtr-WrPtr); + temp_output_buffer_offset+=UnpPtr-WrPtr; /* update offset within buffer */ + } + } + return true; + } + /** + * Reads into the buffer InBuf from the archive stream. If the flag FirstBuf + * is set, the method preserves the last 32 bytes of InBuf and copies them to the front + * of the buffer, filling the buffer with only InBuf.length-32 bytes.

+ *

+     * Global modify set:
+     *       ReadTop                    (int)
+     *       InAddr                     (int)
+     *       Through UnpRead:
+     *         UnpPackedSize            (int)
+     *         CurUnpRead               (int)
+     * 
+     * Global read set:
+     *       InBuf                      (byte[])          (contents modified in UnpRead)
+     *
+     * Local use set:
+     * (in)  FirstBuf                   (boolean)
+     *       RetCode                    (int)
+     *
+     * Call set:
+     *       {@link UnpRead}
+     * 
+ * @param FirstBuf flag indicating whether or not we will treat this read as the first read + * to the buffer, thus destroying any previous content + */ + private void UnpReadBuf(boolean FirstBuf) { + int RetCode; + if(FirstBuf) { + ReadTop = UnpRead(InBuf, 0, InBuf.length); + InAddr = 0; + } + else { + System.arraycopy(InBuf, InBuf.length-32, InBuf, 0, 32); + InAddr &= 0x1f; // discard all but the five least significant bytes... is this modulo 32? think so. + RetCode = UnpRead(InBuf, 32, InBuf.length-32); + if(RetCode > 0) + ReadTop=RetCode+32; + else + ReadTop=InAddr; + } + } + + /** + * Reads Count bytes from the stream ArcPtr into + * the buffer Addr at position offset. If the + * data is encrypted, it is automatically decrypted. (The variable + * Encryption tells the function whether is shall consider + * the data to be encrypted.)

+ *

+     * Global read set:
+     *       ArcPtr                     ({@link java.io.InputStream})
+     *       Encryption                 (int)
+     *       
+     * Global modify set:
+     *       UnpPackedSize              (int)
+     *       CurUnpRead                 (int)
+     * 
+     * Local use set:
+     * (in)  Addr                       (byte[])
+     * (in)  offset                     (int)
+     * (in)  Count                      (int)
+     *       RetCode                    (int)
+     *       I                          (int)
+     *       ReadSize                   (int)
+     *       TotalRead                  (int)
+     *       ReadAddr                   (byte[])
+     *       readAddrPointer            (int)
+     *
+     * Call set:
+     *       tread(File, byte[], int, int)
+     *       debug_log(String)
+     *       DecryptBlock(byte[], int, int)
+     * 
+ * @return the number of bytes read, or -1 if an error occurred. + */ + private /*unsigned int*/ int UnpRead(/*unsigned char **/ byte[] Addr, int offset, /*unsigned int*/ int Count) { + int RetCode=0; + /*unsigned int*/ int I,ReadSize,TotalRead=0; + /*unsigned char **/ byte[] ReadAddr; + int readAddrPointer = offset; // catacombae + ReadAddr=Addr; + while(Count > 0) { + ReadSize=(/*unsigned int*/ int)((Count>(/*unsigned long*/ int)UnpPackedSize) ? + UnpPackedSize : Count); + if (ArcPtr==null) + return(0); + RetCode=tread(ArcPtr,ReadAddr,readAddrPointer,ReadSize); + debug_log("Read " + RetCode + " from file."); + + CurUnpRead+=RetCode; + readAddrPointer+=RetCode; + TotalRead+=RetCode; + Count-=RetCode; + UnpPackedSize-=RetCode; + break; // Why the while-loop? if would work just as well. + } + if (RetCode!= -1) { + RetCode=TotalRead; + if (Encryption != 0) { + if (Encryption<20) { + debug_log("Old Crypt() not supported!"); + } + else { + for (I=0;I<(/*unsigned int*/ short)RetCode;I+=16) + DecryptBlock(/*&Addr[I]*/Addr, I); + } + } + } + return(RetCode); + } + + + /** + * Reads and initializes the decompression tables.

+ *

+     * Global read set (constants):
+     *       BC                         (final short)
+     *       DC                         (final short)
+     *       MC                         (final short)
+     *       NC                         (final short)
+     *       RC                         (final short)
+     *
+     * Global read set (variables):
+     *
+     * Global modify set:
+     *       BD                         (BitDecode)
+     *       BitField                   (int)
+     *       CurChannel                 (int)
+     *       DD                         (DistDecode)
+     *       InAddr                     (int)
+     *       InBit                      (int) (through AddBits)
+     *       InBuf                      (final byte[8192])
+     *       MDPtr                      (final MultDecode[4])
+     *       RD                         (RepDecode)
+     *       UnpAudioBlock              (int)
+     *       UnpChannels                (int)
+     *       UnpOldTable                (final byte[MC*4])
+     *
+     *
+     * Local use set:
+     *       BitLength                  (final byte[BC])
+     *       Table                      (final byte[MC*4])
+     *       TableSize                  (int)
+     *       N                          (int)
+     *       I                          (int)
+     *
+     * Call set:
+     *       UnpReadBuf
+     *       GetBits
+     *       Util.zero
+     *       AddBits
+     *       MakeDecodeTables
+     *       DecodeNumber
+     *       System.arraycopy
+     * 
+ */ + private void ReadTables() { + System.out.println("ReadTables():"); + final /*UBYTE*/ byte[] BitLength = new byte[BC]; + final /*unsigned char*/ byte[] Table = new byte[MC*4]; + /*int*/ int TableSize,N,I; + + if(InAddr>InBuf.length-25) { + System.out.println("InAddr == " + InAddr); + UnpReadBuf(false); + } + BitField = GetBits(InBuf, InAddr, InBit); + UnpAudioBlock = (BitField & 0x8000); + + if((BitField & 0x4000) == 0) + Util.zero(UnpOldTable); + AddBits(2); + + + if(UnpAudioBlock != 0) { + UnpChannels=((BitField >>> 12) & 3)+1; + debug_log("WARNING: UnpChannels = " + UnpChannels); + if (CurChannel>=UnpChannels) + CurChannel=0; + AddBits(2); + TableSize=(short)(MC*UnpChannels); + } + else + TableSize=NC+DC+RC; + + + for (I=0;I>> 12); + AddBits(4); + } + MakeDecodeTables(BitLength, BD, 0, BC); + + I=0; + while(IInBuf.length-5) + UnpReadBuf(false); + int number = DecodeNumber(BD); + if(number<16) + Table[I++]=(byte)((number+UnpOldTable[I]) & 0xf); + else + if(number==16) { + BitField = GetBits(InBuf, InAddr, InBit); + N=((BitField >>> 14)+3); + AddBits(2); + while(N-- > 0 && I>> 13)+3); + AddBits(3); + } + else { + BitField = GetBits(InBuf, InAddr, InBit); + N=((BitField >>> 9)+11); + AddBits(7); + } + while(N-- > 0 && I=InAddr+5) { + if (UnpAudioBlock != 0) { + int number = DecodeNumber(MDPtr[CurChannel]); + if (number==256) + ReadTables(); + } + else { + int number = DecodeNumber(LD); + if (number==269) + ReadTables(); + } + } + } + + /** + * Modifies the Decode object Dec supplied as parameter + * according to the data in LenTab. Initializes Dec for + * further use in decompression.

+ *

+     * Global modify set:
+     *       
+     *
+     * Global read set:
+     *       
+     * 
+     * Local use set:
+     * (in)  LenTab                     (byte[])
+     * (i/o) Dec                        ({@link Decode})
+     * (in)  offset                     (int)
+     * (in)  Size                       (int)
+     *       LenCount                   (final int[16])
+     *       TmpPos                     (final int[16])
+     *       I                          (int)
+     *       M                          (int)
+     *       N                          (int)
+     * 
+ */ + private void MakeDecodeTables(/*unsigned char **/ byte[] LenTab, + Decode Dec, + int offset, + int Size) { + final /*int*/int[] LenCount = new int[16]; + final /*int*/int[] TmpPos = new int[16]; + /*int*/int I; + /*long*/int M, N; + //memset(LenCount,0,sizeof(LenCount)); // Java does this automatically + for(I=offset; I0xFFFF) + M=0xFFFF; + Dec.DecodeLen[I]=(/*unsigned int*/int)M; + TmpPos[I]=Dec.DecodePos[I]=((Dec.DecodePos[I-1] & 0xFFFF)+LenCount[I-1]); + } + + for(I=offset; IDecode object.

+ *

+     * Global modify set:
+     *       BitField                   (int)
+     *       In AddBits:
+     *         InAddr                   (int)
+     *         InBit                    (int)
+     *
+     * Local use set:
+     * (in)  Deco                       ({@link Decode})
+     *       I                          (int)
+     *       N                          (int)
+     *
+     * Call set:
+     *       GetBits
+     *       AddBits
+     * 
+ * + * @return the decoded number...? + */ + private int DecodeNumber(Decode Deco) { + /*unsigned int*/ int I; + /*register unsigned int*/ int N; + System.out.println("GetBits(" + InBuf + ", " + InAddr + ", " + InBit + ");"); + BitField = GetBits(InBuf, InAddr, InBit); + + N=(BitField & 0xFFFE); + System.out.println("(1) N == " + N + " (BitField == " + BitField + ")"); + if(N>> (16-I)); + System.out.println("(2) N == " + N); + if(N >= Deco.MaxNum) + N=0; + System.out.println("(3) N == " + N); + + System.out.println("Deco.DecodeNum[" + N + "] == " + Deco.DecodeNum[N]); + return Deco.DecodeNum[N]; + } + + /** + * Intializes data for the unpack process by setting the variables InAddr and InBit to 0.
+ * If the archive is a solid archive the method also does the following:
+ *
    + *
  • Set ChannelDelta and CurChannel to 0.
  • + *
  • Zero all AudioVariables objects in AudV through {@link AudioVariables#zero}.
  • + *
  • Zero the arrays unpBuf and UnpOldTable.
  • + *

+ *

+     * Global read set:
+     *       NewLhd                     ({@link Struct_NewFileHeader})
+     *       LHD_SOLID                  (final int)
+     *       MAXWINSIZE                 (final int)
+     *
+     * Global modify set:
+     *       InAddr                     (int)
+     *       InBit                      (int)
+     *       ChannelDelta               (int)
+     *       CurChannel                 (int)
+     *       AudV                       ({@link AudioVariables})
+     *       
+     * Local use set:
+     * (in)  unpBuf                     (byte[])
+     * 
+ */ + private void UnpInitData(byte[] unpBuf) { + InAddr=InBit=0; + if(!((NewLhd.getFlags() & LHD_SOLID) != 0)) { + System.out.println("1"); + ChannelDelta=CurChannel=0; + + //memset(AudV,0,sizeof(AudV)); + System.out.println("2"); + for(AudioVariables av : AudV) + av.zero(); + //memset(OldDist,0,sizeof(OldDist)); + //Util.zero(OldDist); + //OldDistPtr=0; + //LastDist=LastLength=0; + //memset(UnpBuf,0,MAXWINSIZE); + System.out.println("3"); + Util.zero(unpBuf, 0, MAXWINSIZE); + //memset(UnpOldTable,0,sizeof(UnpOldTable)); + System.out.println("4"); + Util.zero(UnpOldTable); + //UnpPtr=WrPtr=0; + } + } + + /** + * Does some kind of audio decoding that I'm not familiar with conceptually.

+ *

 
+     * Global read set:
+     *       CurChannel                 (int)
+     *
+     * Global modify set:
+     *       AudV                       ({@link AudioVariables}[])
+     *       ChannelDelta               (int)
+     *
+     * Local use set:
+     * (in)  Delta                      (int)
+     *       V                          ({@link AudioVariables})
+     *       Ch                         (int)
+     *       NumMinDif                  (int)
+     *       MinDif                     (int)
+     *       PCh                        (int)
+     *       I                          (int)
+     * 
+ */ + private /*UBYTE*/ byte DecodeAudio(int Delta) { + AudioVariables V; + /*unsigned */int Ch; + /*unsigned */int NumMinDif,MinDif; + int PCh,I; + + V=AudV[CurChannel]; + V.ByteCount++; + V.D4=V.D3; + V.D3=V.D2; + V.D2=V.LastDelta-V.D1; + V.D1=V.LastDelta; + PCh=8*V.LastChar+V.K1*V.D1+V.K2*V.D2+ + V.K3*V.D3+V.K4*V.D4+V.K5*ChannelDelta; + PCh=(PCh>>3) & 0xFF; + + Ch=PCh-Delta; + + I=((/*signed char*/byte)Delta)<<3; + + V.Dif[0]+=Math.abs(I); + V.Dif[1]+=Math.abs(I-V.D1); + V.Dif[2]+=Math.abs(I+V.D1); + V.Dif[3]+=Math.abs(I-V.D2); + V.Dif[4]+=Math.abs(I+V.D2); + V.Dif[5]+=Math.abs(I-V.D3); + V.Dif[6]+=Math.abs(I+V.D3); + V.Dif[7]+=Math.abs(I-V.D4); + V.Dif[8]+=Math.abs(I+V.D4); + V.Dif[9]+=Math.abs(I-ChannelDelta); + V.Dif[10]+=Math.abs(I+ChannelDelta); + + ChannelDelta=V.LastDelta=(/*signed char*/byte)(Ch-V.LastChar); + V.LastChar=Ch; + + if((V.ByteCount & 0x1F)==0) { + MinDif=V.Dif[0]; + NumMinDif=0; + V.Dif[0]=0; + for (I=1;(/*unsigned */int)I=-16) + V.K1--; + break; + case 2: + if(V.K1<16) + V.K1++; + break; + case 3: + if(V.K2>=-16) + V.K2--; + break; + case 4: + if(V.K2<16) + V.K2++; + break; + case 5: + if(V.K3>=-16) + V.K3--; + break; + case 6: + if(V.K3<16) + V.K3++; + break; + case 7: + if(V.K4>=-16) + V.K4--; + break; + case 8: + if(V.K4<16) + V.K4++; + break; + case 9: + if(V.K5>=-16) + V.K5--; + break; + case 10: + if(V.K5<16) + V.K5++; + break; + } + } + return((/*UBYTE*/byte)Ch); + } + + + + + + + + /* *************************************************** + * ** CRCCrypt Code - decryption engine starts here ** + * ***************************************************/ + + + +/* #define rol(x,n) (((x)<<(n)) | ((x)>>(8*sizeof(x)-(n)))) */ + /** Rotate left. Pure functional behavior, no side effects. */ + private static byte rol(byte value, int shift) { + return (byte) (((value)<<(shift)) | ((value)>>>(8*1-(shift)))); + } + /** @see #rol(byte,int) */ + private static short rol(short value, int shift) { + return (short)(((value)<<(shift)) | ((value)>>>(8*2-(shift)))); + } + /** @see #rol(byte,int) */ + private static int rol(int value, int shift) { + return (((value)<<(shift)) | ((value)>>>(8*4-(shift)))); + } + /** @see #rol(byte,int) */ + private static long rol(long value, int shift) { + return (((value)<<(shift)) | ((value)>>>(8*8-(shift)))); + } + +/* #define ror(x,n) (((x)>>(n)) | ((x)<<(8*sizeof(x)-(n)))) */ + /** Rotate right. Pure functional behavior, no side effects. */ + private static byte ror(byte value, int shift) { + return (byte) (((value)>>>(shift)) | ((value)<<(8*1-(shift)))); + } + /** @see #ror(byte,int) */ + private static short ror(short value, int shift) { + return (short)(((value)>>>(shift)) | ((value)<<(8*2-(shift)))); + } + /** @see #ror(byte,int) */ + private static int ror(int value, int shift) { + return (((value)>>>(shift)) | ((value)<<(8*4-(shift)))); + } + /** @see #ror(byte,int) */ + private static long ror(long value, int shift) { + return (((value)>>>(shift)) | ((value)<<(8*8-(shift)))); + } + +/* +#define substLong(t) ( (UDWORD)SubstTable[(int)t&255] | \ + ((UDWORD)SubstTable[(int)(t>> 8)&255]<< 8) | \ + ((UDWORD)SubstTable[(int)(t>>16)&255]<<16) | \ + ((UDWORD)SubstTable[(int)(t>>24)&255]<<24) ) +*/ + private int substLong(int t) { + return ( ((/*UDWORD*/int)SubstTable[(int)(t>> 0)&255]<< 0) | + ((/*UDWORD*/int)SubstTable[(int)(t>> 8)&255]<< 8) | + ((/*UDWORD*/int)SubstTable[(int)(t>>16)&255]<<16) | + ((/*UDWORD*/int)SubstTable[(int)(t>>24)&255]<<24) ); + } + + // public static final /*UDWORD*/ int[] CRCTab = new int[256]; // Initialized in static constructor + + + public /*UDWORD*/ int[] Key = new int[4]; + + + public void EncryptBlock(/*UBYTE*/byte[] Buf) { + //int I; + + int /*UDWORD*/ A,B,C,D,T,TA,TB; +// #ifdef NON_INTEL_BYTE_ORDER + if(true) { + A = ((0xFF & Buf[0] ) | ((0xFF & Buf[1] )<<8) | ((0xFF & Buf[2] )<<16) | ((0xFF & Buf[3] )<<24))^Key[0]; + B = ((0xFF & Buf[4] ) | ((0xFF & Buf[5] )<<8) | ((0xFF & Buf[6] )<<16) | ((0xFF & Buf[7] )<<24))^Key[1]; + C = ((0xFF & Buf[8] ) | ((0xFF & Buf[9] )<<8) | ((0xFF & Buf[10])<<16) | ((0xFF & Buf[11])<<24))^Key[2]; + D = ((0xFF & Buf[12]) | ((0xFF & Buf[13])<<8) | ((0xFF & Buf[14])<<16) | ((0xFF & Buf[15])<<24))^Key[3]; + } + else { // The above code should yield the same result as these lines. Test this assumption. + A = Util.readIntLE(Buf, 0 )^Key[0]; + B = Util.readIntLE(Buf, 4 )^Key[1]; + C = Util.readIntLE(Buf, 8 )^Key[2]; + D = Util.readIntLE(Buf, 12)^Key[3]; + } +// #else +// UDWORD *BufPtr; +// BufPtr=(UDWORD *)Buf; +// A=BufPtr[0]^Key[0]; +// B=BufPtr[1]^Key[1]; +// C=BufPtr[2]^Key[2]; +// D=BufPtr[3]^Key[3]; +// #endif + for(int I=0;I>>8)); + Buf[2]=(byte)(0xFF & (C>>>16)); + Buf[3]=(byte)(0xFF & (C>>>24)); + D ^= Key[1]; + Buf[4]=(byte)(0xFF & D); + Buf[5]=(byte)(0xFF & (D>>>8)); + Buf[6]=(byte)(0xFF & (D>>>16)); + Buf[7]=(byte)(0xFF & (D>>>24)); + A ^= Key[2]; + Buf[8]=(byte)(0xFF & A); + Buf[9]=(byte)(0xFF & (A>>>8)); + Buf[10]=(byte)(0xFF & (A>>>16)); + Buf[11]=(byte)(0xFF & (A>>>24)); + B ^= Key[3]; + Buf[12]=(byte)(0xFF & B); + Buf[13]=(byte)(0xFF & (B>>>8)); + Buf[14]=(byte)(0xFF & (B>>>16)); + Buf[15]=(byte)(0xFF & (B>>>24)); + } + else { + System.arraycopy(Util.toByteArrayLE(C^Key[0]), 0, Buf, 0, 4); + System.arraycopy(Util.toByteArrayLE(D^Key[1]), 4, Buf, 0, 4); + System.arraycopy(Util.toByteArrayLE(A^Key[2]), 8, Buf, 0, 4); + System.arraycopy(Util.toByteArrayLE(B^Key[3]), 12, Buf, 0, 4); + } +// #else +// BufPtr[0]=C^Key[0]; +// BufPtr[1]=D^Key[1]; +// BufPtr[2]=A^Key[2]; +// BufPtr[3]=B^Key[3]; +// #endif + UpdKeys(Buf); +} + + + /** + * Decrypts a 16 byte block in the buffer Buf at position offset. + * The decrypted data is stored at the same place in Buf, thus overwriting the + * encrypted contents.

+ *

+     * Global read set:
+     *
+     * Global modify set:
+     *       In UpdKeys:
+     *         Key                      (final int[4])
+     *
+     * Local use set:
+     * (in)  Buf                        (byte[])
+     * (in)  offset                     (int)
+     *       InBuf                      (byte[])
+     *       A                          (int)
+     *       B                          (int)
+     *       C                          (int)
+     *       D                          (int)
+     *       T                          (int)
+     *       TA                         (int)
+     *       TB                         (int)
+     * 
+ */ + public void DecryptBlock(/*UBYTE*/byte[] Buf, int offset) { + //int I; + final int n = offset; + byte[] /*UBYTE*/ InBuf = new byte[16]; + int /*UDWORD*/ A,B,C,D,T,TA,TB; + System.arraycopy(Buf, n, InBuf, 0, InBuf.length); // memcpy(InBuf,Buf,sizeof(InBuf)); + + // Swap all bytes since data is stored in little endian format. +// if(true) { + A = ((0xFF & Buf[n+0] ) | ((0xFF & Buf[n+1] )<<8) | ((0xFF & Buf[n+2] )<<16) | ((0xFF & Buf[n+3] )<<24))^Key[0]; + B = ((0xFF & Buf[n+4] ) | ((0xFF & Buf[n+5] )<<8) | ((0xFF & Buf[n+6] )<<16) | ((0xFF & Buf[n+7] )<<24))^Key[1]; + C = ((0xFF & Buf[n+8] ) | ((0xFF & Buf[n+9] )<<8) | ((0xFF & Buf[n+10])<<16) | ((0xFF & Buf[n+11])<<24))^Key[2]; + D = ((0xFF & Buf[n+12]) | ((0xFF & Buf[n+13])<<8) | ((0xFF & Buf[n+14])<<16) | ((0xFF & Buf[n+15])<<24))^Key[3]; +// } +// else { // The above code should yield the same result as these lines. Test this assumption. + int A2 = Util.readIntLE(Buf, n+0 )^Key[0]; + int B2 = Util.readIntLE(Buf, n+4 )^Key[1]; + int C2 = Util.readIntLE(Buf, n+8 )^Key[2]; + int D2 = Util.readIntLE(Buf, n+12)^Key[3]; +// } + + if(A != A2 || B != B2 || C != C2 || D != D2) { + System.out.println("Assumption broken!"); + System.out.println(" A: 0x" + Util.toHexStringBE(A) + " A2: 0x" + Util.toHexStringBE(A2)); + System.out.println(" B: 0x" + Util.toHexStringBE(B) + " B2: 0x" + Util.toHexStringBE(B2)); + System.out.println(" C: 0x" + Util.toHexStringBE(C) + " C2: 0x" + Util.toHexStringBE(C2)); + System.out.println(" D: 0x" + Util.toHexStringBE(D) + " D2: 0x" + Util.toHexStringBE(D2)); + } + else + System.out.println("Assumption correct!"); + + for(int I=NROUNDS-1; I>=0; I--) { + T=((C+rol(D,11))^Key[I&3]); + TA=A^substLong(T); + T=((D^rol(C,17))+Key[I&3]); + TB=B^substLong(T); + A=C; + B=D; + C=TA; + D=TB; + } + + if(true) { + C ^= Key[0]; + Buf[n+0 ]=(byte)(0xFF & C); + Buf[n+1 ]=(byte)(0xFF & (C>>>8)); + Buf[n+2 ]=(byte)(0xFF & (C>>>16)); + Buf[n+3 ]=(byte)(0xFF & (C>>>24)); + D ^= Key[1]; + Buf[n+4 ]=(byte)(0xFF & D); + Buf[n+5 ]=(byte)(0xFF & (D>>>8)); + Buf[n+6 ]=(byte)(0xFF & (D>>>16)); + Buf[n+7 ]=(byte)(0xFF & (D>>>24)); + A ^= Key[2]; + Buf[n+8 ]=(byte)(0xFF & A); + Buf[n+9 ]=(byte)(0xFF & (A>>>8)); + Buf[n+10]=(byte)(0xFF & (A>>>16)); + Buf[n+11]=(byte)(0xFF & (A>>>24)); + B ^= Key[3]; + Buf[n+12]=(byte)(0xFF & B); + Buf[n+13]=(byte)(0xFF & (B>>>8)); + Buf[n+14]=(byte)(0xFF & (B>>>16)); + Buf[n+15]=(byte)(0xFF & (B>>>24)); + } + else { + System.arraycopy(Util.toByteArrayLE(C^Key[0]), 0, Buf, n+0 , 4); + System.arraycopy(Util.toByteArrayLE(D^Key[1]), 0, Buf, n+4 , 4); + System.arraycopy(Util.toByteArrayLE(A^Key[2]), 0, Buf, n+8 , 4); + System.arraycopy(Util.toByteArrayLE(B^Key[3]), 0, Buf, n+12, 4); + } + + UpdKeys(InBuf); + } + + + /* + * As we can't use unsigned data types in Java, we'll have to unsign the data + * every time we use it. Modifications: unsign the usage of Buf[I] by "& 0xFF". + */ + /** + * Updates keys. ;) + *
+     * Global modify set:
+     *       Key                        (int[4])
+     * Global read set:
+     *       CRCTab                     (int[256])
+     * Local use set:
+     * (in)  Buf                        (byte[])
+     *       I                          (int)
+     * 
+ */ + public void UpdKeys(byte[]/*UBYTE*/ Buf) { + for(int I=0; I<16; I+=4) { + Key[0]^=CRCTab[Buf[I] & 0xFF]; /* xxx may be I'll rewrite this */ + Key[1]^=CRCTab[Buf[I+1] & 0xFF]; /* in asm for speedup */ + Key[2]^=CRCTab[Buf[I+2] & 0xFF]; + Key[3]^=CRCTab[Buf[I+3] & 0xFF]; + } + } + + /* Password is supposed to be trimmed to the actual password length and not zero-terminated. */ + /** + * Sets crypt keys. ;)
+ * Password is supposed to be trimmed to the actual + * password length and not zero-terminated.

+ *

+     * Global read set:
+     *       InitSubstTable             (final short[256])
+     *       CRCTab
+     *
+     * Global modify set:
+     *       Key                        (final int[4])
+     *       SubstTable                 (final short[256])
+     *       In SetOldKeys:
+     *         OldKey                   (final short[4])
+     *         PN1                      (byte)
+     *         PN2                      (byte)
+     *         PN3                      (byte)
+     *
+     * Local use set:
+     *       Password                   (byte[])
+     *       I                          (int)
+     *       J                          (int)
+     *       K                          (int)
+     *       N1                         (short)
+     *       N2                         (short)
+     *       Psw                        (final byte[256])
+     *       Ch                         (short)
+     *
+     * Call set:
+     *       SetOldKeys
+     *       System.arraycopy
+     *       EncryptBlock
+     * 
+ */ + public void SetCryptKeys(byte[] Password) { + /*unsigned int*/ int I,J,K, PswLength; + /*unsigned char*/ short N1,N2; + final /*unsigned char*/ byte[] Psw = new byte[256]; + + /*UBYTE*/ short Ch; + + SetOldKeys(Password); + + Key[0]=0xD3A3B879; // Removed the L at the end (indicates 32 bits in C, 64 in Java) + Key[1]=0x3F6D12F7; // -||- + Key[2]=0x7515A235; // -||- + Key[3]=0xA4E7F123; // -||- + //memset(Psw,0,sizeof(Psw)); // Arrays are automatically initialized to 0 in Java. + System.arraycopy(Password, 0, Psw, 0, (Password.length + * Global read set: + * CRCTab (final int[256]) + * + * Global modify set: + * OldKey (final short[4]) + * PN1 (byte) + * PN2 (byte) + * PN3 (byte) + * + * Local use set: + * (in) Password (byte[]) + * PswCRC (int) + * Ch (byte) + * + * Call set: + * //CalcCRC32 + * rol + * + */ + private void SetOldKeys(/*char **/byte[] Password) { + /*UDWORD*/int PswCRC; + /*UBYTE*/byte Ch; + crc.reset(); + crc.update(Password); + PswCRC=(int)crc.getValue();//CalcCRC32(0xFFFFFFFF,/*(UBYTE*)*/Password,0,Util.strlen(Password)); + OldKey[0]=(/*UWORD*/short)PswCRC; + OldKey[1]=(/*UWORD*/short)(PswCRC>>>16); + OldKey[2]=OldKey[3]=0; + PN1=PN2=PN3=0; + //while ((Ch=*Password)!=0) { + for(int i = 0; (Ch=Password[i])!=0; ++i) { + PN1+=Ch; + PN2^=Ch; + PN3+=Ch; + PN3=(/*UBYTE*/byte)rol(PN3,1); + OldKey[2]^=((/*UWORD*/short)(Ch^CRCTab[Ch])); + OldKey[3]+=((/*UWORD*/short)(Ch+(CRCTab[Ch]>>>16))); + //Password++; + } + } + + /** + * Initializes the CRC table crcTab, which has to have a length of 256 elements. + * @param crcTab the array where the initialized CRC table is to be stored + * @return the same array that was given as input parameter (for convenience) + */ + static int[] InitCRC(int[] crcTab) { + int I, J; + /*UDWORD*/int C; + for (I=0;I<256;I++) { + for (C=I,J=0;J<8;J++) + C=(C & 1)!=0 ? (C>>>1)^0xEDB88320 : (C>>>1); + crcTab[I]=C; + } + return crcTab; + } + + + /** + * Calculates the CRC32 checksum from its arguments. + *
+     * Global read set:
+     *       CRCTab                     ([256])
+     *
+     * Local use set:
+     * (in) StartCRC                   (int)
+     * (in)  Addr                       (byte[])
+     * (in)  offset                     (int)
+     * (in)  Size                       (int)
+     *       I                          (int)
+     *
+     * Purely functional behavior, no side effects.
+     * 
+ * @return the updated sum + */ + static int CalcCRC32(int StartCRC, byte[] Addr, int offset, int Size) { + /*unsigned */int I; + for (I=offset; I>> 8); + return(StartCRC); + } + + /* No side effects. */ + private static void debug_log(String s) { + System.err.println("DEBUG: " + s); + } + + /** No side effects (except position in f increasing). */ + private static int tread(RARFileEntryStream f, byte[] buffer, int offset, int length) { + try { + return f.read(buffer, offset, length); + } catch(Exception e) { e.printStackTrace(); return -1; } + } +} + +/* ************************************************************************** + **************************************************************************** + **************************************************************************** + ************************************************************************** */ + + + + + + + + + + + + + + + + + + + + + + + + + +/* ************************************************************************** + **************************************************************************** + **************************************************************************** + **************************************************************************** + ******* ******* + ******* ******* + ******* ******* + ******* D E B U G F U N C T I O N S ******* + ******* ******* + ******* ******* + ******* ******* + **************************************************************************** + **************************************************************************** + **************************************************************************** + ************************************************************************** */ +// #ifdef _DEBUG_LOG + + +// /* -- global stuff -------------------------------------------------------- */ +// char log_file_name[256]; /* file name for the log file */ +// DWORD debug_start_time; /* starttime of debug */ +// BOOL debug_started = FALSE; /* debug_log writes only if */ +// /* this is TRUE */ +// /* ------------------------------------------------------------------------ */ + + +// /* -- global functions ---------------------------------------------------- */ +// void debug_init_proc(char *file_name) +// /* Create/Rewrite a log file */ +// { +// FILE *fp; +// char date[] = __DATE__; +// char time[] = __TIME__; + +// debug_start_time = GetTickCount(); /* get start time */ +// strcpy(log_file_name, file_name); /* save file name */ + +// if((fp = fopen(log_file_name, CREATETEXT)) != NULL) +// { +// debug_started = TRUE; /* enable debug */ +// fprintf(fp, "Debug log of UniquE's RARFileLib\n"\ +// "~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~\n"); +// fprintf(fp, "(executable compiled on %s at %s)\n\n", date, time); +// fclose(fp); +// } +// } + + +// void debug_log_proc(char *text, char *sourcefile, int sourceline) +// /* add a line to the log file */ +// { +// FILE *fp; + +// if(debug_started == FALSE) return; /* exit if not initialized */ + +// if((fp = fopen(log_file_name, APPENDTEXT)) != NULL) /* append to logfile */ + +// { +// fprintf(fp, " %8u ms (line %u in %s):\n - %s\n", +// (/*unsigned */int)(GetTickCount() - debug_start_time), +// sourceline, sourcefile, text); +// fclose(fp); +// } +// } + +// /* ------------------------------------------------------------------------ */ +// #endif +/* ************************************************************************** + **************************************************************************** + **************************************************************************** + ************************************************************************** */ + -- cgit v1.2.3