diff options
Diffstat (limited to 'CPP/7zip/Compress/Rar')
-rwxr-xr-x | CPP/7zip/Compress/Rar/DllExports.cpp | 91 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/Rar1Decoder.cpp | 485 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/Rar1Decoder.h | 90 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/Rar29.dsp | 297 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/Rar29.dsw | 29 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/Rar2Decoder.cpp | 401 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/Rar2Decoder.h | 176 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/Rar3Decoder.cpp | 832 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/Rar3Decoder.h | 294 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/Rar3Vm.cpp | 1089 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/Rar3Vm.h | 219 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/StdAfx.cpp | 3 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/StdAfx.h | 8 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/makefile | 49 | ||||
-rwxr-xr-x | CPP/7zip/Compress/Rar/resource.rc | 3 |
15 files changed, 4066 insertions, 0 deletions
diff --git a/CPP/7zip/Compress/Rar/DllExports.cpp b/CPP/7zip/Compress/Rar/DllExports.cpp new file mode 100755 index 00000000..acc3068e --- /dev/null +++ b/CPP/7zip/Compress/Rar/DllExports.cpp @@ -0,0 +1,91 @@ +// DLLExports.cpp + +#include "StdAfx.h" + +#include "Common/MyInitGuid.h" +#include "Common/ComTry.h" + +#include "Rar1Decoder.h" +#include "Rar2Decoder.h" +#include "Rar3Decoder.h" +// #include "Rar29Decoder.h" + +#define RarClassId(ver) CLSID_CCompressRar ## ver ## Decoder + +#define MyClassRar(ver) DEFINE_GUID(RarClassId(ver), \ +0x23170F69, 0x40C1, 0x278B, 0x04, 0x03, ver, 0x00, 0x00, 0x00, 0x00, 0x00); + +MyClassRar(1); +MyClassRar(2); +MyClassRar(3); + +#define CreateCoder(ver) if (*clsid == RarClassId(ver)) \ +{ if (!correctInterface) return E_NOINTERFACE; \ +coder = (ICompressCoder *)new NCompress::NRar ## ver::CDecoder; } + +extern "C" +BOOL WINAPI DllMain(HINSTANCE /* hInstance */, DWORD /* dwReason */, LPVOID /*lpReserved*/) +{ + return TRUE; +} + +STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) +{ + COM_TRY_BEGIN + *outObject = 0; + int correctInterface = (*iid == IID_ICompressCoder); + CMyComPtr<ICompressCoder> coder; + CreateCoder(1) else + CreateCoder(2) else + CreateCoder(3) else + return CLASS_E_CLASSNOTAVAILABLE; + *outObject = coder.Detach(); + COM_TRY_END + return S_OK; +} + +struct CRarMethodItem +{ + char ID[3]; + const wchar_t *UserName; + const GUID *Decoder; +}; + +static CRarMethodItem g_Methods[] = +{ + { { 0x04, 0x03, 0x01 }, L"Rar15", &RarClassId(1) }, + { { 0x04, 0x03, 0x02 }, L"Rar20", &RarClassId(2) }, + { { 0x04, 0x03, 0x03 }, L"Rar29", &RarClassId(3) } +}; + +STDAPI GetNumberOfMethods(UINT32 *numMethods) +{ + *numMethods = sizeof(g_Methods) / sizeof(g_Methods[1]); + return S_OK; +} + +STDAPI GetMethodProperty(UINT32 index, PROPID propID, PROPVARIANT *value) +{ + if (index > sizeof(g_Methods) / sizeof(g_Methods[1])) + return E_INVALIDARG; + VariantClear((tagVARIANT *)value); + const CRarMethodItem &method = g_Methods[index]; + switch(propID) + { + case NMethodPropID::kID: + if ((value->bstrVal = ::SysAllocStringByteLen(method.ID, + sizeof(method.ID))) != 0) + value->vt = VT_BSTR; + return S_OK; + case NMethodPropID::kName: + if ((value->bstrVal = ::SysAllocString(method.UserName)) != 0) + value->vt = VT_BSTR; + return S_OK; + case NMethodPropID::kDecoder: + if ((value->bstrVal = ::SysAllocStringByteLen( + (const char *)method.Decoder, sizeof(GUID))) != 0) + value->vt = VT_BSTR; + return S_OK; + } + return S_OK; +} diff --git a/CPP/7zip/Compress/Rar/Rar1Decoder.cpp b/CPP/7zip/Compress/Rar/Rar1Decoder.cpp new file mode 100755 index 00000000..c30443de --- /dev/null +++ b/CPP/7zip/Compress/Rar/Rar1Decoder.cpp @@ -0,0 +1,485 @@ +// Rar1Decoder.cpp +// According to unRAR license, +// this code may not be used to develop a +// RAR (WinRAR) compatible archiver + +#include "StdAfx.h" + +#include "Rar1Decoder.h" + +namespace NCompress { +namespace NRar1 { + +static UInt32 PosL1[]={0,0,0,2,3,5,7,11,16,20,24,32,32, 256}; +static UInt32 PosL2[]={0,0,0,0,5,7,9,13,18,22,26,34,36, 256}; +static UInt32 PosHf0[]={0,0,0,0,0,8,16,24,33,33,33,33,33, 257}; +static UInt32 PosHf1[]={0,0,0,0,0,0,4,44,60,76,80,80,127, 257}; +static UInt32 PosHf2[]={0,0,0,0,0,0,2,7,53,117,233, 257,0}; +static UInt32 PosHf3[]={0,0,0,0,0,0,0,2,16,218,251, 257,0}; +static UInt32 PosHf4[]={0,0,0,0,0,0,0,0,0,255, 257,0,0}; + +static const UInt32 kHistorySize = (1 << 16); + +class CCoderReleaser +{ + CDecoder *m_Coder; +public: + CCoderReleaser(CDecoder *coder): m_Coder(coder) {} + ~CCoderReleaser() { m_Coder->ReleaseStreams(); } +}; + +CDecoder::CDecoder(): m_IsSolid(false) { } + +void CDecoder::InitStructures() +{ + for(int i = 0; i < kNumRepDists; i++) + m_RepDists[i] = 0; + m_RepDistPtr = 0; + LastLength = 0; + LastDist = 0; +} + +UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); } + +HRESULT CDecoder::CopyBlock(UInt32 distance, UInt32 len) +{ + m_UnpackSize -= len; + return m_OutWindowStream.CopyBlock(distance, len) ? S_OK : S_FALSE; +} + + +UInt32 CDecoder::DecodeNum(const UInt32 *posTab) +{ + UInt32 startPos = 2; + UInt32 num = m_InBitStream.GetValue(12); + for (;;) + { + UInt32 cur = (posTab[startPos + 1] - posTab[startPos]) << (12 - startPos); + if (num < cur) + break; + startPos++; + num -= cur; + } + m_InBitStream.MovePos(startPos); + return((num >> (12 - startPos)) + posTab[startPos]); +} + +static Byte kShortLen1[] = {1,3,4,4,5,6,7,8,8,4,4,5,6,6 }; +static Byte kShortLen1a[] = {1,4,4,4,5,6,7,8,8,4,4,5,6,6,4 }; +static Byte kShortLen2[] = {2,3,3,3,4,4,5,6,6,4,4,5,6,6 }; +static Byte kShortLen2a[] = {2,3,3,4,4,4,5,6,6,4,4,5,6,6,4 }; +static UInt32 kShortXor1[] = {0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0}; +static UInt32 kShortXor2[] = {0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0}; + +HRESULT CDecoder::ShortLZ() +{ + UInt32 len, saveLen, dist; + int distancePlace; + Byte *kShortLen; + const UInt32 *kShortXor; + NumHuf = 0; + + if (LCount == 2) + { + if (ReadBits(1)) + return CopyBlock(LastDist, LastLength); + LCount = 0; + } + + UInt32 bitField = m_InBitStream.GetValue(8); + + if (AvrLn1 < 37) + { + kShortLen = Buf60 ? kShortLen1a : kShortLen1; + kShortXor = kShortXor1; + } + else + { + kShortLen = Buf60 ? kShortLen2a : kShortLen2; + kShortXor = kShortXor2; + } + + for (len = 0; ((bitField ^ kShortXor[len]) & (~(0xff >> kShortLen[len]))) != 0; len++); + m_InBitStream.MovePos(kShortLen[len]); + + if (len >= 9) + { + if (len == 9) + { + LCount++; + return CopyBlock(LastDist, LastLength); + } + if (len == 14) + { + LCount = 0; + len = DecodeNum(PosL2) + 5; + dist = 0x8000 + ReadBits(15) - 1; + LastLength = len; + LastDist = dist; + return CopyBlock(dist, len); + } + + LCount = 0; + saveLen = len; + dist = m_RepDists[(m_RepDistPtr - (len - 9)) & 3]; + len = DecodeNum(PosL1) + 2; + if (len == 0x101 && saveLen == 10) + { + Buf60 ^= 1; + return S_OK; + } + if (dist >= 256) + len++; + if (dist >= MaxDist3 - 1) + len++; + } + else + { + LCount = 0; + AvrLn1 += len; + AvrLn1 -= AvrLn1 >> 4; + + distancePlace = DecodeNum(PosHf2) & 0xff; + dist = ChSetA[distancePlace]; + if (--distancePlace != -1) + { + PlaceA[dist]--; + UInt32 lastDistance = ChSetA[distancePlace]; + PlaceA[lastDistance]++; + ChSetA[distancePlace + 1] = lastDistance; + ChSetA[distancePlace] = dist; + } + len += 2; + } + m_RepDists[m_RepDistPtr++] = dist; + m_RepDistPtr &= 3; + LastLength = len; + LastDist = dist; + return CopyBlock(dist, len); +} + + +HRESULT CDecoder::LongLZ() +{ + UInt32 len; + UInt32 dist; + UInt32 distancePlace, newDistancePlace; + UInt32 oldAvr2, oldAvr3; + + NumHuf = 0; + Nlzb += 16; + if (Nlzb > 0xff) + { + Nlzb = 0x90; + Nhfb >>= 1; + } + oldAvr2=AvrLn2; + + if (AvrLn2 >= 122) + len = DecodeNum(PosL2); + else if (AvrLn2 >= 64) + len = DecodeNum(PosL1); + else + { + UInt32 bitField = m_InBitStream.GetValue(16); + if (bitField < 0x100) + { + len = bitField; + m_InBitStream.MovePos(16); + } + else + { + for (len = 0; ((bitField << len) & 0x8000) == 0; len++) + ; + m_InBitStream.MovePos(len + 1); + } + } + + AvrLn2 += len; + AvrLn2 -= AvrLn2 >> 5; + + if (AvrPlcB > 0x28ff) + distancePlace = DecodeNum(PosHf2); + else if (AvrPlcB > 0x6ff) + distancePlace = DecodeNum(PosHf1); + else + distancePlace = DecodeNum(PosHf0); + + AvrPlcB += distancePlace; + AvrPlcB -= AvrPlcB >> 8; + for (;;) + { + dist = ChSetB[distancePlace & 0xff]; + newDistancePlace = NToPlB[dist++ & 0xff]++; + if (!(dist & 0xff)) + CorrHuff(ChSetB,NToPlB); + else + break; + } + + ChSetB[distancePlace] = ChSetB[newDistancePlace]; + ChSetB[newDistancePlace] = dist; + + dist = ((dist & 0xff00) >> 1) | ReadBits(7); + + oldAvr3 = AvrLn3; + if (len != 1 && len != 4) + if (len == 0 && dist <= MaxDist3) + { + AvrLn3++; + AvrLn3 -= AvrLn3 >> 8; + } + else + if (AvrLn3 > 0) + AvrLn3--; + len += 3; + if (dist >= MaxDist3) + len++; + if (dist <= 256) + len += 8; + if (oldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && oldAvr2 < 0x40) + MaxDist3 = 0x7f00; + else + MaxDist3 = 0x2001; + m_RepDists[m_RepDistPtr++] = --dist; + m_RepDistPtr &= 3; + LastLength = len; + LastDist = dist; + return CopyBlock(dist, len); +} + + +HRESULT CDecoder::HuffDecode() +{ + UInt32 curByte, newBytePlace; + UInt32 len; + UInt32 dist; + int bytePlace; + + if (AvrPlc > 0x75ff) bytePlace = DecodeNum(PosHf4); + else if (AvrPlc > 0x5dff) bytePlace = DecodeNum(PosHf3); + else if (AvrPlc > 0x35ff) bytePlace = DecodeNum(PosHf2); + else if (AvrPlc > 0x0dff) bytePlace = DecodeNum(PosHf1); + else bytePlace = DecodeNum(PosHf0); + if (StMode) + { + if (--bytePlace == -1) + { + if (ReadBits(1)) + { + NumHuf = StMode = 0; + return S_OK; + } + else + { + len = (ReadBits(1)) ? 4 : 3; + dist = DecodeNum(PosHf2); + dist = (dist << 5) | ReadBits(5); + return CopyBlock(dist - 1, len); + } + } + } + else if (NumHuf++ >= 16 && FlagsCnt == 0) + StMode = 1; + bytePlace &= 0xff; + AvrPlc += bytePlace; + AvrPlc -= AvrPlc >> 8; + Nhfb+=16; + if (Nhfb > 0xff) + { + Nhfb=0x90; + Nlzb >>= 1; + } + + m_UnpackSize --; + m_OutWindowStream.PutByte((Byte)(ChSet[bytePlace] >> 8)); + + for (;;) + { + curByte = ChSet[bytePlace]; + newBytePlace = NToPl[curByte++ & 0xff]++; + if ((curByte & 0xff) > 0xa1) + CorrHuff(ChSet, NToPl); + else + break; + } + + ChSet[bytePlace] = ChSet[newBytePlace]; + ChSet[newBytePlace] = curByte; + return S_OK; +} + + +void CDecoder::GetFlagsBuf() +{ + UInt32 flags, newFlagsPlace; + UInt32 flagsPlace = DecodeNum(PosHf2); + + for (;;) + { + 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; +} + +void CDecoder::InitData() +{ + if (!m_IsSolid) + { + AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0; + AvrPlc = 0x3500; + MaxDist3 = 0x2001; + Nhfb = Nlzb = 0x80; + } + FlagsCnt = 0; + FlagBuf = 0; + StMode = 0; + LCount = 0; +} + +void CDecoder::CorrHuff(UInt32 *CharSet,UInt32 *NumToPlace) +{ + int i; + for (i = 7; i >= 0; i--) + for (int j = 0; j < 32; j++, CharSet++) + *CharSet = (*CharSet & ~0xff) | i; + memset(NumToPlace, 0, sizeof(NToPl)); + for (i = 6; i >= 0; i--) + NumToPlace[i] = (7 - i) * 32; +} + +void CDecoder::InitHuff() +{ + for (UInt32 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; + } + memset(NToPl, 0, sizeof(NToPl)); + memset(NToPlB, 0, sizeof(NToPlB)); + memset(NToPlC, 0, sizeof(NToPlC)); + CorrHuff(ChSetB, NToPlB); +} + +STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo * /* progress */) +{ + if (inSize == NULL || outSize == NULL) + return E_INVALIDARG; + + if (!m_OutWindowStream.Create(kHistorySize)) + return E_OUTOFMEMORY; + if (!m_InBitStream.Create(1 << 20)) + return E_OUTOFMEMORY; + + m_UnpackSize = (Int64)*outSize; + m_OutWindowStream.SetStream(outStream); + m_OutWindowStream.Init(m_IsSolid); + m_InBitStream.SetStream(inStream); + m_InBitStream.Init(); + + CCoderReleaser coderReleaser(this); + InitData(); + if (!m_IsSolid) + { + InitStructures(); + InitHuff(); + } + if (m_UnpackSize > 0) + { + GetFlagsBuf(); + FlagsCnt = 8; + } + + while (m_UnpackSize > 0) + { + if (StMode) + { + RINOK(HuffDecode()); + continue; + } + + if (--FlagsCnt < 0) + { + GetFlagsBuf(); + FlagsCnt=7; + } + + if (FlagBuf & 0x80) + { + FlagBuf <<= 1; + if (Nlzb > Nhfb) + { + RINOK(LongLZ()); + } + else + { + RINOK(HuffDecode()); + } + } + else + { + FlagBuf <<= 1; + if (--FlagsCnt < 0) + { + GetFlagsBuf(); + FlagsCnt = 7; + } + if (FlagBuf & 0x80) + { + FlagBuf <<= 1; + if (Nlzb > Nhfb) + { + RINOK(HuffDecode()); + } + else + { + RINOK(LongLZ()); + } + } + else + { + FlagBuf <<= 1; + RINOK(ShortLZ()); + } + } + } + if (m_UnpackSize < 0) + return S_FALSE; + return m_OutWindowStream.Flush(); +} + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + try + { + HRESULT res = CodeReal(inStream, outStream, inSize, outSize, progress); + m_OutWindowStream.Flush(); + return res; + } + catch(const CLZOutWindowException &e) { m_OutWindowStream.Flush(); return e.ErrorCode; } + catch(...) { m_OutWindowStream.Flush(); return S_FALSE; } +} + +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size < 1) + return E_INVALIDARG; + m_IsSolid = (data[0] != 0); + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/Rar/Rar1Decoder.h b/CPP/7zip/Compress/Rar/Rar1Decoder.h new file mode 100755 index 00000000..bdaf4d85 --- /dev/null +++ b/CPP/7zip/Compress/Rar/Rar1Decoder.h @@ -0,0 +1,90 @@ +// Rar15Decoder.h +// According to unRAR license, +// this code may not be used to develop a +// RAR (WinRAR) compatible archiver + +#ifndef __RAR10_DECODER_H +#define __RAR10_DECODER_H + +#include "../../../Common/MyCom.h" + +#include "../../ICoder.h" +#include "../../Common/MSBFDecoder.h" +#include "../../Common/InBuffer.h" + +#include "../LZ/LZOutWindow.h" +#include "../Huffman/HuffmanDecoder.h" + +namespace NCompress { +namespace NRar1 { + +const UInt32 kNumRepDists = 4; + +typedef NStream::NMSBF::CDecoder<CInBuffer> CBitDecoder; + +class CDecoder : + public ICompressCoder, + public ICompressSetDecoderProperties2, + public CMyUnknownImp +{ +public: + CLZOutWindow m_OutWindowStream; + CBitDecoder m_InBitStream; + + UInt32 m_RepDists[kNumRepDists]; + UInt32 m_RepDistPtr; + + UInt32 LastDist; + UInt32 LastLength; + + Int64 m_UnpackSize; + bool m_IsSolid; + + UInt32 ReadBits(int numBits); + HRESULT CopyBlock(UInt32 distance, UInt32 len); + + UInt32 DecodeNum(const UInt32 *posTab); + HRESULT ShortLZ(); + HRESULT LongLZ(); + HRESULT HuffDecode(); + void GetFlagsBuf(); + void InitData(); + void InitHuff(); + void CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace); + void OldUnpWriteBuf(); + + UInt32 ChSet[256],ChSetA[256],ChSetB[256],ChSetC[256]; + UInt32 Place[256],PlaceA[256],PlaceB[256],PlaceC[256]; + UInt32 NToPl[256],NToPlB[256],NToPlC[256]; + UInt32 FlagBuf,AvrPlc,AvrPlcB,AvrLn1,AvrLn2,AvrLn3; + int Buf60,NumHuf,StMode,LCount,FlagsCnt; + UInt32 Nhfb,Nlzb,MaxDist3; + + void InitStructures(); + +public: + CDecoder(); + + MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) + + void ReleaseStreams() + { + m_OutWindowStream.ReleaseStream(); + m_InBitStream.ReleaseStream(); + } + + STDMETHOD(CodeReal)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); + + STDMETHOD(Code)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); + + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); + +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Rar/Rar29.dsp b/CPP/7zip/Compress/Rar/Rar29.dsp new file mode 100755 index 00000000..9a0b86bb --- /dev/null +++ b/CPP/7zip/Compress/Rar/Rar29.dsp @@ -0,0 +1,297 @@ +# Microsoft Developer Studio Project File - Name="Rar29" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=Rar29 - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Rar29.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Rar29.mak" CFG="Rar29 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Rar29 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Rar29 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Rar29 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RAR29_EXPORTS" /YX /FD /c +# ADD CPP /nologo /Gz /MD /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RAR29_EXPORTS" /D "SILENT" /D "NOCRYPT" /D "NOVOLUME" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Program Files\7-Zip\Codecs\Rar29.dll" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "Rar29 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RAR29_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /Gz /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RAR29_EXPORTS" /D "SILENT" /D "NOCRYPT" /D "NOVOLUME" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\7-Zip\Codecs\Rar29.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "Rar29 - Win32 Release" +# Name "Rar29 - Win32 Debug" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Codec.def +# End Source File +# Begin Source File + +SOURCE=.\DllExports.cpp +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "7zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\InBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MSBFDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# End Group +# Begin Group "LZ" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\LZ\LZOutWindow.cpp +# End Source File +# Begin Source File + +SOURCE=..\LZ\LZOutWindow.h +# End Source File +# End Group +# Begin Group "Huffman" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Huffman\HuffmanDecoder.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\Alloc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Vector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Vector.h +# End Source File +# End Group +# Begin Group "Rar3" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\PPMD\PPMDContext.h +# End Source File +# Begin Source File + +SOURCE=..\PPMD\PPMDDecode.h +# End Source File +# Begin Source File + +SOURCE=..\PPMD\PPMDSubAlloc.h +# End Source File +# Begin Source File + +SOURCE=..\PPMD\PPMDType.h +# End Source File +# Begin Source File + +SOURCE=.\Rar1Decoder.cpp + +!IF "$(CFG)" == "Rar29 - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Rar29 - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Rar1Decoder.h +# End Source File +# Begin Source File + +SOURCE=.\Rar2Decoder.cpp + +!IF "$(CFG)" == "Rar29 - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Rar29 - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Rar2Decoder.h +# End Source File +# Begin Source File + +SOURCE=.\Rar3Decoder.cpp + +!IF "$(CFG)" == "Rar29 - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Rar29 - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Rar3Decoder.h +# End Source File +# Begin Source File + +SOURCE=.\Rar3Vm.cpp + +!IF "$(CFG)" == "Rar29 - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Rar29 - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Rar3Vm.h +# End Source File +# End Group +# End Target +# End Project diff --git a/CPP/7zip/Compress/Rar/Rar29.dsw b/CPP/7zip/Compress/Rar/Rar29.dsw new file mode 100755 index 00000000..70172e1a --- /dev/null +++ b/CPP/7zip/Compress/Rar/Rar29.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Rar29"=.\Rar29.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/Compress/Rar/Rar2Decoder.cpp b/CPP/7zip/Compress/Rar/Rar2Decoder.cpp new file mode 100755 index 00000000..43473695 --- /dev/null +++ b/CPP/7zip/Compress/Rar/Rar2Decoder.cpp @@ -0,0 +1,401 @@ +// Rar2Decoder.cpp +// According to unRAR license, +// this code may not be used to develop a +// RAR (WinRAR) compatible archiver + +#include "StdAfx.h" + +#include "Rar2Decoder.h" + +namespace NCompress { +namespace NRar2 { + +namespace NMultimedia { + +Byte CFilter::Decode(int &channelDelta, Byte deltaByte) +{ + D4 = D3; + D3 = D2; + D2 = LastDelta - D1; + D1 = LastDelta; + int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3); + + Byte realValue = (Byte)(predictedValue - deltaByte); + int i = ((int)(signed char)deltaByte) << 3; + + Dif[0] += abs(i); + Dif[1] += abs(i - D1); + Dif[2] += abs(i + D1); + Dif[3] += abs(i - D2); + Dif[4] += abs(i + D2); + Dif[5] += abs(i - D3); + Dif[6] += abs(i + D3); + Dif[7] += abs(i - D4); + Dif[8] += abs(i + D4); + Dif[9] += abs(i - channelDelta); + Dif[10] += abs(i + channelDelta); + + channelDelta = LastDelta = (signed char)(realValue - LastChar); + LastChar = realValue; + + if (((++ByteCount) & 0x1F) == 0) + { + UInt32 minDif = Dif[0]; + UInt32 numMinDif = 0; + Dif[0] = 0; + for (i = 1; i < sizeof(Dif) / sizeof(Dif[0]); i++) + { + if (Dif[i] < minDif) + { + minDif = Dif[i]; + numMinDif = i; + } + Dif[i] = 0; + } + switch(numMinDif) + { + case 1: if (K1 >= -16) K1--; break; + case 2: if (K1 < 16) K1++; break; + case 3: if (K2 >= -16) K2--; break; + case 4: if (K2 < 16) K2++; break; + case 5: if (K3 >= -16) K3--; break; + case 6: if (K3 < 16) K3++; break; + case 7: if (K4 >= -16) K4--; break; + case 8: if (K4 < 16) K4++; break; + case 9: if (K5 >= -16) K5--; break; + case 10:if (K5 < 16) K5++; break; + } + } + return realValue; +} +} + +class CException +{ +public: + enum ECauseType + { + kData + } Cause; + CException(ECauseType cause): Cause(cause) {} +}; + +static const char *kNumberErrorMessage = "Number error"; + +static const UInt32 kHistorySize = 1 << 20; + +static const int kNumStats = 11; + +static const UInt32 kWindowReservSize = (1 << 22) + 256; + +CDecoder::CDecoder(): + m_IsSolid(false) +{ +} + +void CDecoder::InitStructures() +{ + m_MmFilter.Init(); + for(int i = 0; i < kNumRepDists; i++) + m_RepDists[i] = 0; + m_RepDistPtr = 0; + m_LastLength = 0; + memset(m_LastLevels, 0, kMaxTableSize); +} + +UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); } + +#define RIF(x) { if (!(x)) return false; } + +bool CDecoder::ReadTables(void) +{ + Byte levelLevels[kLevelTableSize]; + Byte newLevels[kMaxTableSize]; + m_AudioMode = (ReadBits(1) == 1); + + if (ReadBits(1) == 0) + memset(m_LastLevels, 0, kMaxTableSize); + int numLevels; + if (m_AudioMode) + { + m_NumChannels = ReadBits(2) + 1; + if (m_MmFilter.CurrentChannel >= m_NumChannels) + m_MmFilter.CurrentChannel = 0; + numLevels = m_NumChannels * kMMTableSize; + } + else + numLevels = kHeapTablesSizesSum; + + int i; + for (i = 0; i < kLevelTableSize; i++) + levelLevels[i] = (Byte)ReadBits(4); + RIF(m_LevelDecoder.SetCodeLengths(levelLevels)); + i = 0; + while (i < numLevels) + { + UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream); + if (number < kTableDirectLevels) + { + newLevels[i] = (Byte)((number + m_LastLevels[i]) & kLevelMask); + i++; + } + else + { + if (number == kTableLevelRepNumber) + { + int t = ReadBits(2) + 3; + for (int reps = t; reps > 0 && i < numLevels ; reps--, i++) + newLevels[i] = newLevels[i - 1]; + } + else + { + int num; + if (number == kTableLevel0Number) + num = ReadBits(3) + 3; + else if (number == kTableLevel0Number2) + num = ReadBits(7) + 11; + else + return false; + for (;num > 0 && i < numLevels; num--) + newLevels[i++] = 0; + } + } + } + if (m_AudioMode) + for (i = 0; i < m_NumChannels; i++) + { + RIF(m_MMDecoders[i].SetCodeLengths(&newLevels[i * kMMTableSize])); + } + else + { + RIF(m_MainDecoder.SetCodeLengths(&newLevels[0])); + RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize])); + RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize])); + } + memcpy(m_LastLevels, newLevels, kMaxTableSize); + return true; +} + +bool CDecoder::ReadLastTables() +{ + // it differs a little from pure RAR sources; + // UInt64 ttt = m_InBitStream.GetProcessedSize() + 2; + // + 2 works for: return 0xFF; in CInBuffer::ReadByte. + if (m_InBitStream.GetProcessedSize() + 7 <= m_PackSize) // test it: probably incorrect; + // if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect; + if (m_AudioMode) + { + UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream); + if (symbol == 256) + return ReadTables(); + if (symbol >= kMMTableSize) + return false; + } + else + { + UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream); + if (number == kReadTableNumber) + return ReadTables(); + if (number >= kMainTableSize) + return false; + } + return true; +} + +class CCoderReleaser +{ + CDecoder *m_Coder; +public: + CCoderReleaser(CDecoder *coder): m_Coder(coder) {} + ~CCoderReleaser() + { + m_Coder->ReleaseStreams(); + } +}; + +bool CDecoder::DecodeMm(UInt32 pos) +{ + while (pos-- > 0) + { + UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream); + if (symbol == 256) + return true; + if (symbol >= kMMTableSize) + return false; + /* + Byte byPredict = m_Predictor.Predict(); + Byte byReal = (Byte)(byPredict - (Byte)symbol); + m_Predictor.Update(byReal, byPredict); + */ + Byte byReal = m_MmFilter.Decode((Byte)symbol); + m_OutWindowStream.PutByte(byReal); + if (++m_MmFilter.CurrentChannel == m_NumChannels) + m_MmFilter.CurrentChannel = 0; + } + return true; +} + +bool CDecoder::DecodeLz(Int32 pos) +{ + while (pos > 0) + { + UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream); + UInt32 length, distance; + if (number < 256) + { + m_OutWindowStream.PutByte(Byte(number)); + pos--; + continue; + } + else if (number >= kMatchNumber) + { + number -= kMatchNumber; + length = kNormalMatchMinLen + UInt32(kLenStart[number]) + + m_InBitStream.ReadBits(kLenDirectBits[number]); + number = m_DistDecoder.DecodeSymbol(&m_InBitStream); + if (number >= kDistTableSize) + return false; + distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]); + if (distance >= kDistLimit3) + { + length += 2 - ((distance - kDistLimit4) >> 31); + // length++; + // if (distance >= kDistLimit4) + // length++; + } + } + else if (number == kRepBothNumber) + { + length = m_LastLength; + distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3]; + } + else if (number < kLen2Number) + { + distance = m_RepDists[(m_RepDistPtr - (number - kRepNumber + 1)) & 3]; + number = m_LenDecoder.DecodeSymbol(&m_InBitStream); + if (number >= kLenTableSize) + return false; + length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]); + if (distance >= kDistLimit2) + { + length++; + if (distance >= kDistLimit3) + { + length += 2 - ((distance - kDistLimit4) >> 31); + // length++; + // if (distance >= kDistLimit4) + // length++; + } + } + } + else if (number < kReadTableNumber) + { + number -= kLen2Number; + distance = kLen2DistStarts[number] + + m_InBitStream.ReadBits(kLen2DistDirectBits[number]); + length = 2; + } + else if (number == kReadTableNumber) + return true; + else + return false; + m_RepDists[m_RepDistPtr++ & 3] = distance; + m_LastLength = length; + if (!m_OutWindowStream.CopyBlock(distance, length)) + return false; + pos -= length; + } + return true; +} + +STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + if (inSize == NULL || outSize == NULL) + return E_INVALIDARG; + + if (!m_OutWindowStream.Create(kHistorySize)) + return E_OUTOFMEMORY; + if (!m_InBitStream.Create(1 << 20)) + return E_OUTOFMEMORY; + + m_PackSize = *inSize; + + UInt64 pos = 0, unPackSize = *outSize; + + m_OutWindowStream.SetStream(outStream); + m_OutWindowStream.Init(m_IsSolid); + m_InBitStream.SetStream(inStream); + m_InBitStream.Init(); + + CCoderReleaser coderReleaser(this); + if (!m_IsSolid) + { + InitStructures(); + if (unPackSize == 0) + { + if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect; + if (!ReadTables()) + return S_FALSE; + return S_OK; + } + if (!ReadTables()) + return S_FALSE; + } + + UInt64 startPos = m_OutWindowStream.GetProcessedSize(); + while(pos < unPackSize) + { + UInt32 blockSize = 1 << 20; + if (blockSize > unPackSize - pos) + blockSize = (UInt32)(unPackSize - pos); + UInt64 blockStartPos = m_OutWindowStream.GetProcessedSize(); + if (m_AudioMode) + { + if (!DecodeMm(blockSize)) + return S_FALSE; + } + else + { + if (!DecodeLz((Int32)blockSize)) + return S_FALSE; + } + UInt64 globalPos = m_OutWindowStream.GetProcessedSize(); + pos = globalPos - blockStartPos; + if (pos < blockSize) + if (!ReadTables()) + return S_FALSE; + pos = globalPos - startPos; + if (progress != 0) + { + UInt64 packSize = m_InBitStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &pos)); + } + } + if (pos > unPackSize) + throw CException(CException::kData); + + if (!ReadLastTables()) + return S_FALSE; + return m_OutWindowStream.Flush(); +} + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CLZOutWindowException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size < 1) + return E_INVALIDARG; + m_IsSolid = (data[0] != 0); + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/Rar/Rar2Decoder.h b/CPP/7zip/Compress/Rar/Rar2Decoder.h new file mode 100755 index 00000000..dfd0f816 --- /dev/null +++ b/CPP/7zip/Compress/Rar/Rar2Decoder.h @@ -0,0 +1,176 @@ +// Rar2Decoder.h +// According to unRAR license, +// this code may not be used to develop a +// RAR (WinRAR) compatible archiver + +#ifndef __RAR2DECODER_H +#define __RAR2DECODER_H + +#include "../../../Common/MyCom.h" + +#include "../../ICoder.h" +#include "../../Common/MSBFDecoder.h" +#include "../../Common/InBuffer.h" + +#include "../LZ/LZOutWindow.h" +#include "../Huffman/HuffmanDecoder.h" + +namespace NCompress { +namespace NRar2 { + +const UInt32 kNumRepDists = 4; +const UInt32 kDistTableSize = 48; + +const int kMMTableSize = 256 + 1; + +const UInt32 kMainTableSize = 298; +const UInt32 kLenTableSize = 28; + +const UInt32 kDistTableStart = kMainTableSize; +const UInt32 kLenTableStart = kDistTableStart + kDistTableSize; + +const UInt32 kHeapTablesSizesSum = kMainTableSize + kDistTableSize + kLenTableSize; + +const UInt32 kLevelTableSize = 19; + +const UInt32 kMMTablesSizesSum = kMMTableSize * 4; + +const UInt32 kMaxTableSize = kMMTablesSizesSum; + +const UInt32 kTableDirectLevels = 16; +const UInt32 kTableLevelRepNumber = kTableDirectLevels; +const UInt32 kTableLevel0Number = kTableLevelRepNumber + 1; +const UInt32 kTableLevel0Number2 = kTableLevel0Number + 1; + +const UInt32 kLevelMask = 0xF; + + +const UInt32 kRepBothNumber = 256; +const UInt32 kRepNumber = kRepBothNumber + 1; +const UInt32 kLen2Number = kRepNumber + 4; + +const UInt32 kLen2NumNumbers = 8; +const UInt32 kReadTableNumber = kLen2Number + kLen2NumNumbers; +const UInt32 kMatchNumber = kReadTableNumber + 1; + +const Byte kLenStart[kLenTableSize] = {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}; +const Byte kLenDirectBits[kLenTableSize] = {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}; + +const UInt32 kDistStart[kDistTableSize] = {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,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040}; +const Byte kDistDirectBits[kDistTableSize] = {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}; + +const Byte kLevelDirectBits[kLevelTableSize] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7}; + +const Byte kLen2DistStarts[kLen2NumNumbers]={0,4,8,16,32,64,128,192}; +const Byte kLen2DistDirectBits[kLen2NumNumbers]={2,2,3, 4, 5, 6, 6, 6}; + +const UInt32 kDistLimit2 = 0x101 - 1; +const UInt32 kDistLimit3 = 0x2000 - 1; +const UInt32 kDistLimit4 = 0x40000 - 1; + +const UInt32 kMatchMaxLen = 255 + 2; +const UInt32 kMatchMaxLenMax = 255 + 5; +const UInt32 kNormalMatchMinLen = 3; + +namespace NMultimedia { + +struct CFilter +{ + int K1,K2,K3,K4,K5; + int D1,D2,D3,D4; + int LastDelta; + UInt32 Dif[11]; + UInt32 ByteCount; + int LastChar; + + Byte Decode(int &channelDelta, Byte delta); + + void Init() { memset(this, 0, sizeof(*this)); } + +}; + +const int kNumChanelsMax = 4; + +class CFilter2 +{ +public: + CFilter m_Filters[kNumChanelsMax]; + int m_ChannelDelta; + int CurrentChannel; + + void Init() { memset(this, 0, sizeof(*this)); } + Byte Decode(Byte delta) + { + return m_Filters[CurrentChannel].Decode(m_ChannelDelta, delta); + } + +}; + +} + +typedef NStream::NMSBF::CDecoder<CInBuffer> CBitDecoder; + +const int kNumHuffmanBits = 15; + +class CDecoder : + public ICompressCoder, + public ICompressSetDecoderProperties2, + public CMyUnknownImp +{ + CLZOutWindow m_OutWindowStream; + CBitDecoder m_InBitStream; + NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder; + NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder; + NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder; + NHuffman::CDecoder<kNumHuffmanBits, kMMTableSize> m_MMDecoders[NMultimedia::kNumChanelsMax]; + NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder; + + bool m_AudioMode; + + NMultimedia::CFilter2 m_MmFilter; + int m_NumChannels; + + UInt32 m_RepDists[kNumRepDists]; + UInt32 m_RepDistPtr; + + UInt32 m_LastLength; + + Byte m_LastLevels[kMaxTableSize]; + + UInt64 m_PackSize; + bool m_IsSolid; + + void InitStructures(); + UInt32 ReadBits(int numBits); + bool ReadTables(); + bool ReadLastTables(); + + bool DecodeMm(UInt32 pos); + bool DecodeLz(Int32 pos); + +public: + CDecoder(); + + MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) + + void ReleaseStreams() + { + m_OutWindowStream.ReleaseStream(); + m_InBitStream.ReleaseStream(); + } + + STDMETHOD(CodeReal)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); + + STDMETHOD(Code)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); + + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); + +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Rar/Rar3Decoder.cpp b/CPP/7zip/Compress/Rar/Rar3Decoder.cpp new file mode 100755 index 00000000..478b6587 --- /dev/null +++ b/CPP/7zip/Compress/Rar/Rar3Decoder.cpp @@ -0,0 +1,832 @@ +// Rar3Decoder.cpp +// According to unRAR license, +// this code may not be used to develop a +// RAR (WinRAR) compatible archiver + +#include "StdAfx.h" + +#include "Rar3Decoder.h" +#include "../../Common/StreamUtils.h" + +namespace NCompress { +namespace NRar3 { + +static const UInt32 kNumAlignReps = 15; + +static const UInt32 kSymbolReadTable = 256; +static const UInt32 kSymbolRep = 259; +static const UInt32 kSymbolLen2 = kSymbolRep + kNumReps; + +static const Byte kLenStart[kLenTableSize] = {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}; +static const Byte kLenDirectBits[kLenTableSize] = {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}; + +static const Byte kDistDirectBits[kDistTableSize] = + {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, + 18,18,18,18,18,18,18,18,18,18,18,18}; + +static const Byte kLevelDirectBits[kLevelTableSize] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +static const Byte kLen2DistStarts[kNumLen2Symbols]={0,4,8,16,32,64,128,192}; +static const Byte kLen2DistDirectBits[kNumLen2Symbols]={2,2,3, 4, 5, 6, 6, 6}; + +static const UInt32 kDistLimit3 = 0x2000 - 2; +static const UInt32 kDistLimit4 = 0x40000 - 2; + +static const UInt32 kNormalMatchMinLen = 3; + +static const UInt32 kVmDataSizeMax = 1 << 16; +static const UInt32 kVmCodeSizeMax = 1 << 16; + +CDecoder::CDecoder(): + _window(0), + _winPos(0), + _wrPtr(0), + _lzSize(0), + _writtenFileSize(0), + _vmData(0), + _vmCode(0), + m_IsSolid(false) +{ +} + +CDecoder::~CDecoder() +{ + InitFilters(); + if (_vmData) + ::MidFree(_vmData); +} + +HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size) +{ + UInt32 processedSize; + HRESULT res = WriteStream(_outStream, data, size, &processedSize); + if (res == S_OK && processedSize != size) + res = E_FAIL; + return res; +} + +HRESULT CDecoder::WriteData(const Byte *data, UInt32 size) +{ + HRESULT res = S_OK; + if (_writtenFileSize < _unpackSize) + { + UInt32 curSize = size; + UInt64 remain = _unpackSize - _writtenFileSize; + if (remain < curSize) + curSize = (UInt32)remain; + res = WriteDataToStream(data, curSize); + } + _writtenFileSize += size; + return res; +} + +HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr) +{ + if (startPtr <= endPtr) + return WriteData(_window + startPtr, endPtr - startPtr); + RINOK(WriteData(_window + startPtr, kWindowSize - startPtr)); + return WriteData(_window, endPtr); +} + +void CDecoder::ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef) +{ + CTempFilter *tempFilter = _tempFilters[tempFilterIndex]; + tempFilter->InitR[6] = (UInt32)_writtenFileSize; + NVm::SetValue32(&tempFilter->GlobalData[0x24], (UInt32)_writtenFileSize); + NVm::SetValue32(&tempFilter->GlobalData[0x28], (UInt32)(_writtenFileSize >> 32)); + CFilter *filter = _filters[tempFilter->FilterIndex]; + _vm.Execute(filter, tempFilter, outBlockRef, filter->GlobalData); + delete tempFilter; + _tempFilters[tempFilterIndex] = 0; +} + +HRESULT CDecoder::WriteBuf() +{ + UInt32 writtenBorder = _wrPtr; + UInt32 writeSize = (_winPos - writtenBorder) & kWindowMask; + for (int i = 0; i < _tempFilters.Size(); i++) + { + CTempFilter *filter = _tempFilters[i]; + if (filter == NULL) + continue; + if (filter->NextWindow) + { + filter->NextWindow = false; + continue; + } + UInt32 blockStart = filter->BlockStart; + UInt32 blockSize = filter->BlockSize; + if (((blockStart - writtenBorder) & kWindowMask) < writeSize) + { + if (writtenBorder != blockStart) + { + RINOK(WriteArea(writtenBorder, blockStart)); + writtenBorder = blockStart; + writeSize = (_winPos - writtenBorder) & kWindowMask; + } + if (blockSize <= writeSize) + { + UInt32 blockEnd = (blockStart + blockSize) & kWindowMask; + if (blockStart < blockEnd || blockEnd == 0) + _vm.SetMemory(0, _window + blockStart, blockSize); + else + { + UInt32 tailSize = kWindowSize - blockStart; + _vm.SetMemory(0, _window + blockStart, tailSize); + _vm.SetMemory(tailSize, _window, blockEnd); + } + NVm::CBlockRef outBlockRef; + ExecuteFilter(i, outBlockRef); + while (i + 1 < _tempFilters.Size()) + { + CTempFilter *nextFilter = _tempFilters[i + 1]; + if (nextFilter == NULL || nextFilter->BlockStart != blockStart || + nextFilter->BlockSize != outBlockRef.Size || nextFilter->NextWindow) + break; + _vm.SetMemory(0, _vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size); + ExecuteFilter(++i, outBlockRef); + } + WriteDataToStream(_vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size); + _writtenFileSize += outBlockRef.Size; + writtenBorder = blockEnd; + writeSize = (_winPos - writtenBorder) & kWindowMask; + } + else + { + for (int j = i; j < _tempFilters.Size(); j++) + { + CTempFilter *filter = _tempFilters[j]; + if (filter != NULL && filter->NextWindow) + filter->NextWindow = false; + } + _wrPtr = writtenBorder; + return S_OK; // check it + } + } + } + + _wrPtr = _winPos; + return WriteArea(writtenBorder, _winPos); +} + +void CDecoder::InitFilters() +{ + _lastFilter = 0; + int i; + for (i = 0; i < _tempFilters.Size(); i++) + delete _tempFilters[i]; + _tempFilters.Clear(); + for (i = 0; i < _filters.Size(); i++) + delete _filters[i]; + _filters.Clear(); +} + +bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize) +{ + CMemBitDecoder inp; + inp.Init(_vmData, codeSize); + + UInt32 filterIndex; + if (firstByte & 0x80) + { + filterIndex = NVm::ReadEncodedUInt32(inp); + if (filterIndex == 0) + InitFilters(); + else + filterIndex--; + } + else + filterIndex = _lastFilter; + if (filterIndex > (UInt32)_filters.Size()) + return false; + _lastFilter = filterIndex; + bool newFilter = (filterIndex == (UInt32)_filters.Size()); + + CFilter *filter; + if (newFilter) + { + // check if too many filters + if (filterIndex > 1024) + return false; + filter = new CFilter; + _filters.Add(filter); + } + else + { + filter = _filters[filterIndex]; + filter->ExecCount++; + } + + int numEmptyItems = 0; + int i; + for (i = 0; i < _tempFilters.Size(); i++) + { + _tempFilters[i - numEmptyItems] = _tempFilters[i]; + if (_tempFilters[i] == NULL) + numEmptyItems++; + if (numEmptyItems > 0) + _tempFilters[i] = NULL; + } + if (numEmptyItems == 0) + { + _tempFilters.Add(NULL); + numEmptyItems = 1; + } + CTempFilter *tempFilter = new CTempFilter; + _tempFilters[_tempFilters.Size() - numEmptyItems] = tempFilter; + tempFilter->FilterIndex = filterIndex; + tempFilter->ExecCount = filter->ExecCount; + + UInt32 blockStart = NVm::ReadEncodedUInt32(inp); + if (firstByte & 0x40) + blockStart += 258; + tempFilter->BlockStart = (blockStart + _winPos) & kWindowMask; + if (firstByte & 0x20) + filter->BlockSize = NVm::ReadEncodedUInt32(inp); + tempFilter->BlockSize = filter->BlockSize; + tempFilter->NextWindow = _wrPtr != _winPos && ((_wrPtr - _winPos) & kWindowMask) <= blockStart; + + memset(tempFilter->InitR, 0, sizeof(tempFilter->InitR)); + tempFilter->InitR[3] = NVm::kGlobalOffset; + tempFilter->InitR[4] = tempFilter->BlockSize; + tempFilter->InitR[5] = tempFilter->ExecCount; + if (firstByte & 0x10) + { + UInt32 initMask = inp.ReadBits(NVm::kNumGpRegs); + for (int i = 0; i < NVm::kNumGpRegs; i++) + if (initMask & (1 << i)) + tempFilter->InitR[i] = NVm::ReadEncodedUInt32(inp); + } + if (newFilter) + { + UInt32 vmCodeSize = NVm::ReadEncodedUInt32(inp); + if (vmCodeSize >= kVmCodeSizeMax || vmCodeSize == 0) + return false; + for (UInt32 i = 0; i < vmCodeSize; i++) + _vmCode[i] = (Byte)inp.ReadBits(8); + _vm.PrepareProgram(_vmCode, vmCodeSize, filter); + } + + tempFilter->AllocateEmptyFixedGlobal(); + + Byte *globalData = &tempFilter->GlobalData[0]; + for (i = 0; i < NVm::kNumGpRegs; i++) + NVm::SetValue32(&globalData[i * 4], tempFilter->InitR[i]); + NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockSize], tempFilter->BlockSize); + NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockPos], 0); // It was commented. why? + NVm::SetValue32(&globalData[NVm::NGlobalOffset::kExecCount], tempFilter->ExecCount); + + if (firstByte & 8) + { + UInt32 dataSize = NVm::ReadEncodedUInt32(inp); + if (dataSize > NVm::kGlobalSize - NVm::kFixedGlobalSize) + return false; + CRecordVector<Byte> &globalData = tempFilter->GlobalData; + int requredSize = (int)(dataSize + NVm::kFixedGlobalSize); + if (globalData.Size() < requredSize) + { + globalData.Reserve(requredSize); + for (; globalData.Size() < requredSize; i++) + globalData.Add(0); + } + for (UInt32 i = 0; i < dataSize; i++) + globalData[NVm::kFixedGlobalSize + i] = (Byte)inp.ReadBits(8); + } + return true; +} + +bool CDecoder::ReadVmCodeLZ() +{ + UInt32 firstByte = m_InBitStream.ReadBits(8); + UInt32 length = (firstByte & 7) + 1; + if (length == 7) + length = m_InBitStream.ReadBits(8) + 7; + else if (length == 8) + length = m_InBitStream.ReadBits(16); + if (length > kVmDataSizeMax) + return false; + for (UInt32 i = 0; i < length; i++) + _vmData[i] = (Byte)m_InBitStream.ReadBits(8); + return AddVmCode(firstByte, length); +} + +bool CDecoder::ReadVmCodePPM() +{ + int firstByte = DecodePpmSymbol(); + if (firstByte == -1) + return false; + UInt32 length = (firstByte & 7) + 1; + if (length == 7) + { + int b1 = DecodePpmSymbol(); + if (b1 == -1) + return false; + length = b1 + 7; + } + else if (length == 8) + { + int b1 = DecodePpmSymbol(); + if (b1 == -1) + return false; + int b2 = DecodePpmSymbol(); + if (b2 == -1) + return false; + length = b1 * 256 + b2; + } + if (length > kVmDataSizeMax) + return false; + for (UInt32 i = 0; i < length; i++) + { + int b = DecodePpmSymbol(); + if (b == -1) + return false; + _vmData[i] = (Byte)b; + } + return AddVmCode(firstByte, length); +} + +#define RIF(x) { if (!(x)) return S_FALSE; } + +UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); } + +///////////////////////////////////////////////// +// PPM + +HRESULT CDecoder::InitPPM() +{ + Byte maxOrder = (Byte)ReadBits(7); + + bool reset = ((maxOrder & 0x20) != 0); + int maxMB = 0; + if (reset) + maxMB = (Byte)ReadBits(8); + else + { + if (_ppm.SubAllocator.GetSubAllocatorSize()== 0) + return S_FALSE; + } + if (maxOrder & 0x40) + PpmEscChar = (Byte)ReadBits(8); + m_InBitStream.InitRangeCoder(); + /* + if (m_InBitStream.m_BitPos != 0) + return S_FALSE; + */ + if (reset) + { + maxOrder = (maxOrder & 0x1F) + 1; + if (maxOrder > 16) + maxOrder = 16 + (maxOrder - 16) * 3; + if (maxOrder == 1) + { + // SubAlloc.StopSubAllocator(); + _ppm.SubAllocator.StopSubAllocator(); + return S_FALSE; + } + // SubAlloc.StartSubAllocator(MaxMB+1); + // StartModelRare(maxOrder); + + if (!_ppm.SubAllocator.StartSubAllocator((maxMB + 1) << 20)) + return E_OUTOFMEMORY; + _ppm.MaxOrder = 0; + _ppm.StartModelRare(maxOrder); + + } + // return (minContext != NULL); + + return S_OK; +} + +int CDecoder::DecodePpmSymbol() { return _ppm.DecodeSymbol(&m_InBitStream); } + +HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing) +{ + keepDecompressing = false; + do + { + if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos) + { + RINOK(WriteBuf()); + if (_writtenFileSize > _unpackSize) + return S_OK; + } + int c = DecodePpmSymbol(); + if (c == -1) + { + // Original code sets PPMError=true here and then it returns S_OK. Why ??? + // return S_OK; + return S_FALSE; + } + if (c == PpmEscChar) + { + int nextCh = DecodePpmSymbol(); + if (nextCh == 0) + return ReadTables(keepDecompressing); + if (nextCh == 2 || nextCh == -1) + return S_OK; + if (nextCh == 3) + { + if (!ReadVmCodePPM()) + return S_FALSE; + continue; + } + if (nextCh == 4 || nextCh == 5) + { + UInt32 distance = 0; + UInt32 length = 4; + if (nextCh == 4) + { + for (int i = 0; i < 3; i++) + { + int c = DecodePpmSymbol(); + if (c == -1) + return S_OK; + distance = (distance << 8) + (Byte)c; + } + distance++; + length += 28; + } + int c = DecodePpmSymbol(); + if (c == -1) + return S_OK; + length += c; + if (distance >= _lzSize) + return S_FALSE; + CopyBlock(distance, length); + num -= (Int32)length; + continue; + } + } + PutByte((Byte)c); + num--; + } + while (num >= 0); + keepDecompressing = true; + return S_OK; +} + +///////////////////////////////////////////////// +// LZ + +HRESULT CDecoder::ReadTables(bool &keepDecompressing) +{ + keepDecompressing = true; + ReadBits((8 - m_InBitStream.GetBitPosition()) & 7); + if (ReadBits(1) != 0) + { + _lzMode = false; + return InitPPM(); + } + + _lzMode = true; + PrevAlignBits = 0; + PrevAlignCount = 0; + + Byte levelLevels[kLevelTableSize]; + Byte newLevels[kTablesSizesSum]; + + if (ReadBits(1) == 0) + memset(m_LastLevels, 0, kTablesSizesSum); + + int i; + for (i = 0; i < kLevelTableSize; i++) + { + UInt32 length = ReadBits(4); + if (length == 15) + { + UInt32 zeroCount = ReadBits(4); + if (zeroCount != 0) + { + zeroCount += 2; + while (zeroCount-- > 0 && i < kLevelTableSize) + levelLevels[i++]=0; + i--; + continue; + } + } + levelLevels[i] = (Byte)length; + } + RIF(m_LevelDecoder.SetCodeLengths(levelLevels)); + i = 0; + while (i < kTablesSizesSum) + { + UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream); + if (number < 16) + { + newLevels[i] = Byte((number + m_LastLevels[i]) & 15); + i++; + } + else if (number > kLevelTableSize) + return S_FALSE; + else + { + int num; + if (((number - 16) & 1) == 0) + num = ReadBits(3) + 3; + else + num = ReadBits(7) + 11; + if (number < 18) + { + if (i == 0) + return S_FALSE; + for (; num > 0 && i < kTablesSizesSum; num--, i++) + newLevels[i] = newLevels[i - 1]; + } + else + { + for (; num > 0 && i < kTablesSizesSum; num--) + newLevels[i++] = 0; + } + } + } + TablesRead = true; + + // original code has check here: + /* + if (InAddr > ReadTop) + { + keepDecompressing = false; + return true; + } + */ + + RIF(m_MainDecoder.SetCodeLengths(&newLevels[0])); + RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize])); + RIF(m_AlignDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize])); + RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize])); + + memcpy(m_LastLevels, newLevels, kTablesSizesSum); + return S_OK; +} + +class CCoderReleaser +{ + CDecoder *m_Coder; +public: + CCoderReleaser(CDecoder *coder): m_Coder(coder) {} + ~CCoderReleaser() + { + // m_Coder->m_OutWindowStream.Flush(); + m_Coder->ReleaseStreams(); + } +}; + +HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing) +{ + if (ReadBits(1) != 0) + { + // old file + TablesRead = false; + return ReadTables(keepDecompressing); + } + // new file + keepDecompressing = false; + TablesRead = (ReadBits(1) == 0); + return S_OK; +} + +UInt32 kDistStart[kDistTableSize]; + +class CDistInit +{ +public: + CDistInit() { Init(); } + void Init() + { + UInt32 start = 0; + for (UInt32 i = 0; i < kDistTableSize; i++) + { + kDistStart[i] = start; + start += (1 << kDistDirectBits[i]); + } + } +} g_DistInit; + +HRESULT CDecoder::DecodeLZ(bool &keepDecompressing) +{ + UInt32 rep0 = _reps[0]; + UInt32 rep1 = _reps[1]; + UInt32 rep2 = _reps[2]; + UInt32 rep3 = _reps[3]; + UInt32 length = _lastLength; + for (;;) + { + if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos) + { + RINOK(WriteBuf()); + if (_writtenFileSize > _unpackSize) + return S_OK; + } + UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream); + if (number < 256) + { + PutByte(Byte(number)); + + continue; + } + else if (number == kSymbolReadTable) + { + RINOK(ReadEndOfBlock(keepDecompressing)); + break; + } + else if (number == 257) + { + if (!ReadVmCodeLZ()) + return S_FALSE; + continue; + } + else if (number == 258) + { + } + else if (number < kSymbolRep + 4) + { + if (number != kSymbolRep) + { + UInt32 distance; + if (number == kSymbolRep + 1) + distance = rep1; + else + { + if (number == kSymbolRep + 2) + distance = rep2; + else + { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + + UInt32 number = m_LenDecoder.DecodeSymbol(&m_InBitStream); + if (number >= kLenTableSize) + return S_FALSE; + length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]); + } + else + { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + if (number < 271) + { + number -= 263; + rep0 = kLen2DistStarts[number] + m_InBitStream.ReadBits(kLen2DistDirectBits[number]); + length = 2; + } + else if (number < 299) + { + number -= 271; + length = kNormalMatchMinLen + (UInt32)kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]); + UInt32 number = m_DistDecoder.DecodeSymbol(&m_InBitStream); + if (number >= kDistTableSize) + return S_FALSE; + rep0 = kDistStart[number]; + int numBits = kDistDirectBits[number]; + if (number >= (kNumAlignBits * 2) + 2) + { + if (numBits > kNumAlignBits) + rep0 += (m_InBitStream.ReadBits(numBits - kNumAlignBits) << kNumAlignBits); + if (PrevAlignCount > 0) + { + PrevAlignCount--; + rep0 += PrevAlignBits; + } + else + { + UInt32 number = m_AlignDecoder.DecodeSymbol(&m_InBitStream); + if (number < (1 << kNumAlignBits)) + { + rep0 += number; + PrevAlignBits = number; + } + else if (number == (1 << kNumAlignBits)) + { + PrevAlignCount = kNumAlignReps; + rep0 += PrevAlignBits; + } + else + return S_FALSE; + } + } + else + rep0 += m_InBitStream.ReadBits(numBits); + length += ((kDistLimit4 - rep0) >> 31) + ((kDistLimit3 - rep0) >> 31); + } + else + return S_FALSE; + } + if (rep0 >= _lzSize) + return S_FALSE; + CopyBlock(rep0, length); + } + _reps[0] = rep0; + _reps[1] = rep1; + _reps[2] = rep2; + _reps[3] = rep3; + _lastLength = length; + + return S_OK; +} + +HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress) +{ + _writtenFileSize = 0; + if (!m_IsSolid) + { + _lzSize = 0; + _winPos = 0; + _wrPtr = 0; + for (int i = 0; i < kNumReps; i++) + _reps[i] = 0; + _lastLength = 0; + memset(m_LastLevels, 0, kTablesSizesSum); + TablesRead = false; + PpmEscChar = 2; + InitFilters(); + } + if (!m_IsSolid || !TablesRead) + { + bool keepDecompressing; + RINOK(ReadTables(keepDecompressing)); + if (!keepDecompressing) + return S_OK; + } + + for(;;) + { + bool keepDecompressing; + if (_lzMode) + { + RINOK(DecodeLZ(keepDecompressing)) + } + else + { + RINOK(DecodePPM(1 << 18, keepDecompressing)) + } + UInt64 packSize = m_InBitStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize)); + if (!keepDecompressing) + break; + } + RINOK(WriteBuf()); + if (_writtenFileSize < _unpackSize) + return S_FALSE; + // return m_OutWindowStream.Flush(); + return S_OK; +} + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + try + { + if (inSize == NULL || outSize == NULL) + return E_INVALIDARG; + + if (_vmData == 0) + { + _vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax); + if (_vmData == 0) + return E_OUTOFMEMORY; + _vmCode = _vmData + kVmDataSizeMax; + } + + if (_window == 0) + { + _window = (Byte *)::MidAlloc(kWindowSize); + if (_window == 0) + return E_OUTOFMEMORY; + } + if (!m_InBitStream.Create(1 << 20)) + return E_OUTOFMEMORY; + if (!_vm.Create()) + return E_OUTOFMEMORY; + + + m_InBitStream.SetStream(inStream); + m_InBitStream.Init(); + _outStream = outStream; + + CCoderReleaser coderReleaser(this); + _unpackSize = *outSize; + return CodeReal(progress); + } + catch(...) { return S_FALSE; } + // CNewException is possible here. But probably CNewException is caused + // by error in data stream. +} + +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size < 1) + return E_INVALIDARG; + m_IsSolid = (data[0] != 0); + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/Rar/Rar3Decoder.h b/CPP/7zip/Compress/Rar/Rar3Decoder.h new file mode 100755 index 00000000..ec07a4d3 --- /dev/null +++ b/CPP/7zip/Compress/Rar/Rar3Decoder.h @@ -0,0 +1,294 @@ +// Rar3Decoder.h +// According to unRAR license, +// this code may not be used to develop a +// RAR (WinRAR) compatible archiver + +#ifndef __RAR3DECODER_H +#define __RAR3DECODER_H + +#include "../../../Common/MyCom.h" + +#include "../../ICoder.h" +#include "../../Common/MSBFDecoder.h" +#include "../../Common/InBuffer.h" + +// #include "../LZ/LZOutWindow.h" +#include "../Huffman/HuffmanDecoder.h" +#include "../PPMD/PPMDDecode.h" +#include "Rar3Vm.h" + +namespace NCompress { +namespace NRar3 { + +const UInt32 kWindowSize = 1 << 22; +const UInt32 kWindowMask = (kWindowSize - 1); + +const UInt32 kNumReps = 4; +const UInt32 kNumLen2Symbols = 8; +const UInt32 kLenTableSize = 28; +const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize; +const UInt32 kDistTableSize = 60; + +const int kNumAlignBits = 4; +const UInt32 kAlignTableSize = (1 << kNumAlignBits) + 1; + +const UInt32 kLevelTableSize = 20; + +const UInt32 kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize; + +template<class TInByte> +class CBitDecoder2 +{ + UInt32 m_Value; +public: + UInt32 m_BitPos; + TInByte m_Stream; + bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); } + void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream);} + void ReleaseStream() { m_Stream.ReleaseStream();} + + void Init() + { + m_Stream.Init(); + m_BitPos = 0; + m_Value = 0; + // m_BitPos = kNumBigValueBits; + // Normalize(); + } + + UInt64 GetProcessedSize() const + { return m_Stream.GetProcessedSize() - (m_BitPos) / 8; } + UInt32 GetBitPosition() const { return ((8 - m_BitPos) & 7); } + + /* + void Normalize() + { + for (;m_BitPos >= 8; m_BitPos -= 8) + m_Value = (m_Value << 8) | m_Stream.ReadByte(); + } + */ + + UInt32 GetValue(UInt32 numBits) + { + // return (m_Value << m_BitPos) >> (kNumBigValueBits - numBits); + // return ((m_Value >> (8 - m_BitPos)) & kMask) >> (kNumValueBits - numBits); + if (m_BitPos < numBits) + { + m_BitPos += 8; + m_Value = (m_Value << 8) | m_Stream.ReadByte(); + if (m_BitPos < numBits) + { + m_BitPos += 8; + m_Value = (m_Value << 8) | m_Stream.ReadByte(); + } + } + return m_Value >> (m_BitPos - numBits); + } + + void MovePos(UInt32 numBits) + { + m_BitPos -= numBits; + m_Value = m_Value & ((1 << m_BitPos) - 1); + } + + UInt32 ReadBits(UInt32 numBits) + { + UInt32 res = GetValue(numBits); + MovePos(numBits); + return res; + } +}; + +typedef CBitDecoder2<CInBuffer> CBitDecoder; + +const int kNumTopBits = 24; +const UInt32 kTopValue = (1 << kNumTopBits); +const UInt32 kBot = (1 << 15); + +class CRangeDecoder:public NPPMD::CRangeDecoderVirt, public CBitDecoder +{ +public: + UInt32 Range; + UInt32 Low; + UInt32 Code; + + void Normalize() + { + while ((Low ^ (Low + Range)) < kTopValue || + Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1)) + { + Code = (Code << 8) | m_Stream.ReadByte(); + Range <<= 8; + Low <<= 8; + } + } + + void InitRangeCoder() + { + Code = 0; + Low = 0; + Range = 0xFFFFFFFF; + for(int i = 0; i < 4; i++) + Code = (Code << 8) | ReadBits(8); + } + + virtual UInt32 GetThreshold(UInt32 total) + { + return (Code - Low) / ( Range /= total); + } + + virtual void Decode(UInt32 start, UInt32 size) + { + Low += start * Range; + Range *= size; + Normalize(); + } + + virtual UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits) + { + if (((Code - Low) / (Range >>= numTotalBits)) < size0) + { + Decode(0, size0); + return 0; + } + else + { + Decode(size0, (1 << numTotalBits) - size0); + return 1; + } + } + + // UInt64 GetProcessedSizeRangeCoder() {return Stream.GetProcessedSize(); } +}; + + +struct CFilter: public NVm::CProgram +{ + CRecordVector<Byte> GlobalData; + UInt32 BlockStart; + UInt32 BlockSize; + UInt32 ExecCount; + CFilter(): BlockStart(0), BlockSize(0), ExecCount(0) {} +}; + +struct CTempFilter: public NVm::CProgramInitState +{ + UInt32 BlockStart; + UInt32 BlockSize; + UInt32 ExecCount; + bool NextWindow; + + UInt32 FilterIndex; +}; + +const int kNumHuffmanBits = 15; + +class CDecoder: + public ICompressCoder, + public ICompressSetDecoderProperties2, + public CMyUnknownImp +{ + CRangeDecoder m_InBitStream; + Byte *_window; + UInt32 _winPos; + UInt32 _wrPtr; + UInt64 _lzSize; + UInt64 _unpackSize; + UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written + CMyComPtr<ISequentialOutStream> _outStream; + NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder; + NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder; + NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder; + NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder; + NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder; + + UInt32 _reps[kNumReps]; + UInt32 _lastLength; + + Byte m_LastLevels[kTablesSizesSum]; + + Byte *_vmData; + Byte *_vmCode; + NVm::CVm _vm; + CRecordVector<CFilter *> _filters; + CRecordVector<CTempFilter *> _tempFilters; + UInt32 _lastFilter; + + bool m_IsSolid; + + bool _lzMode; + + UInt32 PrevAlignBits; + UInt32 PrevAlignCount; + + bool TablesRead; + + NPPMD::CDecodeInfo _ppm; + int PpmEscChar; + + HRESULT WriteDataToStream(const Byte *data, UInt32 size); + HRESULT WriteData(const Byte *data, UInt32 size); + HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr); + void ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef); + HRESULT WriteBuf(); + + void InitFilters(); + bool AddVmCode(UInt32 firstByte, UInt32 codeSize); + bool ReadVmCodeLZ(); + bool ReadVmCodePPM(); + + UInt32 ReadBits(int numBits); + + HRESULT InitPPM(); + int DecodePpmSymbol(); + HRESULT DecodePPM(Int32 num, bool &keepDecompressing); + + HRESULT ReadTables(bool &keepDecompressing); + HRESULT ReadEndOfBlock(bool &keepDecompressing); + HRESULT DecodeLZ(bool &keepDecompressing); + HRESULT CodeReal(ICompressProgressInfo *progress); +public: + CDecoder(); + ~CDecoder(); + + MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) + + void ReleaseStreams() + { + _outStream.Release(); + m_InBitStream.ReleaseStream(); + } + + + STDMETHOD(Code)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); + + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); + + void CopyBlock(UInt32 distance, UInt32 len) + { + _lzSize += len; + UInt32 pos = (_winPos - distance - 1) & kWindowMask; + do + { + _window[_winPos] = _window[pos]; + _winPos = (_winPos + 1) & kWindowMask; + pos = (pos + 1) & kWindowMask; + } + while(--len != 0); + } + + void PutByte(Byte b) + { + _window[_winPos] = b; + _winPos = (_winPos + 1) & kWindowMask; + _lzSize++; + } + + +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Rar/Rar3Vm.cpp b/CPP/7zip/Compress/Rar/Rar3Vm.cpp new file mode 100755 index 00000000..69918d94 --- /dev/null +++ b/CPP/7zip/Compress/Rar/Rar3Vm.cpp @@ -0,0 +1,1089 @@ +// Rar3Vm.cpp +// According to unRAR license, +// this code may not be used to develop a +// RAR (WinRAR) compatible archiver + +/* +Note: + Due to performance considerations Rar VM may set Flags C incorrectly + for some operands (SHL x, 0, ... ). + Check implementation of concrete VM command + to see if it sets flags right. +*/ + +#include "StdAfx.h" + +#include "Rar3Vm.h" +#include "Common/CRC.h" +#include "Common/Alloc.h" + +namespace NCompress { +namespace NRar3 { + +UInt32 CMemBitDecoder::ReadBits(int numBits) +{ + UInt32 res = 0; + for (;;) + { + Byte b = _bitPos < _bitSize ? _data[_bitPos >> 3] : 0; + int avail = (int)(8 - (_bitPos & 7)); + if (numBits <= avail) + { + _bitPos += numBits; + return res | (b >> (avail - numBits)) & ((1 << numBits) - 1); + } + numBits -= avail; + res |= (UInt32)(b & ((1 << avail) - 1)) << numBits; + _bitPos += avail; + } +} + +UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); } + +namespace NVm { + +const UInt32 kStackRegIndex = kNumRegs - 1; + +enum EFlags {FLAG_C = 1, FLAG_Z = 2, FLAG_S = 0x80000000}; + +const Byte CF_OP0 = 0; +const Byte CF_OP1 = 1; +const Byte CF_OP2 = 2; +const Byte CF_OPMASK = 3; +const Byte CF_BYTEMODE = 4; +const Byte CF_JUMP = 8; +const Byte CF_PROC = 16; +const Byte CF_USEFLAGS = 32; +const Byte CF_CHFLAGS = 64; + +static Byte kCmdFlags[]= +{ + /* CMD_MOV */ CF_OP2 | CF_BYTEMODE, + /* CMD_CMP */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_ADD */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_SUB */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_JZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JNZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_INC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_DEC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_JMP */ CF_OP1 | CF_JUMP, + /* CMD_XOR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_AND */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_OR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_TEST */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_JS */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JNS */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JB */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JBE */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JA */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JAE */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_PUSH */ CF_OP1, + /* CMD_POP */ CF_OP1, + /* CMD_CALL */ CF_OP1 | CF_PROC, + /* CMD_RET */ CF_OP0 | CF_PROC, + /* CMD_NOT */ CF_OP1 | CF_BYTEMODE, + /* CMD_SHL */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_SHR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_SAR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_NEG */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_PUSHA */ CF_OP0, + /* CMD_POPA */ CF_OP0, + /* CMD_PUSHF */ CF_OP0 | CF_USEFLAGS, + /* CMD_POPF */ CF_OP0 | CF_CHFLAGS, + /* CMD_MOVZX */ CF_OP2, + /* CMD_MOVSX */ CF_OP2, + /* CMD_XCHG */ CF_OP2 | CF_BYTEMODE, + /* CMD_MUL */ CF_OP2 | CF_BYTEMODE, + /* CMD_DIV */ CF_OP2 | CF_BYTEMODE, + /* CMD_ADC */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS , + /* CMD_SBB */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS , + /* CMD_PRINT */ CF_OP0 +}; + +CVm::CVm(): Mem(NULL) {} + +bool CVm::Create() +{ + if (Mem == NULL) + Mem = (Byte *)::MyAlloc(kSpaceSize + 4); + return (Mem != NULL); +} + +CVm::~CVm() +{ + ::MyFree(Mem); +} + +// CVm::Execute can change CProgram object: it clears progarm if VM returns error. + +bool CVm::Execute(CProgram *prg, const CProgramInitState *initState, + CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData) +{ + memcpy(R, initState->InitR, sizeof(initState->InitR)); + R[kStackRegIndex] = kSpaceSize; + R[kNumRegs] = 0; + Flags = 0; + + UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize); + if (globalSize != 0) + memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize); + UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize); + if (staticSize != 0) + memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize); + + bool res = true; + #ifdef RARVM_STANDARD_FILTERS + if (prg->StandardFilterIndex >= 0) + ExecuteStandardFilter(prg->StandardFilterIndex); + else + #endif + { + res = ExecuteCode(prg); + if (!res) + prg->Commands[0].OpCode = CMD_RET; + } + UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask; + UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask; + if (newBlockPos + newBlockSize >= kSpaceSize) + newBlockPos = newBlockSize = 0; + outBlockRef.Offset = newBlockPos; + outBlockRef.Size = newBlockSize; + + outGlobalData.Clear(); + UInt32 dataSize = GetFixedGlobalValue32(NGlobalOffset::kGlobalMemOutSize); + dataSize = MyMin(dataSize, kGlobalSize - kFixedGlobalSize); + if (dataSize != 0) + { + dataSize += kFixedGlobalSize; + outGlobalData.Reserve(dataSize); + for (UInt32 i = 0; i < dataSize; i++) + outGlobalData.Add(Mem[kGlobalOffset + i]); + } + return res; +} + + +#define SET_IP(IP) \ + if ((IP) >= numCommands) return true; \ + if (--maxOpCount <= 0) return false; \ + cmd = commands + (IP); + +#define GET_FLAG_S_B(res) (((res) & 0x80) ? FLAG_S : 0) +#define SET_IP_OP1 { UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val); } +#define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S +#define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res) + +UInt32 CVm::GetOperand32(const COperand *op) const +{ + switch(op->Type) + { + case OP_TYPE_REG: return R[op->Data]; + case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]); + default: return op->Data; + } +} + +void CVm::SetOperand32(const COperand *op, UInt32 val) +{ + switch(op->Type) + { + case OP_TYPE_REG: R[op->Data] = val; return; + case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return; + } +} + +Byte CVm::GetOperand8(const COperand *op) const +{ + switch(op->Type) + { + case OP_TYPE_REG: return (Byte)R[op->Data]; + case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];; + default: return (Byte)op->Data; + } +} + +void CVm::SetOperand8(const COperand *op, Byte val) +{ + switch(op->Type) + { + case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return; + case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return; + } +} + +UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const +{ + if (byteMode) + return GetOperand8(op); + return GetOperand32(op); +} + +void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val) +{ + if (byteMode) + SetOperand8(op, (Byte)(val & 0xFF)); + else + SetOperand32(op, val); +} + +bool CVm::ExecuteCode(const CProgram *prg) +{ + Int32 maxOpCount = 25000000; + const CCommand *commands = &prg->Commands[0]; + const CCommand *cmd = commands; + UInt32 numCommands = prg->Commands.Size(); + for (;;) + { + switch(cmd->OpCode) + { + #ifndef RARVM_NO_VM + + case CMD_MOV: + SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2)); + break; + case CMD_MOVB: + SetOperand8(&cmd->Op1, GetOperand8(&cmd->Op2)); + break; + case CMD_CMP: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + UInt32 res = v1 - GetOperand32(&cmd->Op2); + Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); + } + break; + case CMD_CMPB: + { + Byte v1 = GetOperand8(&cmd->Op1); + Byte res = v1 - GetOperand8(&cmd->Op2); + res &= 0xFF; + Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res); + } + break; + case CMD_ADD: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + UInt32 res = v1 + GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S)); + } + break; + case CMD_ADDB: + { + Byte v1 = GetOperand8(&cmd->Op1); + Byte res = v1 + GetOperand8(&cmd->Op2); + res &= 0xFF; + SetOperand8(&cmd->Op1, (Byte)res); + Flags = (res < v1) | (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)); + } + break; + case CMD_ADC: + { + UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); + UInt32 FC = (Flags & FLAG_C); + UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC; + if (cmd->ByteMode) + res &= 0xFF; + SetOperand(cmd->ByteMode, &cmd->Op1, res); + Flags = (res < v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S)); + } + break; + case CMD_SUB: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + UInt32 res = v1 - GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); + } + break; + case CMD_SUBB: + { + UInt32 v1 = GetOperand8(&cmd->Op1); + UInt32 res = v1 - GetOperand8(&cmd->Op2); + SetOperand8(&cmd->Op1, (Byte)res); + Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); + } + break; + case CMD_SBB: + { + UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); + UInt32 FC = (Flags & FLAG_C); + UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC; + // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S); + if (cmd->ByteMode) + res &= 0xFF; + SetOperand(cmd->ByteMode, &cmd->Op1, res); + Flags = (res > v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S)); + } + break; + case CMD_INC: + { + UInt32 res = GetOperand32(&cmd->Op1) + 1; + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_INCB: + { + Byte res = GetOperand8(&cmd->Op1) + 1; + SetOperand8(&cmd->Op1, res);; + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_DEC: + { + UInt32 res = GetOperand32(&cmd->Op1) - 1; + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_DECB: + { + Byte res = GetOperand8(&cmd->Op1) - 1; + SetOperand8(&cmd->Op1, res);; + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_XOR: + { + UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_XORB: + { + Byte res = GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_AND: + { + UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_ANDB: + { + Byte res = GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_OR: + { + UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_ORB: + { + Byte res = GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_TEST: + { + UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2); + FLAGS_UPDATE_SZ; + } + break; + case CMD_TESTB: + { + Byte res = GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_NOT: + SetOperand(cmd->ByteMode, &cmd->Op1, ~GetOperand(cmd->ByteMode, &cmd->Op1)); + break; + case CMD_NEG: + { + UInt32 res = 0 - GetOperand32(&cmd->Op1); + SetOperand32(&cmd->Op1, res); + Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S); + } + break; + case CMD_NEGB: + { + Byte res = (Byte)(0 - GetOperand8(&cmd->Op1)); + SetOperand8(&cmd->Op1, res); + Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res); + } + break; + + case CMD_SHL: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + int v2 = (int)GetOperand32(&cmd->Op2); + UInt32 res = v1 << v2; + SetOperand32(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0); + } + break; + case CMD_SHLB: + { + Byte v1 = GetOperand8(&cmd->Op1); + int v2 = (int)GetOperand8(&cmd->Op2); + Byte res = (Byte)(v1 << v2); + SetOperand8(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0); + } + break; + case CMD_SHR: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + int v2 = (int)GetOperand32(&cmd->Op2); + UInt32 res = v1 >> v2; + SetOperand32(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + case CMD_SHRB: + { + Byte v1 = GetOperand8(&cmd->Op1); + int v2 = (int)GetOperand8(&cmd->Op2); + Byte res = (Byte)(v1 >> v2); + SetOperand8(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + case CMD_SAR: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + int v2 = (int)GetOperand32(&cmd->Op2); + UInt32 res = UInt32(((Int32)v1) >> v2); + SetOperand32(&cmd->Op1, res); + Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + case CMD_SARB: + { + Byte v1 = GetOperand8(&cmd->Op1); + int v2 = (int)GetOperand8(&cmd->Op2); + Byte res = (Byte)(((signed char)v1) >> v2); + SetOperand8(&cmd->Op1, res); + Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + + case CMD_JMP: + SET_IP_OP1; + continue; + case CMD_JZ: + if ((Flags & FLAG_Z) != 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JNZ: + if ((Flags & FLAG_Z) == 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JS: + if ((Flags & FLAG_S) != 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JNS: + if ((Flags & FLAG_S) == 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JB: + if ((Flags & FLAG_C) != 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JBE: + if ((Flags & (FLAG_C | FLAG_Z)) != 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JA: + if ((Flags & (FLAG_C | FLAG_Z)) == 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JAE: + if ((Flags & FLAG_C) == 0) + { + SET_IP_OP1; + continue; + } + break; + + case CMD_PUSH: + R[kStackRegIndex] -= 4; + SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1)); + break; + case CMD_POP: + SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask])); + R[kStackRegIndex] += 4; + break; + case CMD_CALL: + R[kStackRegIndex] -= 4; + SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1)); + SET_IP_OP1; + continue; + + case CMD_PUSHA: + { + for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4) + SetValue32(&Mem[SP & kSpaceMask], R[i]); + R[kStackRegIndex] -= kNumRegs * 4; + } + break; + case CMD_POPA: + { + for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4) + R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]); + } + break; + case CMD_PUSHF: + R[kStackRegIndex] -= 4; + SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags); + break; + case CMD_POPF: + Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]); + R[kStackRegIndex] += 4; + break; + + case CMD_MOVZX: + SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2)); + break; + case CMD_MOVSX: + SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2)); + break; + case CMD_XCHG: + { + UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); + SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2)); + SetOperand(cmd->ByteMode, &cmd->Op2, v1); + } + break; + case CMD_MUL: + { + UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + } + break; + case CMD_MULB: + { + Byte res = GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2); + SetOperand8(&cmd->Op1, res); + } + break; + case CMD_DIV: + { + UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2); + if (divider != 0) + { + UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider; + SetOperand(cmd->ByteMode, &cmd->Op1, res); + } + } + break; + + #endif + + case CMD_RET: + { + if (R[kStackRegIndex] >= kSpaceSize) + return true; + UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]); + SET_IP(ip); + R[kStackRegIndex] += 4; + continue; + } + case CMD_PRINT: + break; + } + cmd++; + --maxOpCount; + } +} + + +////////////////////////////////////////////////////// +// Read program + +UInt32 ReadEncodedUInt32(CMemBitDecoder &inp) +{ + switch(inp.ReadBits(2)) + { + case 0: + return inp.ReadBits(4); + case 1: + { + UInt32 v = inp.ReadBits(4); + if (v == 0) + return 0xFFFFFF00 | inp.ReadBits(8); + else + return (v << 4) | inp.ReadBits(4); + } + case 2: + return inp.ReadBits(16); + default: + return inp.ReadBits(32); + } +} + +void CVm::DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode) +{ + if (inp.ReadBit()) + { + op.Type = OP_TYPE_REG; + op.Data = inp.ReadBits(kNumRegBits); + } + else if (inp.ReadBit() == 0) + { + op.Type = OP_TYPE_INT; + if (byteMode) + op.Data = inp.ReadBits(8); + else + op.Data = ReadEncodedUInt32(inp); + } + else + { + op.Type = OP_TYPE_REGMEM; + if (inp.ReadBit() == 0) + { + op.Data = inp.ReadBits(kNumRegBits); + op.Base = 0; + } + else + { + if (inp.ReadBit() == 0) + op.Data = inp.ReadBits(kNumRegBits); + else + op.Data = kNumRegs; + op.Base = ReadEncodedUInt32(inp); + } + } +} + +void CVm::ReadVmProgram(const Byte *code, UInt32 codeSize, CProgram *prg) +{ + CMemBitDecoder inp; + inp.Init(code, codeSize); + + prg->StaticData.Clear(); + if (inp.ReadBit()) + { + UInt32 dataSize = ReadEncodedUInt32(inp) + 1; + for (UInt32 i = 0; inp.Avail() && i < dataSize; i++) + prg->StaticData.Add((Byte)inp.ReadBits(8)); + } + while (inp.Avail()) + { + prg->Commands.Add(CCommand()); + CCommand *cmd = &prg->Commands.Back(); + if (inp.ReadBit() == 0) + cmd->OpCode = (ECommand)inp.ReadBits(3); + else + cmd->OpCode = (ECommand)(8 + inp.ReadBits(5)); + if (kCmdFlags[cmd->OpCode] & CF_BYTEMODE) + cmd->ByteMode = (inp.ReadBit()) ? true : false; + else + cmd->ByteMode = 0; + int opNum = (kCmdFlags[cmd->OpCode] & CF_OPMASK); + if (opNum > 0) + { + DecodeArg(inp, cmd->Op1, cmd->ByteMode); + if (opNum == 2) + DecodeArg(inp, cmd->Op2, cmd->ByteMode); + else + { + if (cmd->Op1.Type == OP_TYPE_INT && (kCmdFlags[cmd->OpCode] & (CF_JUMP | CF_PROC))) + { + int Distance = cmd->Op1.Data; + if (Distance >= 256) + Distance -= 256; + else + { + if (Distance >= 136) + Distance -= 264; + else if (Distance >= 16) + Distance -= 8; + else if (Distance >= 8) + Distance -= 16; + Distance += prg->Commands.Size() - 1; + } + cmd->Op1.Data = Distance; + } + } + } + if (cmd->ByteMode) + { + switch (cmd->OpCode) + { + case CMD_MOV: cmd->OpCode = CMD_MOVB; break; + case CMD_CMP: cmd->OpCode = CMD_CMPB; break; + case CMD_ADD: cmd->OpCode = CMD_ADDB; break; + case CMD_SUB: cmd->OpCode = CMD_SUBB; break; + case CMD_INC: cmd->OpCode = CMD_INCB; break; + case CMD_DEC: cmd->OpCode = CMD_DECB; break; + case CMD_XOR: cmd->OpCode = CMD_XORB; break; + case CMD_AND: cmd->OpCode = CMD_ANDB; break; + case CMD_OR: cmd->OpCode = CMD_ORB; break; + case CMD_TEST: cmd->OpCode = CMD_TESTB; break; + case CMD_NEG: cmd->OpCode = CMD_NEGB; break; + case CMD_SHL: cmd->OpCode = CMD_SHLB; break; + case CMD_SHR: cmd->OpCode = CMD_SHRB; break; + case CMD_SAR: cmd->OpCode = CMD_SARB; break; + case CMD_MUL: cmd->OpCode = CMD_MULB; break; + } + } + } +} + +#ifdef RARVM_STANDARD_FILTERS + +enum EStandardFilter +{ + SF_E8, + SF_E8E9, + SF_ITANIUM, + SF_RGB, + SF_AUDIO, + SF_DELTA, + SF_UPCASE +}; + +struct StandardFilterSignature +{ + UInt32 Length; + UInt32 CRC; + EStandardFilter Type; +} +kStdFilters[]= +{ + 53, 0xad576887, SF_E8, + 57, 0x3cd7e57e, SF_E8E9, + 120, 0x3769893f, SF_ITANIUM, + 29, 0x0e06077d, SF_DELTA, + 149, 0x1c2c5dc8, SF_RGB, + 216, 0xbc85e701, SF_AUDIO, + 40, 0x46b9c560, SF_UPCASE +}; + +static int FindStandardFilter(const Byte *code, UInt32 codeSize) +{ + UInt32 crc = CCRC::CalculateDigest(code, codeSize); + for (int i = 0; i < sizeof(kStdFilters) / sizeof(kStdFilters[0]); i++) + { + StandardFilterSignature &sfs = kStdFilters[i]; + if (sfs.CRC == crc && sfs.Length == codeSize) + return i; + } + return -1; +} + +#endif + +void CVm::PrepareProgram(const Byte *code, UInt32 codeSize, CProgram *prg) +{ + Byte xorSum = 0; + for (UInt32 i = 1; i < codeSize; i++) + xorSum ^= code[i]; + + prg->Commands.Clear(); + #ifdef RARVM_STANDARD_FILTERS + prg->StandardFilterIndex = -1; + #endif + + if (xorSum == code[0] && codeSize > 0) + { + #ifdef RARVM_STANDARD_FILTERS + prg->StandardFilterIndex = FindStandardFilter(code, codeSize); + if (prg->StandardFilterIndex >= 0) + return; + #endif + // 1 byte for checksum + ReadVmProgram(code + 1, codeSize - 1, prg); + } + prg->Commands.Add(CCommand()); + CCommand *cmd = &prg->Commands.Back(); + cmd->OpCode = CMD_RET; +} + +void CVm::SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize) +{ + if (pos < kSpaceSize && data != Mem + pos) + memmove(Mem + pos, data, MyMin(dataSize, kSpaceSize - pos)); +} + +#ifdef RARVM_STANDARD_FILTERS + +static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9) +{ + if (dataSize <= 4) + return; + dataSize -= 4; + const UInt32 kFileSize = 0x1000000; + Byte cmpByte2 = (e9 ? 0xE9 : 0xE8); + for (UInt32 curPos = 0; curPos < dataSize;) + { + Byte curByte = *(data++); + curPos++; + if (curByte == 0xE8 || curByte == cmpByte2) + { + UInt32 offset = curPos + fileOffset; + UInt32 addr = (Int32)GetValue32(data); + if (addr < kFileSize) + SetValue32(data, addr - offset); + else if ((Int32)addr < 0 && (Int32)(addr + offset) >= 0) + SetValue32(data, addr + kFileSize); + data += 4; + curPos += 4; + } + } +} + +static inline UInt32 ItaniumGetOpType(const Byte *data, int bitPos) +{ + return (data[(unsigned int)bitPos >> 3] >> (bitPos & 7)) & 0xF; +} + + +static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset) +{ + UInt32 curPos = 0; + fileOffset >>= 4; + while (curPos < dataSize - 21) + { + int b = (data[0] & 0x1F) - 0x10; + if (b >= 0) + { + static Byte kCmdMasks[16] = {4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0}; + Byte cmdMask = kCmdMasks[b]; + if (cmdMask != 0) + for (int i = 0; i < 3; i++) + if (cmdMask & (1 << i)) + { + int startPos = i * 41 + 18; + if (ItaniumGetOpType(data, startPos + 24) == 5) + { + const UInt32 kMask = 0xFFFFF; + Byte *p = data + ((unsigned int)startPos >> 3); + UInt32 bitField = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16); + int inBit = (startPos & 7); + UInt32 offset = (bitField >> inBit) & kMask; + UInt32 andMask = ~(kMask << inBit); + bitField = ((offset - fileOffset) & kMask) << inBit; + for (int j = 0; j < 3; j++) + { + p[j] &= andMask; + p[j] |= bitField; + andMask >>= 8; + bitField >>= 8; + } + } + } + } + data += 16; + curPos += 16; + fileOffset++; + } +} + +static void DeltaDecode(Byte *data, UInt32 dataSize, UInt32 numChannels) +{ + UInt32 srcPos = 0; + UInt32 border = dataSize * 2; + for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++) + { + Byte prevByte = 0; + for (UInt32 destPos = dataSize + curChannel; destPos < border; destPos += numChannels) + data[destPos] = (prevByte = prevByte - data[srcPos++]); + } +} + +static void RgbDecode(Byte *srcData, UInt32 dataSize, UInt32 width, UInt32 posR) +{ + Byte *destData = srcData + dataSize; + const UInt32 numChannels = 3; + for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++) + { + Byte prevByte = 0; + + for (UInt32 i = curChannel; i < dataSize; i+= numChannels) + { + unsigned int predicted; + if (i < width) + predicted = prevByte; + else + { + unsigned int upperLeftByte = destData[i - width]; + unsigned int upperByte = destData[i - width + 3]; + predicted = prevByte + upperByte - upperLeftByte; + int pa = abs((int)(predicted - prevByte)); + int pb = abs((int)(predicted - upperByte)); + int pc = abs((int)(predicted - upperLeftByte)); + if (pa <= pb && pa <= pc) + predicted = prevByte; + else + if (pb <= pc) + predicted = upperByte; + else + predicted = upperLeftByte; + } + destData[i] = prevByte = (Byte)(predicted - *(srcData++)); + } + } + if (dataSize < 3) + return; + for (UInt32 i = posR, border = dataSize - 2; i < border; i += 3) + { + Byte g = destData[i + 1]; + destData[i] = destData[i] + g; + destData[i + 2] = destData[i + 2] + g; + } +} + +static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels) +{ + Byte *destData = srcData + dataSize; + for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++) + { + UInt32 prevByte = 0, prevDelta = 0, dif[7]; + Int32 D1 = 0, D2 = 0, D3; + Int32 K1 = 0, K2 = 0, K3 = 0; + memset(dif, 0, sizeof(dif)); + + for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++) + { + D3 = D2; + D2 = prevDelta - D1; + D1 = prevDelta; + + UInt32 predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3; + predicted = (predicted >> 3) & 0xFF; + + UInt32 curByte = *(srcData++); + + predicted -= curByte; + destData[i] = (Byte)predicted; + prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte); + prevByte = predicted; + + Int32 D = ((Int32)(signed char)curByte) << 3; + + dif[0] += abs(D); + dif[1] += abs(D - D1); + dif[2] += abs(D + D1); + dif[3] += abs(D - D2); + dif[4] += abs(D + D2); + dif[5] += abs(D - D3); + dif[6] += abs(D + D3); + + if ((byteCount & 0x1F) == 0) + { + UInt32 minDif = dif[0], numMinDif = 0; + dif[0] = 0; + for (int j = 1; j < sizeof(dif) / sizeof(dif[0]); j++) + { + if (dif[j] < minDif) + { + minDif = dif[j]; + numMinDif = j; + } + dif[j] = 0; + } + switch (numMinDif) + { + case 1: if (K1 >= -16) K1--; break; + case 2: if (K1 < 16) K1++; break; + case 3: if (K2 >= -16) K2--; break; + case 4: if (K2 < 16) K2++; break; + case 5: if (K3 >= -16) K3--; break; + case 6: if (K3 < 16) K3++; break; + } + } + } + } +} + +static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize) +{ + UInt32 srcPos = 0, destPos = dataSize; + while (srcPos < dataSize) + { + Byte curByte = data[srcPos++]; + if (curByte == 2 && (curByte = data[srcPos++]) != 2) + curByte -= 32; + data[destPos++] = curByte; + } + return destPos - dataSize; +} + +void CVm::ExecuteStandardFilter(int filterIndex) +{ + UInt32 dataSize = R[4]; + if (dataSize >= kGlobalOffset) + return; + EStandardFilter filterType = kStdFilters[filterIndex].Type; + + switch (filterType) + { + case SF_E8: + case SF_E8E9: + E8E9Decode(Mem, dataSize, R[6], (filterType == SF_E8E9)); + break; + case SF_ITANIUM: + ItaniumDecode(Mem, dataSize, R[6]); + break; + case SF_DELTA: + if (dataSize >= kGlobalOffset / 2) + break; + SetBlockPos(dataSize); + DeltaDecode(Mem, dataSize, R[0]); + break; + case SF_RGB: + if (dataSize >= kGlobalOffset / 2) + break; + { + UInt32 width = R[0]; + if (width <= 3) + break; + SetBlockPos(dataSize); + RgbDecode(Mem, dataSize, width, R[1]); + } + break; + case SF_AUDIO: + if (dataSize >= kGlobalOffset / 2) + break; + SetBlockPos(dataSize); + AudioDecode(Mem, dataSize, R[0]); + break; + case SF_UPCASE: + if (dataSize >= kGlobalOffset / 2) + break; + UInt32 destSize = UpCaseDecode(Mem, dataSize); + SetBlockSize(destSize); + SetBlockPos(dataSize); + break; + } +} + +#endif + +}}} diff --git a/CPP/7zip/Compress/Rar/Rar3Vm.h b/CPP/7zip/Compress/Rar/Rar3Vm.h new file mode 100755 index 00000000..d0a4f82c --- /dev/null +++ b/CPP/7zip/Compress/Rar/Rar3Vm.h @@ -0,0 +1,219 @@ +// Rar3Vm.h +// According to unRAR license, +// this code may not be used to develop a +// RAR (WinRAR) compatible archiver + +#ifndef __RAR3VM_H +#define __RAR3VM_H + +#include "Common/Types.h" +#include "Common/Vector.h" + +#define RARVM_STANDARD_FILTERS +#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__) // || defined(_M_IA64) || defined(__ia64__) +// Define RARVM_LITTLE_ENDIAN_UNALIGN, if CPU is LITTLE_ENDIAN and if it supports +// unaligned 32-bit memory accesses. +// It's for speed optimization, if you are not sure, just don't define it. +#define RARVM_LITTLE_ENDIAN_UNALIGN +#endif + +namespace NCompress { +namespace NRar3 { + +class CMemBitDecoder +{ + const Byte *_data; + UInt32 _bitSize; + UInt32 _bitPos; +public: + void Init(const Byte *data, UInt32 byteSize) + { + _data = data; + _bitSize = (byteSize << 3); + _bitPos = 0; + } + UInt32 ReadBits(int numBits); + UInt32 ReadBit(); + bool Avail() const { return (_bitPos < _bitSize); } +}; + +namespace NVm { + +inline UInt32 GetValue32(const void *addr) +{ + #ifdef RARVM_LITTLE_ENDIAN_UNALIGN + return *(const UInt32 *)addr; + #else + const Byte *b = (const Byte *)addr; + return UInt32((UInt32)b[0]|((UInt32)b[1]<<8)|((UInt32)b[2]<<16)|((UInt32)b[3]<<24)); + #endif +} + +inline void SetValue32(void *addr, UInt32 value) +{ + #ifdef RARVM_LITTLE_ENDIAN_UNALIGN + *(UInt32 *)addr = value; + #else + ((Byte *)addr)[0] = (Byte)value; + ((Byte *)addr)[1] = (Byte)(value >> 8); + ((Byte *)addr)[2] = (Byte)(value >> 16); + ((Byte *)addr)[3] = (Byte)(value >> 24); + #endif +} + +UInt32 ReadEncodedUInt32(CMemBitDecoder &inp); + +const int kNumRegBits = 3; +const UInt32 kNumRegs = 1 << kNumRegBits; +const UInt32 kNumGpRegs = kNumRegs - 1; + +const UInt32 kSpaceSize = 0x40000; +const UInt32 kSpaceMask = kSpaceSize -1; +const UInt32 kGlobalOffset = 0x3C000; +const UInt32 kGlobalSize = 0x2000; +const UInt32 kFixedGlobalSize = 64; + +namespace NGlobalOffset +{ + const UInt32 kBlockSize = 0x1C; + const UInt32 kBlockPos = 0x20; + const UInt32 kExecCount = 0x2C; + const UInt32 kGlobalMemOutSize = 0x30; +}; + +enum ECommand +{ + CMD_MOV, CMD_CMP, CMD_ADD, CMD_SUB, CMD_JZ, CMD_JNZ, CMD_INC, CMD_DEC, + CMD_JMP, CMD_XOR, CMD_AND, CMD_OR, CMD_TEST, CMD_JS, CMD_JNS, CMD_JB, + CMD_JBE, CMD_JA, CMD_JAE, CMD_PUSH, CMD_POP, CMD_CALL, CMD_RET, CMD_NOT, + CMD_SHL, CMD_SHR, CMD_SAR, CMD_NEG, CMD_PUSHA,CMD_POPA, CMD_PUSHF,CMD_POPF, + CMD_MOVZX,CMD_MOVSX,CMD_XCHG, CMD_MUL, CMD_DIV, CMD_ADC, CMD_SBB, CMD_PRINT, + + CMD_MOVB, CMD_CMPB, CMD_ADDB, CMD_SUBB, CMD_INCB, CMD_DECB, + CMD_XORB, CMD_ANDB, CMD_ORB, CMD_TESTB,CMD_NEGB, + CMD_SHLB, CMD_SHRB, CMD_SARB, CMD_MULB +}; + +enum EOpType {OP_TYPE_REG, OP_TYPE_INT, OP_TYPE_REGMEM, OP_TYPE_NONE}; + +// Addr in COperand object can link (point) to CVm object!!! + +struct COperand +{ + EOpType Type; + UInt32 Data; + UInt32 Base; + COperand(): Type(OP_TYPE_NONE), Data(0), Base(0) {} +}; + +struct CCommand +{ + ECommand OpCode; + bool ByteMode; + COperand Op1, Op2; +}; + +struct CBlockRef +{ + UInt32 Offset; + UInt32 Size; +}; + +struct CProgram +{ + CRecordVector<CCommand> Commands; + #ifdef RARVM_STANDARD_FILTERS + int StandardFilterIndex; + #endif + CRecordVector<Byte> StaticData; +}; + +struct CProgramInitState +{ + UInt32 InitR[kNumGpRegs]; + CRecordVector<Byte> GlobalData; + + void AllocateEmptyFixedGlobal() + { + GlobalData.Clear(); + GlobalData.Reserve(NVm::kFixedGlobalSize); + for (UInt32 i = 0; i < NVm::kFixedGlobalSize; i++) + GlobalData.Add(0); + } +}; + +class CVm +{ + static UInt32 GetValue(bool byteMode, const void *addr) + { + if (byteMode) + return(*(const Byte *)addr); + else + { + #ifdef RARVM_LITTLE_ENDIAN_UNALIGN + return *(const UInt32 *)addr; + #else + const Byte *b = (const Byte *)addr; + return UInt32((UInt32)b[0]|((UInt32)b[1]<<8)|((UInt32)b[2]<<16)|((UInt32)b[3]<<24)); + #endif + } + } + + static void SetValue(bool byteMode, void *addr, UInt32 value) + { + if (byteMode) + *(Byte *)addr = (Byte)value; + else + { + #ifdef RARVM_LITTLE_ENDIAN_UNALIGN + *(UInt32 *)addr = value; + #else + ((Byte *)addr)[0] = (Byte)value; + ((Byte *)addr)[1] = (Byte)(value >> 8); + ((Byte *)addr)[2] = (Byte)(value >> 16); + ((Byte *)addr)[3] = (Byte)(value >> 24); + #endif + } + } + + UInt32 GetFixedGlobalValue32(UInt32 globalOffset) { return GetValue(false, &Mem[kGlobalOffset + globalOffset]); } + + void SetBlockSize(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockSize], v); } + void SetBlockPos(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockPos], v); } +public: + static void SetValue(void *addr, UInt32 value) { SetValue(false, addr, value); } +private: + UInt32 GetOperand32(const COperand *op) const; + void SetOperand32(const COperand *op, UInt32 val); + Byte GetOperand8(const COperand *op) const; + void SetOperand8(const COperand *op, Byte val); + UInt32 GetOperand(bool byteMode, const COperand *op) const; + void SetOperand(bool byteMode, const COperand *op, UInt32 val); + + void DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode); + + bool ExecuteCode(const CProgram *prg); + + #ifdef RARVM_STANDARD_FILTERS + void ExecuteStandardFilter(int filterIndex); + #endif + + Byte *Mem; + UInt32 R[kNumRegs + 1]; // R[kNumRegs] = 0 always (speed optimization) + UInt32 Flags; + void ReadVmProgram(const Byte *code, UInt32 codeSize, CProgram *prg); +public: + CVm(); + ~CVm(); + bool Create(); + void PrepareProgram(const Byte *code, UInt32 codeSize, CProgram *prg); + void SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize); + bool Execute(CProgram *prg, const CProgramInitState *initState, + CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData); + const Byte *GetDataPointer(UInt32 offset) const { return Mem + offset; } + +}; + +#endif + +}}} diff --git a/CPP/7zip/Compress/Rar/StdAfx.cpp b/CPP/7zip/Compress/Rar/StdAfx.cpp new file mode 100755 index 00000000..d0feea85 --- /dev/null +++ b/CPP/7zip/Compress/Rar/StdAfx.cpp @@ -0,0 +1,3 @@ +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Compress/Rar/StdAfx.h b/CPP/7zip/Compress/Rar/StdAfx.h new file mode 100755 index 00000000..e7fb6986 --- /dev/null +++ b/CPP/7zip/Compress/Rar/StdAfx.h @@ -0,0 +1,8 @@ +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/MyWindows.h" + +#endif diff --git a/CPP/7zip/Compress/Rar/makefile b/CPP/7zip/Compress/Rar/makefile new file mode 100755 index 00000000..4d8d5304 --- /dev/null +++ b/CPP/7zip/Compress/Rar/makefile @@ -0,0 +1,49 @@ +PROG = Rar29.dll +DEF_FILE = ../Codec.def +CFLAGS = $(CFLAGS) -I ../../../ +LIBS = $(LIBS) oleaut32.lib + +RAR29_OBJS = \ + $O\DllExports.obj \ + +RAR29_OPT_OBJS = \ + $O\Rar1Decoder.obj \ + $O\Rar2Decoder.obj \ + $O\Rar3Decoder.obj \ + $O\Rar3Vm.obj \ + +COMMON_OBJS = \ + $O\Alloc.obj \ + $O\CRC.obj \ + $O\Vector.obj \ + +7ZIP_COMMON_OBJS = \ + $O\InBuffer.obj \ + $O\OutBuffer.obj \ + $O\StreamUtils.obj \ + +LZ_OBJS = \ + $O\LZOutWindow.obj \ + + +OBJS = \ + $O\StdAfx.obj \ + $(RAR29_OBJS) \ + $(RAR29_OPT_OBJS) \ + $(COMMON_OBJS) \ + $(7ZIP_COMMON_OBJS) \ + $(LZ_OBJS) \ + $O\resource.res + +!include "../../../Build.mak" + +$(RAR29_OBJS): $(*B).cpp + $(COMPL) +$(RAR29_OPT_OBJS): $(*B).cpp + $(COMPL_O2) +$(COMMON_OBJS): ../../../Common/$(*B).cpp + $(COMPL) +$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp + $(COMPL) +$(LZ_OBJS): ../LZ/$(*B).cpp + $(COMPL) diff --git a/CPP/7zip/Compress/Rar/resource.rc b/CPP/7zip/Compress/Rar/resource.rc new file mode 100755 index 00000000..bb5e2ec9 --- /dev/null +++ b/CPP/7zip/Compress/Rar/resource.rc @@ -0,0 +1,3 @@ +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_DLL("Rar29 Codec", "Rar29") |