/*
* 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 ">"
* "@": "@"
*/
using SharpCompress.Compressor.Rar.decode;
namespace SharpCompress.Compressor.Rar
{
/// DOCUMENT ME
///
///
/// $LastChangedBy$
///
/// $LastChangedRevision$
///
internal abstract class Unpack20 : Unpack15
{
public Unpack20()
{
InitBlock();
}
private void InitBlock()
{
UnpOldTable20 = new byte[Compress.MC20 * 4];
}
protected internal MultDecode[] MD = new MultDecode[4];
//UPGRADE_NOTE: The initialization of 'UnpOldTable20' was moved to method 'InitBlock'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
protected internal byte[] UnpOldTable20;
protected internal int UnpAudioBlock, UnpChannels, UnpCurChannel, UnpChannelDelta;
private readonly AudioVariables[] AudV = new AudioVariables[4];
protected internal LitDecode LD = new LitDecode();
protected internal DistDecode DD = new DistDecode();
protected internal LowDistDecode LDD = new LowDistDecode();
protected internal RepDecode RD = new RepDecode();
protected internal BitDecode BD = new BitDecode();
//UPGRADE_NOTE: Final was removed from the declaration of 'LDecode'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public static readonly int[] LDecode = new int[] { 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 };
//UPGRADE_NOTE: Final was removed from the declaration of 'LBits'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public static readonly byte[] LBits = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 };
//UPGRADE_NOTE: Final was removed from the declaration of 'DDecode'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public static readonly int[] DDecode = new int[] { 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 };
//UPGRADE_NOTE: Final was removed from the declaration of 'DBits'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public static readonly int[] DBits = new int[] { 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 };
//UPGRADE_NOTE: Final was removed from the declaration of 'SDDecode'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public static readonly int[] SDDecode = new int[] { 0, 4, 8, 16, 32, 64, 128, 192 };
//UPGRADE_NOTE: Final was removed from the declaration of 'SDBits'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
public static readonly int[] SDBits = new int[] { 2, 2, 3, 4, 5, 6, 6, 6 };
internal void unpack20(bool solid)
{
int Bits;
if (suspended)
{
unpPtr = wrPtr;
}
else
{
unpInitData(solid);
if (!unpReadBuf())
{
return;
}
if (!solid)
{
if (!ReadTables20())
{
return;
}
}
--destUnpSize;
}
while (destUnpSize >= 0)
{
unpPtr &= Compress.MAXWINMASK;
if (inAddr > readTop - 30)
if (!unpReadBuf())
break;
if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 270 && wrPtr != unpPtr)
{
oldUnpWriteBuf();
if (suspended)
return;
}
if (UnpAudioBlock != 0)
{
int AudioNumber = this.decodeNumber(MD[UnpCurChannel]);
if (AudioNumber == 256)
{
if (!ReadTables20())
break;
continue;
}
window[unpPtr++] = DecodeAudio(AudioNumber);
if (++UnpCurChannel == UnpChannels)
UnpCurChannel = 0;
--destUnpSize;
continue;
}
int Number = this.decodeNumber(LD);
if (Number < 256)
{
window[unpPtr++] = (byte)Number;
--destUnpSize;
continue;
}
if (Number > 269)
{
int Length = LDecode[Number -= 270] + 3;
if ((Bits = LBits[Number]) > 0)
{
Length += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
int DistNumber = this.decodeNumber(DD);
int Distance = DDecode[DistNumber] + 1;
if ((Bits = DBits[DistNumber]) > 0)
{
Distance += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
if (Distance >= 0x2000)
{
Length++;
if (Distance >= 0x40000L)
Length++;
}
CopyString20(Length, Distance);
continue;
}
if (Number == 269)
{
if (!ReadTables20())
break;
continue;
}
if (Number == 256)
{
CopyString20(lastLength, lastDist);
continue;
}
if (Number < 261)
{
int Distance = oldDist[(oldDistPtr - (Number - 256)) & 3];
int LengthNumber = this.decodeNumber(RD);
int Length = LDecode[LengthNumber] + 2;
if ((Bits = LBits[LengthNumber]) > 0)
{
Length += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
if (Distance >= 0x101)
{
Length++;
if (Distance >= 0x2000)
{
Length++;
if (Distance >= 0x40000)
Length++;
}
}
CopyString20(Length, Distance);
continue;
}
if (Number < 270)
{
int Distance = SDDecode[Number -= 261] + 1;
if ((Bits = SDBits[Number]) > 0)
{
Distance += Utility.URShift(GetBits(), (16 - Bits));
AddBits(Bits);
}
CopyString20(2, Distance);
continue;
}
}
ReadLastTables();
oldUnpWriteBuf();
}
private void CopyString20(int Length, int Distance)
{
lastDist = oldDist[oldDistPtr++ & 3] = Distance;
lastLength = Length;
destUnpSize -= Length;
int DestPtr = unpPtr - Distance;
if (DestPtr < Compress.MAXWINSIZE - 300 && unpPtr < Compress.MAXWINSIZE - 300)
{
window[unpPtr++] = window[DestPtr++];
window[unpPtr++] = window[DestPtr++];
while (Length > 2)
{
Length--;
window[unpPtr++] = window[DestPtr++];
}
}
else
{
while ((Length--) != 0)
{
window[unpPtr] = window[DestPtr++ & Compress.MAXWINMASK];
unpPtr = (unpPtr + 1) & Compress.MAXWINMASK;
}
}
}
private bool ReadTables20()
{
byte[] BitLength = new byte[Compress.BC20];
byte[] Table = new byte[Compress.MC20 * 4];
int TableSize, N, I;
if (inAddr > readTop - 25)
{
if (!unpReadBuf())
{
return (false);
}
}
int BitField = GetBits();
UnpAudioBlock = (BitField & 0x8000);
if (0 == (BitField & 0x4000))
{
// memset(UnpOldTable20,0,sizeof(UnpOldTable20));
Utility.Fill(UnpOldTable20, (byte)0);
}
AddBits(2);
if (UnpAudioBlock != 0)
{
UnpChannels = ((Utility.URShift(BitField, 12)) & 3) + 1;
if (UnpCurChannel >= UnpChannels)
{
UnpCurChannel = 0;
}
AddBits(2);
TableSize = Compress.MC20 * UnpChannels;
}
else
{
TableSize = Compress.NC20 + Compress.DC20 + Compress.RC20;
}
for (I = 0; I < Compress.BC20; I++)
{
BitLength[I] = (byte)(Utility.URShift(GetBits(), 12));
AddBits(4);
}
UnpackUtility.makeDecodeTables(BitLength, 0, BD, Compress.BC20);
I = 0;
while (I < TableSize)
{
if (inAddr > readTop - 5)
{
if (!unpReadBuf())
{
return (false);
}
}
int Number = this.decodeNumber(BD);
if (Number < 16)
{
Table[I] = (byte)((Number + UnpOldTable20[I]) & 0xf);
I++;
}
else if (Number == 16)
{
N = (Utility.URShift(GetBits(), 14)) + 3;
AddBits(2);
while (N-- > 0 && I < TableSize)
{
Table[I] = Table[I - 1];
I++;
}
}
else
{
if (Number == 17)
{
N = (Utility.URShift(GetBits(), 13)) + 3;
AddBits(3);
}
else
{
N = (Utility.URShift(GetBits(), 9)) + 11;
AddBits(7);
}
while (N-- > 0 && I < TableSize)
Table[I++] = 0;
}
}
if (inAddr > readTop)
{
return (true);
}
if (UnpAudioBlock != 0)
for (I = 0; I < UnpChannels; I++)
UnpackUtility.makeDecodeTables(Table, I * Compress.MC20, MD[I], Compress.MC20);
else
{
UnpackUtility.makeDecodeTables(Table, 0, LD, Compress.NC20);
UnpackUtility.makeDecodeTables(Table, Compress.NC20, DD, Compress.DC20);
UnpackUtility.makeDecodeTables(Table, Compress.NC20 + Compress.DC20, RD, Compress.RC20);
}
// memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20));
for (int i = 0; i < UnpOldTable20.Length; i++)
{
UnpOldTable20[i] = Table[i];
}
return (true);
}
protected void unpInitData20(bool Solid)
{
if (!Solid)
{
UnpChannelDelta = UnpCurChannel = 0;
UnpChannels = 1;
// memset(AudV,0,sizeof(AudV));
AudV[0] = new AudioVariables();
AudV[1] = new AudioVariables();
AudV[2] = new AudioVariables();
AudV[3] = new AudioVariables();
// memset(UnpOldTable20,0,sizeof(UnpOldTable20));
Utility.Fill(UnpOldTable20, (byte)0);
}
}
private void ReadLastTables()
{
if (readTop >= inAddr + 5)
{
if (UnpAudioBlock != 0)
{
if (this.decodeNumber(MD[UnpCurChannel]) == 256)
{
ReadTables20();
}
}
else
{
if (this.decodeNumber(LD) == 269)
{
ReadTables20();
}
}
}
}
private byte DecodeAudio(int Delta)
{
AudioVariables v = AudV[UnpCurChannel];
v.ByteCount = v.ByteCount + 1;
v.D4 = v.D3;
v.D3 = v.D2; // ->D3=V->D2;
v.D2 = v.LastDelta - v.D1; // ->D2=V->LastDelta-V->D1;
v.D1 = v.LastDelta; // V->D1=V->LastDelta;
// int PCh=8*V->LastChar+V->K1*V->D1 +V->K2*V->D2 +V->K3*V->D3
// +V->K4*V->D4+ V->K5*UnpChannelDelta;
int PCh = 8 * v.LastChar + v.K1 * v.D1;
PCh += v.K2 * v.D2 + v.K3 * v.D3;
PCh += v.K4 * v.D4 + v.K5 * UnpChannelDelta;
PCh = (Utility.URShift(PCh, 3)) & 0xFF;
int Ch = PCh - Delta;
int D = ((byte)Delta) << 3;
v.Dif[0] += System.Math.Abs(D); // V->Dif[0]+=abs(D);
v.Dif[1] += System.Math.Abs(D - v.D1); // V->Dif[1]+=abs(D-V->D1);
v.Dif[2] += System.Math.Abs(D + v.D1); // V->Dif[2]+=abs(D+V->D1);
v.Dif[3] += System.Math.Abs(D - v.D2); // V->Dif[3]+=abs(D-V->D2);
v.Dif[4] += System.Math.Abs(D + v.D2); // V->Dif[4]+=abs(D+V->D2);
v.Dif[5] += System.Math.Abs(D - v.D3); // V->Dif[5]+=abs(D-V->D3);
v.Dif[6] += System.Math.Abs(D + v.D3); // V->Dif[6]+=abs(D+V->D3);
v.Dif[7] += System.Math.Abs(D - v.D4); // V->Dif[7]+=abs(D-V->D4);
v.Dif[8] += System.Math.Abs(D + v.D4); // V->Dif[8]+=abs(D+V->D4);
v.Dif[9] += System.Math.Abs(D - UnpChannelDelta); // V->Dif[9]+=abs(D-UnpChannelDelta);
v.Dif[10] += System.Math.Abs(D + UnpChannelDelta); // V->Dif[10]+=abs(D+UnpChannelDelta);
v.LastDelta = (byte)(Ch - v.LastChar);
UnpChannelDelta = v.LastDelta;
v.LastChar = Ch; // V->LastChar=Ch;
if ((v.ByteCount & 0x1F) == 0)
{
int MinDif = v.Dif[0], NumMinDif = 0;
v.Dif[0] = 0; // ->Dif[0]=0;
for (int I = 1; I < v.Dif.Length; I++)
{
if (v.Dif[I] < MinDif)
{
MinDif = v.Dif[I];
NumMinDif = I;
}
v.Dif[I] = 0;
}
switch (NumMinDif)
{
case 1:
if (v.K1 >= -16)
{
v.K1 = v.K1 - 1; // V->K1--;
}
break;
case 2:
if (v.K1 < 16)
{
v.K1 = v.K1 + 1; // V->K1++;
}
break;
case 3:
if (v.K2 >= -16)
{
v.K2 = v.K2 - 1; // V->K2--;
}
break;
case 4:
if (v.K2 < 16)
{
v.K2 = v.K2 + 1; // V->K2++;
}
break;
case 5:
if (v.K3 >= -16)
{
v.K3 = v.K3 - 1;
}
break;
case 6:
if (v.K3 < 16)
{
v.K3 = v.K3 + 1;
}
break;
case 7:
if (v.K4 >= -16)
{
v.K4 = v.K4 - 1;
}
break;
case 8:
if (v.K4 < 16)
{
v.K4 = v.K4 + 1;
}
break;
case 9:
if (v.K5 >= -16)
{
v.K5 = v.K5 - 1;
}
break;
case 10:
if (v.K5 < 16)
{
v.K5 = v.K5 + 1;
}
break;
}
}
return ((byte)Ch);
}
}
}