diff options
author | XhmikosR <xhmikosr@users.sourceforge.net> | 2013-05-20 19:43:54 +0400 |
---|---|---|
committer | XhmikosR <xhmikosr@users.sourceforge.net> | 2013-05-20 19:46:10 +0400 |
commit | ae4d75d223b7de9d8edbaad1498740211c47a291 (patch) | |
tree | dffa8a3fde62fd655d798bd1bec40f1a2c9f951a /src/thirdparty/unrar | |
parent | 720ba19a3c00e4918b4bc05f5c657c8b6e9b4079 (diff) |
Update Unrar to v5.0.4.
Diffstat (limited to 'src/thirdparty/unrar')
-rw-r--r-- | src/thirdparty/unrar/dll.rc | 8 | ||||
-rw-r--r-- | src/thirdparty/unrar/loclang.hpp | 2 | ||||
-rw-r--r-- | src/thirdparty/unrar/unpack.cpp | 70 | ||||
-rw-r--r-- | src/thirdparty/unrar/unpack.hpp | 22 | ||||
-rw-r--r-- | src/thirdparty/unrar/unpack50.cpp | 61 | ||||
-rw-r--r-- | src/thirdparty/unrar/unpack50frag.cpp | 92 | ||||
-rw-r--r-- | src/thirdparty/unrar/unpackinline.cpp | 4 | ||||
-rw-r--r-- | src/thirdparty/unrar/version.hpp | 4 |
8 files changed, 220 insertions, 43 deletions
diff --git a/src/thirdparty/unrar/dll.rc b/src/thirdparty/unrar/dll.rc index 3c0c6fce4..e8e8ad184 100644 --- a/src/thirdparty/unrar/dll.rc +++ b/src/thirdparty/unrar/dll.rc @@ -2,8 +2,8 @@ #include <commctrl.h>
VS_VERSION_INFO VERSIONINFO
-FILEVERSION 5, 0, 3, 860
-PRODUCTVERSION 5, 0, 3, 860
+FILEVERSION 5, 0, 4, 871
+PRODUCTVERSION 5, 0, 4, 871
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
{
@@ -14,8 +14,8 @@ FILETYPE VFT_APP VALUE "CompanyName", "Alexander Roshal\0"
VALUE "ProductName", "RAR decompression library\0"
VALUE "FileDescription", "RAR decompression library\0"
- VALUE "FileVersion", "5.0.3\0"
- VALUE "ProductVersion", "5.0.3\0"
+ VALUE "FileVersion", "5.0.4\0"
+ VALUE "ProductVersion", "5.0.4\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2013\0"
VALUE "OriginalFilename", "Unrar.dll\0"
}
diff --git a/src/thirdparty/unrar/loclang.hpp b/src/thirdparty/unrar/loclang.hpp index 6941a3189..aa6b12f72 100644 --- a/src/thirdparty/unrar/loclang.hpp +++ b/src/thirdparty/unrar/loclang.hpp @@ -384,3 +384,5 @@ #define MErrCreateLnkS "\nCannot create symbolic link %s" #define MErrCreateLnkH "\nCannot create hard link %s" #define MNeedAdmin "\nYou may need to run RAR as administrator" +#define MDictOutMem "\nNot enough memory for %d MB compression dictionary, changed to %d MB." +#define MUseSmalllerDict "\nPlease use a smaller compression dictionary." diff --git a/src/thirdparty/unrar/unpack.cpp b/src/thirdparty/unrar/unpack.cpp index a20d37f9e..df9259c61 100644 --- a/src/thirdparty/unrar/unpack.cpp +++ b/src/thirdparty/unrar/unpack.cpp @@ -13,12 +13,14 @@ #endif #include "unpack30.cpp" #include "unpack50.cpp" +#include "unpack50frag.cpp" Unpack::Unpack(ComprDataIO *DataIO) :Inp(true),VMCodeInp(true) { UnpIO=DataIO; Window=NULL; + Fragmented=false; Suspended=false; UnpAllBuf=false; UnpSomeRead=false; @@ -30,6 +32,16 @@ Unpack::Unpack(ComprDataIO *DataIO) #endif MaxWinSize=0; MaxWinMask=0; + + // Perform initialization, which should be done only once for all files. + // It prevents crash if first DoUnpack call is later made with wrong + // (true) 'Solid' value. + UnpInitData(false); +#ifndef SFX_MODULE + // RAR 1.5 decompression initialization + UnpInitData15(false); + InitHuff(); +#endif } @@ -37,7 +49,8 @@ Unpack::~Unpack() { InitFilters30(); - delete[] Window; + if (Window!=NULL) + free(Window); #ifdef RAR_SMP DestroyThreadPool(UnpThreadPool); delete[] ReadBufMT; @@ -48,17 +61,6 @@ Unpack::~Unpack() void Unpack::Init(size_t WinSize,bool Solid) { - if (Window==NULL) // Perform initialization, which should be done only once for all files. - { - // Prevent crash if DoUnpack is later called with wrong 'Solid' value. - UnpInitData(false); -#ifndef SFX_MODULE - // RAR 1.5 decompression initialization - UnpInitData15(false); - InitHuff(); -#endif - } - // If 32-bit RAR unpacks an archive with 4 GB dictionary, the window size // will be 0 because of size_t overflow. Let's issue the memory error. if (WinSize==0) @@ -83,23 +85,41 @@ void Unpack::Init(size_t WinSize,bool Solid) // or increasing the size of non-solid window. So we could safely reject // current window data without copying them to a new window, though being // extra cautious, we still handle the solid window grow case below. + bool Grow=Solid && (Window!=NULL || Fragmented); - byte *NewWindow=new byte[WinSize]; + byte *NewWindow=(byte *)malloc(WinSize); - // Clean the window to generate the same output when unpacking corrupt - // RAR files, which may access to unused areas of sliding dictionary. - memset(NewWindow,0,WinSize); + // We do not handle growth for fragmented window now. + if (Grow && (NewWindow==NULL || Fragmented)) + throw std::bad_alloc(); - // If Window is not NULL, it means that window size has grown. - // In solid streams we need to copy data to a new window in such case. - // RAR archiving code does not allow it in solid streams now, - // but let's implement it anyway just in case we'll change it sometimes. - if (Solid && Window!=NULL) - for (size_t I=1;I<MaxWinSize;I++) - NewWindow[(UnpPtr-I)&(WinSize-1)]=Window[(UnpPtr-I)&(MaxWinSize-1)]; + if (NewWindow==NULL) + if (WinSize<0x1000000) // Exclude RAR4 and small dictionaries. + throw std::bad_alloc(); + else + { + FragWindow.Init(WinSize); + Fragmented=true; + } - delete Window; - Window=NewWindow; + if (!Fragmented) + { + // Clean the window to generate the same output when unpacking corrupt + // RAR files, which may access to unused areas of sliding dictionary. + memset(NewWindow,0,WinSize); + + // If Window is not NULL, it means that window size has grown. + // In solid streams we need to copy data to a new window in such case. + // RAR archiving code does not allow it in solid streams now, + // but let's implement it anyway just in case we'll change it sometimes. + if (Grow) + for (size_t I=1;I<MaxWinSize;I++) + NewWindow[(UnpPtr-I)&(WinSize-1)]=Window[(UnpPtr-I)&(MaxWinSize-1)]; + + if (Window!=NULL) + free(Window); + Window=NewWindow; + } MaxWinSize=WinSize; MaxWinMask=MaxWinSize-1; diff --git a/src/thirdparty/unrar/unpack.hpp b/src/thirdparty/unrar/unpack.hpp index 87dfee2b4..2cd739722 100644 --- a/src/thirdparty/unrar/unpack.hpp +++ b/src/thirdparty/unrar/unpack.hpp @@ -165,6 +165,25 @@ struct AudioVariables // For RAR 2.0 archives only. }; +// We can use the fragmented dictionary in case heap does not have the single +// large enough memory block. It is slower than normal dictionary. +class FragmentedWindow +{ + private: + enum {MAX_MEM_BLOCKS=32}; + byte *Mem[MAX_MEM_BLOCKS]; + size_t MemSize[MAX_MEM_BLOCKS]; + public: + FragmentedWindow(); + ~FragmentedWindow(); + void Init(size_t WinSize); + byte& operator [](size_t Item); + void CopyString(uint Length,uint Distance,size_t &UnpPtr,size_t MaxWinMask); + void CopyData(byte *Dest,size_t WinPos,size_t Size); + size_t GetBlockSize(size_t StartPos,size_t RequiredSize); +}; + + class Unpack { private: @@ -237,6 +256,9 @@ class Unpack byte *Window; + FragmentedWindow FragWindow; + bool Fragmented; + int64 DestUnpSize; diff --git a/src/thirdparty/unrar/unpack50.cpp b/src/thirdparty/unrar/unpack50.cpp index 989d15bd1..6132409b9 100644 --- a/src/thirdparty/unrar/unpack50.cpp +++ b/src/thirdparty/unrar/unpack50.cpp @@ -52,7 +52,10 @@ void Unpack::Unpack5(bool Solid) uint MainSlot=DecodeNumber(Inp,&BlockTables.LD); if (MainSlot<256) { - Window[UnpPtr++]=(byte)MainSlot; + if (Fragmented) + FragWindow[UnpPtr++]=(byte)MainSlot; + else + Window[UnpPtr++]=(byte)MainSlot; continue; } if (MainSlot>=262) @@ -103,7 +106,10 @@ void Unpack::Unpack5(bool Solid) InsertOldDist(Distance); LastLength=Length; - CopyString(Length,Distance); + if (Fragmented) + FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask); + else + CopyString(Length,Distance); continue; } if (MainSlot==256) @@ -116,7 +122,10 @@ void Unpack::Unpack5(bool Solid) if (MainSlot==257) { if (LastLength!=0) - CopyString(LastLength,OldDist[0]); + if (Fragmented) + FragWindow.CopyString(LastLength,OldDist[0],UnpPtr,MaxWinMask); + else + CopyString(LastLength,OldDist[0]); continue; } if (MainSlot<262) @@ -130,7 +139,10 @@ void Unpack::Unpack5(bool Solid) uint LengthSlot=DecodeNumber(Inp,&BlockTables.RD); uint Length=SlotToLength(Inp,LengthSlot); LastLength=Length; - CopyString(Length,Distance); + if (Fragmented) + FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask); + else + CopyString(Length,Distance); continue; } } @@ -286,12 +298,25 @@ void Unpack::UnpWriteBuf() FilterSrcMemory.Alloc(BlockLength); byte *Mem=&FilterSrcMemory[0]; if (BlockStart<BlockEnd || BlockEnd==0) - memcpy(Mem,Window+BlockStart,BlockLength); + { + if (Fragmented) + FragWindow.CopyData(Mem,BlockStart,BlockLength); + else + memcpy(Mem,Window+BlockStart,BlockLength); + } else { size_t FirstPartLength=size_t(MaxWinSize-BlockStart); - memcpy(Mem,Window+BlockStart,FirstPartLength); - memcpy(Mem+FirstPartLength,Window,BlockEnd); + if (Fragmented) + { + FragWindow.CopyData(Mem,BlockStart,FirstPartLength); + FragWindow.CopyData(Mem+FirstPartLength,0,BlockEnd); + } + else + { + memcpy(Mem,Window+BlockStart,FirstPartLength); + memcpy(Mem+FirstPartLength,Window,BlockEnd); + } } byte *OutMem=ApplyFilter(Mem,BlockLength,flt); @@ -652,13 +677,27 @@ void Unpack::UnpWriteArea(size_t StartPtr,size_t EndPtr) if (EndPtr!=StartPtr) UnpSomeRead=true; if (EndPtr<StartPtr) - { - UnpWriteData(&Window[StartPtr],-(int)StartPtr & MaxWinMask); - UnpWriteData(Window,EndPtr); UnpAllBuf=true; + + if (Fragmented) + { + size_t SizeToWrite=(EndPtr-StartPtr) & MaxWinMask; + while (SizeToWrite>0) + { + size_t BlockSize=FragWindow.GetBlockSize(StartPtr,SizeToWrite); + UnpWriteData(&FragWindow[StartPtr],BlockSize); + SizeToWrite-=BlockSize; + StartPtr=(StartPtr+BlockSize) & MaxWinMask; + } } else - UnpWriteData(&Window[StartPtr],EndPtr-StartPtr); + if (EndPtr<StartPtr) + { + UnpWriteData(Window+StartPtr,MaxWinSize-StartPtr); + UnpWriteData(Window,EndPtr); + } + else + UnpWriteData(Window+StartPtr,EndPtr-StartPtr); } diff --git a/src/thirdparty/unrar/unpack50frag.cpp b/src/thirdparty/unrar/unpack50frag.cpp new file mode 100644 index 000000000..32c09b6fb --- /dev/null +++ b/src/thirdparty/unrar/unpack50frag.cpp @@ -0,0 +1,92 @@ +FragmentedWindow::FragmentedWindow() +{ + memset(Mem,0,sizeof(Mem)); + memset(MemSize,0,sizeof(MemSize)); +} + + +FragmentedWindow::~FragmentedWindow() +{ + for (uint I=0;I<ASIZE(Mem);I++) + if (Mem[I]!=NULL) + free(Mem[I]); +} + + +void FragmentedWindow::Init(size_t WinSize) +{ + uint BlockNum=0; + size_t TotalSize=0; // Already allocated. + while (TotalSize<WinSize && BlockNum<ASIZE(Mem)) + { + size_t Size=WinSize-TotalSize; // Size needed to allocate. + + // Minimum still acceptable block size. Next allocations cannot be larger + // than current, so we do not need blocks if they are smaller than + // "size left / attempts left". Also we do not waste time to blocks + // smaller than some artbitrary constant. + size_t MinSize=Max(Size/(ASIZE(Mem)-BlockNum), 0x400000); + + byte *NewMem=NULL; + while (Size>=MinSize) + { + NewMem=(byte *)malloc(Size); + if (NewMem!=NULL) + break; + Size-=Size/32; + } + if (NewMem==NULL) + throw std::bad_alloc(); + + // Clean the window to generate the same output when unpacking corrupt + // RAR files, which may access to unused areas of sliding dictionary. + memset(NewMem,0,Size); + + Mem[BlockNum]=NewMem; + TotalSize+=Size; + MemSize[BlockNum]=TotalSize; + BlockNum++; + } + if (TotalSize<WinSize) // Not found enough free blocks. + throw std::bad_alloc(); +} + + +byte& FragmentedWindow::operator [](size_t Item) +{ + if (Item<MemSize[0]) + return Mem[0][Item]; + for (uint I=1;I<ASIZE(MemSize);I++) + if (Item<MemSize[I]) + return Mem[I][Item-MemSize[I-1]]; + return Mem[0][0]; // Must never happen; +} + + +void FragmentedWindow::CopyString(uint Length,uint Distance,size_t &UnpPtr,size_t MaxWinMask) +{ + size_t SrcPtr=UnpPtr-Distance; + while (Length-- > 0) + { + (*this)[UnpPtr]=(*this)[SrcPtr++ & MaxWinMask]; + // We need to have masked UnpPtr after quit from loop, so it must not + // be replaced with '(*this)[UnpPtr++ & MaxWinMask]' + UnpPtr=(UnpPtr+1) & MaxWinMask; + } +} + + +void FragmentedWindow::CopyData(byte *Dest,size_t WinPos,size_t Size) +{ + for (size_t I=0;I<Size;I++) + Dest[I]=(*this)[WinPos+I]; +} + + +size_t FragmentedWindow::GetBlockSize(size_t StartPos,size_t RequiredSize) +{ + for (uint I=0;I<ASIZE(MemSize);I++) + if (StartPos<MemSize[I]) + return Min(MemSize[I]-StartPos,RequiredSize); + return 0; // Must never be here. +} diff --git a/src/thirdparty/unrar/unpackinline.cpp b/src/thirdparty/unrar/unpackinline.cpp index 807c24ded..70b533dbb 100644 --- a/src/thirdparty/unrar/unpackinline.cpp +++ b/src/thirdparty/unrar/unpackinline.cpp @@ -64,9 +64,11 @@ _forceinline void Unpack::CopyString(uint Length,uint Distance) if (Length>6) { Dest[6]=Src[6]; } } } } } } } // Close all nested "if"s. } else - while (Length--) // Slow copying with all possible precautions. + while (Length-- > 0) // Slow copying with all possible precautions. { Window[UnpPtr]=Window[SrcPtr++ & MaxWinMask]; + // We need to have masked UnpPtr after quit from loop, so it must not + // be replaced with 'Window[UnpPtr++ & MaxWinMask]' UnpPtr=(UnpPtr+1) & MaxWinMask; } } diff --git a/src/thirdparty/unrar/version.hpp b/src/thirdparty/unrar/version.hpp index 0e53da493..f34a08f54 100644 --- a/src/thirdparty/unrar/version.hpp +++ b/src/thirdparty/unrar/version.hpp @@ -1,6 +1,6 @@ #define RARVER_MAJOR 5 #define RARVER_MINOR 0 -#define RARVER_BETA 3 -#define RARVER_DAY 9 +#define RARVER_BETA 4 +#define RARVER_DAY 20 #define RARVER_MONTH 5 #define RARVER_YEAR 2013 |