diff --git a/Frameworks/File_Extractor/File_Extractor.xcodeproj/project.pbxproj b/Frameworks/File_Extractor/File_Extractor.xcodeproj/project.pbxproj index d0c8bd143..73fca1ced 100644 --- a/Frameworks/File_Extractor/File_Extractor.xcodeproj/project.pbxproj +++ b/Frameworks/File_Extractor/File_Extractor.xcodeproj/project.pbxproj @@ -111,7 +111,6 @@ 8359007517FEF40E0060F3ED /* getbits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8359FFE917FEF40E0060F3ED /* getbits.cpp */; }; 8359007617FEF40E0060F3ED /* getbits.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 8359FFEA17FEF40E0060F3ED /* getbits.hpp */; }; 8359007717FEF40E0060F3ED /* headers.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 8359FFEB17FEF40E0060F3ED /* headers.hpp */; }; - 8359007917FEF40E0060F3ED /* model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8359FFED17FEF40E0060F3ED /* model.cpp */; }; 8359007A17FEF40E0060F3ED /* model.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 8359FFEE17FEF40E0060F3ED /* model.hpp */; }; 8359007B17FEF40E0060F3ED /* rar.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 8359FFEF17FEF40E0060F3ED /* rar.hpp */; }; 8359007C17FEF40E0060F3ED /* rarvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8359FFF017FEF40E0060F3ED /* rarvm.cpp */; }; @@ -119,20 +118,29 @@ 8359007E17FEF40E0060F3ED /* rarvmtbl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8359FFF217FEF40E0060F3ED /* rarvmtbl.cpp */; }; 8359007F17FEF40E0060F3ED /* rawread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8359FFF317FEF40E0060F3ED /* rawread.cpp */; }; 8359008017FEF40E0060F3ED /* rawread.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 8359FFF417FEF40E0060F3ED /* rawread.hpp */; }; - 8359008217FEF40E0060F3ED /* suballoc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8359FFF617FEF40E0060F3ED /* suballoc.cpp */; }; 8359008317FEF40E0060F3ED /* suballoc.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 8359FFF717FEF40E0060F3ED /* suballoc.hpp */; }; 8359008517FEF40E0060F3ED /* unicode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8359FFF917FEF40E0060F3ED /* unicode.cpp */; }; 8359008617FEF40E0060F3ED /* unicode.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 8359FFFA17FEF40E0060F3ED /* unicode.hpp */; }; 8359008717FEF40E0060F3ED /* unpack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8359FFFB17FEF40E0060F3ED /* unpack.cpp */; }; 8359008817FEF40E0060F3ED /* unpack.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 8359FFFC17FEF40E0060F3ED /* unpack.hpp */; }; - 8359008917FEF40E0060F3ED /* unpack15.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8359FFFD17FEF40E0060F3ED /* unpack15.cpp */; }; - 8359008A17FEF40E0060F3ED /* unpack20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8359FFFE17FEF40E0060F3ED /* unpack20.cpp */; }; 8359008B17FEF40E0060F3ED /* unrar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8359FFFF17FEF40E0060F3ED /* unrar.cpp */; }; 8359008C17FEF40E0060F3ED /* unrar.h in Headers */ = {isa = PBXBuildFile; fileRef = 8359000017FEF40E0060F3ED /* unrar.h */; }; 8359008D17FEF40E0060F3ED /* unrar_misc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8359000117FEF40E0060F3ED /* unrar_misc.cpp */; }; 8359009117FEF5830060F3ED /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8359009017FEF5830060F3ED /* libz.dylib */; }; 8359009F17FF073E0060F3ED /* 7zStream.c in Sources */ = {isa = PBXBuildFile; fileRef = 8359009E17FF073E0060F3ED /* 7zStream.c */; }; 8359FF4A17FEF39F0060F3ED /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8359FF4817FEF39F0060F3ED /* InfoPlist.strings */; }; + 83C2109719CD81F50093C461 /* headers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83C2108E19CD81F50093C461 /* headers.cpp */; }; + 83C2109819CD81F50093C461 /* headers5.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83C2108F19CD81F50093C461 /* headers5.hpp */; }; + 83C2109B19CD88A30093C461 /* secpassword.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83C2109A19CD88A30093C461 /* secpassword.cpp */; }; + 83C210A219CD89C70093C461 /* hash.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83C2109C19CD89C70093C461 /* hash.cpp */; }; + 83C210A419CD89C70093C461 /* blake2s.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83C2109E19CD89C70093C461 /* blake2s.cpp */; }; + 83C210A519CD89C70093C461 /* blake2s.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83C2109F19CD89C70093C461 /* blake2s.hpp */; }; + 83C210A719CD89C70093C461 /* hash.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83C210A119CD89C70093C461 /* hash.hpp */; }; + 83C210AA19CD8F8F0093C461 /* strfn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83C210A819CD8F8F0093C461 /* strfn.cpp */; }; + 83C210AB19CD8F8F0093C461 /* strfn.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83C210A919CD8F8F0093C461 /* strfn.hpp */; }; + 83C210AD19CD92960093C461 /* pathfn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83C210AC19CD92960093C461 /* pathfn.cpp */; }; + 83C210B019CD97DB0093C461 /* timefn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83C210AE19CD97DB0093C461 /* timefn.cpp */; }; + 83C210B119CD97DB0093C461 /* timefn.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83C210AF19CD97DB0093C461 /* timefn.hpp */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -247,7 +255,6 @@ 8359FFE917FEF40E0060F3ED /* getbits.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = getbits.cpp; sourceTree = ""; }; 8359FFEA17FEF40E0060F3ED /* getbits.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = getbits.hpp; sourceTree = ""; }; 8359FFEB17FEF40E0060F3ED /* headers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = headers.hpp; sourceTree = ""; }; - 8359FFED17FEF40E0060F3ED /* model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = model.cpp; sourceTree = ""; }; 8359FFEE17FEF40E0060F3ED /* model.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = model.hpp; sourceTree = ""; }; 8359FFEF17FEF40E0060F3ED /* rar.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = rar.hpp; sourceTree = ""; }; 8359FFF017FEF40E0060F3ED /* rarvm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rarvm.cpp; sourceTree = ""; }; @@ -255,15 +262,24 @@ 8359FFF217FEF40E0060F3ED /* rarvmtbl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rarvmtbl.cpp; sourceTree = ""; }; 8359FFF317FEF40E0060F3ED /* rawread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rawread.cpp; sourceTree = ""; }; 8359FFF417FEF40E0060F3ED /* rawread.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = rawread.hpp; sourceTree = ""; }; - 8359FFF617FEF40E0060F3ED /* suballoc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = suballoc.cpp; sourceTree = ""; }; 8359FFF717FEF40E0060F3ED /* suballoc.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = suballoc.hpp; sourceTree = ""; }; 8359FFF917FEF40E0060F3ED /* unicode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unicode.cpp; sourceTree = ""; }; 8359FFFA17FEF40E0060F3ED /* unicode.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = unicode.hpp; sourceTree = ""; }; 8359FFFB17FEF40E0060F3ED /* unpack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unpack.cpp; sourceTree = ""; }; 8359FFFC17FEF40E0060F3ED /* unpack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = unpack.hpp; sourceTree = ""; }; - 8359FFFD17FEF40E0060F3ED /* unpack15.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unpack15.cpp; sourceTree = ""; }; - 8359FFFE17FEF40E0060F3ED /* unpack20.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unpack20.cpp; sourceTree = ""; }; 8359FFFF17FEF40E0060F3ED /* unrar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unrar.cpp; sourceTree = ""; }; + 83C2108E19CD81F50093C461 /* headers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = headers.cpp; sourceTree = ""; }; + 83C2108F19CD81F50093C461 /* headers5.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = headers5.hpp; sourceTree = ""; }; + 83C2109A19CD88A30093C461 /* secpassword.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = secpassword.cpp; sourceTree = ""; }; + 83C2109C19CD89C70093C461 /* hash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hash.cpp; sourceTree = ""; }; + 83C2109E19CD89C70093C461 /* blake2s.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blake2s.cpp; sourceTree = ""; }; + 83C2109F19CD89C70093C461 /* blake2s.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = blake2s.hpp; sourceTree = ""; }; + 83C210A119CD89C70093C461 /* hash.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = hash.hpp; sourceTree = ""; }; + 83C210A819CD8F8F0093C461 /* strfn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strfn.cpp; sourceTree = ""; }; + 83C210A919CD8F8F0093C461 /* strfn.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = strfn.hpp; sourceTree = ""; }; + 83C210AC19CD92960093C461 /* pathfn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pathfn.cpp; sourceTree = ""; }; + 83C210AE19CD97DB0093C461 /* timefn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = timefn.cpp; sourceTree = ""; }; + 83C210AF19CD97DB0093C461 /* timefn.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = timefn.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -447,6 +463,18 @@ 8359FFDC17FEF40E0060F3ED /* unrar */ = { isa = PBXGroup; children = ( + 83C210AE19CD97DB0093C461 /* timefn.cpp */, + 83C210AF19CD97DB0093C461 /* timefn.hpp */, + 83C210AC19CD92960093C461 /* pathfn.cpp */, + 83C210A819CD8F8F0093C461 /* strfn.cpp */, + 83C210A919CD8F8F0093C461 /* strfn.hpp */, + 83C2109C19CD89C70093C461 /* hash.cpp */, + 83C2109E19CD89C70093C461 /* blake2s.cpp */, + 83C2109F19CD89C70093C461 /* blake2s.hpp */, + 83C210A119CD89C70093C461 /* hash.hpp */, + 83C2109A19CD88A30093C461 /* secpassword.cpp */, + 83C2108E19CD81F50093C461 /* headers.cpp */, + 83C2108F19CD81F50093C461 /* headers5.hpp */, 8359FFDD17FEF40E0060F3ED /* archive.cpp */, 8359FFDE17FEF40E0060F3ED /* archive.hpp */, 8359FFDF17FEF40E0060F3ED /* arcread.cpp */, @@ -461,7 +489,6 @@ 8359FFE917FEF40E0060F3ED /* getbits.cpp */, 8359FFEA17FEF40E0060F3ED /* getbits.hpp */, 8359FFEB17FEF40E0060F3ED /* headers.hpp */, - 8359FFED17FEF40E0060F3ED /* model.cpp */, 8359FFEE17FEF40E0060F3ED /* model.hpp */, 8359FFEF17FEF40E0060F3ED /* rar.hpp */, 8359FFF017FEF40E0060F3ED /* rarvm.cpp */, @@ -469,14 +496,11 @@ 8359FFF217FEF40E0060F3ED /* rarvmtbl.cpp */, 8359FFF317FEF40E0060F3ED /* rawread.cpp */, 8359FFF417FEF40E0060F3ED /* rawread.hpp */, - 8359FFF617FEF40E0060F3ED /* suballoc.cpp */, 8359FFF717FEF40E0060F3ED /* suballoc.hpp */, 8359FFF917FEF40E0060F3ED /* unicode.cpp */, 8359FFFA17FEF40E0060F3ED /* unicode.hpp */, 8359FFFB17FEF40E0060F3ED /* unpack.cpp */, 8359FFFC17FEF40E0060F3ED /* unpack.hpp */, - 8359FFFD17FEF40E0060F3ED /* unpack15.cpp */, - 8359FFFE17FEF40E0060F3ED /* unpack20.cpp */, 8359FFFF17FEF40E0060F3ED /* unrar.cpp */, 8359000017FEF40E0060F3ED /* unrar.h */, 8359000117FEF40E0060F3ED /* unrar_misc.cpp */, @@ -495,6 +519,8 @@ 8359005517FEF40E0060F3ED /* blargg_errors.h in Headers */, 8359003417FEF40E0060F3ED /* Lzma2Enc.h in Headers */, 8359008817FEF40E0060F3ED /* unpack.hpp in Headers */, + 83C210AB19CD8F8F0093C461 /* strfn.hpp in Headers */, + 83C210A719CD89C70093C461 /* hash.hpp in Headers */, 8359001817FEF40E0060F3ED /* 7zIn.h in Headers */, 8359003D17FEF40E0060F3ED /* LzmaLib.h in Headers */, 8359001417FEF40E0060F3ED /* 7zFile.h in Headers */, @@ -524,7 +550,9 @@ 8359007617FEF40E0060F3ED /* getbits.hpp in Headers */, 8359001A17FEF40E0060F3ED /* 7zItem.h in Headers */, 8359007B17FEF40E0060F3ED /* rar.hpp in Headers */, + 83C210B119CD97DB0093C461 /* timefn.hpp in Headers */, 8359004917FEF40E0060F3ED /* RotateDefs.h in Headers */, + 83C2109819CD81F50093C461 /* headers5.hpp in Headers */, 8359000417FEF40E0060F3ED /* 7z.h in Headers */, 8359004A17FEF40E0060F3ED /* Threads.h in Headers */, 8359006417FEF40E0060F3ED /* Zip7_Extractor.h in Headers */, @@ -539,6 +567,7 @@ 8359008017FEF40E0060F3ED /* rawread.hpp in Headers */, 8359008317FEF40E0060F3ED /* suballoc.hpp in Headers */, 8359005817FEF40E0060F3ED /* Data_Reader.h in Headers */, + 83C210A519CD89C70093C461 /* blake2s.hpp in Headers */, 8359007D17FEF40E0060F3ED /* rarvm.hpp in Headers */, 8359005217FEF40E0060F3ED /* blargg_config.h in Headers */, 8359006017FEF40E0060F3ED /* Gzip_Reader.h in Headers */, @@ -636,7 +665,6 @@ 8359003A17FEF40E0060F3ED /* LzmaEnc.c in Sources */, 8359001E17FEF40E0060F3ED /* Alloc.c in Sources */, 8359008D17FEF40E0060F3ED /* unrar_misc.cpp in Sources */, - 8359007917FEF40E0060F3ED /* model.cpp in Sources */, 8359007117FEF40E0060F3ED /* crc.cpp in Sources */, 8359003717FEF40E0060F3ED /* Lzma86Enc.c in Sources */, 8359006917FEF40E0060F3ED /* archive.cpp in Sources */, @@ -645,11 +673,12 @@ 8359007F17FEF40E0060F3ED /* rawread.cpp in Sources */, 8359000717FEF40E0060F3ED /* 7zBuf.c in Sources */, 8359002917FEF40E0060F3ED /* Delta.c in Sources */, + 83C2109719CD81F50093C461 /* headers.cpp in Sources */, 8359005017FEF40E0060F3ED /* blargg_common.cpp in Sources */, 8359005F17FEF40E0060F3ED /* Gzip_Reader.cpp in Sources */, + 83C210AD19CD92960093C461 /* pathfn.cpp in Sources */, 8359002D17FEF40E0060F3ED /* LzFindMt.c in Sources */, 8359000B17FEF40E0060F3ED /* 7zCrc.c in Sources */, - 8359008917FEF40E0060F3ED /* unpack15.cpp in Sources */, 8359009F17FF073E0060F3ED /* 7zStream.c in Sources */, 8359000917FEF40E0060F3ED /* 7zBuf2.c in Sources */, 8359002517FEF40E0060F3ED /* BraIA64.c in Sources */, @@ -661,7 +690,7 @@ 8359006117FEF40E0060F3ED /* Rar_Extractor.cpp in Sources */, 8359003F17FEF40E0060F3ED /* MtCoder.c in Sources */, 8359003317FEF40E0060F3ED /* Lzma2Enc.c in Sources */, - 8359008217FEF40E0060F3ED /* suballoc.cpp in Sources */, + 83C210AA19CD8F8F0093C461 /* strfn.cpp in Sources */, 8359003617FEF40E0060F3ED /* Lzma86Dec.c in Sources */, 8359002217FEF40E0060F3ED /* Bra.c in Sources */, 8359000517FEF40E0060F3ED /* 7zAlloc.c in Sources */, @@ -672,15 +701,18 @@ 8359003117FEF40E0060F3ED /* Lzma2Dec.c in Sources */, 8359007217FEF40E0060F3ED /* encname.cpp in Sources */, 8359004117FEF40E0060F3ED /* Threads.c in Sources */, + 83C210B019CD97DB0093C461 /* timefn.cpp in Sources */, 8359008717FEF40E0060F3ED /* unpack.cpp in Sources */, 8359003C17FEF40E0060F3ED /* LzmaLib.c in Sources */, 8359005917FEF40E0060F3ED /* fex.cpp in Sources */, + 83C2109B19CD88A30093C461 /* secpassword.cpp in Sources */, + 83C210A219CD89C70093C461 /* hash.cpp in Sources */, 8359004717FEF40E0060F3ED /* Ppmd7Enc.c in Sources */, - 8359008A17FEF40E0060F3ED /* unpack20.cpp in Sources */, 8359004E17FEF40E0060F3ED /* Binary_Extractor.cpp in Sources */, 8359007417FEF40E0060F3ED /* extract.cpp in Sources */, 8359006517FEF40E0060F3ED /* Zip_Extractor.cpp in Sources */, 8359002717FEF40E0060F3ED /* CpuArch.c in Sources */, + 83C210A419CD89C70093C461 /* blake2s.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -721,6 +753,7 @@ GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", + _UNIX, ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -754,6 +787,7 @@ ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PREPROCESSOR_DEFINITIONS = _UNIX; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/acknow.txt b/Frameworks/File_Extractor/File_Extractor/unrar/acknow.txt new file mode 100644 index 000000000..a68b67277 --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/acknow.txt @@ -0,0 +1,92 @@ + ACKNOWLEDGMENTS + +* We used "Screaming Fast Galois Field Arithmetic Using Intel + SIMD Instructions" paper by James S. Plank, Kevin M. Greenan + and Ethan L. Miller to improve Reed-Solomon coding performance. + Also we are grateful to Artem Drobanov and Bulat Ziganshin + for samples and ideas allowed to make Reed-Solomon coding + more efficient. + +* RAR text compression algorithm is based on Dmitry Shkarin PPMII + and Dmitry Subbotin carryless rangecoder public domain source code. + You may find it in ftp.elf.stuba.sk/pub/pc/pack. + +* RAR encryption includes parts of code from Szymon Stefanek + and Brian Gladman AES implementations also as Steve Reid SHA-1 source. + + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + + Source code of this package also as other cryptographic technology + and computing project related links are available on Brian Gladman's + web site: http://www.gladman.me.uk + +* RAR uses CRC32 function based on Intel Slicing-by-8 algorithm. + Original Intel Slicing-by-8 code is available here: + + http://sourceforge.net/projects/slicing-by-8/ + + Original Intel Slicing-by-8 code is licensed under BSD License + available at http://www.opensource.org/licenses/bsd-license.html + + Copyright (c) 2004-2006 Intel Corporation. + All Rights Reserved + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with + the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +* RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ), + designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn + and Christian Winnerlein. + +* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed + to significantly improve RAR compression and speed. diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/archive.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/archive.cpp index 20b6cd27e..528da7506 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/archive.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/archive.cpp @@ -5,92 +5,89 @@ Archive::Archive() : Raw( this ) { - OldFormat=false; + Format=RARFMT15; Solid=false; CurBlockPos=0; NextBlockPos=0; - memset(&NewMhd,0,sizeof(NewMhd)); - NewMhd.HeadType=MAIN_HEAD; - NewMhd.HeadSize=SIZEOF_NEWMHD; - HeaderCRC=0; + memset(&MainHead,0,sizeof(MainHead)); + memset(&EndArcHead,0,sizeof(EndArcHead)); + + HeaderCRC=0; } -bool Archive::IsSignature(byte *D) +RARFORMAT Archive::IsSignature(const byte *D,size_t Size) { - bool Valid=false; - if (D[0]==0x52) - { + RARFORMAT Type=RARFMT_NONE; + if (Size>=1 && D[0]==0x52) #ifndef SFX_MODULE - if (D[1]==0x45 && D[2]==0x7e && D[3]==0x5e) - { - OldFormat=true; - Valid=true; - } + if (Size>=4 && D[1]==0x45 && D[2]==0x7e && D[3]==0x5e) + Type=RARFMT14; else #endif - if (D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07 && D[6]==0x00) + if (Size>=7 && D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07) { - OldFormat=false; - Valid=true; + // We check for non-zero last signature byte, so we can return + // a sensible warning in case we'll want to change the archive + // format sometimes in the future. + if (D[6]==0) + Type=RARFMT15; + else if (D[6]==1) + Type=RARFMT50; + else if (D[6]==2) + Type=RARFMT_FUTURE; } - } - return(Valid); + return Type; } unrar_err_t Archive::IsArchive() { - if (Read(MarkHead.Mark,SIZEOF_MARKHEAD)!=SIZEOF_MARKHEAD) + if (Read(MarkHead.Mark,SIZEOF_MARKHEAD3)!=SIZEOF_MARKHEAD3) return unrar_err_not_arc; - if (IsSignature(MarkHead.Mark)) + RARFORMAT Type; + if ((Type=IsSignature(MarkHead.Mark,SIZEOF_MARKHEAD3))!=RARFMT_NONE) { - if (OldFormat) - Seek(0,SEEK_SET); + Format=Type; + if (Format==RARFMT14) + Seek(Tell()-SIZEOF_MARKHEAD3,SEEK_SET); } else { if (SFXSize==0) return unrar_err_not_arc; } + if (Format==RARFMT_FUTURE) + return unrar_err_new_algo; + if (Format==RARFMT50) // RAR 5.0 signature is one byte longer. + { + Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1); + if (MarkHead.Mark[SIZEOF_MARKHEAD3]!=0) + return unrar_err_not_arc; + MarkHead.HeadSize=SIZEOF_MARKHEAD5; + } + else + MarkHead.HeadSize=SIZEOF_MARKHEAD3; - unrar_err_t error = - ReadHeader(); - // (no need to seek to next) + unrar_err_t error; + size_t HeaderSize; + while ((error=ReadHeader(&HeaderSize))==unrar_ok && HeaderSize!=0) + { + HEADER_TYPE Type=GetHeaderType(); + // In RAR 5.0 we need to quit after reading HEAD_CRYPT if we wish to + // avoid the password prompt. + if (Type==HEAD_MAIN) + break; + SeekToNext(); + } if ( error != unrar_ok ) return error; -#ifndef SFX_MODULE - if (OldFormat) - { - NewMhd.Flags=OldMhd.Flags & 0x3f; - NewMhd.HeadSize=OldMhd.HeadSize; - } - else -#endif - { - if (HeaderCRC!=NewMhd.HeadCRC) - { - return unrar_err_corrupt; - } - } - bool - Volume=(NewMhd.Flags & MHD_VOLUME); - Solid=(NewMhd.Flags & MHD_SOLID)!=0; - bool - Encrypted=(NewMhd.Flags & MHD_PASSWORD)!=0; - - // (removed decryption and volume handling) - - if ( Encrypted ) - return unrar_err_encrypted; - - if ( Volume ) - return unrar_err_segmented; - - return unrar_ok; + SeekToNext(); + + return unrar_ok; } void Archive::SeekToNext() diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/archive.hpp b/Frameworks/File_Extractor/File_Extractor/unrar/archive.hpp index 4d117c839..dbd32a651 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/archive.hpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/archive.hpp @@ -4,39 +4,49 @@ typedef ComprDataIO File; #include "rawread.hpp" +enum RARFORMAT {RARFMT_NONE,RARFMT14,RARFMT15,RARFMT50,RARFMT_FUTURE}; + class Archive:public File { private: - bool IsSignature(byte *D); - void ConvertUnknownHeader(); - int ReadOldHeader(); + void ConvertFileHeader(FileHeader *hd); + void WriteBlock50(HEADER_TYPE HeaderType,BaseBlock *wb,bool OnlySetSize,bool NonFinalWrite); + unrar_err_t ReadHeader14(size_t *ReadSize); + unrar_err_t ReadHeader15(size_t *ReadSize); + unrar_err_t ReadHeader50(size_t *ReadSize); + unrar_err_t ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb); RawRead Raw; - MarkHeader MarkHead; - OldMainHeader OldMhd; - - int CurHeaderType; - + HEADER_TYPE CurHeaderType; + public: Archive(); + RARFORMAT IsSignature(const byte *D,size_t Size); unrar_err_t IsArchive(); - unrar_err_t ReadHeader(); + size_t SearchBlock(HEADER_TYPE HeaderType); + size_t SearchSubBlock(const wchar *Type); + size_t SearchRR(); + unrar_err_t ReadHeader(size_t *ReadSize); void SeekToNext(); bool IsArcDir(); bool IsArcLabel(); - int GetHeaderType() {return(CurHeaderType);}; + int64 GetStartPos(); + HEADER_TYPE GetHeaderType() {return(CurHeaderType);}; BaseBlock ShortBlock; - MainHeader NewMhd; - FileHeader NewLhd; + MarkHeader MarkHead; + MainHeader MainHead; + FileHeader FileHead; + EndArcHeader EndArcHead; SubBlockHeader SubBlockHead; FileHeader SubHead; ProtectHeader ProtectHead; - Int64 CurBlockPos; - Int64 NextBlockPos; + int64 CurBlockPos; + int64 NextBlockPos; + RARFORMAT Format; bool Solid; enum { SFXSize = 0 }; // self-extracting not supported ushort HeaderCRC; diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/arcread.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/arcread.cpp index 626ec7065..727b0ce3c 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/arcread.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/arcread.cpp @@ -5,310 +5,731 @@ #include "encname.hpp" // arcread.cpp -unrar_err_t Archive::ReadHeader() +unrar_err_t Archive::ReadHeader(size_t * ReadSize_) { CurBlockPos=Tell(); - + + unrar_err_t Error; + size_t ReadSize; + switch(Format) + { #ifndef SFX_MODULE - if (OldFormat) - { - ReadOldHeader(); - - if ( Raw.Size() == 0 ) - return unrar_err_arc_eof; // right at end of file - - if ( Raw.PaddedSize() > 0 ) // added check - return unrar_err_corrupt; // missing data - - return unrar_ok; - } + case RARFMT14: + Error=ReadHeader14(&ReadSize); + break; #endif + case RARFMT15: + Error=ReadHeader15(&ReadSize); + break; + case RARFMT50: + Error=ReadHeader50(&ReadSize); + break; + + default: // unreachable + Error=unrar_err_corrupt; + break; + } + + if (Error!=unrar_ok) + return Error; + + if (ReadSize>0 & NextBlockPos<=CurBlockPos) + return unrar_err_corrupt; - Raw.Reset(); - - // (removed decryption) - - Raw.Read(SIZEOF_SHORTBLOCKHEAD); - if (Raw.Size()==0) - { - return unrar_err_arc_eof; // right at end of file - } - - Raw.Get(ShortBlock.HeadCRC); - byte HeadType; - Raw.Get(HeadType); - ShortBlock.HeadType=(HEADER_TYPE)HeadType; - Raw.Get(ShortBlock.Flags); - Raw.Get(ShortBlock.HeadSize); - if (ShortBlock.HeadSize 0 ) // fewer than requested bytes read above? - return unrar_err_corrupt; // missing data - - NextBlockPos=CurBlockPos+ShortBlock.HeadSize; - - switch(ShortBlock.HeadType) - { - case MAIN_HEAD: - *(BaseBlock *)&NewMhd=ShortBlock; - Raw.Get(NewMhd.HighPosAV); - Raw.Get(NewMhd.PosAV); - check( Raw.ReadPos == Raw.DataSize ); // we should have read all fields - break; - case FILE_HEAD: - case NEWSUB_HEAD: - { - FileHeader *hd=ShortBlock.HeadType==FILE_HEAD ? &NewLhd:&SubHead; - *(BaseBlock *)hd=ShortBlock; - Raw.Get(hd->PackSize); - Raw.Get(hd->UnpSize); - Raw.Get(hd->HostOS); - Raw.Get(hd->FileCRC); - Raw.Get(hd->FileTime); - Raw.Get(hd->UnpVer); - Raw.Get(hd->Method); - Raw.Get(hd->NameSize); - Raw.Get(hd->FileAttr); - if (hd->Flags & LHD_LARGE) - { - Raw.Get(hd->HighPackSize); - Raw.Get(hd->HighUnpSize); - } - else - { - hd->HighPackSize=hd->HighUnpSize=0; - if (hd->UnpSize==0xffffffff) - { - // TODO: what the heck is this for anyway? - hd->UnpSize=0; - hd->HighUnpSize=0x7fffffff; - } - } - hd->FullPackSize=int32to64(hd->HighPackSize,hd->PackSize); - hd->FullUnpSize=int32to64(hd->HighUnpSize,hd->UnpSize); - - if ( int32to64( 1, 0 ) == 0 && (hd->HighPackSize || hd->HighUnpSize) ) - return unrar_err_huge; - - char (&FileName) [sizeof hd->FileName] = hd->FileName; // eliminated local buffer - int NameSize=Min(hd->NameSize,sizeof(FileName)-1); - Raw.Get((byte *)FileName,NameSize); - FileName[NameSize]=0; - - if (hd->HeadType==NEWSUB_HEAD) - { - // have to adjust this, even through we're ignoring this block - NextBlockPos+=hd->FullPackSize; - break; - } - else - if (hd->HeadType==FILE_HEAD) - { - if (hd->Flags & LHD_UNICODE) - { - EncodeFileName NameCoder; - int Length=(int)strlen(FileName); - if (Length==hd->NameSize) - { - UtfToWide(FileName,hd->FileNameW,sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0])-1); - WideToChar(hd->FileNameW,hd->FileName,sizeof(hd->FileName)/sizeof(hd->FileName[0])-1); - ExtToInt(hd->FileName,hd->FileName); - } - else - { - Length++; - NameCoder.Decode(FileName,(byte *)FileName+Length, - hd->NameSize-Length,hd->FileNameW, - sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0])); - } - if (*hd->FileNameW==0) - hd->Flags &= ~LHD_UNICODE; - } - else - *hd->FileNameW=0; - - ConvertUnknownHeader(); - } - if (hd->Flags & LHD_SALT) - Raw.Get(hd->Salt,SALT_SIZE); - hd->mtime.SetDos(hd->FileTime); - if (hd->Flags & LHD_EXTTIME) - { - ushort Flags; - Raw.Get(Flags); - // Ignore additional time information - for (int I=0;I<4;I++) - { - uint rmode=Flags>>(3-I)*4; - if ((rmode & 8)==0) - continue; - if (I!=0) - { - uint DosTime; - Raw.Get(DosTime); - } - - // skip time info - int count=rmode&3; - for (int J=0;JFullPackSize; - bool CRCProcessedOnly=(hd->Flags & LHD_COMMENT)!=0; - HeaderCRC=~Raw.GetCRC(CRCProcessedOnly)&0xffff; - if (hd->HeadCRC!=HeaderCRC) - return unrar_err_corrupt; - check( CRCProcessedOnly == false ); // I need to test on archives where this doesn't hold - check( Raw.ReadPos == Raw.DataSize ); // we should have read all fields - } - break; -#ifndef SFX_MODULE - // Handle these block types just so we can adjust NextBlockPos properly - case PROTECT_HEAD: - Raw.Get(ProtectHead.DataSize); - NextBlockPos+=ProtectHead.DataSize; - break; - case SUB_HEAD: - Raw.Get(SubBlockHead.DataSize); - NextBlockPos+=SubBlockHead.DataSize; - break; -#endif - default: - if (ShortBlock.Flags & LONG_BLOCK) - { - uint DataSize; - Raw.Get(DataSize); - NextBlockPos+=DataSize; - } - break; - } - HeaderCRC=~Raw.GetCRC(false)&0xffff; - CurHeaderType=ShortBlock.HeadType; - // (removed decryption) - - if (NextBlockPosReset(); + + *(BaseBlock *)hd=ShortBlock; + + hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0; + hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0; + hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0; + hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0; + hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0; + hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY; + hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5); + hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0; + hd->Version=(hd->Flags & LHD_VERSION)!=0; + + hd->DataSize=Raw.Get4(); + uint LowUnpSize=Raw.Get4(); + hd->HostOS=Raw.Get1(); + + hd->FileHash.Type=HASH_CRC32; + hd->FileHash.CRC32=Raw.Get4(); + + uint FileTime=Raw.Get4(); + hd->UnpVer=Raw.Get1(); + hd->Method=Raw.Get1()-0x30; + size_t NameSize=Raw.Get2(); + hd->FileAttr=Raw.Get4(); + + if (hd->Encrypted) + return unrar_err_encrypted; + + hd->HSType=HSYS_UNKNOWN; + if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS) + hd->HSType=HSYS_UNIX; + else + if (hd->HostOSHSType=HSYS_WINDOWS; + + hd->RedirType=FSREDIR_NONE; + + // RAR 4.x Unix symlink. + if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000) + { + hd->RedirType=FSREDIR_UNIXSYMLINK; + *hd->RedirName=0; + } + + hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0; + + hd->LargeFile=(hd->Flags & LHD_LARGE)!=0; + + uint HighPackSize,HighUnpSize; + if (hd->LargeFile) + { + HighPackSize=Raw.Get4(); + HighUnpSize=Raw.Get4(); + hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff); + } + else + { + HighPackSize=HighUnpSize=0; + // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates + // that we do not know the unpacked file size and must unpack it + // until we find the end of file marker in compressed data. + hd->UnknownUnpSize=(LowUnpSize==0xffffffff); + } + hd->PackSize=int32to64(HighPackSize,hd->DataSize); + hd->UnpSize=int32to64(HighUnpSize,LowUnpSize); + if (hd->UnknownUnpSize) + hd->UnpSize=INT64NDF; + + char FileName[NM*4]; + size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1); + Raw.GetB((byte *)FileName,ReadNameSize); + FileName[ReadNameSize]=0; + + if (FileBlock) + { + if ((hd->Flags & LHD_UNICODE)!=0) + { + EncodeFileName NameCoder; + size_t Length=strlen(FileName); + Length++; + NameCoder.Decode(FileName,(byte *)FileName+Length, + NameSize-Length,hd->FileName, + ASIZE(hd->FileName)); + } + else + *hd->FileName=0; + + char AnsiName[NM]; + IntToExt(FileName,AnsiName,ASIZE(AnsiName)); + GetWideName(AnsiName,hd->FileName,hd->FileName,ASIZE(hd->FileName)); + + ConvertFileHeader(hd); + } + else + { + CharToWide(FileName,hd->FileName,ASIZE(hd->FileName)); + + // Calculate the size of optional data. + int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3); + if ((hd->Flags & LHD_SALT)!=0) + return unrar_err_encrypted; + + if (DataSize>0) + { + // Here we read optional additional fields for subheaders. + // They are stored after the file name and before salt. + hd->SubData.Alloc(DataSize); + Raw.GetB(&hd->SubData[0],DataSize); + } + } + if ((hd->Flags & LHD_SALT)!=0) + return unrar_err_encrypted; + hd->mtime.SetDos(FileTime); + if ((hd->Flags & LHD_EXTTIME)!=0) + { + ushort Flags=Raw.Get2(); + RarTime *tbl[4]; + tbl[0]=&FileHead.mtime; + tbl[1]=&FileHead.ctime; + tbl[2]=&FileHead.atime; + tbl[3]=NULL; // Archive time is not used now. + for (int I=0;I<4;I++) + { + RarTime *CurTime=tbl[I]; + uint rmode=Flags>>(3-I)*4; + if ((rmode & 8)==0 || CurTime==NULL) + continue; + if (I!=0) + { + uint DosTime=Raw.Get4(); + CurTime->SetDos(DosTime); + } + RarLocalTime rlt; + CurTime->GetLocal(&rlt); + if (rmode & 4) + rlt.Second++; + rlt.Reminder=0; + int count=rmode&3; + for (int J=0;JSetLocal(&rlt); + } + } + NextBlockPos+=hd->PackSize; + bool CRCProcessedOnly=hd->CommentInHeader; + ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly); + if (hd->HeadCRC!=HeaderCRC) + return unrar_err_corrupt; + } + break; + case HEAD_ENDARC: + *(BaseBlock *)&EndArcHead=ShortBlock; + EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0; + EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0; + EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0; + EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0; + if (EndArcHead.DataCRC) + EndArcHead.ArcDataCRC=Raw.Get4(); + if (EndArcHead.StoreVolNumber) + return unrar_err_segmented; + break; + default: + if (ShortBlock.Flags & LONG_BLOCK) + NextBlockPos+=Raw.Get4(); + break; + } + + ushort HeaderCRC=Raw.GetCRC15(false); + + // Old AV header does not have header CRC properly set. + if (ShortBlock.HeadCRC!=HeaderCRC && ShortBlock.HeaderType!=HEAD3_SIGN && + ShortBlock.HeaderType!=HEAD3_AV) + return unrar_err_corrupt; + + if (NextBlockPos<=CurBlockPos) + return unrar_err_corrupt; + + *ReadSize=Raw.Size(); + return unrar_ok; +} - NewLhd.Flags=OldLhd.Flags|LONG_BLOCK; - NewLhd.UnpVer=(OldLhd.UnpVer==2) ? 13 : 10; - NewLhd.Method=OldLhd.Method+0x30; - NewLhd.NameSize=OldLhd.NameSize; - NewLhd.FileAttr=OldLhd.FileAttr; - NewLhd.FileCRC=OldLhd.FileCRC; - NewLhd.FullPackSize=NewLhd.PackSize; - NewLhd.FullUnpSize=NewLhd.UnpSize; - NewLhd.mtime.SetDos(NewLhd.FileTime); - // (removed other times) +unrar_err_t Archive::ReadHeader50(size_t *ReadSize) +{ + Raw.Reset(); + + // Header size must not occupy more than 3 variable length integer bytes + // resulting in 2 MB maximum header size, so here we read 4 byte CRC32 + // followed by 3 bytes or less of header size. + const size_t FirstReadSize=7; // Smallest possible block size. + if (Raw.Read(FirstReadSize)=ShortBlock.HeadSize) + return unrar_err_corrupt; + } + + uint64 DataSize=0; + if ((ShortBlock.Flags & HFL_DATA)!=0) + DataSize=Raw.GetV(); + + NextBlockPos=CurBlockPos+ShortBlock.HeadSize+DataSize; + + switch(ShortBlock.HeaderType) + { + case HEAD_CRYPT: + return unrar_err_encrypted; + case HEAD_MAIN: + { + MainHead.Reset(); + *(BaseBlock *)&MainHead=ShortBlock; + uint ArcFlags=(uint)Raw.GetV(); + + Solid=(ArcFlags & MHFL_SOLID)!=0; + + if (ExtraSize!=0) + { + unrar_err_t Error; + if ((Error=ProcessExtra50(&Raw,(size_t)ExtraSize,&MainHead))!=unrar_ok) + return Error; + } + } + break; + case HEAD_FILE: + case HEAD_SERVICE: + { + FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead; + hd->Reset(); + *(BaseBlock *)hd=ShortBlock; + + bool FileBlock=ShortBlock.HeaderType==HEAD_FILE; + + hd->LargeFile=true; + + hd->PackSize=DataSize; + hd->FileFlags=(uint)Raw.GetV(); + hd->UnpSize=Raw.GetV(); + + hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0; + if (hd->UnknownUnpSize) + hd->UnpSize=INT64NDF; + + hd->MaxSize=Max(hd->PackSize,hd->UnpSize); + hd->FileAttr=(uint)Raw.GetV(); + if ((hd->FileFlags & FHFL_UTIME)!=0) + hd->mtime=(time_t)Raw.Get4(); + + hd->FileHash.Type=HASH_NONE; + if ((hd->FileFlags & FHFL_CRC32)!=0) + { + hd->FileHash.Type=HASH_CRC32; + hd->FileHash.CRC32=Raw.Get4(); + } + + hd->RedirType=FSREDIR_NONE; + + uint CompInfo=(uint)Raw.GetV(); + hd->Method=(CompInfo>>7) & 7; + hd->UnpVer=CompInfo & 0x3f; + + hd->HostOS=(byte)Raw.GetV(); + size_t NameSize=(size_t)Raw.GetV(); + hd->Inherited=(ShortBlock.Flags & HFL_INHERITED)!=0; + + hd->HSType=HSYS_UNKNOWN; + if (hd->HostOS==HOST5_UNIX) + hd->HSType=HSYS_UNIX; + else + if (hd->HostOS==HOST5_WINDOWS) + hd->HSType=HSYS_WINDOWS; + + hd->SplitBefore=(hd->Flags & HFL_SPLITBEFORE)!=0; + hd->SplitAfter=(hd->Flags & HFL_SPLITAFTER)!=0; + hd->SubBlock=(hd->Flags & HFL_CHILD)!=0; + hd->Solid=FileBlock && (CompInfo & FCI_SOLID)!=0; + hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0; + hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf); + + if (hd->Encrypted) + return unrar_err_encrypted; + + char FileName[NM*4]; + size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1); + Raw.GetB((byte *)FileName,ReadNameSize); + FileName[ReadNameSize]=0; + + UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName)-1); + + // Should do it before converting names, because extra fields can + // affect name processing, like in case of NTFS streams. + if (ExtraSize!=0) + ProcessExtra50(&Raw,(size_t)ExtraSize,hd); + + if (FileBlock) + ConvertFileHeader(hd); + + if (BadCRC) // Add the file name to broken header message displayed above. + return unrar_err_corrupt; + } + break; + case HEAD_ENDARC: + { + *(BaseBlock *)&EndArcHead=ShortBlock; + uint ArcFlags=(uint)Raw.GetV(); + EndArcHead.NextVolume=(ArcFlags & EHFL_NEXTVOLUME)!=0; + EndArcHead.StoreVolNumber=false; + EndArcHead.DataCRC=false; + EndArcHead.RevSpace=false; + } + break; + } + + if (NextBlockPos<=CurBlockPos) + return unrar_err_corrupt; + + *ReadSize=Raw.Size(); + + return unrar_ok; +} - Raw.Read(OldLhd.NameSize); - Raw.Get((byte *)NewLhd.FileName,OldLhd.NameSize); - NewLhd.FileName[OldLhd.NameSize]=0; - // (removed name case conversion) - *NewLhd.FileNameW=0; - if (Raw.Size()!=0) - NextBlockPos=CurBlockPos+NewLhd.HeadSize+NewLhd.PackSize; - CurHeaderType=FILE_HEAD; - } - return(NextBlockPos>CurBlockPos ? Raw.Size():0); +unrar_err_t Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb) +{ + // Read extra data from the end of block skipping any fields before it. + size_t ExtraStart=Raw->Size()-ExtraSize; + if (ExtraStartGetPos()) + return unrar_err_corrupt; + Raw->SetPos(ExtraStart); + while (Raw->DataLeft()>=2) + { + int64 FieldSize=Raw->GetV(); + if (FieldSize==0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft()) + break; + size_t NextPos=size_t(Raw->GetPos()+FieldSize); + uint64 FieldType=Raw->GetV(); + + FieldSize=Raw->DataLeft(); // Field size without size and type fields. + + if (bb->HeaderType==HEAD_MAIN) + { + MainHeader *hd=(MainHeader *)bb; + if (FieldType==MHEXTRA_LOCATOR) + { + hd->Locator=true; + uint Flags=(uint)Raw->GetV(); + if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0) + { + uint64 Offset=Raw->GetV(); + if (Offset!=0) // 0 means that reserved space was not enough to write the offset. + hd->QOpenOffset=Offset+CurBlockPos; + } + if ((Flags & MHEXTRA_LOCATOR_RR)!=0) + { + uint64 Offset=Raw->GetV(); + if (Offset!=0) // 0 means that reserved space was not enough to write the offset. + hd->RROffset=Offset+CurBlockPos; + } + } + } + + if (bb->HeaderType==HEAD_FILE || bb->HeaderType==HEAD_SERVICE) + { + FileHeader *hd=(FileHeader *)bb; + switch(FieldType) + { + case FHEXTRA_CRYPT: + return unrar_err_encrypted; + case FHEXTRA_HASH: + { + FileHeader *hd=(FileHeader *)bb; + uint Type=(uint)Raw->GetV(); + if (Type==FHEXTRA_HASH_BLAKE2) + { + hd->FileHash.Type=HASH_BLAKE2; + Raw->GetB(hd->FileHash.Digest,BLAKE2_DIGEST_SIZE); + } + } + break; + case FHEXTRA_HTIME: + if (FieldSize>=9) + { + byte Flags=(byte)Raw->GetV(); + bool UnixTime=(Flags & FHEXTRA_HTIME_UNIXTIME)!=0; + if ((Flags & FHEXTRA_HTIME_MTIME)!=0) + { + if (UnixTime) + hd->mtime=(time_t)Raw->Get4(); + else + hd->mtime.SetRaw(Raw->Get8()); + } + if ((Flags & FHEXTRA_HTIME_CTIME)!=0) + { + if (UnixTime) + hd->ctime=(time_t)Raw->Get4(); + else + hd->ctime.SetRaw(Raw->Get8()); + } + if ((Flags & FHEXTRA_HTIME_ATIME)!=0) + { + if (UnixTime) + hd->atime=(time_t)Raw->Get4(); + else + hd->atime.SetRaw(Raw->Get8()); + } + } + break; + case FHEXTRA_REDIR: + { + hd->RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV(); + uint Flags=(uint)Raw->GetV(); + hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0; + size_t NameSize=(size_t)Raw->GetV(); + + char UtfName[NM*4]; + *UtfName=0; + if (NameSizeGetB(UtfName,NameSize); + UtfName[NameSize]=0; + } +#ifdef _WIN_ALL + UnixSlashToDos(UtfName,UtfName,ASIZE(UtfName)); +#endif + UtfToWide(UtfName,hd->RedirName,ASIZE(hd->RedirName)); + } + break; + case FHEXTRA_UOWNER: + { + uint Flags=(uint)Raw->GetV(); + hd->UnixOwnerNumeric=(Flags & FHEXTRA_UOWNER_NUMUID)!=0; + hd->UnixGroupNumeric=(Flags & FHEXTRA_UOWNER_NUMGID)!=0; + *hd->UnixOwnerName=*hd->UnixGroupName=0; + if ((Flags & FHEXTRA_UOWNER_UNAME)!=0) + { + size_t Length=(size_t)Raw->GetV(); + Length=Min(Length,ASIZE(hd->UnixOwnerName)-1); + Raw->GetB(hd->UnixOwnerName,Length); + hd->UnixOwnerName[Length]=0; + } + if ((Flags & FHEXTRA_UOWNER_GNAME)!=0) + { + size_t Length=(size_t)Raw->GetV(); + Length=Min(Length,ASIZE(hd->UnixGroupName)-1); + Raw->GetB(hd->UnixGroupName,Length); + hd->UnixGroupName[Length]=0; + } +#ifdef _UNIX + if (hd->UnixOwnerNumeric) + hd->UnixOwnerID=(uid_t)Raw->GetV(); + if (hd->UnixGroupNumeric) + hd->UnixGroupID=(uid_t)Raw->GetV(); +#else + // Need these fields in Windows too for 'list' command, + // but uid_t and gid_t are not defined. + if (hd->UnixOwnerNumeric) + hd->UnixOwnerID=(uint)Raw->GetV(); + if (hd->UnixGroupNumeric) + hd->UnixGroupID=(uint)Raw->GetV(); +#endif + hd->UnixOwnerSet=true; + } + break; + case FHEXTRA_SUBDATA: + { + hd->SubData.Alloc((size_t)FieldSize); + Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize); + } + break; + } + } + + Raw->SetPos(NextPos); + } + + return unrar_ok; +} + + +#ifndef SFX_MODULE +unrar_err_t Archive::ReadHeader14(size_t *ReadSize) +{ + Raw.Reset(); + + if (CurBlockPos<=(int64)SFXSize) + { + Raw.Read(SIZEOF_MAINHEAD14); + MainHead.Reset(); + byte Mark[4]; + Raw.GetB(Mark,4); + uint HeadSize=Raw.Get2(); + byte Flags=Raw.Get1(); + NextBlockPos=CurBlockPos+HeadSize; + CurHeaderType=HEAD_MAIN; + + Solid=(Flags & MHD_SOLID)!=0; + MainHead.CommentInHeader=(Flags & MHD_COMMENT)!=0; + MainHead.PackComment=(Flags & MHD_PACK_COMMENT)!=0; + } + else + { + Raw.Read(SIZEOF_FILEHEAD14); + FileHead.Reset(); + + FileHead.HeaderType=HEAD_FILE; + FileHead.DataSize=Raw.Get4(); + FileHead.UnpSize=Raw.Get4(); + FileHead.FileHash.Type=HASH_RAR14; + FileHead.FileHash.CRC32=Raw.Get2(); + FileHead.HeadSize=Raw.Get2(); + uint FileTime=Raw.Get4(); + FileHead.FileAttr=Raw.Get1(); + FileHead.Flags=Raw.Get1()|LONG_BLOCK; + FileHead.UnpVer=(Raw.Get1()==2) ? 13 : 10; + size_t NameSize=Raw.Get1(); + FileHead.Method=Raw.Get1(); + + FileHead.SplitBefore=(FileHead.Flags & LHD_SPLIT_BEFORE)!=0; + FileHead.SplitAfter=(FileHead.Flags & LHD_SPLIT_AFTER)!=0; + FileHead.Encrypted=(FileHead.Flags & LHD_PASSWORD)!=0; + if (FileHead.Encrypted) + return unrar_err_encrypted; + + FileHead.PackSize=FileHead.DataSize; + FileHead.WinSize=0x10000; + + FileHead.mtime.SetDos(FileTime); + + Raw.Read(NameSize); + + char FileName[NM]; + Raw.GetB((byte *)FileName,Min(NameSize,ASIZE(FileName))); + FileName[NameSize]=0; + IntToExt(FileName,FileName,ASIZE(FileName)); + CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName)); + + if (Raw.Size()!=0) + NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize; + CurHeaderType=HEAD_FILE; + } + *ReadSize=(NextBlockPos>CurBlockPos ? Raw.Size():0); + return unrar_ok; } #endif + // (removed name case and attribute conversion) bool Archive::IsArcDir() { - return((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY); + return FileHead.Dir; } bool Archive::IsArcLabel() { - return(NewLhd.HostOS<=HOST_WIN32 && (NewLhd.FileAttr & 8)); + return(FileHead.HostOS<=HOST_WIN32 && (FileHead.FileAttr & 8)); } -// TODO: use '\\' on Windows? -char const CPATHDIVIDER = '/'; -#define charnext(s) ((s)+1) -void Archive::ConvertUnknownHeader() +void Archive::ConvertFileHeader(FileHeader *hd) { - if (NewLhd.UnpVer<20 && (NewLhd.FileAttr & 0x10)) - NewLhd.Flags|=LHD_DIRECTORY; - if (NewLhd.HostOS>=HOST_MAX) - { - if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY) - NewLhd.FileAttr=0x10; - else - NewLhd.FileAttr=0x20; - } - { - for (char *s=NewLhd.FileName;*s!=0;s=charnext(s)) - { - if (*s=='/' || *s=='\\') - *s=CPATHDIVIDER; - } - } - // (removed Apple Unicode handling) - for (wchar *s=NewLhd.FileNameW;*s!=0;s++) - { - if (*s=='/' || *s=='\\') - *s=CPATHDIVIDER; - } + if (Format==RARFMT15 && hd->UnpVer<20 && (hd->FileAttr & 0x10)) + hd->Dir=true; + if (hd->HSType==HSYS_UNKNOWN) + if (hd->Dir) + hd->FileAttr=0x10; + else + hd->FileAttr=0x20; +} + + +int64 Archive::GetStartPos() +{ + int64 StartPos=SFXSize+MarkHead.HeadSize; + StartPos+=MainHead.HeadSize; + return StartPos; } diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/array.hpp b/Frameworks/File_Extractor/File_Extractor/unrar/array.hpp index 6b6ae98c6..46bf4126c 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/array.hpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/array.hpp @@ -1,26 +1,33 @@ #ifndef _RAR_ARRAY_ #define _RAR_ARRAY_ +#include + template class Array { private: T *Buffer; - int BufSize; - int AllocSize; + size_t BufSize; + size_t AllocSize; + size_t MaxSize; public: - Rar_Error_Handler& ErrHandler; - Array(Rar_Error_Handler*); - Array(int Size,Rar_Error_Handler*); + Array(); + Array(size_t Size); + Array(const Array &Src); // Copy constructor. ~Array(); inline void CleanData(); - inline T& operator [](int Item); - inline int Size(); - void Add(int Items); - void Alloc(int Items); + inline T& operator [](size_t Item) const; + inline T* operator + (size_t Pos); + inline size_t Size(); + void Add(size_t Items); + void Alloc(size_t Items); void Reset(); + void SoftReset(); void operator = (Array &Src); void Push(T Item); - T* Addr() {return(Buffer);} + void Append(T *Item,size_t Count); + T* Addr(size_t Item) {return Buffer+Item;} + void SetMaxSize(size_t Size) {MaxSize=Size;} }; template void Array::CleanData() @@ -28,67 +35,80 @@ template void Array::CleanData() Buffer=NULL; BufSize=0; AllocSize=0; + MaxSize=0; } -template Array::Array(Rar_Error_Handler* eh) : ErrHandler( *eh ) +template Array::Array() { CleanData(); } -template Array::Array(int Size, Rar_Error_Handler* eh) : ErrHandler( *eh ) +template Array::Array(size_t Size) { - Buffer=(T *)rarmalloc(sizeof(T)*Size); - if (Buffer==NULL && Size!=0) - ErrHandler.MemoryError(); + CleanData(); + Add(Size); +} - AllocSize=BufSize=Size; + +// Copy constructor in case we need to pass an object as value. +template Array::Array(const Array &Src) +{ + CleanData(); + Alloc(Src.BufSize); + if (Src.BufSize!=0) + memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T)); } template Array::~Array() { - if (Buffer!=NULL) - rarfree(Buffer); + if (Buffer!=NULL) + rarfree(Buffer); } -template inline T& Array::operator [](int Item) +template inline T& Array::operator [](size_t Item) const { - return(Buffer[Item]); + return Buffer[Item]; } -template inline int Array::Size() +template inline T* Array::operator +(size_t Pos) { - return(BufSize); + return Buffer+Pos; } -template void Array::Add(int Items) +template inline size_t Array::Size() { - int BufSize = this->BufSize; // don't change actual vars until alloc succeeds - T* Buffer = this->Buffer; - - BufSize+=Items; - if (BufSize>AllocSize) + return BufSize; +} + + +template void Array::Add(size_t Items) +{ + size_t NewBufSize=BufSize+Items; + if (NewBufSize>AllocSize) { - int Suggested=AllocSize+AllocSize/4+32; - int NewSize=Max(BufSize,Suggested); + if (MaxSize!=0 && NewBufSize>MaxSize) + throw std::bad_alloc(); - Buffer=(T *)rarrealloc(Buffer,NewSize*sizeof(T)); - if (Buffer==NULL) - ErrHandler.MemoryError(); + size_t Suggested=AllocSize+AllocSize/4+32; + size_t NewSize=Max(NewBufSize,Suggested); + + T *NewBuffer=(T *)rarrealloc(Buffer,NewSize*sizeof(T)); + if (NewBuffer==NULL) + throw std::bad_alloc(); + Buffer=NewBuffer; AllocSize=NewSize; } - - this->Buffer = Buffer; - this->BufSize = BufSize; + BufSize=NewBufSize; } -template void Array::Alloc(int Items) +template void Array::Alloc(size_t Items) { if (Items>AllocSize) Add(Items-BufSize); @@ -117,6 +137,14 @@ template void Array::Reset() } +// Reset buffer size, but preserve already allocated memory if any, +// so we can reuse it without wasting time to allocation. +template void Array::SoftReset() +{ + BufSize=0; +} + + template void Array::operator =(Array &Src) { Reset(); @@ -132,4 +160,12 @@ template void Array::Push(T Item) (*this)[Size()-1]=Item; } + +template void Array::Append(T *Items,size_t Count) +{ + size_t CurSize=Size(); + Add(Count); + memcpy(Buffer+CurSize,Items,Count*sizeof(T)); +} + #endif diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/blake2s.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/blake2s.cpp new file mode 100644 index 000000000..e51748907 --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/blake2s.cpp @@ -0,0 +1,189 @@ +// Based on public domain code written in 2012 by Samuel Neves + +#include "rar.hpp" + +#ifdef USE_SSE +#include "blake2s_sse.cpp" +#endif + +static void blake2s_init_param( blake2s_state *S, uint32 node_offset, uint32 node_depth); +static void blake2s_update( blake2s_state *S, const byte *in, size_t inlen ); +static void blake2s_final( blake2s_state *S, byte *digest ); + +#include "blake2sp.cpp" + +static const uint32 blake2s_IV[8] = +{ + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL +}; + +static const byte blake2s_sigma[10][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , +}; + +static inline void blake2s_set_lastnode( blake2s_state *S ) +{ + S->f[1] = ~0U; +} + + +/* Some helper functions, not necessarily useful */ +static inline void blake2s_set_lastblock( blake2s_state *S ) +{ + if( S->last_node ) blake2s_set_lastnode( S ); + + S->f[0] = ~0U; +} + + +static inline void blake2s_increment_counter( blake2s_state *S, const uint32 inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + + +/* init2 xors IV with input parameter block */ +void blake2s_init_param( blake2s_state *S, uint32 node_offset, uint32 node_depth) +{ +#ifdef USE_SSE + if (_SSE_Version>=SSE_SSE2) + blake2s_init_sse(); +#endif + + S->init(); // Clean data. + for( int i = 0; i < 8; ++i ) + S->h[i] = blake2s_IV[i]; + + S->h[0] ^= 0x02080020; // We use BLAKE2sp parameters block. + S->h[2] ^= node_offset; + S->h[3] ^= (node_depth<<16)|0x20000000; +} + + +static inline uint32 rotr32( const uint32 w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + + +#define G(r,i,m,a,b,c,d) \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = rotr32(d ^ a, 16); \ + c = c + d; \ + b = rotr32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = rotr32(d ^ a, 8); \ + c = c + d; \ + b = rotr32(b ^ c, 7); + + +static void blake2s_compress( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] ) +{ + uint32 m[16]; + uint32 v[16]; + + for( size_t i = 0; i < 16; ++i ) + m[i] = RawGet4( block + i * 4 ); + + for( size_t i = 0; i < 8; ++i ) + v[i] = S->h[i]; + + v[ 8] = blake2s_IV[0]; + v[ 9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; + + for ( uint r = 0; r <= 9; ++r ) // No gain on i7 if unrolled, but exe size grows. + { + G(r,0,m,v[ 0],v[ 4],v[ 8],v[12]); + G(r,1,m,v[ 1],v[ 5],v[ 9],v[13]); + G(r,2,m,v[ 2],v[ 6],v[10],v[14]); + G(r,3,m,v[ 3],v[ 7],v[11],v[15]); + G(r,4,m,v[ 0],v[ 5],v[10],v[15]); + G(r,5,m,v[ 1],v[ 6],v[11],v[12]); + G(r,6,m,v[ 2],v[ 7],v[ 8],v[13]); + G(r,7,m,v[ 3],v[ 4],v[ 9],v[14]); + } + + for( size_t i = 0; i < 8; ++i ) + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; +} + + +void blake2s_update( blake2s_state *S, const byte *in, size_t inlen ) +{ + while( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = 2 * BLAKE2S_BLOCKBYTES - left; + + if( inlen > fill ) + { + memcpy( S->buf + left, in, fill ); // Fill buffer + S->buflen += fill; + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + +#ifdef USE_SSE +#ifdef _WIN_32 // We use SSSE3 _mm_shuffle_epi8 only in x64 mode. + if (_SSE_Version>=SSE_SSE2) +#else + if (_SSE_Version>=SSE_SSSE3) +#endif + blake2s_compress_sse( S, S->buf ); + else + blake2s_compress( S, S->buf ); // Compress +#else + blake2s_compress( S, S->buf ); // Compress +#endif + + memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); // Shift buffer left + S->buflen -= BLAKE2S_BLOCKBYTES; + in += fill; + inlen -= fill; + } + else // inlen <= fill + { + memcpy( S->buf + left, in, (size_t)inlen ); + S->buflen += (size_t)inlen; // Be lazy, do not compress + in += inlen; + inlen -= inlen; + } + } +} + + +void blake2s_final( blake2s_state *S, byte *digest ) +{ + if( S->buflen > BLAKE2S_BLOCKBYTES ) + { + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + blake2s_compress( S, S->buf ); + S->buflen -= BLAKE2S_BLOCKBYTES; + memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, S->buflen ); + } + + blake2s_increment_counter( S, ( uint32 )S->buflen ); + blake2s_set_lastblock( S ); + memset( S->buf + S->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ + blake2s_compress( S, S->buf ); + + for( int i = 0; i < 8; ++i ) /* Output full hash */ + RawPut4( S->h[i], digest + 4 * i ); +} + diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/blake2s.hpp b/Frameworks/File_Extractor/File_Extractor/unrar/blake2s.hpp new file mode 100644 index 000000000..7dd715713 --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/blake2s.hpp @@ -0,0 +1,101 @@ +// Based on public domain code written in 2012 by Samuel Neves +#ifndef _RAR_BLAKE2_ +#define _RAR_BLAKE2_ + +#define BLAKE2_DIGEST_SIZE 32 + +enum blake2s_constant +{ + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32 +}; + + +// Alignment to 64 improves performance of both SSE and non-SSE versions. +// Alignment to n*16 is required for SSE version, so we selected 64. +// We use the custom alignment scheme instead of __declspec(align(x)), +// because it is less compiler dependent. Also the compiler directive +// does not help if structure is a member of class allocated through +// 'new' operator. +struct blake2s_state +{ + enum { BLAKE_ALIGNMENT = 64 }; + + // buffer and uint32 h[8], t[2], f[2]; + enum { BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES }; + + byte ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT]; + + byte *buf; // byte buf[2 * BLAKE2S_BLOCKBYTES]. + uint32 *h, *t, *f; // uint32 h[8], t[2], f[2]. + + size_t buflen; + byte last_node; + + blake2s_state() + { + set_pointers(); + } + + // Required when we declare and assign in the same command. + blake2s_state(blake2s_state &st) + { + set_pointers(); + *this=st; + } + + void set_pointers() + { + // Set aligned pointers. Must be done in constructor, not in Init(), + // so assignments like 'blake2sp_state res=blake2ctx' work correctly + // even if blake2sp_init is not called for 'res'. + buf = (byte *) ALIGN_VALUE(ubuf, BLAKE_ALIGNMENT); + h = (uint32 *) (buf + 2 * BLAKE2S_BLOCKBYTES); + t = h + 8; + f = t + 2; + } + + void init() + { + memset( ubuf, 0, sizeof( ubuf ) ); + buflen = 0; + last_node = 0; + } + + // Since we use pointers, the default = would work incorrectly. + blake2s_state& operator = (blake2s_state &st) + { + if (this != &st) + { + memcpy(buf, st.buf, BLAKE_DATA_SIZE); + buflen = st.buflen; + last_node = st.last_node; + } + return *this; + } +}; + + +#ifdef RAR_SMP +class ThreadPool; +#endif + +struct blake2sp_state +{ + blake2s_state S[8]; + blake2s_state R; + byte buf[8 * BLAKE2S_BLOCKBYTES]; + size_t buflen; + +#ifdef RAR_SMP + ThreadPool *ThPool; + uint MaxThreads; +#endif +}; + +void blake2sp_init( blake2sp_state *S ); +void blake2sp_update( blake2sp_state *S, const byte *in, size_t inlen ); +void blake2sp_final( blake2sp_state *S, byte *digest ); + +#endif + diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/blake2s_sse.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/blake2s_sse.cpp new file mode 100644 index 000000000..af34b01dc --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/blake2s_sse.cpp @@ -0,0 +1,127 @@ +// Based on public domain code written in 2012 by Samuel Neves + +extern const byte blake2s_sigma[10][16]; + +// Initialization vector. +static __m128i blake2s_IV_0_3, blake2s_IV_4_7; + +#ifdef _WIN_64 +// Constants for cyclic rotation. Used in 64-bit mode in mm_rotr_epi32 macro. +static __m128i crotr8, crotr16; +#endif + +static void blake2s_init_sse() +{ + // We cannot initialize these 128 bit variables in place when declaring + // them globally, because global scope initialization is performed before + // our SSE check and it would make code incompatible with older non-SSE2 + // CPUs. Also we cannot initialize them as static inside of function + // using these variables, because SSE static initialization is not thread + // safe: first thread starts initialization and sets "init done" flag even + // if it is not done yet, second thread can attempt to access half-init + // SSE data. So we moved init code here. + + blake2s_IV_0_3 = _mm_setr_epi32( 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A ); + blake2s_IV_4_7 = _mm_setr_epi32( 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 ); + +#ifdef _WIN_64 + crotr8 = _mm_set_epi8( 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1 ); + crotr16 = _mm_set_epi8( 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2 ); +#endif +} + + +#define LOAD(p) _mm_load_si128( (__m128i *)(p) ) +#define STORE(p,r) _mm_store_si128((__m128i *)(p), r) + +#ifdef _WIN_32 +// 32-bit mode has less SSE2 registers and in MSVC2008 it is more efficient +// to not use _mm_shuffle_epi8 here. +#define mm_rotr_epi32(r, c) ( \ + _mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) ) +#else +#define mm_rotr_epi32(r, c) ( \ + c==8 ? _mm_shuffle_epi8(r,crotr8) \ + : c==16 ? _mm_shuffle_epi8(r,crotr16) \ + : _mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) ) +#endif + + +#define G1(row1,row2,row3,row4,buf) \ + row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \ + row4 = _mm_xor_si128( row4, row1 ); \ + row4 = mm_rotr_epi32(row4, 16); \ + row3 = _mm_add_epi32( row3, row4 ); \ + row2 = _mm_xor_si128( row2, row3 ); \ + row2 = mm_rotr_epi32(row2, 12); + +#define G2(row1,row2,row3,row4,buf) \ + row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \ + row4 = _mm_xor_si128( row4, row1 ); \ + row4 = mm_rotr_epi32(row4, 8); \ + row3 = _mm_add_epi32( row3, row4 ); \ + row2 = _mm_xor_si128( row2, row3 ); \ + row2 = mm_rotr_epi32(row2, 7); + +#define DIAGONALIZE(row1,row2,row3,row4) \ + row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(2,1,0,3) ); \ + row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \ + row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(0,3,2,1) ); + +#define UNDIAGONALIZE(row1,row2,row3,row4) \ + row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(0,3,2,1) ); \ + row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \ + row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(2,1,0,3) ); + +#ifdef _WIN_64 + // MSVC 2008 in x64 mode expands _mm_set_epi32 to store to stack and load + // from stack operations, which are slower than this code. + #define _mm_set_epi32(i3,i2,i1,i0) \ + _mm_unpacklo_epi32(_mm_unpacklo_epi32(_mm_cvtsi32_si128(i0),_mm_cvtsi32_si128(i2)), \ + _mm_unpacklo_epi32(_mm_cvtsi32_si128(i1),_mm_cvtsi32_si128(i3))) +#endif + +// Original BLAKE2 SSE4.1 message loading code was a little slower in x86 mode +// and about the same in x64 mode in our test. Perhaps depends on compiler. +#define SSE_ROUND(m,row,r) \ +{ \ + __m128i buf; \ + buf=_mm_set_epi32(m[blake2s_sigma[r][6]],m[blake2s_sigma[r][4]],m[blake2s_sigma[r][2]],m[blake2s_sigma[r][0]]); \ + G1(row[0],row[1],row[2],row[3],buf); \ + buf=_mm_set_epi32(m[blake2s_sigma[r][7]],m[blake2s_sigma[r][5]],m[blake2s_sigma[r][3]],m[blake2s_sigma[r][1]]); \ + G2(row[0],row[1],row[2],row[3],buf); \ + DIAGONALIZE(row[0],row[1],row[2],row[3]); \ + buf=_mm_set_epi32(m[blake2s_sigma[r][14]],m[blake2s_sigma[r][12]],m[blake2s_sigma[r][10]],m[blake2s_sigma[r][8]]); \ + G1(row[0],row[1],row[2],row[3],buf); \ + buf=_mm_set_epi32(m[blake2s_sigma[r][15]],m[blake2s_sigma[r][13]],m[blake2s_sigma[r][11]],m[blake2s_sigma[r][9]]); \ + G2(row[0],row[1],row[2],row[3],buf); \ + UNDIAGONALIZE(row[0],row[1],row[2],row[3]); \ +} + + +static int blake2s_compress_sse( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] ) +{ + __m128i row[4]; + __m128i ff0, ff1; + + const uint32 *m = ( uint32 * )block; + + row[0] = ff0 = LOAD( &S->h[0] ); + row[1] = ff1 = LOAD( &S->h[4] ); + + row[2] = blake2s_IV_0_3; + row[3] = _mm_xor_si128( blake2s_IV_4_7, LOAD( &S->t[0] ) ); + SSE_ROUND( m, row, 0 ); + SSE_ROUND( m, row, 1 ); + SSE_ROUND( m, row, 2 ); + SSE_ROUND( m, row, 3 ); + SSE_ROUND( m, row, 4 ); + SSE_ROUND( m, row, 5 ); + SSE_ROUND( m, row, 6 ); + SSE_ROUND( m, row, 7 ); + SSE_ROUND( m, row, 8 ); + SSE_ROUND( m, row, 9 ); + STORE( &S->h[0], _mm_xor_si128( ff0, _mm_xor_si128( row[0], row[2] ) ) ); + STORE( &S->h[4], _mm_xor_si128( ff1, _mm_xor_si128( row[1], row[3] ) ) ); + return 0; +} diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/blake2sp.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/blake2sp.cpp new file mode 100644 index 000000000..da645883b --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/blake2sp.cpp @@ -0,0 +1,153 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ + +#define PARALLELISM_DEGREE 8 + +void blake2sp_init( blake2sp_state *S ) +{ + memset( S->buf, 0, sizeof( S->buf ) ); + S->buflen = 0; + + blake2s_init_param( &S->R, 0, 1 ); // Init root. + + for( uint i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_init_param( &S->S[i], i, 0 ); // Init leaf. + + S->R.last_node = 1; + S->S[PARALLELISM_DEGREE - 1].last_node = 1; +} + + +struct Blake2ThreadData +{ + void Update(); + blake2s_state *S; + const byte *in; + size_t inlen; +}; + + +void Blake2ThreadData::Update() +{ + size_t inlen__ = inlen; + const byte *in__ = ( const byte * )in; + + while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ) + { +#ifdef USE_SSE + // We gain 5% in i7 SSE mode by prefetching next data block. + if (_SSE_Version>=SSE_SSE && inlen__ >= 2 * PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES) + _mm_prefetch((char*)(in__ + PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES), _MM_HINT_T0); +#endif + blake2s_update( S, in__, BLAKE2S_BLOCKBYTES ); + in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + } +} + +#ifdef RAR_SMP +THREAD_PROC(Blake2Thread) +{ + Blake2ThreadData *td=(Blake2ThreadData *)Data; + td->Update(); +} +#endif + + +void blake2sp_update( blake2sp_state *S, const byte *in, size_t inlen ) +{ + size_t left = S->buflen; + size_t fill = sizeof( S->buf ) - left; + + if( left && inlen >= fill ) + { + memcpy( S->buf + left, in, fill ); + + for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( &S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); + + in += fill; + inlen -= fill; + left = 0; + } + + Blake2ThreadData btd_array[PARALLELISM_DEGREE]; + +#ifdef RAR_SMP + uint ThreadNumber = inlen < 0x1000 ? 1 : S->MaxThreads; + + if (ThreadNumber==6 || ThreadNumber==7) // 6 and 7 threads work slower than 4 here. + ThreadNumber=4; +#else + uint ThreadNumber=1; +#endif + + for (size_t id__=0;id__inlen = inlen; + btd->in = in + id__ * BLAKE2S_BLOCKBYTES; + btd->S = &S->S[id__]; + +#ifdef RAR_SMP + if (ThreadNumber>1) + S->ThPool->AddTask(Blake2Thread,(void*)btd); + else + btd->Update(); +#else + btd->Update(); +#endif + id__++; + } +#ifdef RAR_SMP + if (S->ThPool!=NULL) // Can be NULL in -mt1 mode. + S->ThPool->WaitDone(); +#endif // RAR_SMP + } + + in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ); + inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + + if( inlen > 0 ) + memcpy( S->buf + left, in, (size_t)inlen ); + + S->buflen = left + (size_t)inlen; +} + + +void blake2sp_final( blake2sp_state *S, byte *digest ) +{ + byte hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES]; + + for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) + { + if( S->buflen > i * BLAKE2S_BLOCKBYTES ) + { + size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES; + + if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES; + + blake2s_update( &S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left ); + } + + blake2s_final( &S->S[i], hash[i] ); + } + + for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( &S->R, hash[i], BLAKE2S_OUTBYTES ); + + blake2s_final( &S->R, digest ); +} diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/coder.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/coder.cpp index 1f090574f..ad09fc52a 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/coder.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/coder.cpp @@ -18,9 +18,10 @@ void RangeCoder::InitDecoder(Unpack *UnpackRead) } +// (int) cast before "low" added only to suppress compiler warnings. #define ARI_DEC_NORMALIZE(code,low,range,read) \ { \ - while ((low^(low+range))GetChar(); \ range <<= 8; \ diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/coder.hpp b/Frameworks/File_Extractor/File_Extractor/unrar/coder.hpp index 81eaabf48..7fd45327a 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/coder.hpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/coder.hpp @@ -2,7 +2,6 @@ * Contents: 'Carryless rangecoder' by Dmitry Subbotin * ****************************************************************************/ -const uint TOP=1 << 24, BOT=1 << 15; class RangeCoder { diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/compress.hpp b/Frameworks/File_Extractor/File_Extractor/unrar/compress.hpp index dfb86e50d..4b6d47800 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/compress.hpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/compress.hpp @@ -1,36 +1,50 @@ #ifndef _RAR_COMPRESS_ #define _RAR_COMPRESS_ -class ComprDataIO; -class PackingFileTable; +// Combine pack and unpack constants to class to avoid polluting global +// namespace with numerous short names. +class PackDef +{ + public: + static const uint MAX_LZ_MATCH = 0x1001; + static const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3. + static const uint LOW_DIST_REP_COUNT = 16; -#define CODEBUFSIZE 0x4000 -#define MAXWINSIZE 0x400000 -#define MAXWINMASK (MAXWINSIZE-1) + static const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */ + static const uint DC = 64; + static const uint LDC = 16; + static const uint RC = 44; + static const uint HUFF_TABLE_SIZE = NC + DC + RC + LDC; + static const uint BC = 20; -#define LOW_DIST_REP_COUNT 16 + static const uint NC30 = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */ + static const uint DC30 = 60; + static const uint LDC30 = 17; + static const uint RC30 = 28; + static const uint BC30 = 20; + static const uint HUFF_TABLE_SIZE30 = NC30 + DC30 + RC30 + LDC30; -#define NC 299 /* alphabet = {0, 1, 2, ..., NC - 1} */ -#define DC 60 -#define LDC 17 -#define RC 28 -#define HUFF_TABLE_SIZE (NC+DC+RC+LDC) -#define BC 20 + static const uint NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */ + static const uint DC20 = 48; + static const uint RC20 = 28; + static const uint BC20 = 19; + static const uint MC20 = 257; -#define NC20 298 /* alphabet = {0, 1, 2, ..., NC - 1} */ -#define DC20 48 -#define RC20 28 -#define BC20 19 -#define MC20 257 + // Largest alphabet size among all values listed above. + static const uint LARGEST_TABLE_SIZE = 306; -enum {CODE_HUFFMAN,CODE_LZ,CODE_LZ2,CODE_REPEATLZ,CODE_CACHELZ, - CODE_STARTFILE,CODE_ENDFILE,CODE_VM,CODE_VMDATA}; + enum { + CODE_HUFFMAN, CODE_LZ, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE, + CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA + }; +}; enum FilterType { - FILTER_NONE, FILTER_PPM /*dummy*/, FILTER_E8, FILTER_E8E9, - FILTER_UPCASETOLOW, FILTER_AUDIO, FILTER_RGB, FILTER_DELTA, - FILTER_ITANIUM, FILTER_E8E9V2 + // These values must not be changed, because we use them directly + // in RAR5 compression and decompression code. + FILTER_DELTA=0, FILTER_E8, FILTER_E8E9, FILTER_ARM, + FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_PPM, FILTER_NONE }; #endif diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/crc.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/crc.cpp index 76b1c7dbc..909504902 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/crc.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/crc.cpp @@ -1,69 +1,97 @@ +// This CRC function is based on Intel Slicing-by-8 algorithm. +// +// Original Intel Slicing-by-8 code is available here: +// +// http://sourceforge.net/projects/slicing-by-8/ +// +// Original Intel Slicing-by-8 code is licensed as: +// +// Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved +// +// This software program is licensed subject to the BSD License, +// available at http://www.opensource.org/licenses/bsd-license.html + + #include "rar.hpp" -uint CRCTab[256]; +uint crc_tables[8][256]; // Tables for Slicing-by-8. -void InitCRC() + +// Build the classic CRC32 lookup table. +// We also provide this function to legacy RAR and ZIP decryption code. +void InitCRC32(uint *CRCTab) { - for (int I=0;I<256;I++) + if (CRCTab[1]!=0) + return; + for (uint I=0;I<256;I++) { uint C=I; - for (int J=0;J<8;J++) - C=(C & 1) ? (C>>1)^0xEDB88320L : (C>>1); + for (uint J=0;J<8;J++) + C=(C & 1) ? (C>>1)^0xEDB88320 : (C>>1); CRCTab[I]=C; } } -uint CRC(uint StartCRC,const void *Addr,size_t Size) +void InitCRCTables() { - // Always initialized ahead of time, and this func call makes it a non-leaf func. - if (false) - if (CRCTab[1]==0) - InitCRC(); - byte *Data=(byte *)Addr; -#if defined(LITTLE_ENDIAN) && defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT) - -#ifdef _MSC_VER - // avoid a warning about 'Data' pointer truncation in 64 bit mode - #pragma warning( disable : 4311 ) -#endif - - while (Size>0 && ((long)Data & 7)) - { - StartCRC=CRCTab[(byte)(StartCRC^Data[0])]^(StartCRC>>8); - Size--; - Data++; - } - while (Size>=8) - { - StartCRC^=*(uint32 *)Data; - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC^=*(uint32 *)(Data+4); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8); - Data+=8; - Size-=8; - } -#endif - for (size_t I=0;I>8); - return(StartCRC); + InitCRC32(crc_tables[0]); + + for (uint I=0;I<256;I++) // Build additional lookup tables. + { + uint C=crc_tables[0][I]; + for (uint J=1;J<8;J++) + { + C=crc_tables[0][(byte)C]^(C>>8); + crc_tables[J][I]=C; + } + } } +uint CRC32(uint StartCRC,const void *Addr,size_t Size) +{ + byte *Data=(byte *)Addr; + + // Align Data to 8 for better performance. + for (;Size>0 && ((size_t)Data & 7);Size--,Data++) + StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); + + for (;Size>=8;Size-=8,Data+=8) + { +#ifdef BIG_ENDIAN + StartCRC ^= Data[0]|(Data[1] << 8)|(Data[2] << 16)|(Data[3] << 24); + uint NextData = Data[4]|(Data[5] << 8)|(Data[6] << 16)|(Data[7] << 24); +#else + StartCRC ^= *(uint32 *) Data; + uint NextData = *(uint32 *) (Data +4); +#endif + StartCRC = crc_tables[7][(byte) StartCRC ] ^ + crc_tables[6][(byte)(StartCRC >> 8) ] ^ + crc_tables[5][(byte)(StartCRC >> 16)] ^ + crc_tables[4][(byte)(StartCRC >> 24)] ^ + crc_tables[3][(byte) NextData ] ^ + crc_tables[2][(byte)(NextData >>8 ) ] ^ + crc_tables[1][(byte)(NextData >> 16)] ^ + crc_tables[0][(byte)(NextData >> 24)]; + } + + for (;Size>0;Size--,Data++) // Process left data. + StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); + + return StartCRC; +} + + #ifndef SFX_MODULE -ushort OldCRC(ushort StartCRC,const void *Addr,size_t Size) +// For RAR 1.4 archives in case somebody still has them. +ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size) { - byte *Data=(byte *)Addr; - for (size_t I=0;I>15))&0xffff; - } - return(StartCRC); + byte *Data=(byte *)Addr; + for (size_t I=0;I>15))&0xffff; + } + return StartCRC; } #endif diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/encname.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/encname.cpp index dab8c7bfa..555894a85 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/encname.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/encname.cpp @@ -11,10 +11,10 @@ EncodeFileName::EncodeFileName() -void EncodeFileName::Decode(char *Name,byte *EncName,int EncSize,wchar *NameW, - int MaxDecSize) +void EncodeFileName::Decode(char *Name,byte *EncName,size_t EncSize,wchar *NameW, + size_t MaxDecSize) { - int EncPos=0,DecPos=0; + size_t EncPos=0,DecPos=0; byte HighByte=EncName[EncPos++]; while (EncPosUNP_VER) + if (Arc.FileHead.UnpVer!=VER_UNPACK5 && + (Arc.FileHead.UnpVer<13 || Arc.FileHead.UnpVer>VER_UNPACK)) #endif { - if (Arc.NewLhd.UnpVer>UNP_VER) + if (Arc.FileHead.UnpVer>VER_UNPACK) return unrar_err_new_algo; return unrar_err_old_algo; } @@ -44,12 +45,15 @@ unrar_err_t CmdExtract::ExtractCurrentFile( bool SkipSolid, bool check_compatibi FileCount++; DataIO.UnpFileCRC=Arc.OldFormat ? 0 : 0xffffffff; // (removed decryption) - DataIO.SetPackedSizeToRead(Arc.NewLhd.FullPackSize); + DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,1); + DataIO.PackedDataHash.Init(Arc.FileHead.FileHash.Type,1); + DataIO.SetPackedSizeToRead(Arc.FileHead.PackSize); + DataIO.SetSkipUnpCRC(SkipSolid); // (removed command-line handling) DataIO.SetSkipUnpCRC(SkipSolid); - if (Arc.NewLhd.Method==0x30) - UnstoreFile(Arc.NewLhd.FullUnpSize); + if (Arc.FileHead.Method==0) + UnstoreFile(Arc.FileHead.UnpSize); else { // Defer creation of Unpack until first extraction @@ -59,25 +63,26 @@ unrar_err_t CmdExtract::ExtractCurrentFile( bool SkipSolid, bool check_compatibi if ( !Unp ) return unrar_err_memory; - Unp->Init( NULL ); + Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid); } - Unp->SetDestSize(Arc.NewLhd.FullUnpSize); + Unp->SetDestSize(Arc.FileHead.UnpSize); #ifndef SFX_MODULE - if (Arc.NewLhd.UnpVer<=15) + if (Arc.FileHead.UnpVer>=13 && Arc.FileHead.UnpVer<=15) Unp->DoUnpack(15,FileCount>1 && Arc.Solid); else #endif - Unp->DoUnpack(Arc.NewLhd.UnpVer,Arc.NewLhd.Flags & LHD_SOLID); + Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Flags & LHD_SOLID); } // (no need to seek to next file) if (!SkipSolid) { - if ((Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC)) || - (!Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC^0xffffffff))) - { + HashValue UnpHash; + DataIO.UnpHash.Result(&UnpHash); + if (UnpHash==Arc.FileHead.FileHash) + { // CRC is correct } else @@ -93,12 +98,12 @@ unrar_err_t CmdExtract::ExtractCurrentFile( bool SkipSolid, bool check_compatibi } -void CmdExtract::UnstoreFile(Int64 DestUnpSize) +void CmdExtract::UnstoreFile(int64 DestUnpSize) { - Buffer.Alloc((int)Min(DestUnpSize,0x10000)); + Buffer.Alloc(Min(DestUnpSize,0x10000)); while (1) { - unsigned int Code=DataIO.UnpRead(&Buffer[0],Buffer.Size()); + unsigned int Code=DataIO.UnpRead(&Buffer[0],(uint)Buffer.Size()); if (Code==0 || (int)Code==-1) break; Code=Code>3; InBit=Bits&7; } - unsigned int getbits() + + // Return 16 bits from current position in the buffer. + // Bit at (InAddr,InBit) has the highest position in returning data. + uint getbits() { - unsigned int BitField=(uint)InBuf[InAddr] << 16; + uint BitField=(uint)InBuf[InAddr] << 16; BitField|=(uint)InBuf[InAddr+1] << 8; BitField|=(uint)InBuf[InAddr+2]; BitField >>= (8-InBit); return(BitField & 0xffff); } - void faddbits(int Bits); - unsigned int fgetbits(); - bool Overflow(int IncPtr) {return(InAddr+IncPtr>=MAX_SIZE);} + + // Return 32 bits from current position in the buffer. + // Bit at (InAddr,InBit) has the highest position in returning data. + uint getbits32() + { + uint BitField=(uint)InBuf[InAddr] << 24; + BitField|=(uint)InBuf[InAddr+1] << 16; + BitField|=(uint)InBuf[InAddr+2] << 8; + BitField|=(uint)InBuf[InAddr+3]; + BitField <<= InBit; + BitField|=(uint)InBuf[InAddr+4] >> (8-InBit); + return(BitField & 0xffffffff); + } + + void faddbits(uint Bits); + uint fgetbits(); + + // Check if buffer has enough space for IncPtr bytes. Returns 'true' + // if buffer will be overflown. + bool Overflow(uint IncPtr) + { + return(InAddr+IncPtr>=MAX_SIZE); + } + + void SetExternalBuffer(byte *Buf); }; #endif diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/hash.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/hash.cpp new file mode 100644 index 000000000..4e4f43c34 --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/hash.cpp @@ -0,0 +1,118 @@ +#include "rar.hpp" + +void HashValue::Init(HASH_TYPE Type) +{ + HashValue::Type=Type; + + // Zero length data CRC32 is 0. It is important to set it when creating + // headers with no following data like directories or symlinks. + if (Type==HASH_RAR14 || Type==HASH_CRC32) + CRC32=0; + if (Type==HASH_BLAKE2) + { + // dd0e891776933f43c7d032b08a917e25741f8aa9a12c12e1cac8801500f2ca4f + // is BLAKE2sp hash of empty data. We init the structure to this value, + // so if we create a file or service header with no following data like + // "file copy" or "symlink", we set the checksum to proper value avoiding + // additional header type or size checks when extracting. + static byte EmptyHash[32]={ + 0xdd, 0x0e, 0x89, 0x17, 0x76, 0x93, 0x3f, 0x43, + 0xc7, 0xd0, 0x32, 0xb0, 0x8a, 0x91, 0x7e, 0x25, + 0x74, 0x1f, 0x8a, 0xa9, 0xa1, 0x2c, 0x12, 0xe1, + 0xca, 0xc8, 0x80, 0x15, 0x00, 0xf2, 0xca, 0x4f + }; + memcpy(Digest,EmptyHash,sizeof(Digest)); + } +} + + +bool HashValue::operator == (const HashValue &cmp) +{ + if (Type==HASH_NONE || cmp.Type==HASH_NONE) + return true; + if ((Type==HASH_RAR14 && cmp.Type==HASH_RAR14) || + (Type==HASH_CRC32 && cmp.Type==HASH_CRC32)) + return CRC32==cmp.CRC32; + if (Type==HASH_BLAKE2 && cmp.Type==HASH_BLAKE2) + return memcmp(Digest,cmp.Digest,sizeof(Digest))==0; + return false; +} + + +DataHash::DataHash() +{ + HashType=HASH_NONE; +#ifdef RAR_SMP + ThPool=NULL; + MaxThreads=0; +#endif +} + + +DataHash::~DataHash() +{ +#ifdef RAR_SMP + DestroyThreadPool(ThPool); +#endif + cleandata(&blake2ctx, sizeof(blake2ctx)); + cleandata(&CurCRC32, sizeof(CurCRC32)); +} + + +void DataHash::Init(HASH_TYPE Type,uint MaxThreads) +{ + HashType=Type; + if (Type==HASH_RAR14) + CurCRC32=0; + if (Type==HASH_CRC32) + CurCRC32=0xffffffff; // Initial CRC32 value. + if (Type==HASH_BLAKE2) + blake2sp_init( &blake2ctx ); +#ifdef RAR_SMP + DataHash::MaxThreads=Min(MaxThreads,MaxHashThreads); +#endif +} + + +void DataHash::Update(const void *Data,size_t DataSize) +{ +#ifndef SFX_MODULE + if (HashType==HASH_RAR14) + CurCRC32=Checksum14((ushort)CurCRC32,Data,DataSize); +#endif + if (HashType==HASH_CRC32) + CurCRC32=CRC32(CurCRC32,Data,DataSize); + + if (HashType==HASH_BLAKE2) + { +#ifdef RAR_SMP + if (MaxThreads>1 && ThPool==NULL) + ThPool=CreateThreadPool(); + blake2ctx.ThPool=ThPool; + blake2ctx.MaxThreads=MaxThreads; +#endif + blake2sp_update( &blake2ctx, (byte *)Data, DataSize); + } +} + + +void DataHash::Result(HashValue *Result) +{ + Result->Type=HashType; + if (HashType==HASH_RAR14) + Result->CRC32=CurCRC32; + if (HashType==HASH_CRC32) + Result->CRC32=CurCRC32^0xffffffff; + if (HashType==HASH_BLAKE2) + { + // Preserve the original context, so we can continue hashing if necessary. + blake2sp_state res=blake2ctx; + blake2sp_final( &res, Result->Digest ); + } +} + + +uint DataHash::GetCRC32() +{ + return HashType==HASH_CRC32 ? CurCRC32^0xffffffff : 0; +} diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/hash.hpp b/Frameworks/File_Extractor/File_Extractor/unrar/hash.hpp new file mode 100644 index 000000000..dae31d1b2 --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/hash.hpp @@ -0,0 +1,52 @@ +#ifndef _RAR_DATAHASH_ +#define _RAR_DATAHASH_ + +enum HASH_TYPE {HASH_NONE,HASH_RAR14,HASH_CRC32,HASH_BLAKE2}; + +struct HashValue +{ + void Init(HASH_TYPE Type); + bool operator == (const HashValue &cmp); + bool operator != (const HashValue &cmp) {return !(*this==cmp);} + + HASH_TYPE Type; + union + { + uint CRC32; + byte Digest[SHA256_DIGEST_SIZE]; + }; +}; + + +#ifdef RAR_SMP +class ThreadPool; +class DataHash; +#endif + + +class DataHash +{ + private: + HASH_TYPE HashType; + uint CurCRC32; + blake2sp_state blake2ctx; + +#ifdef RAR_SMP + ThreadPool *ThPool; + + uint MaxThreads; + // Upper limit for maximum threads to prevent wasting threads in pool. + static const uint MaxHashThreads=8; +#endif + public: + DataHash(); + ~DataHash(); + void Init(HASH_TYPE Type,uint MaxThreads); + void Update(const void *Data,size_t DataSize); + void Result(HashValue *Result); + uint GetCRC32(); + bool Cmp(HashValue *CmpValue,byte *Key); + HASH_TYPE Type() {return HashType;} +}; + +#endif diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/headers.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/headers.cpp new file mode 100644 index 000000000..70c550437 --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/headers.cpp @@ -0,0 +1,60 @@ +#include "rar.hpp" + +void FileHeader::Reset(size_t SubDataSize) +{ + SubData.Alloc(SubDataSize); + BaseBlock::Reset(); +#ifndef SHELL_EXT + FileHash.Init(HASH_NONE); +#endif + mtime.Reset(); + atime.Reset(); + ctime.Reset(); + SplitBefore=false; + SplitAfter=false; + + UnknownUnpSize=0; + + SubFlags=0; // Important for RAR 3.0 subhead. + + Encrypted=false; + UsePswCheck=false; + UseHashKey=false; + Lg2Count=0; + + Solid=false; + Dir=false; + WinSize=0; + Inherited=false; + SubBlock=false; + CommentInHeader=false; + Version=false; + LargeFile=false; + + RedirType=FSREDIR_NONE; + UnixOwnerSet=false; +} + + +FileHeader& FileHeader::operator = (FileHeader &hd) +{ + SubData.Reset(); + memcpy(this,&hd,sizeof(*this)); + SubData.CleanData(); + SubData=hd.SubData; + return *this; +} + + +void MainHeader::Reset() +{ + HighPosAV=0; + PosAV=0; + CommentInHeader=false; + PackComment=false; + Locator=false; + QOpenOffset=0; + QOpenMaxSize=0; + RROffset=0; + RRMaxSize=0; +} diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/headers.hpp b/Frameworks/File_Extractor/File_Extractor/unrar/headers.hpp index 38a0bdb28..9b336655a 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/headers.hpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/headers.hpp @@ -1,145 +1,362 @@ -#ifndef _RAR_HEADERS_ -#define _RAR_HEADERS_ - -#define SIZEOF_MARKHEAD 7 -#define SIZEOF_OLDMHD 7 -#define SIZEOF_NEWMHD 13 -#define SIZEOF_OLDLHD 21 -#define SIZEOF_NEWLHD 32 -#define SIZEOF_SHORTBLOCKHEAD 7 -#define SIZEOF_SUBBLOCKHEAD 14 -#define SIZEOF_COMMHEAD 13 - -#define UNP_VER 36 - -#define MHD_VOLUME 0x0001 -#define MHD_COMMENT 0x0002 -#define MHD_SOLID 0x0008 -#define MHD_PASSWORD 0x0080 - -#define LHD_SPLIT_BEFORE 0x0001 -#define LHD_SPLIT_AFTER 0x0002 -#define LHD_PASSWORD 0x0004 -#define LHD_COMMENT 0x0008 -#define LHD_SOLID 0x0010 - -#define LHD_WINDOWMASK 0x00e0 -#define LHD_DIRECTORY 0x00e0 - -#define LHD_LARGE 0x0100 -#define LHD_UNICODE 0x0200 -#define LHD_SALT 0x0400 -#define LHD_EXTTIME 0x1000 - -#define LONG_BLOCK 0x8000 - -enum HEADER_TYPE { - MARK_HEAD=0x72,MAIN_HEAD=0x73,FILE_HEAD=0x74,COMM_HEAD=0x75,AV_HEAD=0x76, - SUB_HEAD=0x77,PROTECT_HEAD=0x78,SIGN_HEAD=0x79,NEWSUB_HEAD=0x7a, - ENDARC_HEAD=0x7b -}; - -enum HOST_SYSTEM { - HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4, - HOST_BEOS=5,HOST_MAX -}; - -struct OldMainHeader -{ - byte Mark[4]; - ushort HeadSize; - byte Flags; -}; - - -struct OldFileHeader -{ - uint PackSize; - uint UnpSize; - ushort FileCRC; - ushort HeadSize; - uint FileTime; - byte FileAttr; - byte Flags; - byte UnpVer; - byte NameSize; - byte Method; -}; - - -struct MarkHeader -{ - byte Mark[7]; -}; - - -struct BaseBlock -{ - ushort HeadCRC; - HEADER_TYPE HeadType;//byte - ushort Flags; - ushort HeadSize; -}; - -struct BlockHeader:BaseBlock -{ - union { - uint DataSize; - uint PackSize; - }; -}; - - -struct MainHeader:BaseBlock -{ - ushort HighPosAV; - uint PosAV; -}; - -#define SALT_SIZE 8 - -struct FileHeader:BlockHeader -{ - uint UnpSize; - byte HostOS; - uint FileCRC; - uint FileTime; - byte UnpVer; - byte Method; - ushort NameSize; - union { - uint FileAttr; - uint SubFlags; - }; -/* optional */ - uint HighPackSize; - uint HighUnpSize; -/* names */ - char FileName[NM*4]; // *4 to avoid using lots of stack in arcread - wchar FileNameW[NM]; -/* optional */ - byte Salt[SALT_SIZE]; - - RarTime mtime; -/* dummy */ - Int64 FullPackSize; - Int64 FullUnpSize; -}; - -// SubBlockHeader and its successors were used in RAR 2.x format. -// RAR 3.x uses FileHeader with NEWSUB_HEAD HeadType for subblocks. -struct SubBlockHeader:BlockHeader -{ - ushort SubType; - byte Level; -}; - -struct ProtectHeader:BlockHeader -{ - byte Version; - ushort RecSectors; - uint TotalBlocks; - byte Mark[8]; -}; - -#endif +#ifndef _RAR_HEADERS_ +#define _RAR_HEADERS_ + +#define SIZEOF_MARKHEAD3 7 // Size of RAR 4.x archive mark header. +#define SIZEOF_MAINHEAD14 7 // Size of RAR 1.4 main archive header. +#define SIZEOF_MAINHEAD3 13 // Size of RAR 4.x main archive header. +#define SIZEOF_FILEHEAD14 21 // Size of RAR 1.4 file header. +#define SIZEOF_FILEHEAD3 32 // Size of RAR 3.0 file header. +#define SIZEOF_SHORTBLOCKHEAD 7 +#define SIZEOF_LONGBLOCKHEAD 11 +#define SIZEOF_SUBBLOCKHEAD 14 +#define SIZEOF_COMMHEAD 13 +#define SIZEOF_PROTECTHEAD 26 +#define SIZEOF_AVHEAD 14 +#define SIZEOF_SIGNHEAD 15 +#define SIZEOF_UOHEAD 18 +#define SIZEOF_MACHEAD 22 +#define SIZEOF_EAHEAD 24 +#define SIZEOF_BEEAHEAD 24 +#define SIZEOF_STREAMHEAD 26 + +#define VER_PACK 29 +#define VER_PACK5 0 +#define VER_UNPACK 29 +#define VER_UNPACK5 0 + +#define MHD_VOLUME 0x0001U + +// Old style main archive comment embed into main archive header. Must not +// be used in new archives anymore. +#define MHD_COMMENT 0x0002U + +#define MHD_LOCK 0x0004U +#define MHD_SOLID 0x0008U +#define MHD_PACK_COMMENT 0x0010U +#define MHD_NEWNUMBERING 0x0010U +#define MHD_AV 0x0020U +#define MHD_PROTECT 0x0040U +#define MHD_PASSWORD 0x0080U +#define MHD_FIRSTVOLUME 0x0100U + +#define LHD_SPLIT_BEFORE 0x0001U +#define LHD_SPLIT_AFTER 0x0002U +#define LHD_PASSWORD 0x0004U + +// Old style file comment embed into file header. Must not be used +// in new archives anymore. +#define LHD_COMMENT 0x0008U + +// For non-file subheaders it denotes 'subblock having a parent file' flag. +#define LHD_SOLID 0x0010U + + +#define LHD_WINDOWMASK 0x00e0U +#define LHD_WINDOW64 0x0000U +#define LHD_WINDOW128 0x0020U +#define LHD_WINDOW256 0x0040U +#define LHD_WINDOW512 0x0060U +#define LHD_WINDOW1024 0x0080U +#define LHD_WINDOW2048 0x00a0U +#define LHD_WINDOW4096 0x00c0U +#define LHD_DIRECTORY 0x00e0U + +#define LHD_LARGE 0x0100U +#define LHD_UNICODE 0x0200U +#define LHD_SALT 0x0400U +#define LHD_VERSION 0x0800U +#define LHD_EXTTIME 0x1000U + +#define SKIP_IF_UNKNOWN 0x4000U +#define LONG_BLOCK 0x8000U + +#define EARC_NEXT_VOLUME 0x0001U // Not last volume. +#define EARC_DATACRC 0x0002U // Store CRC32 of RAR archive (now is used only in volumes). +#define EARC_REVSPACE 0x0004U // Reserve space for end of REV file 7 byte record. +#define EARC_VOLNUMBER 0x0008U // Store a number of current volume. + +enum HEADER_TYPE { + // RAR 5.0 header types. + HEAD_MARK=0x00, HEAD_MAIN=0x01, HEAD_FILE=0x02, HEAD_SERVICE=0x03, + HEAD_CRYPT=0x04, HEAD_ENDARC=0x05, HEAD_UNKNOWN=0xff, + + // RAR 1.5 - 4.x header types. + HEAD3_MARK=0x72,HEAD3_MAIN=0x73,HEAD3_FILE=0x74,HEAD3_CMT=0x75, + HEAD3_AV=0x76,HEAD3_OLDSERVICE=0x77,HEAD3_PROTECT=0x78,HEAD3_SIGN=0x79, + HEAD3_SERVICE=0x7a,HEAD3_ENDARC=0x7b +}; + +enum { EA_HEAD=0x100,UO_HEAD=0x101,MAC_HEAD=0x102,BEEA_HEAD=0x103, + NTACL_HEAD=0x104,STREAM_HEAD=0x105 }; + + +// Internal implementation, depends on archive format version. +enum HOST_SYSTEM { + // RAR 5.0 host OS + HOST5_WINDOWS=0,HOST5_UNIX=1, + + // RAR 3.0 host OS. + HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4, + HOST_BEOS=5,HOST_MAX +}; + +// Unified archive format independent implementation. +enum HOST_SYSTEM_TYPE { + HSYS_WINDOWS, HSYS_UNIX, HSYS_UNKNOWN +}; + + +// We also use these values in extra field, so do not modify them. +enum FILE_SYSTEM_REDIRECT { + FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION, + FSREDIR_HARDLINK, FSREDIR_FILECOPY +}; + + +static const wchar SUBHEAD_TYPE_CMT[] = {'C', 'M', 'T', 0}; +static const wchar SUBHEAD_TYPE_QOPEN[] = {'Q', 'O', 0}; +static const wchar SUBHEAD_TYPE_ACL[] = {'A', 'C', 'L', 0}; +static const wchar SUBHEAD_TYPE_STREAM[] = {'S', 'T', 'M', 0}; +static const wchar SUBHEAD_TYPE_UOWNER[] = {'U', 'O', 'W', 0}; +static const wchar SUBHEAD_TYPE_AV[] = {'A', 'V', 0}; +static const wchar SUBHEAD_TYPE_RR[] = {'R', 'R', 0}; +static const wchar SUBHEAD_TYPE_OS2EA[] = {'E', 'A', '2', 0}; + +/* new file inherits a subblock when updating a host file */ +#define SUBHEAD_FLAGS_INHERITED 0x80000000 + +#define SUBHEAD_FLAGS_CMT_UNICODE 0x00000001 + + +struct MarkHeader +{ + byte Mark[8]; + + // Following fields are virtual and not present in real blocks. + uint HeadSize; +}; + + +struct BaseBlock +{ + uint HeadCRC; // 'ushort' for RAR 1.5. + HEADER_TYPE HeaderType; // 1 byte for RAR 1.5. + uint Flags; // 'ushort' for RAR 1.5. + uint HeadSize; // 'ushort' for RAR 1.5, up to 2 MB for RAR 5.0. + + bool SkipIfUnknown; + + void Reset() + { + SkipIfUnknown=false; + } +}; + + +struct BlockHeader:BaseBlock +{ + uint DataSize; +}; + + +struct MainHeader:BaseBlock +{ + ushort HighPosAV; + uint PosAV; + bool CommentInHeader; + bool PackComment; // For RAR 1.4 archive format only. + bool Locator; + uint64 QOpenOffset; // Offset of quick list record. + uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field. + uint64 RROffset; // Offset of recovery record. + uint64 RRMaxSize; // Maximum size of RR offset in locator extra field. + void Reset(); +}; + + +struct FileHeader:BlockHeader +{ + byte HostOS; + byte UnpVer; + byte Method; + union { + uint FileAttr; + uint SubFlags; + }; + wchar FileName[NM]; + + Array SubData; + + RarTime mtime; + RarTime ctime; + RarTime atime; + + int64 PackSize; + int64 UnpSize; + int64 MaxSize; // Reserve size bytes for vint of this size. + + HashValue FileHash; + + uint FileFlags; + + bool SplitBefore; + bool SplitAfter; + + bool UnknownUnpSize; + + bool Encrypted; + bool UsePswCheck; + + // Use HMAC calculated from HashKey and checksum instead of plain checksum. + bool UseHashKey; + + uint Lg2Count; // Log2 of PBKDF2 repetition count. + + bool Solid; + bool Dir; + bool CommentInHeader; // RAR 2.0 file comment. + bool Version; // name.ext;ver file name containing the version number. + size_t WinSize; + bool Inherited; // New file inherits a subblock when updating a host file (for subblocks only). + + // 'true' if file sizes use 8 bytes instead of 4. Not used in RAR 5.0. + bool LargeFile; + + // 'true' for HEAD_SERVICE block, which is a child of preceding file block. + // RAR 4.x uses 'solid' flag to indicate child subheader blocks in archives. + bool SubBlock; + + HOST_SYSTEM_TYPE HSType; + + FILE_SYSTEM_REDIRECT RedirType; + wchar RedirName[NM]; + bool DirTarget; + + bool UnixOwnerSet,UnixOwnerNumeric,UnixGroupNumeric; + char UnixOwnerName[256],UnixGroupName[256]; +#ifdef _UNIX + uid_t UnixOwnerID; + uid_t UnixGroupID; +#else // Need these Unix fields in Windows too for 'list' command. + uint UnixOwnerID; + uint UnixGroupID; +#endif + + void Reset(size_t SubDataSize=0); + + bool CmpName(const wchar *Name) + { + return(my_wcscmp(FileName,Name)==0); + } + + FileHeader& operator = (FileHeader &hd); +}; + + +struct EndArcHeader:BaseBlock +{ + // Optional CRC32 of entire archive up to start of EndArcHeader block. + // Present in RAR 4.x archives if EARC_DATACRC flag is set. + uint ArcDataCRC; + + uint VolNumber; // Optional number of current volume. + + // 7 additional zero bytes can be stored here if EARC_REVSPACE is set. + + bool NextVolume; // Not last volume. + bool DataCRC; + bool RevSpace; + bool StoreVolNumber; + void Reset() + { + BaseBlock::Reset(); + NextVolume=false; + DataCRC=false; + RevSpace=false; + StoreVolNumber=false; + } +}; + + +// SubBlockHeader and its successors were used in RAR 2.x format. +// RAR 4.x uses FileHeader with HEAD_SERVICE HeaderType for subblocks. +struct SubBlockHeader:BlockHeader +{ + ushort SubType; + byte Level; +}; + + +struct CommentHeader:BaseBlock +{ + ushort UnpSize; + byte UnpVer; + byte Method; + ushort CommCRC; +}; + + +struct ProtectHeader:BlockHeader +{ + byte Version; + ushort RecSectors; + uint TotalBlocks; + byte Mark[8]; +}; + + +struct AVHeader:BaseBlock +{ + byte UnpVer; + byte Method; + byte AVVer; + uint AVInfoCRC; +}; + + +struct SignHeader:BaseBlock +{ + uint CreationTime; + ushort ArcNameSize; + ushort UserNameSize; +}; + + +struct UnixOwnersHeader:SubBlockHeader +{ + ushort OwnerNameSize; + ushort GroupNameSize; +/* dummy */ + char OwnerName[256]; + char GroupName[256]; +}; + + +struct EAHeader:SubBlockHeader +{ + uint UnpSize; + byte UnpVer; + byte Method; + uint EACRC; +}; + + +struct StreamHeader:SubBlockHeader +{ + uint UnpSize; + byte UnpVer; + byte Method; + uint StreamCRC; + ushort StreamNameSize; + char StreamName[260]; +}; + + +struct MacFInfoHeader:SubBlockHeader +{ + uint fileType; + uint fileCreator; +}; + + +#endif diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/headers5.hpp b/Frameworks/File_Extractor/File_Extractor/unrar/headers5.hpp new file mode 100644 index 000000000..4f403c216 --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/headers5.hpp @@ -0,0 +1,99 @@ +#ifndef _RAR_HEADERS5_ +#define _RAR_HEADERS5_ + +#define SIZEOF_MARKHEAD5 8 // RAR 5.0 signature length. +#define SIZEOF_SHORTBLOCKHEAD5 7 // Smallest RAR 5.0 block size. + +// RAR 5.0 block flags common for all blocks. + +// Additional extra area is present in the end of block header. +#define HFL_EXTRA 0x0001 +// Additional data area is present in the end of block header. +#define HFL_DATA 0x0002 +// Unknown blocks with this flag must be skipped when updating an archive. +#define HFL_SKIPIFUNKNOWN 0x0004 +// Data area of this block is continuing from previous volume. +#define HFL_SPLITBEFORE 0x0008 +// Data area of this block is continuing in next volume. +#define HFL_SPLITAFTER 0x0010 +// Block depends on preceding file block. +#define HFL_CHILD 0x0020 +// Preserve a child block if host is modified. +#define HFL_INHERITED 0x0040 + +// RAR 5.0 main archive header specific flags. +#define MHFL_VOLUME 0x0001 // Volume. +#define MHFL_VOLNUMBER 0x0002 // Volume number field is present. True for all volumes except first. +#define MHFL_SOLID 0x0004 // Solid archive. +#define MHFL_PROTECT 0x0008 // Recovery record is present. +#define MHFL_LOCK 0x0010 // Locked archive. + +// RAR 5.0 file header specific flags. +#define FHFL_DIRECTORY 0x0001 // Directory. +#define FHFL_UTIME 0x0002 // Time field in Unix format is present. +#define FHFL_CRC32 0x0004 // CRC32 field is present. +#define FHFL_UNPUNKNOWN 0x0008 // Unknown unpacked size. + +// RAR 5.0 end of archive header specific flags. +#define EHFL_NEXTVOLUME 0x0001 // Not last volume. + +// RAR 5.0 archive encryption header specific flags. +#define CHFL_CRYPT_PSWCHECK 0x0001 // Password check data is present. + + +// RAR 5.0 file compression flags. +#define FCI_ALGO_BIT0 0x0001 // Version of compression algorithm. +#define FCI_ALGO_BIT1 0x0002 // 0 .. 63. +#define FCI_ALGO_BIT2 0x0004 +#define FCI_ALGO_BIT3 0x0008 +#define FCI_ALGO_BIT4 0x0010 +#define FCI_ALGO_BIT5 0x0020 +#define FCI_SOLID 0x0040 // Solid flag. +#define FCI_METHOD_BIT0 0x0080 // Compression method. +#define FCI_METHOD_BIT1 0x0100 // 0 .. 5 (6 and 7 are not used). +#define FCI_METHOD_BIT2 0x0200 +#define FCI_DICT_BIT0 0x0400 // Dictionary size. +#define FCI_DICT_BIT1 0x0800 // 128 KB .. 4 GB. +#define FCI_DICT_BIT2 0x1000 +#define FCI_DICT_BIT3 0x2000 + +// Main header extra field values. +#define MHEXTRA_LOCATOR 0x01 // Position of quick list and other blocks. + +// Flags for MHEXTRA_LOCATOR. +#define MHEXTRA_LOCATOR_QLIST 0x01 // Quick open offset is present. +#define MHEXTRA_LOCATOR_RR 0x02 // Recovery record offset is present. + +// File and service header extra field values. +#define FHEXTRA_CRYPT 0x01 // Encryption parameters. +#define FHEXTRA_HASH 0x02 // File hash. +#define FHEXTRA_HTIME 0x03 // High precision file time. +#define FHEXTRA_VERSION 0x04 // File version information. +#define FHEXTRA_REDIR 0x05 // File system redirection (links, etc.). +#define FHEXTRA_UOWNER 0x06 // Unix owner and group information. +#define FHEXTRA_SUBDATA 0x07 // Service header subdata array. + + +// Hash type values for FHEXTRA_HASH. +#define FHEXTRA_HASH_BLAKE2 0x00 + +// Flags for FHEXTRA_HTIME. +#define FHEXTRA_HTIME_UNIXTIME 0x01 // Use Unix time_t format. +#define FHEXTRA_HTIME_MTIME 0x02 // mtime is present. +#define FHEXTRA_HTIME_CTIME 0x04 // ctime is present. +#define FHEXTRA_HTIME_ATIME 0x08 // atime is present. + +// Flags for FHEXTRA_CRYPT. +#define FHEXTRA_CRYPT_PSWCHECK 0x01 // Store password check data. +#define FHEXTRA_CRYPT_HASHMAC 0x02 // Use MAC for unpacked data checksums. + +// Flags for FHEXTRA_REDIR. +#define FHEXTRA_REDIR_DIR 0x01 // Link target is directory. + +// Flags for FHEXTRA_UOWNER. +#define FHEXTRA_UOWNER_UNAME 0x01 // User name string is present. +#define FHEXTRA_UOWNER_GNAME 0x02 // Group name string is present. +#define FHEXTRA_UOWNER_NUMUID 0x04 // Numeric user ID is present. +#define FHEXTRA_UOWNER_NUMGID 0x08 // Numeric group ID is present. + +#endif diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/license.txt b/Frameworks/File_Extractor/File_Extractor/unrar/license.txt index 2aa475c71..0811276a1 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/license.txt +++ b/Frameworks/File_Extractor/File_Extractor/unrar/license.txt @@ -1,40 +1,42 @@ - ****** ***** ****** UnRAR - free utility for RAR archives - ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ****** ******* ****** License for use and distribution of - ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ** ** ** ** ** ** FREE portable version - ~~~~~~~~~~~~~~~~~~~~~ - - The source code of UnRAR utility is freeware. This means: - - 1. All copyrights to RAR and the utility UnRAR are exclusively - owned by the author - Alexander Roshal. - - 2. The UnRAR sources may be used in any software to handle RAR - archives without limitations free of charge, but cannot be used - to re-create the RAR compression algorithm, which is proprietary. - Distribution of modified UnRAR sources in separate form or as a - part of other software is permitted, provided that it is clearly - stated in the documentation and source comments that the code may - not be used to develop a RAR (WinRAR) compatible archiver. - - 3. The UnRAR utility may be freely distributed. It is allowed - to distribute UnRAR inside of other software packages. - - 4. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS". - NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT - YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS, - DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING - OR MISUSING THIS SOFTWARE. - - 5. Installing and using the UnRAR utility signifies acceptance of - these terms and conditions of the license. - - 6. If you don't agree with terms of the license you must remove - UnRAR files from your storage devices and cease to use the - utility. - - Thank you for your interest in RAR and UnRAR. - - - Alexander L. Roshal \ No newline at end of file + ****** ***** ****** UnRAR - free utility for RAR archives + ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ****** ******* ****** License for use and distribution of + ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ** ** ** ** ** ** FREE portable version + ~~~~~~~~~~~~~~~~~~~~~ + + The source code of UnRAR utility is freeware. This means: + + 1. All copyrights to RAR and the utility UnRAR are exclusively + owned by the author - Alexander Roshal. + + 2. UnRAR source code may be used in any software to handle + RAR archives without limitations free of charge, but cannot be + used to develop RAR (WinRAR) compatible archiver and to + re-create RAR compression algorithm, which is proprietary. + Distribution of modified UnRAR source code in separate form + or as a part of other software is permitted, provided that + full text of this paragraph, starting from "UnRAR source code" + words, is included in license, or in documentation if license + is not available, and in source code comments of resulting package. + + 3. The UnRAR utility may be freely distributed. It is allowed + to distribute UnRAR inside of other software packages. + + 4. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS". + NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT + YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS, + DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING + OR MISUSING THIS SOFTWARE. + + 5. Installing and using the UnRAR utility signifies acceptance of + these terms and conditions of the license. + + 6. If you don't agree with terms of the license you must remove + UnRAR files from your storage devices and cease to use the + utility. + + Thank you for your interest in RAR and UnRAR. + + + Alexander L. Roshal diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/model.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/model.cpp index c65ae6807..0b2e5c343 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/model.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/model.cpp @@ -1,612 +1,617 @@ -// #included by unpack.cpp -#ifdef RAR_COMMON_HPP -/**************************************************************************** - * This file is part of PPMd project * - * Written and distributed to public domain by Dmitry Shkarin 1997, * - * 1999-2000 * - * Contents: model description and encoding/decoding routines * - ****************************************************************************/ - -inline PPM_CONTEXT* PPM_CONTEXT::createChild(ModelPPM *Model,STATE* pStats, - STATE& FirstState) -{ - PPM_CONTEXT* pc = (PPM_CONTEXT*) Model->SubAlloc.AllocContext(); - if ( pc ) - { - pc->NumStats=1; - pc->OneState=FirstState; - pc->Suffix=this; - pStats->Successor=pc; - } - return pc; -} - - -ModelPPM::ModelPPM() -{ - MinContext=NULL; - MaxContext=NULL; - MedContext=NULL; -} - - -void ModelPPM::RestartModelRare() -{ - int i, k, m; - memset(CharMask,0,sizeof(CharMask)); - SubAlloc.InitSubAllocator(); - InitRL=-(MaxOrder < 12 ? MaxOrder:12)-1; - MinContext = MaxContext = (PPM_CONTEXT*) SubAlloc.AllocContext(); - MinContext->Suffix=NULL; - OrderFall=MaxOrder; - MinContext->U.SummFreq=(MinContext->NumStats=256)+1; - FoundState=MinContext->U.Stats=(STATE*)SubAlloc.AllocUnits(256/2); - for (RunLength=InitRL, PrevSuccess=i=0;i < 256;i++) - { - MinContext->U.Stats[i].Symbol=i; - MinContext->U.Stats[i].Freq=1; - MinContext->U.Stats[i].Successor=NULL; - } - - static const ushort InitBinEsc[]={ - 0x3CDD,0x1F3F,0x59BF,0x48F3,0x64A1,0x5ABC,0x6632,0x6051 - }; - - for (i=0;i < 128;i++) - for (k=0;k < 8;k++) - for (m=0;m < 64;m += 8) - BinSumm[i][k+m]=BIN_SCALE-InitBinEsc[k]/(i+2); - for (i=0;i < 25;i++) - for (k=0;k < 16;k++) - SEE2Cont[i][k].init(5*i+10); -} - - -void ModelPPM::StartModelRare(int MaxOrder) -{ - int i, k, m ,Step; - EscCount=1; -/* - if (MaxOrder < 2) - { - memset(CharMask,0,sizeof(CharMask)); - OrderFall=ModelPPM::MaxOrder; - MinContext=MaxContext; - while (MinContext->Suffix != NULL) - { - MinContext=MinContext->Suffix; - OrderFall--; - } - FoundState=MinContext->U.Stats; - MinContext=MaxContext; - } - else -*/ - { - ModelPPM::MaxOrder=MaxOrder; - RestartModelRare(); - NS2BSIndx[0]=2*0; - NS2BSIndx[1]=2*1; - memset(NS2BSIndx+2,2*2,9); - memset(NS2BSIndx+11,2*3,256-11); - for (i=0;i < 3;i++) - NS2Indx[i]=i; - for (m=i, k=Step=1;i < 256;i++) - { - NS2Indx[i]=m; - if ( !--k ) - { - k = ++Step; - m++; - } - } - memset(HB2Flag,0,0x40); - memset(HB2Flag+0x40,0x08,0x100-0x40); - DummySEE2Cont.Shift=PERIOD_BITS; - } -} - - -void PPM_CONTEXT::rescale(ModelPPM *Model) -{ - int OldNS=NumStats, i=NumStats-1, Adder, EscFreq; - STATE* p1, * p; - for (p=Model->FoundState;p != U.Stats;p--) - _PPMD_SWAP(p[0],p[-1]); - U.Stats->Freq += 4; - U.SummFreq += 4; - EscFreq=U.SummFreq-p->Freq; - Adder=(Model->OrderFall != 0); - U.SummFreq = (p->Freq=(p->Freq+Adder) >> 1); - do - { - EscFreq -= (++p)->Freq; - U.SummFreq += (p->Freq=(p->Freq+Adder) >> 1); - if (p[0].Freq > p[-1].Freq) - { - STATE tmp=*(p1=p); - do - { - p1[0]=p1[-1]; - } while (--p1 != U.Stats && tmp.Freq > p1[-1].Freq); - *p1=tmp; - } - } while ( --i ); - if (p->Freq == 0) - { - do - { - i++; - } while ((--p)->Freq == 0); - EscFreq += i; - if ((NumStats -= i) == 1) - { - STATE tmp=*U.Stats; - do - { - tmp.Freq-=(tmp.Freq >> 1); - EscFreq>>=1; - } while (EscFreq > 1); - Model->SubAlloc.FreeUnits(U.Stats,(OldNS+1) >> 1); - *(Model->FoundState=&OneState)=tmp; return; - } - } - U.SummFreq += (EscFreq -= (EscFreq >> 1)); - int n0=(OldNS+1) >> 1, n1=(NumStats+1) >> 1; - if (n0 != n1) - U.Stats = (STATE*) Model->SubAlloc.ShrinkUnits(U.Stats,n0,n1); - Model->FoundState=U.Stats; -} - - -inline PPM_CONTEXT* ModelPPM::CreateSuccessors(bool Skip,STATE* p1) -{ - // (removed conditional static) - STATE UpState; - PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor; - STATE * p, * ps[MAX_O], ** pps=ps; - if ( !Skip ) - { - *pps++ = FoundState; - if ( !pc->Suffix ) - goto NO_LOOP; - } - if ( p1 ) - { - p=p1; - pc=pc->Suffix; - goto LOOP_ENTRY; - } - do - { - pc=pc->Suffix; - if (pc->NumStats != 1) - { - if ((p=pc->U.Stats)->Symbol != FoundState->Symbol) - do - { - p++; - } while (p->Symbol != FoundState->Symbol); - } - else - p=&(pc->OneState); -LOOP_ENTRY: - if (p->Successor != UpBranch) - { - pc=p->Successor; - break; - } - *pps++ = p; - } while ( pc->Suffix ); -NO_LOOP: - if (pps == ps) - return pc; - UpState.Symbol=*(byte*) UpBranch; - UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1); - if (pc->NumStats != 1) - { - if ((byte*) pc <= SubAlloc.pText) - return(NULL); - if ((p=pc->U.Stats)->Symbol != UpState.Symbol) - do - { - p++; - } while (p->Symbol != UpState.Symbol); - uint cf=p->Freq-1; - uint s0=pc->U.SummFreq-pc->NumStats-cf; - UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0))); - } - else - UpState.Freq=pc->OneState.Freq; - do - { - pc = pc->createChild(this,*--pps,UpState); - if ( !pc ) - return NULL; - } while (pps != ps); - return pc; -} - - -inline void ModelPPM::UpdateModel() -{ - STATE fs = *FoundState, *p = NULL; - PPM_CONTEXT *pc, *Successor; - uint ns1, ns, cf, sf, s0; - if (fs.Freq < MAX_FREQ/4 && (pc=MinContext->Suffix) != NULL) - { - if (pc->NumStats != 1) - { - if ((p=pc->U.Stats)->Symbol != fs.Symbol) - { - do - { - p++; - } while (p->Symbol != fs.Symbol); - if (p[0].Freq >= p[-1].Freq) - { - _PPMD_SWAP(p[0],p[-1]); - p--; - } - } - if (p->Freq < MAX_FREQ-9) - { - p->Freq += 2; - pc->U.SummFreq += 2; - } - } - else - { - p=&(pc->OneState); - p->Freq += (p->Freq < 32); - } - } - if ( !OrderFall ) - { - MinContext=MaxContext=FoundState->Successor=CreateSuccessors(true,p); - if ( !MinContext ) - goto RESTART_MODEL; - return; - } - *SubAlloc.pText++ = fs.Symbol; - Successor = (PPM_CONTEXT*) SubAlloc.pText; - if (SubAlloc.pText >= SubAlloc.FakeUnitsStart) - goto RESTART_MODEL; - if ( fs.Successor ) - { - if ((byte*) fs.Successor <= SubAlloc.pText && - (fs.Successor=CreateSuccessors(false,p)) == NULL) - goto RESTART_MODEL; - if ( !--OrderFall ) - { - Successor=fs.Successor; - SubAlloc.pText -= (MaxContext != MinContext); - } - } - else - { - FoundState->Successor=Successor; - fs.Successor=MinContext; - } - s0=MinContext->U.SummFreq-(ns=MinContext->NumStats)-(fs.Freq-1); - for (pc=MaxContext;pc != MinContext;pc=pc->Suffix) - { - if ((ns1=pc->NumStats) != 1) - { - if ((ns1 & 1) == 0) - { - pc->U.Stats=(STATE*) SubAlloc.ExpandUnits(pc->U.Stats,ns1 >> 1); - if ( !pc->U.Stats ) - goto RESTART_MODEL; - } - pc->U.SummFreq += (2*ns1 < ns)+2*((4*ns1 <= ns) & (pc->U.SummFreq <= 8*ns1)); - } - else - { - p=(STATE*) SubAlloc.AllocUnits(1); - if ( !p ) - goto RESTART_MODEL; - *p=pc->OneState; - pc->U.Stats=p; - if (p->Freq < MAX_FREQ/4-1) - p->Freq += p->Freq; - else - p->Freq = MAX_FREQ-4; - pc->U.SummFreq=p->Freq+InitEsc+(ns > 3); - } - cf=2*fs.Freq*(pc->U.SummFreq+6); - sf=s0+pc->U.SummFreq; - if (cf < 6*sf) - { - cf=1+(cf > sf)+(cf >= 4*sf); - pc->U.SummFreq += 3; - } - else - { - cf=4+(cf >= 9*sf)+(cf >= 12*sf)+(cf >= 15*sf); - pc->U.SummFreq += cf; - } - p=pc->U.Stats+ns1; - p->Successor=Successor; - p->Symbol = fs.Symbol; - p->Freq = cf; - pc->NumStats=++ns1; - } - MaxContext=MinContext=fs.Successor; - return; -RESTART_MODEL: - RestartModelRare(); - EscCount=0; -} - - -// Tabulated escapes for exponential symbol distribution -static const byte ExpEscape[16]={ 25,14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; -#define GET_MEAN(SUMM,SHIFT,ROUND) ((SUMM+(1 << (SHIFT-ROUND))) >> (SHIFT)) - - - -inline void PPM_CONTEXT::decodeBinSymbol(ModelPPM *Model) -{ - STATE& rs=OneState; - Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol]; - ushort& bs=Model->BinSumm[rs.Freq-1][Model->PrevSuccess+ - Model->NS2BSIndx[Suffix->NumStats-1]+ - Model->HiBitsFlag+2*Model->HB2Flag[rs.Symbol]+ - ((Model->RunLength >> 26) & 0x20)]; - if (Model->Coder.GetCurrentShiftCount(TOT_BITS) < bs) - { - Model->FoundState=&rs; - rs.Freq += (rs.Freq < 128); - Model->Coder.SubRange.LowCount=0; - Model->Coder.SubRange.HighCount=bs; - bs = SHORT16(bs+INTERVAL-GET_MEAN(bs,PERIOD_BITS,2)); - Model->PrevSuccess=1; - Model->RunLength++; - } - else - { - Model->Coder.SubRange.LowCount=bs; - bs = SHORT16(bs-GET_MEAN(bs,PERIOD_BITS,2)); - Model->Coder.SubRange.HighCount=BIN_SCALE; - Model->InitEsc=ExpEscape[bs >> 10]; - Model->NumMasked=1; - Model->CharMask[rs.Symbol]=Model->EscCount; - Model->PrevSuccess=0; - Model->FoundState=NULL; - } -} - - -inline void PPM_CONTEXT::update1(ModelPPM *Model,STATE* p) -{ - (Model->FoundState=p)->Freq += 4; - U.SummFreq += 4; - if (p[0].Freq > p[-1].Freq) - { - _PPMD_SWAP(p[0],p[-1]); - Model->FoundState=--p; - if (p->Freq > MAX_FREQ) - rescale(Model); - } -} - - - - -inline bool PPM_CONTEXT::decodeSymbol1(ModelPPM *Model) -{ - Model->Coder.SubRange.scale=U.SummFreq; - STATE* p=U.Stats; - int i, HiCnt; - int count=Model->Coder.GetCurrentCount(); - if (count>=Model->Coder.SubRange.scale) - return(false); - if (count < (HiCnt=p->Freq)) - { - Model->PrevSuccess=(2*(Model->Coder.SubRange.HighCount=HiCnt) > Model->Coder.SubRange.scale); - Model->RunLength += Model->PrevSuccess; - (Model->FoundState=p)->Freq=(HiCnt += 4); - U.SummFreq += 4; - if (HiCnt > MAX_FREQ) - rescale(Model); - Model->Coder.SubRange.LowCount=0; - return(true); - } - else - if (Model->FoundState==NULL) - return(false); - Model->PrevSuccess=0; - i=NumStats-1; - while ((HiCnt += (++p)->Freq) <= count) - if (--i == 0) - { - Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol]; - Model->Coder.SubRange.LowCount=HiCnt; - Model->CharMask[p->Symbol]=Model->EscCount; - i=(Model->NumMasked=NumStats)-1; - Model->FoundState=NULL; - do - { - Model->CharMask[(--p)->Symbol]=Model->EscCount; - } while ( --i ); - Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale; - return(true); - } - Model->Coder.SubRange.LowCount=(Model->Coder.SubRange.HighCount=HiCnt)-p->Freq; - update1(Model,p); - return(true); -} - - -inline void PPM_CONTEXT::update2(ModelPPM *Model,STATE* p) -{ - (Model->FoundState=p)->Freq += 4; - U.SummFreq += 4; - if (p->Freq > MAX_FREQ) - rescale(Model); - Model->EscCount++; - Model->RunLength=Model->InitRL; -} - - -inline SEE2_CONTEXT* PPM_CONTEXT::makeEscFreq2(ModelPPM *Model,int Diff) -{ - SEE2_CONTEXT* psee2c; - if (NumStats != 256) - { - psee2c=Model->SEE2Cont[Model->NS2Indx[Diff-1]]+ - (Diff < Suffix->NumStats-NumStats)+ - 2*(U.SummFreq < 11*NumStats)+4*(Model->NumMasked > Diff)+ - Model->HiBitsFlag; - Model->Coder.SubRange.scale=psee2c->getMean(); - } - else - { - psee2c=&Model->DummySEE2Cont; - Model->Coder.SubRange.scale=1; - } - return psee2c; -} - - - - -inline bool PPM_CONTEXT::decodeSymbol2(ModelPPM *Model) -{ - int count, HiCnt, i=NumStats-Model->NumMasked; - SEE2_CONTEXT* psee2c=makeEscFreq2(Model,i); - STATE* ps[256], ** pps=ps, * p=U.Stats-1; - HiCnt=0; - do - { - do - { - p++; - } while (Model->CharMask[p->Symbol] == Model->EscCount); - HiCnt += p->Freq; - *pps++ = p; - } while ( --i ); - Model->Coder.SubRange.scale += HiCnt; - count=Model->Coder.GetCurrentCount(); - if (count>=Model->Coder.SubRange.scale) - return(false); - p=*(pps=ps); - if (count < HiCnt) - { - HiCnt=0; - while ((HiCnt += p->Freq) <= count) - p=*++pps; - Model->Coder.SubRange.LowCount = (Model->Coder.SubRange.HighCount=HiCnt)-p->Freq; - psee2c->update(); - update2(Model,p); - } - else - { - Model->Coder.SubRange.LowCount=HiCnt; - Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale; - i=NumStats-Model->NumMasked; - pps--; - do - { - Model->CharMask[(*++pps)->Symbol]=Model->EscCount; - } while ( --i ); - psee2c->Summ += Model->Coder.SubRange.scale; - Model->NumMasked = NumStats; - } - return(true); -} - - -inline void ModelPPM::ClearMask() -{ - EscCount=1; - memset(CharMask,0,sizeof(CharMask)); -} - - - - -// reset PPM variables after data error allowing safe resuming -// of further data processing -void ModelPPM::CleanUp() -{ - SubAlloc.StopSubAllocator(); - SubAlloc.StartSubAllocator(1); - StartModelRare(2); -} - - -bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar) -{ - int MaxOrder=UnpackRead->GetChar(); - bool Reset=MaxOrder & 0x20; - - int MaxMB; - MaxMB = 0; // avoids warning of being uninitialized - if (Reset) - MaxMB=UnpackRead->GetChar(); - else - if (SubAlloc.GetAllocatedMemory()==0) - return(false); - if (MaxOrder & 0x40) - EscChar=UnpackRead->GetChar(); - Coder.InitDecoder(UnpackRead); - if (Reset) - { - MaxOrder=(MaxOrder & 0x1f)+1; - if (MaxOrder>16) - MaxOrder=16+(MaxOrder-16)*3; - if (MaxOrder==1) - { - SubAlloc.StopSubAllocator(); - return(false); - } - SubAlloc.StartSubAllocator(MaxMB+1); - StartModelRare(MaxOrder); - } - return(MinContext!=NULL); -} - - -int ModelPPM::DecodeChar() -{ - if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd) - return(-1); - if (MinContext->NumStats != 1) - { - if ((byte*)MinContext->U.Stats <= SubAlloc.pText || (byte*)MinContext->U.Stats>SubAlloc.HeapEnd) - return(-1); - if (!MinContext->decodeSymbol1(this)) - return(-1); - } - else - MinContext->decodeBinSymbol(this); - Coder.Decode(); - while ( !FoundState ) - { - ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead); - do - { - OrderFall++; - MinContext=MinContext->Suffix; - if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd) - return(-1); - } while (MinContext->NumStats == NumMasked); - if (!MinContext->decodeSymbol2(this)) - return(-1); - Coder.Decode(); - } - int Symbol=FoundState->Symbol; - if (!OrderFall && (byte*) FoundState->Successor > SubAlloc.pText) - MinContext=MaxContext=FoundState->Successor; - else - { - UpdateModel(); - if (EscCount == 0) - ClearMask(); - } - ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead); - return(Symbol); -} -#endif +/**************************************************************************** + * This file is part of PPMd project * + * Written and distributed to public domain by Dmitry Shkarin 1997, * + * 1999-2000 * + * Contents: model description and encoding/decoding routines * + ****************************************************************************/ + +static const int MAX_O=64; /* maximum allowed model order */ +const uint TOP=1 << 24, BOT=1 << 15; + +template +inline void _PPMD_SWAP(T& t1,T& t2) { T tmp=t1; t1=t2; t2=tmp; } + + +inline RARPPM_CONTEXT* RARPPM_CONTEXT::createChild(ModelPPM *Model,RARPPM_STATE* pStats, + RARPPM_STATE& FirstState) +{ + RARPPM_CONTEXT* pc = (RARPPM_CONTEXT*) Model->SubAlloc.AllocContext(); + if ( pc ) + { + pc->NumStats=1; + pc->OneState=FirstState; + pc->Suffix=this; + pStats->Successor=pc; + } + return pc; +} + + +ModelPPM::ModelPPM() +{ + MinContext=NULL; + MaxContext=NULL; + MedContext=NULL; +} + + +void ModelPPM::RestartModelRare() +{ + int i, k, m; + memset(CharMask,0,sizeof(CharMask)); + SubAlloc.InitSubAllocator(); + InitRL=-(MaxOrder < 12 ? MaxOrder:12)-1; + MinContext = MaxContext = (RARPPM_CONTEXT*) SubAlloc.AllocContext(); + MinContext->Suffix=NULL; + OrderFall=MaxOrder; + MinContext->U.SummFreq=(MinContext->NumStats=256)+1; + FoundState=MinContext->U.Stats=(RARPPM_STATE*)SubAlloc.AllocUnits(256/2); + for (RunLength=InitRL, PrevSuccess=i=0;i < 256;i++) + { + MinContext->U.Stats[i].Symbol=i; + MinContext->U.Stats[i].Freq=1; + MinContext->U.Stats[i].Successor=NULL; + } + + static const ushort InitBinEsc[]={ + 0x3CDD,0x1F3F,0x59BF,0x48F3,0x64A1,0x5ABC,0x6632,0x6051 + }; + + for (i=0;i < 128;i++) + for (k=0;k < 8;k++) + for (m=0;m < 64;m += 8) + BinSumm[i][k+m]=BIN_SCALE-InitBinEsc[k]/(i+2); + for (i=0;i < 25;i++) + for (k=0;k < 16;k++) + SEE2Cont[i][k].init(5*i+10); +} + + +void ModelPPM::StartModelRare(int MaxOrder) +{ + int i, k, m ,Step; + EscCount=1; +/* + if (MaxOrder < 2) + { + memset(CharMask,0,sizeof(CharMask)); + OrderFall=ModelPPM::MaxOrder; + MinContext=MaxContext; + while (MinContext->Suffix != NULL) + { + MinContext=MinContext->Suffix; + OrderFall--; + } + FoundState=MinContext->U.Stats; + MinContext=MaxContext; + } + else +*/ + { + ModelPPM::MaxOrder=MaxOrder; + RestartModelRare(); + NS2BSIndx[0]=2*0; + NS2BSIndx[1]=2*1; + memset(NS2BSIndx+2,2*2,9); + memset(NS2BSIndx+11,2*3,256-11); + for (i=0;i < 3;i++) + NS2Indx[i]=i; + for (m=i, k=Step=1;i < 256;i++) + { + NS2Indx[i]=m; + if ( !--k ) + { + k = ++Step; + m++; + } + } + memset(HB2Flag,0,0x40); + memset(HB2Flag+0x40,0x08,0x100-0x40); + DummySEE2Cont.Shift=PERIOD_BITS; + } +} + + +void RARPPM_CONTEXT::rescale(ModelPPM *Model) +{ + int OldNS=NumStats, i=NumStats-1, Adder, EscFreq; + RARPPM_STATE* p1, * p; + for (p=Model->FoundState;p != U.Stats;p--) + _PPMD_SWAP(p[0],p[-1]); + U.Stats->Freq += 4; + U.SummFreq += 4; + EscFreq=U.SummFreq-p->Freq; + Adder=(Model->OrderFall != 0); + U.SummFreq = (p->Freq=(p->Freq+Adder) >> 1); + do + { + EscFreq -= (++p)->Freq; + U.SummFreq += (p->Freq=(p->Freq+Adder) >> 1); + if (p[0].Freq > p[-1].Freq) + { + RARPPM_STATE tmp=*(p1=p); + do + { + p1[0]=p1[-1]; + } while (--p1 != U.Stats && tmp.Freq > p1[-1].Freq); + *p1=tmp; + } + } while ( --i ); + if (p->Freq == 0) + { + do + { + i++; + } while ((--p)->Freq == 0); + EscFreq += i; + if ((NumStats -= i) == 1) + { + RARPPM_STATE tmp=*U.Stats; + do + { + tmp.Freq-=(tmp.Freq >> 1); + EscFreq>>=1; + } while (EscFreq > 1); + Model->SubAlloc.FreeUnits(U.Stats,(OldNS+1) >> 1); + *(Model->FoundState=&OneState)=tmp; return; + } + } + U.SummFreq += (EscFreq -= (EscFreq >> 1)); + int n0=(OldNS+1) >> 1, n1=(NumStats+1) >> 1; + if (n0 != n1) + U.Stats = (RARPPM_STATE*) Model->SubAlloc.ShrinkUnits(U.Stats,n0,n1); + Model->FoundState=U.Stats; +} + + +inline RARPPM_CONTEXT* ModelPPM::CreateSuccessors(bool Skip,RARPPM_STATE* p1) +{ +#ifdef __ICL + static +#endif + RARPPM_STATE UpState; + RARPPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor; + RARPPM_STATE * p, * ps[MAX_O], ** pps=ps; + if ( !Skip ) + { + *pps++ = FoundState; + if ( !pc->Suffix ) + goto NO_LOOP; + } + if ( p1 ) + { + p=p1; + pc=pc->Suffix; + goto LOOP_ENTRY; + } + do + { + pc=pc->Suffix; + if (pc->NumStats != 1) + { + if ((p=pc->U.Stats)->Symbol != FoundState->Symbol) + do + { + p++; + } while (p->Symbol != FoundState->Symbol); + } + else + p=&(pc->OneState); +LOOP_ENTRY: + if (p->Successor != UpBranch) + { + pc=p->Successor; + break; + } + *pps++ = p; + } while ( pc->Suffix ); +NO_LOOP: + if (pps == ps) + return pc; + UpState.Symbol=*(byte*) UpBranch; + UpState.Successor=(RARPPM_CONTEXT*) (((byte*) UpBranch)+1); + if (pc->NumStats != 1) + { + if ((byte*) pc <= SubAlloc.pText) + return(NULL); + if ((p=pc->U.Stats)->Symbol != UpState.Symbol) + do + { + p++; + } while (p->Symbol != UpState.Symbol); + uint cf=p->Freq-1; + uint s0=pc->U.SummFreq-pc->NumStats-cf; + UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0))); + } + else + UpState.Freq=pc->OneState.Freq; + do + { + pc = pc->createChild(this,*--pps,UpState); + if ( !pc ) + return NULL; + } while (pps != ps); + return pc; +} + + +inline void ModelPPM::UpdateModel() +{ + RARPPM_STATE fs = *FoundState, *p = NULL; + RARPPM_CONTEXT *pc, *Successor; + uint ns1, ns, cf, sf, s0; + if (fs.Freq < MAX_FREQ/4 && (pc=MinContext->Suffix) != NULL) + { + if (pc->NumStats != 1) + { + if ((p=pc->U.Stats)->Symbol != fs.Symbol) + { + do + { + p++; + } while (p->Symbol != fs.Symbol); + if (p[0].Freq >= p[-1].Freq) + { + _PPMD_SWAP(p[0],p[-1]); + p--; + } + } + if (p->Freq < MAX_FREQ-9) + { + p->Freq += 2; + pc->U.SummFreq += 2; + } + } + else + { + p=&(pc->OneState); + p->Freq += (p->Freq < 32); + } + } + if ( !OrderFall ) + { + MinContext=MaxContext=FoundState->Successor=CreateSuccessors(TRUE,p); + if ( !MinContext ) + goto RESTART_MODEL; + return; + } + *SubAlloc.pText++ = fs.Symbol; + Successor = (RARPPM_CONTEXT*) SubAlloc.pText; + if (SubAlloc.pText >= SubAlloc.FakeUnitsStart) + goto RESTART_MODEL; + if ( fs.Successor ) + { + if ((byte*) fs.Successor <= SubAlloc.pText && + (fs.Successor=CreateSuccessors(FALSE,p)) == NULL) + goto RESTART_MODEL; + if ( !--OrderFall ) + { + Successor=fs.Successor; + SubAlloc.pText -= (MaxContext != MinContext); + } + } + else + { + FoundState->Successor=Successor; + fs.Successor=MinContext; + } + s0=MinContext->U.SummFreq-(ns=MinContext->NumStats)-(fs.Freq-1); + for (pc=MaxContext;pc != MinContext;pc=pc->Suffix) + { + if ((ns1=pc->NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + pc->U.Stats=(RARPPM_STATE*) SubAlloc.ExpandUnits(pc->U.Stats,ns1 >> 1); + if ( !pc->U.Stats ) + goto RESTART_MODEL; + } + pc->U.SummFreq += (2*ns1 < ns)+2*((4*ns1 <= ns) & (pc->U.SummFreq <= 8*ns1)); + } + else + { + p=(RARPPM_STATE*) SubAlloc.AllocUnits(1); + if ( !p ) + goto RESTART_MODEL; + *p=pc->OneState; + pc->U.Stats=p; + if (p->Freq < MAX_FREQ/4-1) + p->Freq += p->Freq; + else + p->Freq = MAX_FREQ-4; + pc->U.SummFreq=p->Freq+InitEsc+(ns > 3); + } + cf=2*fs.Freq*(pc->U.SummFreq+6); + sf=s0+pc->U.SummFreq; + if (cf < 6*sf) + { + cf=1+(cf > sf)+(cf >= 4*sf); + pc->U.SummFreq += 3; + } + else + { + cf=4+(cf >= 9*sf)+(cf >= 12*sf)+(cf >= 15*sf); + pc->U.SummFreq += cf; + } + p=pc->U.Stats+ns1; + p->Successor=Successor; + p->Symbol = fs.Symbol; + p->Freq = cf; + pc->NumStats=++ns1; + } + MaxContext=MinContext=fs.Successor; + return; +RESTART_MODEL: + RestartModelRare(); + EscCount=0; +} + + +// Tabulated escapes for exponential symbol distribution +static const byte ExpEscape[16]={ 25,14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +#define GET_MEAN(SUMM,SHIFT,ROUND) ((SUMM+(1 << (SHIFT-ROUND))) >> (SHIFT)) + + + +inline void RARPPM_CONTEXT::decodeBinSymbol(ModelPPM *Model) +{ + RARPPM_STATE& rs=OneState; + Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol]; + ushort& bs=Model->BinSumm[rs.Freq-1][Model->PrevSuccess+ + Model->NS2BSIndx[Suffix->NumStats-1]+ + Model->HiBitsFlag+2*Model->HB2Flag[rs.Symbol]+ + ((Model->RunLength >> 26) & 0x20)]; + if (Model->Coder.GetCurrentShiftCount(TOT_BITS) < bs) + { + Model->FoundState=&rs; + rs.Freq += (rs.Freq < 128); + Model->Coder.SubRange.LowCount=0; + Model->Coder.SubRange.HighCount=bs; + bs = GET_SHORT16(bs+INTERVAL-GET_MEAN(bs,PERIOD_BITS,2)); + Model->PrevSuccess=1; + Model->RunLength++; + } + else + { + Model->Coder.SubRange.LowCount=bs; + bs = GET_SHORT16(bs-GET_MEAN(bs,PERIOD_BITS,2)); + Model->Coder.SubRange.HighCount=BIN_SCALE; + Model->InitEsc=ExpEscape[bs >> 10]; + Model->NumMasked=1; + Model->CharMask[rs.Symbol]=Model->EscCount; + Model->PrevSuccess=0; + Model->FoundState=NULL; + } +} + + +inline void RARPPM_CONTEXT::update1(ModelPPM *Model,RARPPM_STATE* p) +{ + (Model->FoundState=p)->Freq += 4; + U.SummFreq += 4; + if (p[0].Freq > p[-1].Freq) + { + _PPMD_SWAP(p[0],p[-1]); + Model->FoundState=--p; + if (p->Freq > MAX_FREQ) + rescale(Model); + } +} + + + + +inline bool RARPPM_CONTEXT::decodeSymbol1(ModelPPM *Model) +{ + Model->Coder.SubRange.scale=U.SummFreq; + RARPPM_STATE* p=U.Stats; + int i, HiCnt; + int count=Model->Coder.GetCurrentCount(); + if (count>=(int)Model->Coder.SubRange.scale) + return(false); + if (count < (HiCnt=p->Freq)) + { + Model->PrevSuccess=(2*(Model->Coder.SubRange.HighCount=HiCnt) > Model->Coder.SubRange.scale); + Model->RunLength += Model->PrevSuccess; + (Model->FoundState=p)->Freq=(HiCnt += 4); + U.SummFreq += 4; + if (HiCnt > MAX_FREQ) + rescale(Model); + Model->Coder.SubRange.LowCount=0; + return(true); + } + else + if (Model->FoundState==NULL) + return(false); + Model->PrevSuccess=0; + i=NumStats-1; + while ((HiCnt += (++p)->Freq) <= count) + if (--i == 0) + { + Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol]; + Model->Coder.SubRange.LowCount=HiCnt; + Model->CharMask[p->Symbol]=Model->EscCount; + i=(Model->NumMasked=NumStats)-1; + Model->FoundState=NULL; + do + { + Model->CharMask[(--p)->Symbol]=Model->EscCount; + } while ( --i ); + Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale; + return(true); + } + Model->Coder.SubRange.LowCount=(Model->Coder.SubRange.HighCount=HiCnt)-p->Freq; + update1(Model,p); + return(true); +} + + +inline void RARPPM_CONTEXT::update2(ModelPPM *Model,RARPPM_STATE* p) +{ + (Model->FoundState=p)->Freq += 4; + U.SummFreq += 4; + if (p->Freq > MAX_FREQ) + rescale(Model); + Model->EscCount++; + Model->RunLength=Model->InitRL; +} + + +inline RARPPM_SEE2_CONTEXT* RARPPM_CONTEXT::makeEscFreq2(ModelPPM *Model,int Diff) +{ + RARPPM_SEE2_CONTEXT* psee2c; + if (NumStats != 256) + { + psee2c=Model->SEE2Cont[Model->NS2Indx[Diff-1]]+ + (Diff < Suffix->NumStats-NumStats)+ + 2*(U.SummFreq < 11*NumStats)+4*(Model->NumMasked > Diff)+ + Model->HiBitsFlag; + Model->Coder.SubRange.scale=psee2c->getMean(); + } + else + { + psee2c=&Model->DummySEE2Cont; + Model->Coder.SubRange.scale=1; + } + return psee2c; +} + + + + +inline bool RARPPM_CONTEXT::decodeSymbol2(ModelPPM *Model) +{ + int count, HiCnt, i=NumStats-Model->NumMasked; + RARPPM_SEE2_CONTEXT* psee2c=makeEscFreq2(Model,i); + RARPPM_STATE* ps[256], ** pps=ps, * p=U.Stats-1; + HiCnt=0; + do + { + do + { + p++; + } while (Model->CharMask[p->Symbol] == Model->EscCount); + HiCnt += p->Freq; + *pps++ = p; + } while ( --i ); + Model->Coder.SubRange.scale += HiCnt; + count=Model->Coder.GetCurrentCount(); + if (count>=(int)Model->Coder.SubRange.scale) + return(false); + p=*(pps=ps); + if (count < HiCnt) + { + HiCnt=0; + while ((HiCnt += p->Freq) <= count) + p=*++pps; + Model->Coder.SubRange.LowCount = (Model->Coder.SubRange.HighCount=HiCnt)-p->Freq; + psee2c->update(); + update2(Model,p); + } + else + { + Model->Coder.SubRange.LowCount=HiCnt; + Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale; + i=NumStats-Model->NumMasked; + pps--; + do + { + Model->CharMask[(*++pps)->Symbol]=Model->EscCount; + } while ( --i ); + psee2c->Summ += Model->Coder.SubRange.scale; + Model->NumMasked = NumStats; + } + return(true); +} + + +inline void ModelPPM::ClearMask() +{ + EscCount=1; + memset(CharMask,0,sizeof(CharMask)); +} + + + + +// reset PPM variables after data error allowing safe resuming +// of further data processing +void ModelPPM::CleanUp() +{ + SubAlloc.StopSubAllocator(); + SubAlloc.StartSubAllocator(1); + StartModelRare(2); +} + + +bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar) +{ + int MaxOrder=UnpackRead->GetChar(); + bool Reset=(MaxOrder & 0x20)!=0; + + int MaxMB; + if (Reset) + MaxMB=UnpackRead->GetChar(); + else + if (SubAlloc.GetAllocatedMemory()==0) + return(false); + if (MaxOrder & 0x40) + EscChar=UnpackRead->GetChar(); + Coder.InitDecoder(UnpackRead); + if (Reset) + { + MaxOrder=(MaxOrder & 0x1f)+1; + if (MaxOrder>16) + MaxOrder=16+(MaxOrder-16)*3; + if (MaxOrder==1) + { + SubAlloc.StopSubAllocator(); + return(false); + } + SubAlloc.StartSubAllocator(MaxMB+1); + StartModelRare(MaxOrder); + } + return(MinContext!=NULL); +} + + +int ModelPPM::DecodeChar() +{ + if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd) + return(-1); + if (MinContext->NumStats != 1) + { + if ((byte*)MinContext->U.Stats <= SubAlloc.pText || (byte*)MinContext->U.Stats>SubAlloc.HeapEnd) + return(-1); + if (!MinContext->decodeSymbol1(this)) + return(-1); + } + else + MinContext->decodeBinSymbol(this); + Coder.Decode(); + while ( !FoundState ) + { + ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead); + do + { + OrderFall++; + MinContext=MinContext->Suffix; + if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd) + return(-1); + } while (MinContext->NumStats == NumMasked); + if (!MinContext->decodeSymbol2(this)) + return(-1); + Coder.Decode(); + } + int Symbol=FoundState->Symbol; + if (!OrderFall && (byte*) FoundState->Successor > SubAlloc.pText) + MinContext=MaxContext=FoundState->Successor; + else + { + UpdateModel(); + if (EscCount == 0) + ClearMask(); + } + ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead); + return(Symbol); +} diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/model.hpp b/Frameworks/File_Extractor/File_Extractor/unrar/model.hpp index b4716d12a..52abc89b3 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/model.hpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/model.hpp @@ -1,133 +1,122 @@ -#ifndef _RAR_PPMMODEL_ -#define _RAR_PPMMODEL_ - -#include "coder.hpp" -#include "suballoc.hpp" - -const int MAX_O=64; /* maximum allowed model order */ - -const int INT_BITS=7, PERIOD_BITS=7, TOT_BITS=INT_BITS+PERIOD_BITS, - INTERVAL=1 << INT_BITS, BIN_SCALE=1 << TOT_BITS, MAX_FREQ=124; - -#ifndef STRICT_ALIGNMENT_REQUIRED -#pragma pack(1) -#endif - -struct SEE2_CONTEXT -{ // SEE-contexts for PPM-contexts with masked symbols - ushort Summ; - byte Shift, Count; - void init(int InitVal) - { - Summ=InitVal << (Shift=PERIOD_BITS-4); - Count=4; - } - uint getMean() - { - uint RetVal=SHORT16(Summ) >> Shift; - Summ -= RetVal; - return RetVal+(RetVal == 0); - } - void update() - { - if (Shift < PERIOD_BITS && --Count == 0) - { - Summ += Summ; - Count=3 << Shift++; - } - } -}; - - -class ModelPPM; -struct PPM_CONTEXT; - -struct STATE -{ - byte Symbol; - byte Freq; - PPM_CONTEXT* Successor; -}; - -struct FreqData -{ - ushort SummFreq; - STATE _PACK_ATTR * Stats; -}; - -struct PPM_CONTEXT -{ - ushort NumStats; - union - { - FreqData U; - STATE OneState; - }; - - PPM_CONTEXT* Suffix; - inline void encodeBinSymbol(ModelPPM *Model,int symbol); // MaxOrder: - inline void encodeSymbol1(ModelPPM *Model,int symbol); // ABCD context - inline void encodeSymbol2(ModelPPM *Model,int symbol); // BCD suffix - inline void decodeBinSymbol(ModelPPM *Model); // BCDE successor - inline bool decodeSymbol1(ModelPPM *Model); // other orders: - inline bool decodeSymbol2(ModelPPM *Model); // BCD context - inline void update1(ModelPPM *Model,STATE* p); // CD suffix - inline void update2(ModelPPM *Model,STATE* p); // BCDE successor - void rescale(ModelPPM *Model); - inline PPM_CONTEXT* createChild(ModelPPM *Model,STATE* pStats,STATE& FirstState); - inline SEE2_CONTEXT* makeEscFreq2(ModelPPM *Model,int Diff); -}; - -#ifndef STRICT_ALIGNMENT_REQUIRED -#ifdef _AIX -#pragma pack(pop) -#else -#pragma pack() -#endif -#endif - -const uint UNIT_SIZE=Max(sizeof(PPM_CONTEXT),sizeof(RAR_MEM_BLK)); -const uint FIXED_UNIT_SIZE=12; - -/* -inline PPM_CONTEXT::PPM_CONTEXT(STATE* pStats,PPM_CONTEXT* ShorterContext): - NumStats(1), Suffix(ShorterContext) { pStats->Successor=this; } -inline PPM_CONTEXT::PPM_CONTEXT(): NumStats(0) {} -*/ - -template -inline void _PPMD_SWAP(T& t1,T& t2) { T tmp=t1; t1=t2; t2=tmp; } - - -class ModelPPM -{ - private: - friend struct PPM_CONTEXT; - - /*_PACK_ATTR*/ SEE2_CONTEXT SEE2Cont[25][16], DummySEE2Cont; - - struct PPM_CONTEXT *MinContext, *MedContext, *MaxContext; - STATE* FoundState; // found next state transition - int NumMasked, InitEsc, OrderFall, MaxOrder, RunLength, InitRL; - byte CharMask[256], NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; - byte EscCount, PrevSuccess, HiBitsFlag; - ushort BinSumm[128][64]; // binary SEE-contexts - - RangeCoder Coder; - SubAllocator SubAlloc; - - void RestartModelRare(); - void StartModelRare(int MaxOrder); - inline PPM_CONTEXT* CreateSuccessors(bool Skip,STATE* p1); - - inline void UpdateModel(); - inline void ClearMask(); - friend class Unpack; - public: - ModelPPM(); - void CleanUp(); // reset PPM variables after data error - bool DecodeInit(Unpack *UnpackRead,int &EscChar); - int DecodeChar(); -}; - -#endif +#ifndef _RAR_PPMMODEL_ +#define _RAR_PPMMODEL_ + +#include "coder.hpp" +#include "suballoc.hpp" + +#ifdef ALLOW_MISALIGNED +#pragma pack(1) +#endif + +struct RARPPM_DEF +{ + static const int INT_BITS=7, PERIOD_BITS=7, TOT_BITS=INT_BITS+PERIOD_BITS, + INTERVAL=1 << INT_BITS, BIN_SCALE=1 << TOT_BITS, MAX_FREQ=124; +}; + +struct RARPPM_SEE2_CONTEXT : RARPPM_DEF +{ // SEE-contexts for PPM-contexts with masked symbols + ushort Summ; + byte Shift, Count; + void init(int InitVal) + { + Summ=InitVal << (Shift=PERIOD_BITS-4); + Count=4; + } + uint getMean() + { + uint RetVal=GET_SHORT16(Summ) >> Shift; + Summ -= RetVal; + return RetVal+(RetVal == 0); + } + void update() + { + if (Shift < PERIOD_BITS && --Count == 0) + { + Summ += Summ; + Count=3 << Shift++; + } + } +}; + + +class ModelPPM; +struct RARPPM_CONTEXT; + +struct RARPPM_STATE +{ + byte Symbol; + byte Freq; + RARPPM_CONTEXT* Successor; +}; + + +struct RARPPM_CONTEXT : RARPPM_DEF +{ + ushort NumStats; + + struct FreqData + { + ushort SummFreq; + RARPPM_STATE RARPPM_PACK_ATTR * Stats; + }; + + union + { + FreqData U; + RARPPM_STATE OneState; + }; + + RARPPM_CONTEXT* Suffix; + inline void encodeBinSymbol(ModelPPM *Model,int symbol); // MaxOrder: + inline void encodeSymbol1(ModelPPM *Model,int symbol); // ABCD context + inline void encodeSymbol2(ModelPPM *Model,int symbol); // BCD suffix + inline void decodeBinSymbol(ModelPPM *Model); // BCDE successor + inline bool decodeSymbol1(ModelPPM *Model); // other orders: + inline bool decodeSymbol2(ModelPPM *Model); // BCD context + inline void update1(ModelPPM *Model,RARPPM_STATE* p); // CD suffix + inline void update2(ModelPPM *Model,RARPPM_STATE* p); // BCDE successor + void rescale(ModelPPM *Model); + inline RARPPM_CONTEXT* createChild(ModelPPM *Model,RARPPM_STATE* pStats,RARPPM_STATE& FirstState); + inline RARPPM_SEE2_CONTEXT* makeEscFreq2(ModelPPM *Model,int Diff); +}; + +#ifdef ALLOW_MISALIGNED +#ifdef _AIX +#pragma pack(pop) +#else +#pragma pack() +#endif +#endif + +class ModelPPM : RARPPM_DEF +{ + private: + friend struct RARPPM_CONTEXT; + + RARPPM_SEE2_CONTEXT SEE2Cont[25][16], DummySEE2Cont; + + struct RARPPM_CONTEXT *MinContext, *MedContext, *MaxContext; + RARPPM_STATE* FoundState; // found next state transition + int NumMasked, InitEsc, OrderFall, MaxOrder, RunLength, InitRL; + byte CharMask[256], NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; + byte EscCount, PrevSuccess, HiBitsFlag; + ushort BinSumm[128][64]; // binary SEE-contexts + + RangeCoder Coder; + SubAllocator SubAlloc; + + void RestartModelRare(); + void StartModelRare(int MaxOrder); + inline RARPPM_CONTEXT* CreateSuccessors(bool Skip,RARPPM_STATE* p1); + + inline void UpdateModel(); + inline void ClearMask(); + public: + ModelPPM(); + void CleanUp(); // reset PPM variables after data error + bool DecodeInit(Unpack *UnpackRead,int &EscChar); + int DecodeChar(); +}; + +#endif diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/pathfn.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/pathfn.cpp new file mode 100644 index 000000000..2a5649cd7 --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/pathfn.cpp @@ -0,0 +1,21 @@ +#include "rar.hpp" + +wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestSize) +{ + if (NameW!=NULL && *NameW!=0) + { + if (DestW!=NameW) + my_wcsncpy(DestW,NameW,DestSize); + } + else + if (Name!=NULL) + CharToWide(Name,DestW,DestSize); + else + *DestW=0; + + // Ensure that we return a zero terminate string for security reasons. + if (DestSize>0) + DestW[DestSize-1]=0; + + return(DestW); +} diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/rar.hpp b/Frameworks/File_Extractor/File_Extractor/unrar/rar.hpp index 202321dec..72e5b2d3c 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/rar.hpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/rar.hpp @@ -2,12 +2,13 @@ // It may NOT be used to develop a RAR (WinRAR) compatible archiver. // See license.txt for copyright and licensing. -// unrar_core 3.8.5 +// unrar_core 5.1.7 #ifndef RAR_COMMON_HPP #define RAR_COMMON_HPP #include "unrar.h" +#include #include #include #include @@ -21,7 +22,7 @@ // These names are too generic and might clash (or have already, hmpf) #define Array Rar_Array #define uint32 rar_uint32 -#define sint32 rar_sint32 +#define int32 rar_int32 #define Unpack Rar_Unpack #define Archive Rar_Archive #define RawRead Rar_RawRead @@ -73,6 +74,8 @@ struct Rar_Allocator }; //// os.hpp +#define FALSE 0 +#define TRUE 1 #undef STRICT_ALIGNMENT_REQUIRED #undef LITTLE_ENDIAN #define NM 1024 @@ -92,7 +95,7 @@ struct Rar_Allocator //// rartypes.hpp #if INT_MAX == 0x7FFFFFFF && UINT_MAX == 0xFFFFFFFF typedef unsigned int uint32; //32 bits exactly - typedef int sint32; //signed 32 bits exactly + typedef int int32; //signed 32 bits exactly #define PRESENT_INT32 #endif @@ -102,34 +105,35 @@ typedef unsigned int uint; //32 bits or more typedef blargg_wchar_t wchar; -#define SHORT16(x) (sizeof(ushort)==2 ? (ushort)(x):((x)&0xffff)) -#define UINT32(x) (sizeof(uint )==4 ? (uint )(x):((x)&0xffffffff)) +#define GET_SHORT16(x) (sizeof(ushort)==2 ? (ushort)(x):((x)&0xffff)) +#define GET_UINT32(x) (sizeof(uint )==4 ? (uint )(x):((x)&0xffffffff)) //// rardefs.hpp #define Min(x,y) (((x)<(y)) ? (x):(y)) #define Max(x,y) (((x)>(y)) ? (x):(y)) +#define ALIGN_VALUE(v,a) (size_t(v) + ( (~size_t(v) + 1) & (a - 1) ) ) +#define ASIZE(x) (sizeof(x)/sizeof(x[0])) //// int64.hpp -typedef unrar_long_long Int64; +typedef unrar_long_long int64; +typedef unrar_ulong_long uint64; #define int64to32(x) ((uint)(x)) -#define int32to64(high,low) ((((Int64)(high))<<31<<1)+(low)) +#define int32to64(high,low) ((((int64)(high))<<31<<1)+(low)) #define is64plus(x) (x>=0) #define INT64MAX int32to64(0x7fffffff,0) +#define INT64NDF int32to64(0x7fffffff,0x7fffffff) //// crc.hpp -extern uint CRCTab[256]; -void InitCRC(); -uint CRC(uint StartCRC,const void *Addr,size_t Size); -ushort OldCRC(ushort StartCRC,const void *Addr,size_t Size); +extern uint crc_tables[8][256]; +void InitCRCTables(); +uint CRC32(uint StartCRC,const void *Addr,size_t Size); +ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size); -//// rartime.hpp -struct RarTime -{ - unsigned time; - void SetDos(uint DosTime) { time = DosTime; } -}; +#define SHA256_DIGEST_SIZE 32 +#include "blake2s.hpp" +#include "hash.hpp" //// rdwrfn.hpp class ComprDataIO @@ -141,30 +145,43 @@ public: void* user_read_data; void* user_write_data; unrar_err_t write_error; // once write error occurs, no more writes are made - Int64 Tell_; + int64 Tell_; bool OldFormat; private: - Int64 UnpPackedSize; + int64 UnpPackedSize; bool SkipUnpCRC; public: int UnpRead(byte *Addr,uint Count); void UnpWrite(byte *Addr,uint Count); void SetSkipUnpCRC( bool b ) { SkipUnpCRC = b; } - void SetPackedSizeToRead( Int64 n ) { UnpPackedSize = n; } + void SetPackedSizeToRead( int64 n ) { UnpPackedSize = n; } uint UnpFileCRC; - void Seek(Int64 Offset, int Method = 0 ) { (void)Method; Tell_ = Offset; } - Int64 Tell() { return Tell_; } + void Seek(int64 Offset, int Method = 0 ) { (void)Method; Tell_ = Offset; } + int64 Tell() { return Tell_; } int Read( void* p, int n ); + + DataHash PackedDataHash; // Packed write and unpack read hash. + DataHash PackHash; // Pack read hash. + DataHash UnpHash; // Unpack write hash. }; +//// secpassword.hpp +void cleandata(void *data,size_t size); + +//// pathfn.hpp +wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestSize); + //// rar.hpp class Unpack; #include "array.hpp" +#include "unicode.hpp" +#include "timefn.hpp" #include "headers.hpp" +#include "headers5.hpp" #include "getbits.hpp" #include "archive.hpp" #include "rawread.hpp" @@ -172,8 +189,27 @@ class Unpack; #include "compress.hpp" #include "rarvm.hpp" #include "model.hpp" +#include "strfn.hpp" #include "unpack.hpp" +//// savepos.hpp +class SaveFilePos +{ +private: + File *SaveFile; + int64 SavePos; +public: + SaveFilePos(File &Src) + { + SaveFile=&Src; + SavePos=Src.Tell(); + } + ~SaveFilePos() + { + SaveFile->Seek(SavePos,SEEK_SET); + } +}; + //// extract.hpp /** RAR archive */ struct unrar_t @@ -195,7 +231,7 @@ struct unrar_t unrar_t(); ~unrar_t(); - void UnstoreFile( Int64 ); + void UnstoreFile( int64 ); unrar_err_t ExtractCurrentFile( bool SkipSolid = false, bool check_compatibility_only = false ); void update_first_file_pos() { diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/rarvm.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/rarvm.cpp index a75d19a90..0bc0fc88f 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/rarvm.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/rarvm.cpp @@ -8,6 +8,7 @@ #define VM_FS ((unsigned) VM_FS) RarVM::RarVM() +:BitInput(true) { Mem=NULL; } @@ -55,24 +56,24 @@ inline uint RarVM::GetValue(bool ByteMode,uint *Addr) } else { -#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) +#if defined(BIG_ENDIAN) || !defined(ALLOW_MISALIGNED) if (IS_VM_MEM(Addr)) { byte *B=(byte *)Addr; - return UINT32((uint)B[0]|((uint)B[1]<<8)|((uint)B[2]<<16)|((uint)B[3]<<24)); + return GET_UINT32((uint)B[0]|((uint)B[1]<<8)|((uint)B[2]<<16)|((uint)B[3]<<24)); } else - return UINT32(*Addr); + return GET_UINT32(*Addr); #else - return UINT32(*Addr); + return GET_UINT32(*Addr); #endif } } -#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) -#define GET_VALUE(ByteMode,Addr) GetValue(ByteMode,(uint *)Addr) +#if defined(BIG_ENDIAN) || !defined(ALLOW_MISALIGNED) + #define GET_VALUE(ByteMode,Addr) GetValue(ByteMode,(uint *)Addr) #else - #define GET_VALUE(ByteMode,Addr) ((ByteMode) ? (*(byte *)(Addr)):UINT32(*(uint *)(Addr))) + #define GET_VALUE(ByteMode,Addr) ((ByteMode) ? (*(byte *)(Addr)):GET_UINT32(*(uint *)(Addr))) #endif @@ -91,7 +92,7 @@ inline void RarVM::SetValue(bool ByteMode,uint *Addr,uint Value) } else { -#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) || !defined(PRESENT_INT32) +#if defined(BIG_ENDIAN) || !defined(ALLOW_MISALIGNED) || !defined(PRESENT_INT32) if (IS_VM_MEM(Addr)) { ((byte *)Addr)[0]=(byte)Value; @@ -107,16 +108,16 @@ inline void RarVM::SetValue(bool ByteMode,uint *Addr,uint Value) } } -#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) || !defined(PRESENT_INT32) -#define SET_VALUE(ByteMode,Addr,Value) SetValue(ByteMode,(uint *)Addr,Value) +#if defined(BIG_ENDIAN) || !defined(ALLOW_MISALIGNED) || !defined(PRESENT_INT32) + #define SET_VALUE(ByteMode,Addr,Value) SetValue(ByteMode,(uint *)Addr,Value) #else - #define SET_VALUE(ByteMode,Addr,Value) ((ByteMode) ? (*(byte *)(Addr)=(Value)):(*(uint32 *)(Addr)=((uint32)(Value)))) + #define SET_VALUE(ByteMode,Addr,Value) ((ByteMode) ? (*(byte *)(Addr)=((byte)(Value))):(*(uint32 *)(Addr)=((uint32)(Value)))) #endif void RarVM::SetLowEndianValue(uint *Addr,uint Value) { -#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) || !defined(PRESENT_INT32) +#if defined(BIG_ENDIAN) || !defined(ALLOW_MISALIGNED) || !defined(PRESENT_INT32) ((byte *)Addr)[0]=(byte)Value; ((byte *)Addr)[1]=(byte)(Value>>8); ((byte *)Addr)[2]=(byte)(Value>>16); @@ -139,10 +140,10 @@ inline uint* RarVM::GetOperand(VM_PreparedOperand *CmdOp) void RarVM::Execute(VM_PreparedProgram *Prg) { memcpy(R,Prg->InitR,sizeof(Prg->InitR)); - unsigned int GlobalSize=Min(Prg->GlobalData.Size(),VM_GLOBALMEMSIZE); + size_t GlobalSize=Min(Prg->GlobalData.Size(),VM_GLOBALMEMSIZE); if (GlobalSize) memcpy(Mem+VM_GLOBALMEMADDR,&Prg->GlobalData[0],GlobalSize); - unsigned int StaticSize=Min(Prg->StaticData.Size(),VM_GLOBALMEMSIZE-GlobalSize); + size_t StaticSize=Min(Prg->StaticData.Size(),VM_GLOBALMEMSIZE-GlobalSize); if (StaticSize) memcpy(Mem+VM_GLOBALMEMADDR+GlobalSize,&Prg->StaticData[0],StaticSize); @@ -150,8 +151,11 @@ void RarVM::Execute(VM_PreparedProgram *Prg) Flags=0; VM_PreparedCommand *PreparedCode=Prg->AltCmd ? Prg->AltCmd:&Prg->Cmd[0]; - if (!ExecuteCode(PreparedCode,Prg->CmdCount)) - PreparedCode[0].OpCode=VM_RET; + if (Prg->CmdCount>0 && !ExecuteCode(PreparedCode,Prg->CmdCount)) + { + // Invalid VM program. Let's replace it with 'return' command. + PreparedCode[0].OpCode=VM_RET; + } uint NewBlockPos=GET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20])&VM_MEMMASK; uint NewBlockSize=GET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x1c])&VM_MEMMASK; if (NewBlockPos+NewBlockSize>=VM_MEMSIZE) @@ -185,7 +189,7 @@ Note: return(false); \ Cmd=PreparedCode+(IP); -bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) +bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,uint CodeSize) { int MaxOpCount=25000000; VM_PreparedCommand *Cmd=PreparedCode; @@ -213,7 +217,7 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) case VM_CMP: { uint Value1=GET_VALUE(Cmd->ByteMode,Op1); - uint Result=UINT32(Value1-GET_VALUE(Cmd->ByteMode,Op2)); + uint Result=GET_UINT32(Value1-GET_VALUE(Cmd->ByteMode,Op2)); Flags=Result==0 ? VM_FZ:(Result>Value1)|(Result&VM_FS); } break; @@ -221,14 +225,14 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) case VM_CMPB: { uint Value1=GET_VALUE(true,Op1); - uint Result=UINT32(Value1-GET_VALUE(true,Op2)); + uint Result=GET_UINT32(Value1-GET_VALUE(true,Op2)); Flags=Result==0 ? VM_FZ:(Result>Value1)|(Result&VM_FS); } break; case VM_CMPD: { uint Value1=GET_VALUE(false,Op1); - uint Result=UINT32(Value1-GET_VALUE(false,Op2)); + uint Result=GET_UINT32(Value1-GET_VALUE(false,Op2)); Flags=Result==0 ? VM_FZ:(Result>Value1)|(Result&VM_FS); } break; @@ -236,7 +240,7 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) case VM_ADD: { uint Value1=GET_VALUE(Cmd->ByteMode,Op1); - uint Result=UINT32(Value1+GET_VALUE(Cmd->ByteMode,Op2)); + uint Result=GET_UINT32(Value1+GET_VALUE(Cmd->ByteMode,Op2)); if (Cmd->ByteMode) { Result&=0xff; @@ -258,7 +262,7 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) case VM_SUB: { uint Value1=GET_VALUE(Cmd->ByteMode,Op1); - uint Result=UINT32(Value1-GET_VALUE(Cmd->ByteMode,Op2)); + uint Result=GET_UINT32(Value1-GET_VALUE(Cmd->ByteMode,Op2)); Flags=Result==0 ? VM_FZ:(Result>Value1)|(Result&VM_FS); SET_VALUE(Cmd->ByteMode,Op1,Result); } @@ -287,7 +291,7 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) break; case VM_INC: { - uint Result=UINT32(GET_VALUE(Cmd->ByteMode,Op1)+1); + uint Result=GET_UINT32(GET_VALUE(Cmd->ByteMode,Op1)+1); if (Cmd->ByteMode) Result&=0xff; SET_VALUE(Cmd->ByteMode,Op1,Result); @@ -304,7 +308,7 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) #endif case VM_DEC: { - uint Result=UINT32(GET_VALUE(Cmd->ByteMode,Op1)-1); + uint Result=GET_UINT32(GET_VALUE(Cmd->ByteMode,Op1)-1); SET_VALUE(Cmd->ByteMode,Op1,Result); Flags=Result==0 ? VM_FZ:Result&VM_FS; } @@ -322,28 +326,28 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) continue; case VM_XOR: { - uint Result=UINT32(GET_VALUE(Cmd->ByteMode,Op1)^GET_VALUE(Cmd->ByteMode,Op2)); + uint Result=GET_UINT32(GET_VALUE(Cmd->ByteMode,Op1)^GET_VALUE(Cmd->ByteMode,Op2)); Flags=Result==0 ? VM_FZ:Result&VM_FS; SET_VALUE(Cmd->ByteMode,Op1,Result); } break; case VM_AND: { - uint Result=UINT32(GET_VALUE(Cmd->ByteMode,Op1)&GET_VALUE(Cmd->ByteMode,Op2)); + uint Result=GET_UINT32(GET_VALUE(Cmd->ByteMode,Op1)&GET_VALUE(Cmd->ByteMode,Op2)); Flags=Result==0 ? VM_FZ:Result&VM_FS; SET_VALUE(Cmd->ByteMode,Op1,Result); } break; case VM_OR: { - uint Result=UINT32(GET_VALUE(Cmd->ByteMode,Op1)|GET_VALUE(Cmd->ByteMode,Op2)); + uint Result=GET_UINT32(GET_VALUE(Cmd->ByteMode,Op1)|GET_VALUE(Cmd->ByteMode,Op2)); Flags=Result==0 ? VM_FZ:Result&VM_FS; SET_VALUE(Cmd->ByteMode,Op1,Result); } break; case VM_TEST: { - uint Result=UINT32(GET_VALUE(Cmd->ByteMode,Op1)&GET_VALUE(Cmd->ByteMode,Op2)); + uint Result=GET_UINT32(GET_VALUE(Cmd->ByteMode,Op1)&GET_VALUE(Cmd->ByteMode,Op2)); Flags=Result==0 ? VM_FZ:Result&VM_FS; } break; @@ -399,7 +403,7 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) break; case VM_CALL: R[7]-=4; - SET_VALUE(false,(uint *)&Mem[R[7]&VM_MEMMASK],(uint)(Cmd-PreparedCode+1)); + SET_VALUE(false,(uint *)&Mem[R[7]&VM_MEMMASK],Cmd-PreparedCode+1); SET_IP(GET_VALUE(false,Op1)); continue; case VM_NOT: @@ -409,7 +413,7 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) { uint Value1=GET_VALUE(Cmd->ByteMode,Op1); uint Value2=GET_VALUE(Cmd->ByteMode,Op2); - uint Result=UINT32(Value1<ByteMode,Op1,Result); } @@ -418,7 +422,7 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) { uint Value1=GET_VALUE(Cmd->ByteMode,Op1); uint Value2=GET_VALUE(Cmd->ByteMode,Op2); - uint Result=UINT32(Value1>>Value2); + uint Result=GET_UINT32(Value1>>Value2); Flags=(Result==0 ? VM_FZ:(Result&VM_FS))|((Value1>>(Value2-1))&VM_FC); SET_VALUE(Cmd->ByteMode,Op1,Result); } @@ -427,24 +431,26 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) { uint Value1=GET_VALUE(Cmd->ByteMode,Op1); uint Value2=GET_VALUE(Cmd->ByteMode,Op2); - uint Result=UINT32(((int)Value1)>>Value2); + uint Result=GET_UINT32(((int)Value1)>>Value2); Flags=(Result==0 ? VM_FZ:(Result&VM_FS))|((Value1>>(Value2-1))&VM_FC); SET_VALUE(Cmd->ByteMode,Op1,Result); } break; case VM_NEG: { - uint Result=UINT32(-GET_VALUE(Cmd->ByteMode,Op1)); + // We use "0-value" expression to suppress "unary minus to unsigned" + // compiler warning. + uint Result=GET_UINT32(0-GET_VALUE(Cmd->ByteMode,Op1)); Flags=Result==0 ? VM_FZ:VM_FC|(Result&VM_FS); SET_VALUE(Cmd->ByteMode,Op1,Result); } break; #ifdef VM_OPTIMIZE case VM_NEGB: - SET_VALUE(true,Op1,-GET_VALUE(true,Op1)); + SET_VALUE(true,Op1,0-GET_VALUE(true,Op1)); break; case VM_NEGD: - SET_VALUE(false,Op1,-GET_VALUE(false,Op1)); + SET_VALUE(false,Op1,0-GET_VALUE(false,Op1)); break; #endif case VM_PUSHA: @@ -503,10 +509,10 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) { uint Value1=GET_VALUE(Cmd->ByteMode,Op1); uint FC=(Flags&VM_FC); - uint Result=UINT32(Value1+GET_VALUE(Cmd->ByteMode,Op2)+FC); + uint Result=GET_UINT32(Value1+GET_VALUE(Cmd->ByteMode,Op2)+FC); if (Cmd->ByteMode) Result&=0xff; - Flags=(ResultByteMode,Op1,Result); } break; @@ -514,10 +520,10 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) { uint Value1=GET_VALUE(Cmd->ByteMode,Op1); uint FC=(Flags&VM_FC); - uint Result=UINT32(Value1-GET_VALUE(Cmd->ByteMode,Op2)-FC); + uint Result=GET_UINT32(Value1-GET_VALUE(Cmd->ByteMode,Op2)-FC); if (Cmd->ByteMode) Result&=0xff; - Flags=(Result>Value1 || (Result==Value1 && FC))|(Result==0 ? VM_FZ:(Result&VM_FS)); + Flags=(Result>Value1 || Result==Value1 && FC)|(Result==0 ? VM_FZ:(Result&VM_FS)); SET_VALUE(Cmd->ByteMode,Op1,Result); } break; @@ -531,7 +537,7 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) #ifdef VM_STANDARDFILTERS case VM_STANDARD: ExecuteStandardFilter((VM_StandardFilters)Cmd->Op1.Data); - break; + return true; #endif case VM_PRINT: break; @@ -544,7 +550,7 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) -void RarVM::Prepare(byte *Code,int CodeSize,VM_PreparedProgram *Prg) +void RarVM::Prepare(byte *Code,uint CodeSize,VM_PreparedProgram *Prg) { InitBitInput(); memcpy(InBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); @@ -552,7 +558,7 @@ void RarVM::Prepare(byte *Code,int CodeSize,VM_PreparedProgram *Prg) // Calculate the single byte XOR checksum to check validity of VM code. byte XorSum=0; { - for (int I=1;IOp2.Addr=&CurCmd->Op2.Data; CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE; CodeSize=0; + return; } #endif uint DataFlag=fgetbits(); @@ -583,8 +590,8 @@ void RarVM::Prepare(byte *Code,int CodeSize,VM_PreparedProgram *Prg) if (DataFlag&0x8000) { - int DataSize=ReadData(*this)+1; - for (int I=0;InAddrStaticData.Add(1); Prg->StaticData[I]=fgetbits()>>8; @@ -592,7 +599,7 @@ void RarVM::Prepare(byte *Code,int CodeSize,VM_PreparedProgram *Prg) } } - while (InAddrCmd.Add(1); VM_PreparedCommand *CurCmd=&Prg->Cmd[Prg->CmdCount]; @@ -609,7 +616,7 @@ void RarVM::Prepare(byte *Code,int CodeSize,VM_PreparedProgram *Prg) } if (VM_CmdFlags[CurCmd->OpCode] & VMCF_BYTEMODE) { - CurCmd->ByteMode=fgetbits()>>15; + CurCmd->ByteMode=(fgetbits()>>15)!=0; faddbits(1); } else @@ -773,7 +780,7 @@ uint RarVM::ReadData(BitInput &Inp) } -void RarVM::SetMemory(unsigned int Pos,byte *Data,unsigned int DataSize) +void RarVM::SetMemory(size_t Pos,byte *Data,size_t DataSize) { if (PosCmd[0]; - int CodeSize=Prg->CmdCount; + uint CodeSize=Prg->CmdCount; - for (int I=0;IOpCode=Cmd->ByteMode ? VM_CMPB:VM_CMPD; continue; - - default: break; } if ((VM_CmdFlags[Cmd->OpCode] & VMCF_CHFLAGS)==0) continue; @@ -811,7 +816,7 @@ void RarVM::Optimize(VM_PreparedProgram *Prg) // the current command with faster version which does not need to // modify flags. bool FlagsRequired=false; - for (int J=I+1;JOpCode=Cmd->ByteMode ? VM_NEGB:VM_NEGD; continue; - - default: break; } } } @@ -854,7 +857,7 @@ void RarVM::Optimize(VM_PreparedProgram *Prg) #ifdef VM_STANDARDFILTERS -VM_StandardFilters RarVM::IsStandardFilter(byte *Code,int CodeSize) +VM_StandardFilters RarVM::IsStandardFilter(byte *Code,uint CodeSize) { static const struct StandardFilterSignature @@ -875,12 +878,10 @@ VM_StandardFilters RarVM::IsStandardFilter(byte *Code,int CodeSize) 149, 0x1c2c5dc8, VMSF_RGB, },{ 216, 0xbc85e701, VMSF_AUDIO, - },{ - 40, 0x46b9c560, VMSF_UPCASE } }; - uint CodeCRC=CRC(0xffffffff,Code,CodeSize)^0xffffffff; - for (int I=0;I=VM_GLOBALMEMADDR || DataSize<4) + if ((uint)DataSize>=VM_GLOBALMEMADDR || DataSize<4) break; const int FileSize=0x1000000; @@ -910,8 +911,8 @@ void RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType) if (CurByte==0xe8 || CurByte==CmpByte2) { #ifdef PRESENT_INT32 - sint32 Offset=CurPos+FileOffset; - sint32 Addr=GET_VALUE(false,Data); + int32 Offset=CurPos+FileOffset; + int32 Addr=GET_VALUE(false,Data); if (Addr<0) { if (Addr+Offset>=0) @@ -944,7 +945,7 @@ void RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType) int DataSize=R[4]; uint FileOffset=R[6]; - if (DataSize>=VM_GLOBALMEMADDR || DataSize<21) + if ((uint)DataSize>=VM_GLOBALMEMADDR || DataSize<21) break; int CurPos=0; @@ -982,7 +983,7 @@ void RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType) { int DataSize=R[4],Channels=R[0],SrcPos=0,Border=DataSize*2; SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20],DataSize); - if (DataSize>=VM_GLOBALMEMADDR/2) + if ((uint)DataSize>=VM_GLOBALMEMADDR/2) break; // Bytes from same channels are grouped to continual data blocks, @@ -1001,21 +1002,21 @@ void RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType) byte *SrcData=Mem,*DestData=SrcData+DataSize; const int Channels=3; SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20],DataSize); - if (DataSize>=VM_GLOBALMEMADDR/2 || PosR<0) + if ((uint)DataSize>=VM_GLOBALMEMADDR/2 || Width<0 || PosR<0) break; for (int CurChannel=0;CurChannel=3) { byte *UpperData=DestData+UpperPos; - unsigned int UpperByte=*UpperData; - unsigned int UpperLeftByte=*(UpperData-3); + uint UpperByte=*UpperData; + uint UpperLeftByte=*(UpperData-3); Predicted=PrevByte+UpperByte-UpperLeftByte; int pa=abs((int)(Predicted-PrevByte)); int pb=abs((int)(Predicted-UpperByte)); @@ -1046,11 +1047,11 @@ void RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType) int DataSize=R[4],Channels=R[0]; byte *SrcData=Mem,*DestData=SrcData+DataSize; SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20],DataSize); - if (DataSize>=VM_GLOBALMEMADDR/2) + if ((uint)DataSize>=VM_GLOBALMEMADDR/2) break; for (int CurChannel=0;CurChannel>3) & 0xff; - unsigned int CurByte=*(SrcData++); + uint CurByte=*(SrcData++); Predicted-=CurByte; DestData[I]=Predicted; @@ -1083,7 +1084,7 @@ void RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType) if ((ByteCount & 0x1f)==0) { - unsigned int MinDif=Dif[0],NumMinDif=0; + uint MinDif=Dif[0],NumMinDif=0; Dif[0]=0; for (int J=1;J=VM_GLOBALMEMADDR/2) - break; - while (SrcPos>(32-BitCount); + uint AndMask=0xffffffff>>(32-BitCount); AndMask=~(AndMask< Cmd; VM_PreparedCommand *AltCmd; @@ -71,7 +75,7 @@ struct VM_PreparedProgram uint InitR[7]; byte *FilteredData; - unsigned int FilteredDataSize; + uint FilteredDataSize; }; class RarVM:private BitInput @@ -84,13 +88,12 @@ class RarVM:private BitInput #ifdef VM_OPTIMIZE void Optimize(VM_PreparedProgram *Prg); #endif - bool ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize); + bool ExecuteCode(VM_PreparedCommand *PreparedCode,uint CodeSize); #ifdef VM_STANDARDFILTERS - VM_StandardFilters IsStandardFilter(byte *Code,int CodeSize); + VM_StandardFilters IsStandardFilter(byte *Code,uint CodeSize); void ExecuteStandardFilter(VM_StandardFilters FilterType); unsigned int FilterItanium_GetBits(byte *Data,int BitPos,int BitCount); - void FilterItanium_SetBits(byte *Data,unsigned int BitField,int BitPos, - int BitCount); + void FilterItanium_SetBits(byte *Data,uint BitField,int BitPos,int BitCount); #endif byte *Mem; @@ -102,10 +105,10 @@ class RarVM:private BitInput void Init(); void handle_mem_error( Rar_Error_Handler& ); friend class Unpack; - void Prepare(byte *Code,int CodeSize,VM_PreparedProgram *Prg); + void Prepare(byte *Code,uint CodeSize,VM_PreparedProgram *Prg); void Execute(VM_PreparedProgram *Prg); void SetLowEndianValue(uint *Addr,uint Value); - void SetMemory(unsigned int Pos,byte *Data,unsigned int DataSize); + void SetMemory(size_t Pos,byte *Data,size_t DataSize); static uint ReadData(BitInput &Inp); }; diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/rawread.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/rawread.cpp index bd49b8846..2e8df202e 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/rawread.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/rawread.cpp @@ -1,10 +1,9 @@ #include "rar.hpp" -RawRead::RawRead(ComprDataIO *SrcFile) : Data( SrcFile ) +RawRead::RawRead(ComprDataIO *SrcFile) { RawRead::SrcFile=SrcFile; - ReadPos=0; - DataSize=0; + Reset(); } void RawRead::Reset() @@ -14,73 +13,147 @@ void RawRead::Reset() Data.Reset(); } -void RawRead::Read(int Size) +size_t RawRead::Read(size_t Size) { + size_t ReadSize=0; // (removed decryption) - if (Size!=0) - { - Data.Add(Size); - DataSize+=SrcFile->Read(&Data[DataSize],Size); - } + if (Size!=0) + { + Data.Add(Size); + ReadSize=SrcFile->Read(&Data[DataSize],Size); + DataSize+=ReadSize; + } + return ReadSize; } - - -void RawRead::Get(byte &Field) +void RawRead::Read(byte *SrcData,size_t Size) { - if (ReadPos2 ? CRC(0xffffffff,&Data[2],(ProcessedOnly ? ReadPos:DataSize)-2):0xffffffff); + uint Low=Get4(),High=Get4(); + return int32to64(High,Low); +} + + +uint64 RawRead::GetV() +{ + uint64 Result=0; + for (uint Shift=0;ReadPos0) + memcpy(F,&Data[ReadPos],CopySize); + if (Size>CopySize) + memset(F+CopySize,0,Size-CopySize); + ReadPos+=CopySize; + return CopySize; +} + + +void RawRead::GetW(wchar *Field,size_t Size) +{ + if (ReadPos+2*Size-1 Data; File *SrcFile; - int DataSize; - int ReadPos; - friend class Archive; + size_t DataSize; + size_t ReadPos; public: RawRead(File *SrcFile); void Reset(); - void Read(int Size); - void Get(byte &Field); - void Get(ushort &Field); - void Get(uint &Field); - void Get(byte *Field,int Size); - uint GetCRC(bool ProcessedOnly); - int Size() {return DataSize;} - int PaddedSize() {return Data.Size()-DataSize;} + size_t Read(size_t Size); + void Read(byte *SrcData,size_t Size); + byte Get1(); + ushort Get2(); + uint Get4(); + uint64 Get8(); + uint64 GetV(); + uint GetVSize(size_t Pos); + size_t GetB(void *Field,size_t Size); + void GetW(wchar *Field,size_t Size); + uint GetCRC15(bool ProcessedOnly); + uint GetCRC50(); + byte* GetDataPtr() {return &Data[0];} + size_t Size() {return DataSize;} + size_t PaddedSize() {return Data.Size()-DataSize;} + size_t DataLeft() {return DataSize-ReadPos;} + size_t GetPos() {return ReadPos;} + void SetPos(size_t Pos) {ReadPos=Pos;} + void Skip(size_t Size) {ReadPos+=Size;} + void Rewind() {SetPos(0);} }; +uint64 RawGetV(const byte *Data,uint &ReadPos,uint DataSize,bool &Overflow); + +inline uint RawGet2(const void *Data) +{ + byte *D=(byte *)Data; + return D[0]+(D[1]<<8); +} + +inline uint RawGet4(const void *Data) +{ + byte *D=(byte *)Data; +#if defined(BIG_ENDIAN) || !defined(ALLOW_MISALIGNED) || !defined(PRESENT_INT32) + return D[0]+(D[1]<<8)+(D[2]<<16)+(D[3]<<24); +#else + return GET_UINT32(*(uint32 *)D); +#endif +} + +inline uint64 RawGet8(const void *Data) +{ + byte *D=(byte *)Data; + return int32to64(RawGet4(D+4),RawGet4(D)); +} + + +// We need these "put" functions also in UnRAR code. This is why they are +// in rawread.hpp file even though they are "write" functions. +inline void RawPut2(uint Field,void *Data) +{ + byte *D=(byte *)Data; + D[0]=(byte)(Field); + D[1]=(byte)(Field>>8); +} + + +inline void RawPut4(uint Field,void *Data) +{ + byte *D=(byte *)Data; +#if defined(BIG_ENDIAN) || !defined(ALLOW_MISALIGNED) || !defined(PRESENT_INT32) + D[0]=(byte)(Field); + D[1]=(byte)(Field>>8); + D[2]=(byte)(Field>>16); + D[3]=(byte)(Field>>24); +#else + *(uint32 *)D=Field; +#endif +} + + +inline void RawPut8(uint64 Field,void *Data) +{ + byte *D=(byte *)Data; + D[0]=(byte)(Field); + D[1]=(byte)(Field>>8); + D[2]=(byte)(Field>>16); + D[3]=(byte)(Field>>24); + D[4]=(byte)(Field>>32); + D[5]=(byte)(Field>>40); + D[6]=(byte)(Field>>48); + D[7]=(byte)(Field>>56); +} + #endif diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/readme.txt b/Frameworks/File_Extractor/File_Extractor/unrar/readme.txt index 20e70c772..a1f820af1 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/readme.txt +++ b/Frameworks/File_Extractor/File_Extractor/unrar/readme.txt @@ -1,63 +1,50 @@ - - Portable UnRAR version - - - 1. General - - This package includes freeware Unrar C++ source and a few makefiles - (makefile.bcc, makefile.msc+msc.dep, makefile.unix). Unrar source - is subset of RAR and generated from RAR source automatically, - by a small program removing blocks like '#ifndef UNRAR ... #endif'. - Such method is not perfect and you may find some RAR related - stuff unnecessary in Unrar, especially in header files. - - If you wish to port Unrar to a new platform, you may need to edit - '#define LITTLE_ENDIAN' in os.hpp and data type definitions - in rartypes.hpp. - - if computer architecture does not allow not aligned data access, - you need to undefine ALLOW_NOT_ALIGNED_INT and define - STRICT_ALIGNMENT_REQUIRED in os.h. Note that it will increase memory - requirements. - - If you use Borland C++ makefile (makefile.bcc), you need to define - BASEPATHCC environment (or makefile) variable containing - the path to Borland C++ installation. - - Makefile.unix contains numerous compiler option sets. - GCC Linux is selected by default. If you need to compile Unrar - for other platforms, uncomment corresponding lines. - - - 2. Unrar binaries - - If you compiled Unrar for OS, which is not present in "Downloads" - and "RAR extras" on www.rarlab.com, we will appreciate if you send - us the compiled executable to place it to our site. - - - 3. Acknowledgements - - This source includes parts of code written by the following authors: - - Dmitry Shkarin PPMII v.H text compression - Dmitry Subbotin Carryless rangecoder - Szymon Stefanek AES encryption - Brian Gladman AES encryption - Steve Reid SHA-1 hash function - Marcus Herbert makefile.unix file - Tomasz Klim fixes for libunrar.so - Robert Riebisch makefile.dj and patches for DJGPP - - - 4. Legal stuff - - Unrar source may be used in any software to handle RAR archives - without limitations free of charge, but cannot be used to re-create - the RAR compression algorithm, which is proprietary. Distribution - of modified Unrar source in separate form or as a part of other - software is permitted, provided that it is clearly stated in - the documentation and source comments that the code may not be used - to develop a RAR (WinRAR) compatible archiver. - - More detailed license text is available in license.txt. + + Portable UnRAR version + + + 1. General + + This package includes freeware Unrar C++ source and makefile for + several Unix compilers. + + Unrar source is subset of RAR and generated from RAR source automatically, + by a small program removing blocks like '#ifndef UNRAR ... #endif'. + Such method is not perfect and you may find some RAR related stuff + unnecessary in Unrar, especially in header files. + + If you wish to port Unrar to a new platform, you may need to edit + '#define LITTLE_ENDIAN' in os.hpp and data type definitions + in rartypes.hpp. + + if computer architecture does not allow not aligned data access, + you need to undefine ALLOW_NOT_ALIGNED_INT and define + STRICT_ALIGNMENT_REQUIRED in os.h. + + UnRAR.vcproj and UnRARDll.vcproj are projects for Microsoft Visual C++. + UnRARDll.vcproj lets to build unrar.dll library. + + + 2. Unrar binaries + + If you compiled Unrar for OS, which is not present in "Downloads" + and "RAR extras" on www.rarlab.com, we will appreciate if you send + us the compiled executable to place it to our site. + + + 3. Acknowledgements + + This source includes parts of code written by other authors. + Please see acknow.txt file for details. + + + 4. Legal stuff + + Unrar source may be used in any software to handle RAR archives + without limitations free of charge, but cannot be used to re-create + the RAR compression algorithm, which is proprietary. Distribution + of modified Unrar source in separate form or as a part of other + software is permitted, provided that it is clearly stated in + the documentation and source comments that the code may not be used + to develop a RAR (WinRAR) compatible archiver. + + More detailed license text is available in license.txt. diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/secpassword.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/secpassword.cpp new file mode 100644 index 000000000..913d71fae --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/secpassword.cpp @@ -0,0 +1,18 @@ +#include "rar.hpp" + +// When we call memset in end of function to clean local variables +// for security reason, compiler optimizer can remove such call. +// So we use our own function for this purpose. +void cleandata(void *data,size_t size) +{ +#if defined(_WIN_ALL) && defined(_MSC_VER) + SecureZeroMemory(data,size); +#else + // 'volatile' is required. Otherwise optimizers can remove this function + // if cleaning local variables, which are not used after that. + volatile byte *d = (volatile byte *)data; + for (size_t i=0;i + +const char *NullToEmpty(const char *Str) +{ + return Str==NULL ? "":Str; +} + +static const wchar Empty[] = {0}; + +const wchar *NullToEmpty(const wchar *Str) +{ + return Str==NULL ? Empty:Str; +} + + +void IntToExt(const char *Src,char *Dest,size_t DestSize) +{ +#ifdef _WIN_ALL + OemToCharBuffA(Src,Dest,(DWORD)DestSize); + Dest[DestSize-1]=0; +#elif defined(_ANDROID) + wchar DestW[NM]; + UnkToWide(Src,DestW,ASIZE(DestW)); + WideToChar(DestW,Dest,DestSize); +#else + if (Dest!=Src) + strncpyz(Dest,Src,DestSize); +#endif +} + + +int stricomp(const char *s1,const char *s2) +{ +#ifdef _WIN_ALL + return CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,-1,s2,-1)-2; +#else + while (toupper(*s1)==toupper(*s2)) + { + if (*s1==0) + return 0; + s1++; + s2++; + } + return s1 < s2 ? -1 : 1; +#endif +} + + +int strnicomp(const char *s1,const char *s2,size_t n) +{ +#ifdef _WIN_ALL + // If we specify 'n' exceeding the actual string length, CompareString goes + // beyond the trailing zero and compares garbage. So we need to limit 'n' + // to real string length. + // It is important to use strnlen (or memchr(...,0)) instead of strlen, + // because data can be not zero terminated. + size_t l1=Min(strnlen(s1,n),n); + size_t l2=Min(strnlen(s2,n),n); + return CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,(int)l1,s2,(int)l2)-2; +#else + if (n==0) + return 0; + while (toupper(*s1)==toupper(*s2)) + { + if (*s1==0 || --n==0) + return 0; + s1++; + s2++; + } + return s1 < s2 ? -1 : 1; +#endif +} + + +wchar* RemoveEOL(wchar *Str) +{ + for (int I=(int)my_wcslen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n' || Str[I]==' ' || Str[I]=='\t');I--) + Str[I]=0; + return Str; +} + + +wchar* RemoveLF(wchar *Str) +{ + for (int I=(int)my_wcslen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n');I--) + Str[I]=0; + return(Str); +} + + +unsigned char loctolower(unsigned char ch) +{ +#ifdef _WIN_ALL + // Convert to LPARAM first to avoid a warning in 64 bit mode. + return((int)(LPARAM)CharLowerA((LPSTR)ch)); +#else + return(tolower(ch)); +#endif +} + + +unsigned char loctoupper(unsigned char ch) +{ +#ifdef _WIN_ALL + // Convert to LPARAM first to avoid a warning in 64 bit mode. + return((int)(LPARAM)CharUpperA((LPSTR)ch)); +#else + return(toupper(ch)); +#endif +} + + +// toupper with English only results if English input is provided. +// It avoids Turkish (small i) -> (big I with dot) conversion problem. +// We do not define 'ch' as 'int' to avoid necessity to cast all +// signed chars passed to this function to unsigned char. +unsigned char etoupper(unsigned char ch) +{ + if (ch=='i') + return('I'); + return(toupper(ch)); +} + + +// Unicode version of etoupper. +wchar etoupperw(wchar ch) +{ + if (ch=='i') + return('I'); +#ifdef __APPLE__ + return(toupper(ch)); +#else + return(toupperw(ch)); +#endif +} + + +// We do not want to cast every signed char to unsigned when passing to +// isdigit, so we implement the replacement. Shall work for Unicode too. +// If chars are signed, conversion from char to int could generate negative +// values, resulting in undefined behavior in standard isdigit. +bool IsDigit(int ch) +{ + return(ch>='0' && ch<='9'); +} + + +// We do not want to cast every signed char to unsigned when passing to +// isspace, so we implement the replacement. Shall work for Unicode too. +// If chars are signed, conversion from char to int could generate negative +// values, resulting in undefined behavior in standard isspace. +bool IsSpace(int ch) +{ + return(ch==' ' || ch=='\t'); +} + + +// We do not want to cast every signed char to unsigned when passing to +// isalpha, so we implement the replacement. Shall work for Unicode too. +// If chars are signed, conversion from char to int could generate negative +// values, resulting in undefined behavior in standard function. +bool IsAlpha(int ch) +{ + return((ch>='A' && ch<='Z') || (ch>='a' && ch<='z')); +} + + + + +void BinToHex(const byte *Bin,size_t BinSize,char *HexA,wchar *HexW,size_t HexSize) +{ + uint A=0,W=0; // ASCII and Unicode hex output positions. + for (uint I=0;I> 4; + uint Low=Bin[I] & 0xf; + uint HighHex=High>9 ? 'a'+High-10:'0'+High; + uint LowHex=Low>9 ? 'a'+Low-10:'0'+Low; + if (HexA!=NULL && A0) + HexA[A]=0; + if (HexW!=NULL && HexSize>0) + HexW[W]=0; +} + + +#ifndef SFX_MODULE +uint GetDigits(uint Number) +{ + uint Digits=1; + while (Number>=10) + { + Number/=10; + Digits++; + } + return Digits; +} +#endif + + +bool LowAscii(const char *Str) +{ + for (int I=0;Str[I]!=0;I++) + if ((byte)Str[I]<32 || (byte)Str[I]>127) + return false; + return true; +} + + +bool LowAscii(const wchar *Str) +{ + for (int I=0;Str[I]!=0;I++) + { + // We convert wchar_t to uint just in case if some compiler + // uses signed wchar_t. + if ((uint)Str[I]<32 || (uint)Str[I]>127) + return false; + } + return true; +} + + +int wcsicompc(const wchar *Str1,const wchar *Str2) +{ +#if defined(_UNIX) + return my_wcscmp(Str1,Str2); +#else + return wcsicomp(Str1,Str2); +#endif +} + + +// safe strncpy: copies maxlen-1 max and always returns zero terminated dest +char* strncpyz(char *dest, const char *src, size_t maxlen) +{ + if (maxlen>0) + { + strncpy(dest,src,maxlen-1); + dest[maxlen-1]=0; + } + return dest; +} + + +// Safe wcsncpy: copies maxlen-1 max and always returns zero terminated dest. +wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen) +{ + if (maxlen>0) + { + my_wcsncpy(dest,src,maxlen-1); + dest[maxlen-1]=0; +} + return dest; +} + + +// Safe strncat: resulting dest length cannot exceed maxlen and dest +// is always zero terminated. Note that 'maxlen' parameter defines the entire +// dest buffer size and is not compatible with standard strncat. +char* strncatz(char* dest, const char* src, size_t maxlen) +{ + size_t Length = strlen(dest); + if (Length + 1 < maxlen) + strncat(dest, src, maxlen - Length - 1); + return dest; +} + + +// Safe wcsncat: resulting dest length cannot exceed maxlen and dest +// is always zero terminated. Note that 'maxlen' parameter defines the entire +// dest buffer size and is not compatible with standard wcsncat. +wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen) +{ + size_t Length = my_wcslen(dest); + if (Length + 1 < maxlen) + my_wcsncat(dest, src, maxlen - Length - 1); + return dest; +} + + +void itoa(int64 n,char *Str) +{ + char NumStr[50]; + size_t Pos=0; + + do + { + NumStr[Pos++]=char(n%10)+'0'; + n=n/10; + } while (n!=0); + + for (size_t I=0;I= ASIZE(StrTable)) + StrNum=0; + wchar *Str=StrTable[StrNum]; + CharToWide(Src,Str,MaxLength); + Str[MaxLength-1]=0; + return Str; +} + + +// Parse string containing parameters separated with spaces. +// Support quote marks. Param can be NULL to return the pointer to next +// parameter, which can be used to estimate the buffer size for Param. +const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize) +{ + while (IsSpace(*CmdLine)) + CmdLine++; + if (*CmdLine==0) + return NULL; + + size_t ParamSize=0; + bool Quote=false; + while (*CmdLine!=0 && (Quote || !IsSpace(*CmdLine))) + { + if (*CmdLine=='\"') + { + if (CmdLine[1]=='\"') + { + // Insert the quote character instead of two adjoining quote characters. + if (Param!=NULL && ParamSizeinsertAt(&s0); p->Stamp=0xFFFF; p->NU=Indx2Units[i]; diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/suballoc.hpp b/Frameworks/File_Extractor/File_Extractor/unrar/suballoc.hpp index 77440dfae..46852bd69 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/suballoc.hpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/suballoc.hpp @@ -10,21 +10,21 @@ const int N1=4, N2=4, N3=4, N4=(128+3-1*N1-2*N2-3*N3)/4; const int N_INDEXES=N1+N2+N3+N4; -#if defined(__GNUC__) && !defined(STRICT_ALIGNMENT_REQUIRED) -#define _PACK_ATTR __attribute__ ((packed)) +#if defined(__GNUC__) && defined(ALLOW_MISALIGNED) +#define RARPPM_PACK_ATTR __attribute__ ((packed)) #else -#define _PACK_ATTR +#define RARPPM_PACK_ATTR #endif /* defined(__GNUC__) */ -#ifndef STRICT_ALIGNMENT_REQUIRED +#ifdef ALLOW_MISALIGNED #pragma pack(1) #endif -struct RAR_MEM_BLK +struct RARPPM_MEM_BLK { ushort Stamp, NU; - RAR_MEM_BLK* next, * prev; - void insertAt(RAR_MEM_BLK* p) + RARPPM_MEM_BLK* next, * prev; + void insertAt(RARPPM_MEM_BLK* p) { next=(prev=p)->next; p->next=next->prev=this; @@ -34,9 +34,9 @@ struct RAR_MEM_BLK prev->next=next; next->prev=prev; } -} _PACK_ATTR; +} RARPPM_PACK_ATTR; -#ifndef STRICT_ALIGNMENT_REQUIRED +#ifndef ALLOW_MISALIGNED #ifdef _AIX #pragma pack(pop) #else @@ -60,7 +60,7 @@ class SubAllocator uint GetUsedMemory(); inline void GlueFreeBlocks(); void* AllocUnitsRare(int indx); - inline RAR_MEM_BLK* MBPtr(RAR_MEM_BLK *BasePtr,int Items); + inline RARPPM_MEM_BLK* MBPtr(RARPPM_MEM_BLK *BasePtr,int Items); long SubAllocatorSize; byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount; diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/timefn.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/timefn.cpp new file mode 100644 index 000000000..27b34029f --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/timefn.cpp @@ -0,0 +1,298 @@ +#include "rar.hpp" + +#ifdef _WIN_ALL +RarTime& RarTime::operator =(FILETIME &ft) +{ + _ULARGE_INTEGER ul = {ft.dwLowDateTime, ft.dwHighDateTime}; + itime=ul.QuadPart; + return *this; +} + + +void RarTime::GetWin32(FILETIME *ft) +{ + _ULARGE_INTEGER ul; + ul.QuadPart=itime; + ft->dwLowDateTime=ul.LowPart; + ft->dwHighDateTime=ul.HighPart; +} +#endif + + +RarTime& RarTime::operator =(time_t ut) +{ + uint64 ushift=int32to64(0x19DB1DE,0xD53E8000); // 116444736000000000. + itime=uint64(ut)*10000000+ushift; + return *this; +} + + +time_t RarTime::GetUnix() +{ + uint64 ushift=int32to64(0x19DB1DE,0xD53E8000); // 116444736000000000. + time_t ut=(itime-ushift)/10000000; + return ut; +} + + +void RarTime::GetLocal(RarLocalTime *lt) +{ +#ifdef _WIN_ALL + FILETIME ft; + GetWin32(&ft); + FILETIME lft; + + if (WinNT() < WNT_VISTA) + { + // SystemTimeToTzSpecificLocalTime based code produces 1 hour error on XP. + FileTimeToLocalFileTime(&ft,&lft); + } + else + { + // We use these functions instead of FileTimeToLocalFileTime according to + // MSDN recommendation: "To account for daylight saving time + // when converting a file time to a local time ..." + SYSTEMTIME st1,st2; + FileTimeToSystemTime(&ft,&st1); + SystemTimeToTzSpecificLocalTime(NULL,&st1,&st2); + SystemTimeToFileTime(&st2,&lft); + + // Correct precision loss (low 4 decimal digits) in FileTimeToSystemTime. + FILETIME rft; + SystemTimeToFileTime(&st1,&rft); + int64 Corrected=INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime)- + INT32TO64(rft.dwHighDateTime,rft.dwLowDateTime)+ + INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime); + lft.dwLowDateTime=(DWORD)Corrected; + lft.dwHighDateTime=(DWORD)(Corrected>>32); + } + + SYSTEMTIME st; + FileTimeToSystemTime(&lft,&st); + lt->Year=st.wYear; + lt->Month=st.wMonth; + lt->Day=st.wDay; + lt->Hour=st.wHour; + lt->Minute=st.wMinute; + lt->Second=st.wSecond; + lt->wDay=st.wDayOfWeek; + lt->yDay=lt->Day-1; + + static int mdays[12]={31,28,31,30,31,30,31,31,30,31,30,31}; + for (uint I=1;IMonth && I<=ASIZE(mdays);I++) + lt->yDay+=mdays[I-1]; + + if (lt->Month>2 && IsLeapYear(lt->Year)) + lt->yDay++; + + st.wMilliseconds=0; + FILETIME zft; + SystemTimeToFileTime(&st,&zft); + + // Calculate the time reminder, which is the part of time smaller + // than 1 second, represented in 100-nanosecond intervals. + lt->Reminder=INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime)- + INT32TO64(zft.dwHighDateTime,zft.dwLowDateTime); +#else + time_t ut=GetUnix(); + struct tm *t; + t=localtime(&ut); + + lt->Year=t->tm_year+1900; + lt->Month=t->tm_mon+1; + lt->Day=t->tm_mday; + lt->Hour=t->tm_hour; + lt->Minute=t->tm_min; + lt->Second=t->tm_sec; + lt->Reminder=itime % 10000000; + lt->wDay=t->tm_wday; + lt->yDay=t->tm_yday; +#endif +} + + +void RarTime::SetLocal(RarLocalTime *lt) +{ +#ifdef _WIN_ALL + SYSTEMTIME st; + st.wYear=lt->Year; + st.wMonth=lt->Month; + st.wDay=lt->Day; + st.wHour=lt->Hour; + st.wMinute=lt->Minute; + st.wSecond=lt->Second; + st.wMilliseconds=0; + FILETIME lft; + if (SystemTimeToFileTime(&st,&lft)) + { + lft.dwLowDateTime+=lt->Reminder; + if (lft.dwLowDateTimeReminder) + lft.dwHighDateTime++; + + FILETIME ft; + + if (WinNT() < WNT_VISTA) + { + // TzSpecificLocalTimeToSystemTime based code produces 1 hour error on XP. + LocalFileTimeToFileTime(&lft,&ft); + } + else + { + // Reverse procedure which we do in GetLocal. + SYSTEMTIME st1,st2; + FileTimeToSystemTime(&lft,&st2); + TzSpecificLocalTimeToSystemTime(NULL,&st2,&st1); + SystemTimeToFileTime(&st1,&ft); + + // Correct precision loss (low 4 decimal digits) in FileTimeToSystemTime. + FILETIME rft; + SystemTimeToFileTime(&st2,&rft); + int64 Corrected=INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime)- + INT32TO64(rft.dwHighDateTime,rft.dwLowDateTime)+ + INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime); + ft.dwLowDateTime=(DWORD)Corrected; + ft.dwHighDateTime=(DWORD)(Corrected>>32); + } + + *this=ft; + } + else + Reset(); +#else + struct tm t; + + t.tm_sec=lt->Second; + t.tm_min=lt->Minute; + t.tm_hour=lt->Hour; + t.tm_mday=lt->Day; + t.tm_mon=lt->Month-1; + t.tm_year=lt->Year-1900; + t.tm_isdst=-1; + *this=mktime(&t); + itime+=lt->Reminder; +#endif +} + + +// Return the stored time as 64-bit number of 100-nanosecond intervals since +// 01.01.1601. Actually we do not care since which date this time starts from +// as long as this date is the same for GetRaw and SetRaw. We use the value +// returned by GetRaw() for time comparisons, for relative operations +// like SetRaw(GetRaw()-C) and for compact time storage when necessary. +uint64 RarTime::GetRaw() +{ + return itime; +} + + +void RarTime::SetRaw(uint64 RawTime) +{ + itime=RawTime; +} + + +uint RarTime::GetDos() +{ + RarLocalTime lt; + GetLocal(<); + uint DosTime=(lt.Second/2)|(lt.Minute<<5)|(lt.Hour<<11)| + (lt.Day<<16)|(lt.Month<<21)|((lt.Year-1980)<<25); + return DosTime; +} + + +void RarTime::SetDos(uint DosTime) +{ + RarLocalTime lt; + lt.Second=(DosTime & 0x1f)*2; + lt.Minute=(DosTime>>5) & 0x3f; + lt.Hour=(DosTime>>11) & 0x1f; + lt.Day=(DosTime>>16) & 0x1f; + lt.Month=(DosTime>>21) & 0x0f; + lt.Year=(DosTime>>25)+1980; + lt.Reminder=0; + SetLocal(<); +} + + +#ifndef SFX_MODULE +void RarTime::SetIsoText(const wchar *TimeText) +{ + int Field[6]; + memset(Field,0,sizeof(Field)); + for (uint DigitCount=0;*TimeText!=0;TimeText++) + if (IsDigit(*TimeText)) + { + int FieldPos=DigitCount<4 ? 0:(DigitCount-4)/2+1; + if (FieldPos + +struct RarLocalTime +{ + uint Year; + uint Month; + uint Day; + uint Hour; + uint Minute; + uint Second; + uint Reminder; // Part of time smaller than 1 second, represented in 100-nanosecond intervals. + uint wDay; + uint yDay; +}; + + +class RarTime +{ + private: + // Internal FILETIME like time representation in 100 nanoseconds + // since 01.01.1601. + uint64 itime; + public: + RarTime() {Reset();} +#ifdef _WIN_ALL + RarTime(FILETIME &ft) {*this=ft;} + RarTime& operator =(FILETIME &ft); + void GetWin32(FILETIME *ft); +#endif + RarTime(time_t ut) {*this=ut;} + RarTime& operator =(time_t ut); + time_t GetUnix(); + bool operator == (RarTime &rt) {return itime==rt.itime;} + bool operator < (RarTime &rt) {return itime (RarTime &rt) {return itime>rt.itime;} + bool operator >= (RarTime &rt) {return itime>rt.itime || itime==rt.itime;} + void GetLocal(RarLocalTime *lt); + void SetLocal(RarLocalTime *lt); + uint64 GetRaw(); + void SetRaw(uint64 RawTime); + uint GetDos(); + void SetDos(uint DosTime); + void SetIsoText(const wchar *TimeText); + void SetAgeText(const wchar *TimeText); + void SetCurrentTime(); + void Reset() {itime=0;} + bool IsSet() {return itime!=0;} +}; + +bool IsLeapYear(int Year); + +#endif diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/unicode.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/unicode.cpp index 5b04d6665..1c718481b 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/unicode.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/unicode.cpp @@ -2,6 +2,48 @@ #include "unicode.hpp" +bool CharToWide(const char *Src,wchar *Dest,int DestSize) +{ + bool RetCode=true; +#ifdef _WIN_32 + if (MultiByteToWideChar(CP_ACP,0,Src,-1,Dest,DestSize,NULL,NULL)==0) + RetCode=false; +#else +#ifdef _APPLE + UtfToWide(Src,Dest,DestSize); +#else +#ifdef MBFUNCTIONS + + size_t ResultingSize=mbstowcs(Dest,Src,DestSize); + if (ResultingSize==(size_t)-1) + RetCode=false; + if (ResultingSize==0 && *Src!=0) + RetCode=false; + + if ((!RetCode || *Dest==0 && *Src!=0) && DestSize>NM && strlen(Src)NextWindow flag + // in UnpWriteBuf(). Minimum window size 0x20000 would be enough, but let's + // use 0x40000 for extra safety and possible filter area size expansion. + const size_t MinAllocSize=0x40000; + if (WinSize>16)>0x10000) // Window size must not exceed 4 GB. + return; + + // Archiving code guarantees that window size does not grow in the same + // solid stream. So if we are here, we are either creating a new window + // 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); + + // We do not handle growth for existing fragmented window. + if (Grow && Fragmented) + throw std::bad_alloc(); + + byte *NewWindow=Fragmented ? NULL : (byte *)malloc(WinSize); + + if (NewWindow==NULL) + if (Grow || WinSize<0x1000000) + { + // We do not support growth for new fragmented window. + // Also exclude RAR4 and small dictionaries. + throw std::bad_alloc(); + } + else + { + if (Window!=NULL) // If allocated by preceding files. + { + free(Window); + Window=NULL; + } + FragWindow.Init(WinSize); + Fragmented=true; + } + + if (!Fragmented) { - Unpack::Window = (byte*) rarmalloc( MAXWINSIZE ); - if (Unpack::Window==NULL) - ErrHandler.MemoryError(); + // 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;IUnpPtr; // cache in register - byte* const Window = this->Window; // cache in register - - unsigned int DestPtr=UnpPtr-Distance; - if (UnpPtrUnpPtr += Length; - if ( Distance < Length ) // can't use memcpy when source and dest overlap - { - // Length always >= 1 - do - { - Window[UnpPtr++]=Window[DestPtr++]; - } - while (--Length>0) - ; - } - else - { - memcpy( &Window[UnpPtr], &Window[DestPtr], Length ); - } - } - else - { - while (Length--) - { - Window[UnpPtr]=Window[DestPtr++ & MAXWINMASK]; - UnpPtr=(UnpPtr+1) & MAXWINMASK; - } - - this->UnpPtr = UnpPtr; - } -} - - -int Unpack::DecodeNumber(struct Decode *Dec) -{ - unsigned int Bits; - unsigned int BitField=getbits() & 0xfffe; - if (BitFieldDecodeLen[8]) - if (BitFieldDecodeLen[4]) - if (BitFieldDecodeLen[2]) - if (BitFieldDecodeLen[1]) - Bits=1; - else - Bits=2; - else - if (BitFieldDecodeLen[3]) - Bits=3; - else - Bits=4; - else - if (BitFieldDecodeLen[6]) - if (BitFieldDecodeLen[5]) - Bits=5; - else - Bits=6; - else - if (BitFieldDecodeLen[7]) - Bits=7; - else - Bits=8; - else - if (BitFieldDecodeLen[12]) - if (BitFieldDecodeLen[10]) - if (BitFieldDecodeLen[9]) - Bits=9; - else - Bits=10; - else - if (BitFieldDecodeLen[11]) - Bits=11; - else - Bits=12; - else - if (BitFieldDecodeLen[14]) - if (BitFieldDecodeLen[13]) - Bits=13; - else - Bits=14; - else - Bits=15; - - unsigned int N=Dec->DecodePos[Bits]+((BitField-Dec->DecodeLen[Bits-1])>>(16-Bits)); - if (N>=Dec->MaxNum) - N=0; - // do after reading values, to allow better instruction scheduling - addbits(Bits); - return(Dec->DecodeNum[N]); -} - -const -static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224}; -const -static unsigned char LBits[]= {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 int DDecode[DC]; -static byte DBits[DC]; -const -static int DBitLengthCounts[]= {4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,0,12}; -const -static unsigned char SDDecode[]={0,4,8,16,32,64,128,192}; -const -static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6}; - -void Unpack::init_tables() -{ - if (DDecode[1]==0) - { - int Dist=0,BitLength=0,Slot=0; - for (int I=0;IReadBorder) - { - if (!UnpReadBuf()) - break; - } - if (((WrPtr-UnpPtr) & MAXWINMASK)<260 && WrPtr!=UnpPtr) - { - UnpWriteBuf(); - if (WrittenFileSize>DestUnpSize) - return; - if (Suspended) - { - FileExtracted=false; - return; - } - } - if (UnpBlockType==BLOCK_PPM) - { - int Ch=PPM.DecodeChar(); - if (Ch==-1) - { - PPM.CleanUp(); - - // turn off PPM compression mode in case of error, so UnRAR will - // call PPM.DecodeInit in case it needs to turn it on back later. - UnpBlockType=BLOCK_LZ; - break; - } - if (Ch==PPMEscChar) - { - int NextCh=PPM.DecodeChar(); - if (NextCh==0) - { - if (!ReadTables()) - break; - continue; - } - if (NextCh==2 || NextCh==-1) - break; - if (NextCh==3) - { - if (!ReadVMCodePPM()) - break; - continue; - } - if (NextCh==4) - { - unsigned int Distance=0,Length; - Length = 0; // avoids warning - bool Failed=false; - for (int I=0;I<4 && !Failed;I++) - { - int Ch=PPM.DecodeChar(); - if (Ch==-1) - Failed=true; - else - if (I==3) - Length=(byte)Ch; - else - Distance=(Distance<<8)+(byte)Ch; - } - if (Failed) - break; - -#ifdef _MSC_VER - // avoid a warning about uninitialized 'Length' variable - #pragma warning( disable : 4701 ) -#endif - CopyString(Length+32,Distance+2); - continue; - } - if (NextCh==5) - { - int Length=PPM.DecodeChar(); - if (Length==-1) - break; - CopyString(Length+4,1); - continue; - } - } - Window[UnpPtr++]=Ch; - continue; - } - - int Number=DecodeNumber((struct Decode *)&LD); - if (Number<256) - { - Window[UnpPtr++]=(byte)Number; - continue; - } - if (Number>=271) - { - int Length=LDecode[Number-=271]+3; - if ((Bits=LBits[Number])>0) - { - Length+=getbits()>>(16-Bits); - addbits(Bits); - } - - int DistNumber=DecodeNumber((struct Decode *)&DD); - unsigned int Distance=DDecode[DistNumber]+1; - if ((Bits=DBits[DistNumber])>0) - { - if (DistNumber>9) - { - if (Bits>4) - { - Distance+=((getbits()>>(20-Bits))<<4); - addbits(Bits-4); - } - if (LowDistRepCount>0) - { - LowDistRepCount--; - Distance+=PrevLowDist; - } - else - { - int LowDist=DecodeNumber((struct Decode *)&LDD); - if (LowDist==16) - { - LowDistRepCount=LOW_DIST_REP_COUNT-1; - Distance+=PrevLowDist; - } - else - { - Distance+=LowDist; - PrevLowDist=LowDist; - } - } - } - else - { - Distance+=getbits()>>(16-Bits); - addbits(Bits); - } - } - - if (Distance>=0x2000) - { - Length++; - if (Distance>=0x40000L) - Length++; - } - - InsertOldDist(Distance); - InsertLastMatch(Length,Distance); - CopyString(Length,Distance); - continue; - } - if (Number==256) - { - if (!ReadEndOfBlock()) - break; - continue; - } - if (Number==257) - { - if (!ReadVMCode()) - break; - continue; - } - if (Number==258) - { - if (LastLength!=0) - CopyString(LastLength,LastDist); - continue; - } - if (Number<263) - { - int DistNum=Number-259; - unsigned int Distance=OldDist[DistNum]; - for (int I=DistNum;I>0;I--) - OldDist[I]=OldDist[I-1]; - OldDist[0]=Distance; - - int LengthNumber=DecodeNumber((struct Decode *)&RD); - int Length=LDecode[LengthNumber]+2; - if ((Bits=LBits[LengthNumber])>0) - { - Length+=getbits()>>(16-Bits); - addbits(Bits); - } - InsertLastMatch(Length,Distance); - CopyString(Length,Distance); - continue; - } - if (Number<272) - { - unsigned int Distance=SDDecode[Number-=263]+1; - if ((Bits=SDBits[Number])>0) - { - Distance+=getbits()>>(16-Bits); - addbits(Bits); - } - InsertOldDist(Distance); - InsertLastMatch(2,Distance); - CopyString(2,Distance); - continue; - } - } - UnpWriteBuf(); -} - - -bool Unpack::ReadEndOfBlock() -{ - unsigned int BitField=getbits(); - bool NewTable,NewFile=false; - if (BitField & 0x8000) - { - NewTable=true; - addbits(1); - } - else - { - NewFile=true; - NewTable=(BitField & 0x4000); - addbits(2); - } - TablesRead=!NewTable; - return !(NewFile || (NewTable && !ReadTables())); -} - - -bool Unpack::ReadVMCode() -{ - unsigned int FirstByte=getbits()>>8; - addbits(8); - int Length=(FirstByte & 7)+1; - if (Length==7) - { - Length=(getbits()>>8)+7; - addbits(8); - } - else - if (Length==8) - { - Length=getbits(); - addbits(16); - } - VMCode.Alloc( Length ); - for (int I=0;I=ReadTop-1 && !UnpReadBuf() && I>8; - addbits(8); - } - return(AddVMCode(FirstByte,&VMCode[0],Length)); -} - - -bool Unpack::ReadVMCodePPM() -{ - unsigned int FirstByte=PPM.DecodeChar(); - if ((int)FirstByte==-1) - return(false); - int Length=(FirstByte & 7)+1; - if (Length==7) - { - int B1=PPM.DecodeChar(); - if (B1==-1) - return(false); - Length=B1+7; - } - else - if (Length==8) - { - int B1=PPM.DecodeChar(); - if (B1==-1) - return(false); - int B2=PPM.DecodeChar(); - if (B2==-1) - return(false); - Length=B1*256+B2; - } - VMCode.Alloc( Length ); - for (int I=0;IFilters.Size() || FiltPos>OldFilterLengths.Size()) - return(false); - LastFilter=FiltPos; - bool NewFilter=(FiltPos==Filters.Size()); - - delete LastStackFilter; - LastStackFilter = NULL; - UnpackFilter *StackFilter=new UnpackFilter(&ErrHandler); - LastStackFilter = StackFilter; - if ( !StackFilter ) - ErrHandler.MemoryError(); - - UnpackFilter *Filter; - if (NewFilter) // new filter code, never used before since VM reset - { - // too many different filters, corrupt archive - if (FiltPos>1024) - return(false); - - Filters.Add(1); - Filters[Filters.Size()-1]=Filter=new UnpackFilter(&ErrHandler); - if ( !Filter ) - ErrHandler.MemoryError(); - StackFilter->ParentFilter=Filters.Size()-1; - OldFilterLengths.Add(1); - Filter->ExecCount=0; - } - else // filter was used in the past - { - Filter=Filters[FiltPos]; - StackFilter->ParentFilter=FiltPos; - Filter->ExecCount++; - } - - int EmptyCount=0; - { - for (int I=0;I0) - PrgStack[I]=NULL; - } - } - if (EmptyCount==0) - { - PrgStack.Add(1); - EmptyCount=1; - } - int StackPos=PrgStack.Size()-EmptyCount; - PrgStack[StackPos]=StackFilter; - LastStackFilter = NULL; - StackFilter->ExecCount=Filter->ExecCount; - - uint BlockStart=RarVM::ReadData(Inp); - if (FirstByte & 0x40) - BlockStart+=258; - StackFilter->BlockStart=(BlockStart+UnpPtr)&MAXWINMASK; - if (FirstByte & 0x20) - StackFilter->BlockLength=RarVM::ReadData(Inp); - else - StackFilter->BlockLength=FiltPosNextWindow=WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MAXWINMASK)<=BlockStart; - -// DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x BlockStart=%08x",UnpPtr,WrPtr,BlockStart); - - OldFilterLengths[FiltPos]=StackFilter->BlockLength; - - memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR)); - StackFilter->Prg.InitR[3]=VM_GLOBALMEMADDR; - StackFilter->Prg.InitR[4]=StackFilter->BlockLength; - StackFilter->Prg.InitR[5]=StackFilter->ExecCount; - - if (FirstByte & 0x10) // set registers to optional parameters if any - { - unsigned int InitMask=Inp.fgetbits()>>9; - Inp.faddbits(7); - for (int I=0;I<7;I++) - if (InitMask & (1<Prg.InitR[I]=RarVM::ReadData(Inp); - } - - if (NewFilter) - { - uint VMCodeSize=RarVM::ReadData(Inp); - if (VMCodeSize>=0x10000 || VMCodeSize==0) - return(false); - VMCode.Alloc( VMCodeSize ); - for (int I=0;I>8; - Inp.faddbits(8); - } - VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg); - VMCode.Reset(); - } - StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0]; - StackFilter->Prg.CmdCount=Filter->Prg.CmdCount; - - int StaticDataSize=Filter->Prg.StaticData.Size(); - if (StaticDataSize>0 && StaticDataSizePrg.StaticData.Add(StaticDataSize); - memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize); - } - - if (StackFilter->Prg.GlobalData.Size()Prg.GlobalData.Reset(); - StackFilter->Prg.GlobalData.Add(VM_FIXEDGLOBALSIZE); - } - byte *GlobalData=&StackFilter->Prg.GlobalData[0]; - for (int I=0;I<7;I++) - VM.SetLowEndianValue((uint *)&GlobalData[I*4],StackFilter->Prg.InitR[I]); - VM.SetLowEndianValue((uint *)&GlobalData[0x1c],StackFilter->BlockLength); - VM.SetLowEndianValue((uint *)&GlobalData[0x20],0); - VM.SetLowEndianValue((uint *)&GlobalData[0x2c],StackFilter->ExecCount); - memset(&GlobalData[0x30],0,16); - - if (FirstByte & 8) // put data block passed as parameter if any - { - if (Inp.Overflow(3)) - return(false); - uint DataSize=RarVM::ReadData(Inp); - if (DataSize>VM_GLOBALMEMSIZE-VM_FIXEDGLOBALSIZE) - return(false); - unsigned int CurSize=StackFilter->Prg.GlobalData.Size(); - if (CurSizePrg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize); - byte *GlobalData=&StackFilter->Prg.GlobalData[VM_FIXEDGLOBALSIZE]; - for (int I=0;I>8; - Inp.faddbits(8); - } - } - Inp.InitBitInput(); - return(true); -} - - -bool Unpack::UnpReadBuf() -{ - int DataSize=ReadTop-InAddr; - if (DataSize<0) - return(false); - if (InAddr>BitInput::MAX_SIZE/2) - { - if (DataSize>0) - memmove(InBuf,InBuf+InAddr,DataSize); - InAddr=0; - ReadTop=DataSize; - } - else - DataSize=ReadTop; - int ReadCode=UnpIO->UnpRead(InBuf+DataSize,(BitInput::MAX_SIZE-DataSize)&~0xf); - if (ReadCode>0) - ReadTop+=ReadCode; - ReadBorder=ReadTop-30; - return(ReadCode!=-1); -} - - -void Unpack::UnpWriteBuf() -{ - unsigned int WrittenBorder=WrPtr; - unsigned int WriteSize=(UnpPtr-WrittenBorder)&MAXWINMASK; - for (int I=0;INextWindow) - { - flt->NextWindow=false; - continue; - } - unsigned int BlockStart=flt->BlockStart; - unsigned int BlockLength=flt->BlockLength; - if (((BlockStart-WrittenBorder)&MAXWINMASK)ParentFilter]->Prg; - VM_PreparedProgram *Prg=&flt->Prg; - - if (ParentPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) - { - // copy global data from previous script execution if any - Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); - memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - } - - ExecuteCode(Prg); - - if (Prg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) - { - // save global data for next script execution - if (ParentPrg->GlobalData.Size()GlobalData.Size()) - ParentPrg->GlobalData.Alloc(Prg->GlobalData.Size()); - memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - } - else - ParentPrg->GlobalData.Reset(); - - byte *FilteredData=Prg->FilteredData; - unsigned int FilteredDataSize=Prg->FilteredDataSize; - - delete PrgStack[I]; - PrgStack[I]=NULL; - while (I+1BlockStart!=BlockStart || - NextFilter->BlockLength!=FilteredDataSize || NextFilter->NextWindow) - break; - - // apply several filters to same data block - - VM.SetMemory(0,FilteredData,FilteredDataSize); - - VM_PreparedProgram *ParentPrg=&Filters[NextFilter->ParentFilter]->Prg; - VM_PreparedProgram *NextPrg=&NextFilter->Prg; - - if (ParentPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) - { - // copy global data from previous script execution if any - NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); - memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - } - - ExecuteCode(NextPrg); - - if (NextPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) - { - // save global data for next script execution - if (ParentPrg->GlobalData.Size()GlobalData.Size()) - ParentPrg->GlobalData.Alloc(NextPrg->GlobalData.Size()); - memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); - } - else - ParentPrg->GlobalData.Reset(); - - FilteredData=NextPrg->FilteredData; - FilteredDataSize=NextPrg->FilteredDataSize; - I++; - delete PrgStack[I]; - PrgStack[I]=NULL; - } - UnpIO->UnpWrite(FilteredData,FilteredDataSize); - UnpSomeRead=true; - WrittenFileSize+=FilteredDataSize; - WrittenBorder=BlockEnd; - WriteSize=(UnpPtr-WrittenBorder)&MAXWINMASK; - } - else - { - for (int J=I;JNextWindow) - flt->NextWindow=false; - } - WrPtr=WrittenBorder; - return; - } - } - } - - UnpWriteArea(WrittenBorder,UnpPtr); - WrPtr=UnpPtr; -} - - -void Unpack::ExecuteCode(VM_PreparedProgram *Prg) -{ - if (Prg->GlobalData.Size()>0) - { - Prg->InitR[6]=int64to32(WrittenFileSize); - VM.SetLowEndianValue((uint *)&Prg->GlobalData[0x24],int64to32(WrittenFileSize)); - VM.SetLowEndianValue((uint *)&Prg->GlobalData[0x28],int64to32(WrittenFileSize>>31>>1)); - VM.Execute(Prg); - } -} - - -void Unpack::UnpWriteArea(unsigned int StartPtr,unsigned int EndPtr) -{ - if (EndPtr!=StartPtr) - UnpSomeRead=true; - if (EndPtr=DestUnpSize) - return; - int WriteSize=Size; - Int64 LeftToWrite=DestUnpSize-WrittenFileSize; - if (WriteSize>LeftToWrite) - WriteSize=int64to32(LeftToWrite); - UnpIO->UnpWrite(Data,WriteSize); - WrittenFileSize+=Size; -} - - -bool Unpack::ReadTables() -{ - byte BitLength[BC]; - unsigned char Table[HUFF_TABLE_SIZE]; - if (InAddr>ReadTop-25) - if (!UnpReadBuf()) - return(false); - faddbits((8-InBit)&7); - unsigned int BitField=fgetbits(); - if (BitField & 0x8000) - { - UnpBlockType=BLOCK_PPM; - return(PPM.DecodeInit(this,PPMEscChar)); - } - UnpBlockType=BLOCK_LZ; - - PrevLowDist=0; - LowDistRepCount=0; - - if (!(BitField & 0x4000)) - memset(UnpOldTable,0,sizeof(UnpOldTable)); - faddbits(2); - { - for (int I=0;I> 12); - faddbits(4); - if (Length==15) - { - int ZeroCount=(byte)(fgetbits() >> 12); - faddbits(4); - if (ZeroCount==0) - BitLength[I]=15; - else - { - ZeroCount+=2; - while (ZeroCount-- > 0 && IReadTop-5) - if (!UnpReadBuf()) - return(false); - int Number=DecodeNumber((struct Decode *)&BD); - if (Number<16) - { - Table[I]=(Number+UnpOldTable[I]) & 0xf; - I++; - } - else - if (Number<18) - { - int N; - if (Number==16) - { - N=(fgetbits() >> 13)+3; - faddbits(3); - } - else - { - N=(fgetbits() >> 9)+11; - faddbits(7); - } - while (N-- > 0 && I> 13)+3; - faddbits(3); - } - else - { - N=(fgetbits() >> 9)+11; - faddbits(7); - } - while (N-- > 0 && IReadTop) - return(false); - MakeDecodeTables(&Table[0],(struct Decode *)&LD,NC); - MakeDecodeTables(&Table[NC],(struct Decode *)&DD,DC); - MakeDecodeTables(&Table[NC+DC],(struct Decode *)&LDD,LDC); - MakeDecodeTables(&Table[NC+DC+LDC],(struct Decode *)&RD,RC); - memcpy(UnpOldTable,Table,sizeof(UnpOldTable)); - return(true); -} - - -void Unpack::UnpInitData(int Solid) -{ - if (!Solid) - { - TablesRead=false; - memset(OldDist,0,sizeof(OldDist)); - OldDistPtr=0; - LastDist=LastLength=0; -// memset(Window,0,MAXWINSIZE); - memset(UnpOldTable,0,sizeof(UnpOldTable)); - memset(&LD,0,sizeof(LD)); - memset(&DD,0,sizeof(DD)); - memset(&LDD,0,sizeof(LDD)); - memset(&RD,0,sizeof(RD)); - memset(&BD,0,sizeof(BD)); - UnpPtr=WrPtr=0; - PPMEscChar=2; - UnpBlockType=BLOCK_LZ; - - InitFilters(); - } - InitBitInput(); - WrittenFileSize=0; - ReadTop=0; - ReadBorder=0; + if (!Solid) + { + memset(OldDist,0,sizeof(OldDist)); + OldDistPtr=0; + LastDist=LastLength=0; + // memset(Window,0,MaxWinSize); + memset(&BlockTables,0,sizeof(BlockTables)); + UnpPtr=WrPtr=0; + WriteBorder=Min(MaxWinSize,UNPACK_MAX_WRITE)&MaxWinMask; + + InitFilters(); + } + Inp.InitBitInput(); + WrittenFileSize=0; + ReadTop=0; + ReadBorder=0; + + memset(&BlockHeader,0,sizeof(BlockHeader)); + BlockHeader.BlockSize=-1; // '-1' means not defined yet. #ifndef SFX_MODULE - UnpInitData20(Solid); + UnpInitData20(Solid); #endif + UnpInitData30(Solid); } -void Unpack::InitFilters() +// LengthTable contains the length in bits for every element of alphabet. +// Dec is the structure to decode Huffman code/ +// Size is size of length table and DecodeNum field in Dec structure, +void Unpack::MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size) { - delete LastStackFilter; - LastStackFilter = NULL; - - OldFilterLengths.Reset(); - LastFilter=0; - { - for (int I=0;IDecodeNum,0,Size*sizeof(*Dec->DecodeNum)); - for (I=0;IDecodePos[0]=Dec->DecodeLen[0]=0,N=0,I=1;I<16;I++) - { - N=2*(N+LenCount[I]); - M=N<<(15-I); - if (M>0xFFFF) - M=0xFFFF; - Dec->DecodeLen[I]=(unsigned int)M; - TmpPos[I]=Dec->DecodePos[I]=Dec->DecodePos[I-1]+LenCount[I-1]; - } - - for (I=0;IDecodeNum[TmpPos[LenTab[I] & 0xF]++]=I; - Dec->MaxNum=Size; + // Size of alphabet and DecodePos array. + Dec->MaxNum=Size; + + // Calculate how many entries for every bit length in LengthTable we have. + uint LengthCount[16]; + memset(LengthCount,0,sizeof(LengthCount)); + for (size_t I=0;IDecodeNum,0,Size*sizeof(*Dec->DecodeNum)); + + // Initialize not really used entry for zero length code. + Dec->DecodePos[0]=0; + + // Start code for bit length 1 is 0. + Dec->DecodeLen[0]=0; + + // Right aligned upper limit code for current bit length. + uint UpperLimit=0; + + for (size_t I=1;I<16;I++) + { + // Adjust the upper limit code. + UpperLimit+=LengthCount[I]; + + // Left aligned upper limit code. + uint LeftAligned=UpperLimit<<(16-I); + + // Prepare the upper limit code for next bit length. + UpperLimit*=2; + + // Store the left aligned upper limit code. + Dec->DecodeLen[I]=(uint)LeftAligned; + + // Every item of this array contains the sum of all preceding items. + // So it contains the start position in code list for every bit length. + Dec->DecodePos[I]=Dec->DecodePos[I-1]+LengthCount[I-1]; + } + + // Prepare the copy of DecodePos. We'll modify this copy below, + // so we cannot use the original DecodePos. + uint CopyDecodePos[16]; + memcpy(CopyDecodePos,Dec->DecodePos,sizeof(CopyDecodePos)); + + // For every bit length in the bit length table and so for every item + // of alphabet. + for (uint I=0;IDecodeNum[LastPos]=(ushort)I; + + // We'll use next position number for this bit length next time. + // So we pass through the entire range of positions available + // for every bit length. + CopyDecodePos[CurBitLength]++; + } + } + + // Define the number of bits to process in quick mode. We use more bits + // for larger alphabets. More bits means that more codes will be processed + // in quick mode, but also that more time will be spent to preparation + // of tables for quick decode. + switch (Size) + { + case NC: + case NC20: + case NC30: + Dec->QuickBits=MAX_QUICK_DECODE_BITS; + break; + default: + Dec->QuickBits=MAX_QUICK_DECODE_BITS-3; + break; + } + + // Size of tables for quick mode. + uint QuickDataSize=1<QuickBits; + + // Bit length for current code, start from 1 bit codes. It is important + // to use 1 bit instead of 0 for minimum code length, so we are moving + // forward even when processing a corrupt archive. + uint CurBitLength=1; + + // For every right aligned bit string which supports the quick decoding. + for (uint Code=0;CodeQuickBits); + + // Prepare the table for quick decoding of bit lengths. + + // Find the upper limit for current bit field and adjust the bit length + // accordingly if necessary. + while (BitField>=Dec->DecodeLen[CurBitLength] && CurBitLengthDecodeLen)) + CurBitLength++; + + // Translation of right aligned bit string to bit length. + Dec->QuickLen[Code]=CurBitLength; + + // Prepare the table for quick translation of position in code list + // to position in alphabet. + + // Calculate the distance from the start code for current bit length. + uint Dist=BitField-Dec->DecodeLen[CurBitLength-1]; + + // Right align the distance. + Dist>>=(16-CurBitLength); + + // Now we can calculate the position in the code list. It is the sum + // of first position for current bit length and right aligned distance + // between our bit field and start code for current bit length. + uint Pos=Dec->DecodePos[CurBitLength]+Dist; + + if (PosQuickNum[Code]=Dec->DecodeNum[Pos]; + } + else + Dec->QuickNum[Code]=0; + } } diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/unpack.hpp b/Frameworks/File_Extractor/File_Extractor/unrar/unpack.hpp index 732ebe863..541189a5d 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/unpack.hpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/unpack.hpp @@ -1,227 +1,369 @@ -#ifndef _RAR_UNPACK_ -#define _RAR_UNPACK_ - -enum BLOCK_TYPES {BLOCK_LZ,BLOCK_PPM}; - -struct Decode -{ - unsigned int MaxNum; - unsigned int DecodeLen[16]; - unsigned int DecodePos[16]; - unsigned int DecodeNum[2]; -}; - -struct LitDecode -{ - unsigned int MaxNum; - unsigned int DecodeLen[16]; - unsigned int DecodePos[16]; - unsigned int DecodeNum[NC]; -}; - -struct DistDecode -{ - unsigned int MaxNum; - unsigned int DecodeLen[16]; - unsigned int DecodePos[16]; - unsigned int DecodeNum[DC]; -}; - -struct LowDistDecode -{ - unsigned int MaxNum; - unsigned int DecodeLen[16]; - unsigned int DecodePos[16]; - unsigned int DecodeNum[LDC]; -}; - -struct RepDecode -{ - unsigned int MaxNum; - unsigned int DecodeLen[16]; - unsigned int DecodePos[16]; - unsigned int DecodeNum[RC]; -}; - -struct BitDecode -{ - unsigned int MaxNum; - unsigned int DecodeLen[16]; - unsigned int DecodePos[16]; - unsigned int DecodeNum[BC]; -}; - -struct UnpackFilter - : Rar_Allocator -{ - unsigned int BlockStart; - unsigned int BlockLength; - unsigned int ExecCount; - bool NextWindow; - - // position of parent filter in Filters array used as prototype for filter - // in PrgStack array. Not defined for filters in Filters array. - unsigned int ParentFilter; - - VM_PreparedProgram Prg; - UnpackFilter( Rar_Error_Handler* eh ) : Prg( eh ) { } -}; - -/***************************** Unpack v 2.0 *********************************/ -struct MultDecode -{ - unsigned int MaxNum; - unsigned int DecodeLen[16]; - unsigned int DecodePos[16]; - unsigned int DecodeNum[MC20]; -}; - -struct AudioVariables -{ - int K1,K2,K3,K4,K5; - int D1,D2,D3,D4; - int LastDelta; - unsigned int Dif[11]; - unsigned int ByteCount; - int LastChar; -}; -/***************************** Unpack v 2.0 *********************************/ - - -// public so operator new/delete will be accessible, argh -class Unpack:public BitInput -{ -private: - friend class Pack; - - void Unpack29(bool Solid); - bool UnpReadBuf(); - void UnpWriteBuf(); - void ExecuteCode(VM_PreparedProgram *Prg); - void UnpWriteArea(unsigned int StartPtr,unsigned int EndPtr); - void UnpWriteData(byte *Data,int Size); - bool ReadTables(); - void MakeDecodeTables(unsigned char *LenTab,struct Decode *Dec,int Size); - int DecodeNumber(struct Decode *Dec); - void CopyString(); - inline void InsertOldDist(unsigned int Distance); - inline void InsertLastMatch(unsigned int Length,unsigned int Distance); - void UnpInitData(int Solid); - void CopyString(unsigned int Length,unsigned int Distance); - bool ReadEndOfBlock(); - bool ReadVMCode(); - bool ReadVMCodePPM(); - bool AddVMCode(unsigned int FirstByte,byte *Code,int CodeSize); - void InitFilters(); - - ComprDataIO *UnpIO; - ModelPPM PPM; - int PPMEscChar; - - Array VMCode; // here to avoid leaks - BitInput Inp; // here to avoid leaks - - RarVM VM; - - UnpackFilter* LastStackFilter; // avoids leak for stack-based filter - - /* Filters code, one entry per filter */ - Array Filters; - - /* Filters stack, several entrances of same filter are possible */ - Array PrgStack; - - /* lengths of preceding blocks, one length per filter. Used to reduce - size required to write block length if lengths are repeating */ - Array OldFilterLengths; - - int LastFilter; - - bool TablesRead; - struct LitDecode LD; - struct DistDecode DD; - struct LowDistDecode LDD; - struct RepDecode RD; - struct BitDecode BD; - - unsigned int OldDist[4],OldDistPtr; - unsigned int LastDist,LastLength; - - unsigned int UnpPtr,WrPtr; - - int ReadTop; - int ReadBorder; - - unsigned char UnpOldTable[HUFF_TABLE_SIZE]; - - int UnpBlockType; - - byte *Window; - bool ExternalWindow; - - - Int64 DestUnpSize; - - enum { Suspended = false }; // original source could never set to true - bool UnpAllBuf; - bool UnpSomeRead; - Int64 WrittenFileSize; - bool FileExtracted; - - int PrevLowDist,LowDistRepCount; - - /***************************** Unpack v 1.5 *********************************/ - void Unpack15(bool Solid); - void ShortLZ(); - void LongLZ(); - void HuffDecode(); - void GetFlagsBuf(); - void OldUnpInitData(int Solid); - void InitHuff(); - void CorrHuff(unsigned int *CharSet,unsigned int *NumToPlace); - void OldCopyString(unsigned int Distance,unsigned int Length); - unsigned int DecodeNum(int Num,unsigned int StartPos, - const unsigned int *DecTab,const unsigned int *PosTab); - void OldUnpWriteBuf(); - - unsigned int ChSet[256],ChSetA[256],ChSetB[256],ChSetC[256]; - unsigned int Place[256],PlaceA[256],PlaceB[256],PlaceC[256]; - unsigned int NToPl[256],NToPlB[256],NToPlC[256]; - unsigned int FlagBuf,AvrPlc,AvrPlcB,AvrLn1,AvrLn2,AvrLn3; - int Buf60,NumHuf,StMode,LCount,FlagsCnt; - unsigned int Nhfb,Nlzb,MaxDist3; - /***************************** Unpack v 1.5 *********************************/ - - /***************************** Unpack v 2.0 *********************************/ - void Unpack20(bool Solid); - struct MultDecode MD[4]; - unsigned char UnpOldTable20[MC20*4]; - int UnpAudioBlock,UnpChannels,UnpCurChannel,UnpChannelDelta; - void CopyString20(unsigned int Length,unsigned int Distance); - bool ReadTables20(); - void UnpInitData20(int Solid); - void ReadLastTables(); - byte DecodeAudio(int Delta); - struct AudioVariables AudV[4]; - /***************************** Unpack v 2.0 *********************************/ - -public: - Rar_Error_Handler& ErrHandler; - byte const* window_wrptr() const { return &Window [WrPtr & MAXWINMASK]; } - - static void init_tables(); - Unpack(ComprDataIO *DataIO); - ~Unpack(); - void Init(byte *Window=NULL); - void DoUnpack(int Method,bool Solid); - void SetDestSize(Int64 DestSize) {DestUnpSize=DestSize;FileExtracted=false;} - - unsigned int GetChar() - { - if (InAddr>BitInput::MAX_SIZE-30) - UnpReadBuf(); - return(InBuf[InAddr++]); - } -}; - -#endif +#ifndef _RAR_UNPACK_ +#define _RAR_UNPACK_ + +// Maximum allowed number of compressed bits processed in quick mode. +#define MAX_QUICK_DECODE_BITS 10 + +// Maximum number of filters per entire data block. +#define MAX_UNPACK_FILTERS 8192 + +// Maximum number of filters per entire data block for RAR3 unpack. +#define MAX3_FILTERS 1024 + +// Write data in 4 MB or smaller blocks. +#define UNPACK_MAX_WRITE 0x400000 + +// Decode compressed bit fields to alphabet numbers. +struct DecodeTable:PackDef +{ + // Real size of DecodeNum table. + uint MaxNum; + + // Left aligned start and upper limit codes defining code space + // ranges for bit lengths. DecodeLen[BitLength-1] defines the start of + // range for bit length and DecodeLen[BitLength] defines next code + // after the end of range or in other words the upper limit code + // for specified bit length. + uint DecodeLen[16]; + + // Every item of this array contains the sum of all preceding items. + // So it contains the start position in code list for every bit length. + uint DecodePos[16]; + + // Number of compressed bits processed in quick mode. + // Must not exceed MAX_QUICK_DECODE_BITS. + uint QuickBits; + + // Translates compressed bits (up to QuickBits length) + // to bit length in quick mode. + byte QuickLen[1< FilterSrcMemory; + Array FilterDstMemory; + + // Filters code, one entry per filter. + Array Filters; + + uint OldDist[4],OldDistPtr; + uint LastLength; + + // LastDist is necessary only for RAR2 and older with circular OldDist + // array. In RAR3 last distance is always stored in OldDist[0]. + uint LastDist; + + size_t UnpPtr,WrPtr; + + // Top border of read packed data. + int ReadTop; + + // Border to call UnpReadBuf. We use it instead of (ReadTop-C) + // for optimization reasons. Ensures that we have C bytes in buffer + // unless we are at the end of file. + int ReadBorder; + + UnpackBlockHeader BlockHeader; + UnpackBlockTables BlockTables; + + size_t WriteBorder; + + byte *Window; + + FragmentedWindow FragWindow; + bool Fragmented; + + + int64 DestUnpSize; + + bool Suspended; + bool UnpAllBuf; + bool UnpSomeRead; + int64 WrittenFileSize; + bool FileExtracted; + + +/***************************** Unpack v 1.5 *********************************/ + void Unpack15(bool Solid); + void ShortLZ(); + void LongLZ(); + void HuffDecode(); + void GetFlagsBuf(); + void UnpInitData15(int Solid); + void InitHuff(); + void CorrHuff(ushort *CharSet,byte *NumToPlace); + void CopyString15(uint Distance,uint Length); + uint DecodeNum(uint Num,uint StartPos,uint *DecTab,uint *PosTab); + + ushort ChSet[256],ChSetA[256],ChSetB[256],ChSetC[256]; + byte NToPl[256],NToPlB[256],NToPlC[256]; + uint FlagBuf,AvrPlc,AvrPlcB,AvrLn1,AvrLn2,AvrLn3; + int Buf60,NumHuf,StMode,LCount,FlagsCnt; + uint Nhfb,Nlzb,MaxDist3; +/***************************** Unpack v 1.5 *********************************/ + +/***************************** Unpack v 2.0 *********************************/ + void Unpack20(bool Solid); + + DecodeTable MD[4]; // Decode multimedia data, up to 4 channels. + + unsigned char UnpOldTable20[MC20*4]; + uint UnpAudioBlock,UnpChannels,UnpCurChannel; + int UnpChannelDelta; + void CopyString20(uint Length,uint Distance); + bool ReadTables20(); + void UnpWriteBuf20(); + void UnpInitData20(int Solid); + void ReadLastTables(); + byte DecodeAudio(int Delta); + struct AudioVariables AudV[4]; +/***************************** Unpack v 2.0 *********************************/ + +/***************************** Unpack v 3.0 *********************************/ + enum BLOCK_TYPES {BLOCK_LZ,BLOCK_PPM}; + + void UnpInitData30(bool Solid); + void Unpack29(bool Solid); + void InitFilters30(); + bool ReadEndOfBlock(); + bool ReadVMCode(); + bool ReadVMCodePPM(); + bool AddVMCode(uint FirstByte,byte *Code,int CodeSize); + int SafePPMDecodeChar(); + bool ReadTables30(); + bool UnpReadBuf30(); + void UnpWriteBuf30(); + void ExecuteCode(VM_PreparedProgram *Prg); + + int PrevLowDist,LowDistRepCount; + + ModelPPM PPM; + int PPMEscChar; + + byte UnpOldTable[HUFF_TABLE_SIZE30]; + int UnpBlockType; + + bool TablesRead; + + // Virtual machine to execute filters code. + RarVM VM; + + // Buffer to read VM filters code. We moved it here from AddVMCode + // function to reduce time spent in BitInput constructor. + BitInput VMCodeInp; + + // Filters code, one entry per filter. + Array Filters30; + + // Filters stack, several entrances of same filter are possible. + Array PrgStack; + + // Lengths of preceding data blocks, one length of one last block + // for every filter. Used to reduce the size required to write + // the data block length if lengths are repeating. + Array OldFilterLengths; + + int LastFilter; +/***************************** Unpack v 3.0 *********************************/ + + public: + Unpack(ComprDataIO *DataIO); + ~Unpack(); + void Init(size_t WinSize,bool Solid); + void DoUnpack(int Method,bool Solid); + bool IsFileExtracted() {return(FileExtracted);} + void SetDestSize(int64 DestSize) {DestUnpSize=DestSize;FileExtracted=false;} + void SetSuspended(bool Suspended) {Unpack::Suspended=Suspended;} + + byte const* window_wrptr() const { return &Window [WrPtr & MaxWinMask]; } + + size_t MaxWinSize; + size_t MaxWinMask; + + uint GetChar() + { + if (Inp.InAddr>BitInput::MAX_SIZE-30) + UnpReadBuf(); + return(Inp.InBuf[Inp.InAddr++]); + } +}; + +#endif diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/unpack15.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/unpack15.cpp index 40720f00f..0446ee50c 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/unpack15.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/unpack15.cpp @@ -1,534 +1,481 @@ -// #included by unpack.cpp -#ifdef RAR_COMMON_HPP -#define STARTL1 2 -const -static unsigned int DecL1[]={0x8000,0xa000,0xc000,0xd000,0xe000,0xea00, - 0xee00,0xf000,0xf200,0xf200,0xffff}; -const -static unsigned int PosL1[]={0,0,0,2,3,5,7,11,16,20,24,32,32}; - -#define STARTL2 3 -const -static unsigned int DecL2[]={0xa000,0xc000,0xd000,0xe000,0xea00,0xee00, - 0xf000,0xf200,0xf240,0xffff}; -const -static unsigned int PosL2[]={0,0,0,0,5,7,9,13,18,22,26,34,36}; - -#define STARTHF0 4 -const -static unsigned int DecHf0[]={0x8000,0xc000,0xe000,0xf200,0xf200,0xf200, - 0xf200,0xf200,0xffff}; -const -static unsigned int PosHf0[]={0,0,0,0,0,8,16,24,33,33,33,33,33}; - - -#define STARTHF1 5 -const -static unsigned int DecHf1[]={0x2000,0xc000,0xe000,0xf000,0xf200,0xf200, - 0xf7e0,0xffff}; -const -static unsigned int PosHf1[]={0,0,0,0,0,0,4,44,60,76,80,80,127}; - - -#define STARTHF2 5 -const -static unsigned int DecHf2[]={0x1000,0x2400,0x8000,0xc000,0xfa00,0xffff, - 0xffff,0xffff}; -const -static unsigned int PosHf2[]={0,0,0,0,0,0,2,7,53,117,233,0,0}; - - -#define STARTHF3 6 -const -static unsigned int DecHf3[]={0x800,0x2400,0xee00,0xfe80,0xffff,0xffff, - 0xffff}; -const -static unsigned int PosHf3[]={0,0,0,0,0,0,0,2,16,218,251,0,0}; - - -#define STARTHF4 8 -const -static unsigned int DecHf4[]={0xff00,0xffff,0xffff,0xffff,0xffff,0xffff}; -const -static unsigned int PosHf4[]={0,0,0,0,0,0,0,0,0,255,0,0,0}; - - -void Unpack::Unpack15(bool Solid) -{ - if (Suspended) - UnpPtr=WrPtr; - else - { - UnpInitData(Solid); - OldUnpInitData(Solid); - UnpReadBuf(); - if (!Solid) - { - InitHuff(); - UnpPtr=0; - } - else - UnpPtr=WrPtr; - --DestUnpSize; - } - if (DestUnpSize>=0) - { - GetFlagsBuf(); - FlagsCnt=8; - } - - while (DestUnpSize>=0) - { - UnpPtr&=MAXWINMASK; - - if (InAddr>ReadTop-30 && !UnpReadBuf()) - break; - if (((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr) - { - OldUnpWriteBuf(); - if (Suspended) - return; - } - if (StMode) - { - HuffDecode(); - continue; - } - - if (--FlagsCnt < 0) - { - GetFlagsBuf(); - FlagsCnt=7; - } - - if (FlagBuf & 0x80) - { - FlagBuf<<=1; - if (Nlzb > Nhfb) - LongLZ(); - else - HuffDecode(); - } - else - { - FlagBuf<<=1; - if (--FlagsCnt < 0) - { - GetFlagsBuf(); - FlagsCnt=7; - } - if (FlagBuf & 0x80) - { - FlagBuf<<=1; - if (Nlzb > Nhfb) - HuffDecode(); - else - LongLZ(); - } - else - { - FlagBuf<<=1; - ShortLZ(); - } - } - } - OldUnpWriteBuf(); -} - - -void Unpack::OldUnpWriteBuf() -{ - if (UnpPtr!=WrPtr) - UnpSomeRead=true; - if (UnpPtrUnpWrite(&Window[WrPtr],-WrPtr & MAXWINMASK); - UnpIO->UnpWrite(Window,UnpPtr); - UnpAllBuf=true; - } - else - UnpIO->UnpWrite(&Window[WrPtr],UnpPtr-WrPtr); - WrPtr=UnpPtr; -} - - -#define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos]) -#define GetShortLen2(pos) ((pos)==3 ? Buf60+3:ShortLen2[pos]) - -void Unpack::ShortLZ() -{ - const - static unsigned int ShortLen1[]={1,3,4,4,5,6,7,8,8,4,4,5,6,6,4,0}; - const - static unsigned int ShortXor1[]={0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe, - 0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0}; - const - static unsigned int ShortLen2[]={2,3,3,3,4,4,5,6,6,4,4,5,6,6,4,0}; - const - static unsigned int ShortXor2[]={0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8, - 0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0}; - - - unsigned int Length,SaveLength; - unsigned int LastDistance; - unsigned int Distance; - int DistancePlace; - NumHuf=0; - - unsigned int BitField=fgetbits(); - if (LCount==2) - { - faddbits(1); - if (BitField >= 0x8000) - { - OldCopyString((unsigned int)LastDist,LastLength); - return; - } - BitField <<= 1; - LCount=0; - } - - BitField>>=8; - -// not thread safe, replaced by GetShortLen1 and GetShortLen2 macro -// ShortLen1[1]=ShortLen2[3]=Buf60+3; - - if (AvrLn1<37) - { - for (Length=0;;Length++) - if (((BitField^ShortXor1[Length]) & (~(0xff>>GetShortLen1(Length))))==0) - break; - faddbits(GetShortLen1(Length)); - } - else - { - for (Length=0;;Length++) - if (((BitField^ShortXor2[Length]) & (~(0xff>>GetShortLen2(Length))))==0) - break; - faddbits(GetShortLen2(Length)); - } - - if (Length >= 9) - { - if (Length == 9) - { - LCount++; - OldCopyString((unsigned int)LastDist,LastLength); - return; - } - if (Length == 14) - { - LCount=0; - Length=DecodeNum(fgetbits(),STARTL2,DecL2,PosL2)+5; - Distance=(fgetbits()>>1) | 0x8000; - faddbits(15); - LastLength=Length; - LastDist=Distance; - OldCopyString(Distance,Length); - return; - } - - LCount=0; - SaveLength=Length; - Distance=OldDist[(OldDistPtr-(Length-9)) & 3]; - Length=DecodeNum(fgetbits(),STARTL1,DecL1,PosL1)+2; - if (Length==0x101 && SaveLength==10) - { - Buf60 ^= 1; - return; - } - if (Distance > 256) - Length++; - if (Distance >= MaxDist3) - Length++; - - OldDist[OldDistPtr++]=Distance; - OldDistPtr = OldDistPtr & 3; - LastLength=Length; - LastDist=Distance; - OldCopyString(Distance,Length); - return; - } - - LCount=0; - AvrLn1 += Length; - AvrLn1 -= AvrLn1 >> 4; - - DistancePlace=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2) & 0xff; - Distance=ChSetA[DistancePlace]; - if (--DistancePlace != -1) - { - PlaceA[Distance]--; - LastDistance=ChSetA[DistancePlace]; - PlaceA[LastDistance]++; - ChSetA[DistancePlace+1]=LastDistance; - ChSetA[DistancePlace]=Distance; - } - Length+=2; - OldDist[OldDistPtr++] = ++Distance; - OldDistPtr = OldDistPtr & 3; - LastLength=Length; - LastDist=Distance; - OldCopyString(Distance,Length); -} - - -void Unpack::LongLZ() -{ - unsigned int Length; - unsigned int Distance; - unsigned int DistancePlace,NewDistancePlace; - unsigned int OldAvr2,OldAvr3; - - NumHuf=0; - Nlzb+=16; - if (Nlzb > 0xff) - { - Nlzb=0x90; - Nhfb >>= 1; - } - OldAvr2=AvrLn2; - - unsigned int BitField=fgetbits(); - if (AvrLn2 >= 122) - Length=DecodeNum(BitField,STARTL2,DecL2,PosL2); - else - if (AvrLn2 >= 64) - Length=DecodeNum(BitField,STARTL1,DecL1,PosL1); - else - if (BitField < 0x100) - { - Length=BitField; - faddbits(16); - } - else - { - for (Length=0;((BitField<> 5; - - BitField=fgetbits(); - if (AvrPlcB > 0x28ff) - DistancePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2); - else - if (AvrPlcB > 0x6ff) - DistancePlace=DecodeNum(BitField,STARTHF1,DecHf1,PosHf1); - else - DistancePlace=DecodeNum(BitField,STARTHF0,DecHf0,PosHf0); - - AvrPlcB += DistancePlace; - AvrPlcB -= AvrPlcB >> 8; - while (1) - { - Distance = ChSetB[DistancePlace & 0xff]; - NewDistancePlace = NToPlB[Distance++ & 0xff]++; - if (!(Distance & 0xff)) - CorrHuff(ChSetB,NToPlB); - else - break; - } - - ChSetB[DistancePlace]=ChSetB[NewDistancePlace]; - ChSetB[NewDistancePlace]=Distance; - - Distance=((Distance & 0xff00) | (fgetbits() >> 8)) >> 1; - faddbits(7); - - OldAvr3=AvrLn3; - if (Length!=1 && Length!=4) - { - if (Length==0 && Distance <= MaxDist3) - { - AvrLn3++; - AvrLn3 -= AvrLn3 >> 8; - } - else - if (AvrLn3 > 0) - AvrLn3--; - } - Length+=3; - if (Distance >= MaxDist3) - Length++; - if (Distance <= 256) - Length+=8; - if (OldAvr3 > 0xb0 || (AvrPlc >= 0x2a00 && OldAvr2 < 0x40)) - MaxDist3=0x7f00; - else - MaxDist3=0x2001; - OldDist[OldDistPtr++]=Distance; - OldDistPtr = OldDistPtr & 3; - LastLength=Length; - LastDist=Distance; - OldCopyString(Distance,Length); -} - - -void Unpack::HuffDecode() -{ - unsigned int CurByte,NewBytePlace; - unsigned int Length; - unsigned int Distance; - int BytePlace; - - unsigned int BitField=fgetbits(); - - if (AvrPlc > 0x75ff) - BytePlace=DecodeNum(BitField,STARTHF4,DecHf4,PosHf4); - else - if (AvrPlc > 0x5dff) - BytePlace=DecodeNum(BitField,STARTHF3,DecHf3,PosHf3); - else - if (AvrPlc > 0x35ff) - BytePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2); - else - if (AvrPlc > 0x0dff) - BytePlace=DecodeNum(BitField,STARTHF1,DecHf1,PosHf1); - else - BytePlace=DecodeNum(BitField,STARTHF0,DecHf0,PosHf0); - BytePlace&=0xff; - if (StMode) - { - if (BytePlace==0 && BitField > 0xfff) - BytePlace=0x100; - if (--BytePlace==-1) - { - BitField=fgetbits(); - faddbits(1); - if (BitField & 0x8000) - { - NumHuf=StMode=0; - return; - } - else - { - Length = (BitField & 0x4000) ? 4 : 3; - faddbits(1); - Distance=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2); - Distance = (Distance << 5) | (fgetbits() >> 11); - faddbits(5); - OldCopyString(Distance,Length); - return; - } - } - } - else - if (NumHuf++ >= 16 && FlagsCnt==0) - StMode=1; - AvrPlc += BytePlace; - AvrPlc -= AvrPlc >> 8; - Nhfb+=16; - if (Nhfb > 0xff) - { - Nhfb=0x90; - Nlzb >>= 1; - } - - Window[UnpPtr++]=(byte)(ChSet[BytePlace]>>8); - --DestUnpSize; - - while (1) - { - CurByte=ChSet[BytePlace]; - NewBytePlace=NToPl[CurByte++ & 0xff]++; - if ((CurByte & 0xff) > 0xa1) - CorrHuff(ChSet,NToPl); - else - break; - } - - ChSet[BytePlace]=ChSet[NewBytePlace]; - ChSet[NewBytePlace]=CurByte; -} - - -void Unpack::GetFlagsBuf() -{ - unsigned int Flags,NewFlagsPlace; - unsigned int FlagsPlace=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2); - - while (1) - { - 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 Unpack::OldUnpInitData(int Solid) -{ - if (!Solid) - { - AvrPlcB=AvrLn1=AvrLn2=AvrLn3=NumHuf=Buf60=0; - AvrPlc=0x3500; - MaxDist3=0x2001; - Nhfb=Nlzb=0x80; - } - FlagsCnt=0; - FlagBuf=0; - StMode=0; - LCount=0; - ReadTop=0; -} - - -void Unpack::InitHuff() -{ - for (unsigned int I=0;I<256;I++) - { - Place[I]=PlaceA[I]=PlaceB[I]=I; - PlaceC[I]=(~I+1) & 0xff; - ChSet[I]=ChSetB[I]=I<<8; - ChSetA[I]=I; - ChSetC[I]=((~I+1) & 0xff)<<8; - } - memset(NToPl,0,sizeof(NToPl)); - memset(NToPlB,0,sizeof(NToPlB)); - memset(NToPlC,0,sizeof(NToPlC)); - CorrHuff(ChSetB,NToPlB); -} - - -void Unpack::CorrHuff(unsigned int *CharSet,unsigned int *NumToPlace) -{ - int I,J; - for (I=7;I>=0;I--) - for (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 Unpack::OldCopyString(unsigned int Distance,unsigned int Length) -{ - DestUnpSize-=Length; - while (Length--) - { - Window[UnpPtr]=Window[(UnpPtr-Distance) & MAXWINMASK]; - UnpPtr=(UnpPtr+1) & MAXWINMASK; - } -} - - -unsigned int Unpack::DecodeNum(int Num,unsigned int StartPos, - const unsigned int *DecTab,const unsigned int *PosTab) -{ - int I; - for (Num&=0xfff0,I=0;DecTab[I]<=Num;I++) - StartPos++; - faddbits(StartPos); - return(((Num-(I ? DecTab[I-1]:0))>>(16-StartPos))+PosTab[StartPos]); -} -#endif +#define STARTL1 2 +static unsigned int DecL1[]={0x8000,0xa000,0xc000,0xd000,0xe000,0xea00, + 0xee00,0xf000,0xf200,0xf200,0xffff}; +static unsigned int PosL1[]={0,0,0,2,3,5,7,11,16,20,24,32,32}; + +#define STARTL2 3 +static unsigned int DecL2[]={0xa000,0xc000,0xd000,0xe000,0xea00,0xee00, + 0xf000,0xf200,0xf240,0xffff}; +static unsigned int PosL2[]={0,0,0,0,5,7,9,13,18,22,26,34,36}; + +#define STARTHF0 4 +static unsigned int DecHf0[]={0x8000,0xc000,0xe000,0xf200,0xf200,0xf200, + 0xf200,0xf200,0xffff}; +static unsigned int PosHf0[]={0,0,0,0,0,8,16,24,33,33,33,33,33}; + + +#define STARTHF1 5 +static unsigned int DecHf1[]={0x2000,0xc000,0xe000,0xf000,0xf200,0xf200, + 0xf7e0,0xffff}; +static unsigned int PosHf1[]={0,0,0,0,0,0,4,44,60,76,80,80,127}; + + +#define STARTHF2 5 +static unsigned int DecHf2[]={0x1000,0x2400,0x8000,0xc000,0xfa00,0xffff, + 0xffff,0xffff}; +static unsigned int PosHf2[]={0,0,0,0,0,0,2,7,53,117,233,0,0}; + + +#define STARTHF3 6 +static unsigned int DecHf3[]={0x800,0x2400,0xee00,0xfe80,0xffff,0xffff, + 0xffff}; +static unsigned int PosHf3[]={0,0,0,0,0,0,0,2,16,218,251,0,0}; + + +#define STARTHF4 8 +static unsigned int DecHf4[]={0xff00,0xffff,0xffff,0xffff,0xffff,0xffff}; +static unsigned int PosHf4[]={0,0,0,0,0,0,0,0,0,255,0,0,0}; + + +void Unpack::Unpack15(bool Solid) +{ + UnpInitData(Solid); + UnpInitData15(Solid); + UnpReadBuf(); + if (!Solid) + { + InitHuff(); + UnpPtr=0; + } + else + UnpPtr=WrPtr; + --DestUnpSize; + if (DestUnpSize>=0) + { + GetFlagsBuf(); + FlagsCnt=8; + } + + while (DestUnpSize>=0) + { + UnpPtr&=MaxWinMask; + + if (Inp.InAddr>ReadTop-30 && !UnpReadBuf()) + break; + if (((WrPtr-UnpPtr) & MaxWinMask)<270 && WrPtr!=UnpPtr) + UnpWriteBuf20(); + if (StMode) + { + HuffDecode(); + continue; + } + + if (--FlagsCnt < 0) + { + GetFlagsBuf(); + FlagsCnt=7; + } + + if (FlagBuf & 0x80) + { + FlagBuf<<=1; + if (Nlzb > Nhfb) + LongLZ(); + else + HuffDecode(); + } + else + { + FlagBuf<<=1; + if (--FlagsCnt < 0) + { + GetFlagsBuf(); + FlagsCnt=7; + } + if (FlagBuf & 0x80) + { + FlagBuf<<=1; + if (Nlzb > Nhfb) + HuffDecode(); + else + LongLZ(); + } + else + { + FlagBuf<<=1; + ShortLZ(); + } + } + } + UnpWriteBuf20(); +} + + +#define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos]) +#define GetShortLen2(pos) ((pos)==3 ? Buf60+3:ShortLen2[pos]) + +void Unpack::ShortLZ() +{ + static unsigned int ShortLen1[]={1,3,4,4,5,6,7,8,8,4,4,5,6,6,4,0}; + static unsigned int ShortXor1[]={0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe, + 0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0}; + static unsigned int ShortLen2[]={2,3,3,3,4,4,5,6,6,4,4,5,6,6,4,0}; + static unsigned int ShortXor2[]={0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8, + 0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0}; + + + unsigned int Length,SaveLength; + unsigned int LastDistance; + unsigned int Distance; + int DistancePlace; + NumHuf=0; + + unsigned int BitField=Inp.fgetbits(); + if (LCount==2) + { + Inp.faddbits(1); + if (BitField >= 0x8000) + { + CopyString15((unsigned int)LastDist,LastLength); + return; + } + BitField <<= 1; + LCount=0; + } + + BitField>>=8; + +// not thread safe, replaced by GetShortLen1 and GetShortLen2 macro +// ShortLen1[1]=ShortLen2[3]=Buf60+3; + + if (AvrLn1<37) + { + for (Length=0;;Length++) + if (((BitField^ShortXor1[Length]) & (~(0xff>>GetShortLen1(Length))))==0) + break; + Inp.faddbits(GetShortLen1(Length)); + } + else + { + for (Length=0;;Length++) + if (((BitField^ShortXor2[Length]) & (~(0xff>>GetShortLen2(Length))))==0) + break; + Inp.faddbits(GetShortLen2(Length)); + } + + if (Length >= 9) + { + if (Length == 9) + { + LCount++; + CopyString15((unsigned int)LastDist,LastLength); + return; + } + if (Length == 14) + { + LCount=0; + Length=DecodeNum(Inp.fgetbits(),STARTL2,DecL2,PosL2)+5; + Distance=(Inp.fgetbits()>>1) | 0x8000; + Inp.faddbits(15); + LastLength=Length; + LastDist=Distance; + CopyString15(Distance,Length); + return; + } + + LCount=0; + SaveLength=Length; + Distance=OldDist[(OldDistPtr-(Length-9)) & 3]; + Length=DecodeNum(Inp.fgetbits(),STARTL1,DecL1,PosL1)+2; + if (Length==0x101 && SaveLength==10) + { + Buf60 ^= 1; + return; + } + if (Distance > 256) + Length++; + if (Distance >= MaxDist3) + Length++; + + OldDist[OldDistPtr++]=Distance; + OldDistPtr = OldDistPtr & 3; + LastLength=Length; + LastDist=Distance; + CopyString15(Distance,Length); + return; + } + + LCount=0; + AvrLn1 += Length; + AvrLn1 -= AvrLn1 >> 4; + + DistancePlace=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2) & 0xff; + Distance=ChSetA[DistancePlace]; + if (--DistancePlace != -1) + { + LastDistance=ChSetA[DistancePlace]; + ChSetA[DistancePlace+1]=LastDistance; + ChSetA[DistancePlace]=Distance; + } + Length+=2; + OldDist[OldDistPtr++] = ++Distance; + OldDistPtr = OldDistPtr & 3; + LastLength=Length; + LastDist=Distance; + CopyString15(Distance,Length); +} + + +void Unpack::LongLZ() +{ + unsigned int Length; + unsigned int Distance; + unsigned int DistancePlace,NewDistancePlace; + unsigned int OldAvr2,OldAvr3; + + NumHuf=0; + Nlzb+=16; + if (Nlzb > 0xff) + { + Nlzb=0x90; + Nhfb >>= 1; + } + OldAvr2=AvrLn2; + + unsigned int BitField=Inp.fgetbits(); + if (AvrLn2 >= 122) + Length=DecodeNum(BitField,STARTL2,DecL2,PosL2); + else + if (AvrLn2 >= 64) + Length=DecodeNum(BitField,STARTL1,DecL1,PosL1); + else + if (BitField < 0x100) + { + Length=BitField; + Inp.faddbits(16); + } + else + { + for (Length=0;((BitField<> 5; + + BitField=Inp.fgetbits(); + if (AvrPlcB > 0x28ff) + DistancePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2); + else + if (AvrPlcB > 0x6ff) + DistancePlace=DecodeNum(BitField,STARTHF1,DecHf1,PosHf1); + else + DistancePlace=DecodeNum(BitField,STARTHF0,DecHf0,PosHf0); + + AvrPlcB += DistancePlace; + AvrPlcB -= AvrPlcB >> 8; + while (1) + { + Distance = ChSetB[DistancePlace & 0xff]; + NewDistancePlace = NToPlB[Distance++ & 0xff]++; + if (!(Distance & 0xff)) + CorrHuff(ChSetB,NToPlB); + else + break; + } + + ChSetB[DistancePlace]=ChSetB[NewDistancePlace]; + ChSetB[NewDistancePlace]=Distance; + + Distance=((Distance & 0xff00) | (Inp.fgetbits() >> 8)) >> 1; + Inp.faddbits(7); + + OldAvr3=AvrLn3; + if (Length!=1 && Length!=4) + if (Length==0 && Distance <= MaxDist3) + { + AvrLn3++; + AvrLn3 -= AvrLn3 >> 8; + } + else + if (AvrLn3 > 0) + AvrLn3--; + Length+=3; + if (Distance >= MaxDist3) + Length++; + if (Distance <= 256) + Length+=8; + if (OldAvr3 > 0xb0 || (AvrPlc >= 0x2a00 && OldAvr2 < 0x40)) + MaxDist3=0x7f00; + else + MaxDist3=0x2001; + OldDist[OldDistPtr++]=Distance; + OldDistPtr = OldDistPtr & 3; + LastLength=Length; + LastDist=Distance; + CopyString15(Distance,Length); +} + + +void Unpack::HuffDecode() +{ + unsigned int CurByte,NewBytePlace; + unsigned int Length; + unsigned int Distance; + int BytePlace; + + unsigned int BitField=Inp.fgetbits(); + + if (AvrPlc > 0x75ff) + BytePlace=DecodeNum(BitField,STARTHF4,DecHf4,PosHf4); + else + if (AvrPlc > 0x5dff) + BytePlace=DecodeNum(BitField,STARTHF3,DecHf3,PosHf3); + else + if (AvrPlc > 0x35ff) + BytePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2); + else + if (AvrPlc > 0x0dff) + BytePlace=DecodeNum(BitField,STARTHF1,DecHf1,PosHf1); + else + BytePlace=DecodeNum(BitField,STARTHF0,DecHf0,PosHf0); + BytePlace&=0xff; + if (StMode) + { + if (BytePlace==0 && BitField > 0xfff) + BytePlace=0x100; + if (--BytePlace==-1) + { + BitField=Inp.fgetbits(); + Inp.faddbits(1); + if (BitField & 0x8000) + { + NumHuf=StMode=0; + return; + } + else + { + Length = (BitField & 0x4000) ? 4 : 3; + Inp.faddbits(1); + Distance=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2); + Distance = (Distance << 5) | (Inp.fgetbits() >> 11); + Inp.faddbits(5); + CopyString15(Distance,Length); + return; + } + } + } + else + if (NumHuf++ >= 16 && FlagsCnt==0) + StMode=1; + AvrPlc += BytePlace; + AvrPlc -= AvrPlc >> 8; + Nhfb+=16; + if (Nhfb > 0xff) + { + Nhfb=0x90; + Nlzb >>= 1; + } + + Window[UnpPtr++]=(byte)(ChSet[BytePlace]>>8); + --DestUnpSize; + + while (1) + { + CurByte=ChSet[BytePlace]; + NewBytePlace=NToPl[CurByte++ & 0xff]++; + if ((CurByte & 0xff) > 0xa1) + CorrHuff(ChSet,NToPl); + else + break; + } + + ChSet[BytePlace]=ChSet[NewBytePlace]; + ChSet[NewBytePlace]=CurByte; +} + + +void Unpack::GetFlagsBuf() +{ + unsigned int Flags,NewFlagsPlace; + unsigned int FlagsPlace=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2); + + while (1) + { + 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 Unpack::UnpInitData15(int Solid) +{ + if (!Solid) + { + AvrPlcB=AvrLn1=AvrLn2=AvrLn3=NumHuf=Buf60=0; + AvrPlc=0x3500; + MaxDist3=0x2001; + Nhfb=Nlzb=0x80; + } + FlagsCnt=0; + FlagBuf=0; + StMode=0; + LCount=0; + ReadTop=0; +} + + +void Unpack::InitHuff() +{ + for (unsigned int I=0;I<256;I++) + { + 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); +} + + +void Unpack::CorrHuff(ushort *CharSet,byte *NumToPlace) +{ + int I,J; + for (I=7;I>=0;I--) + for (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 Unpack::CopyString15(uint Distance,uint Length) +{ + DestUnpSize-=Length; + while (Length--) + { + Window[UnpPtr]=Window[(UnpPtr-Distance) & MaxWinMask]; + UnpPtr=(UnpPtr+1) & MaxWinMask; + } +} + + +uint Unpack::DecodeNum(uint Num,uint StartPos,uint *DecTab,uint *PosTab) +{ + int I; + for (Num&=0xfff0,I=0;DecTab[I]<=Num;I++) + StartPos++; + Inp.faddbits(StartPos); + return(((Num-(I ? DecTab[I-1]:0))>>(16-StartPos))+PosTab[StartPos]); +} diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/unpack20.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/unpack20.cpp index 27d47366b..aca520935 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/unpack20.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/unpack20.cpp @@ -1,396 +1,370 @@ -// #included by unpack.cpp -#ifdef RAR_COMMON_HPP -#include "rar.hpp" - -// Presumably these optimizations give similar speedup as those for CopyString in unpack.cpp -void Unpack::CopyString20(unsigned int Length,unsigned int Distance) -{ - LastDist=OldDist[OldDistPtr++ & 3]=Distance; - LastLength=Length; - DestUnpSize-=Length; - - unsigned UnpPtr = this->UnpPtr; // cache in register - byte* const Window = this->Window; // cache in register - - unsigned int DestPtr=UnpPtr-Distance; - if (UnpPtrUnpPtr += Length; - if ( Distance < Length ) // can't use memcpy when source and dest overlap - { - Window[UnpPtr++]=Window[DestPtr++]; - Window[UnpPtr++]=Window[DestPtr++]; - while (Length>2) - { - Length--; - Window[UnpPtr++]=Window[DestPtr++]; - } - } - else - { - memcpy( &Window[UnpPtr], &Window[DestPtr], Length ); - } - } - else - { - while (Length--) - { - Window[UnpPtr]=Window[DestPtr++ & MAXWINMASK]; - UnpPtr=(UnpPtr+1) & MAXWINMASK; - } - this->UnpPtr = UnpPtr; - } -} - - -void Unpack::Unpack20(bool Solid) -{ - const - static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224}; - const - static unsigned char LBits[]= {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 - static int DDecode[]={0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040}; - const - static unsigned char DBits[]= {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; - const - static unsigned char SDDecode[]={0,4,8,16,32,64,128,192}; - const - static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6}; - unsigned int Bits; - - if (Suspended) - UnpPtr=WrPtr; - else - { - UnpInitData(Solid); - if (!UnpReadBuf()) - return; - if (!Solid) - if (!ReadTables20()) - return; - --DestUnpSize; - } - - while (is64plus(DestUnpSize)) - { - UnpPtr&=MAXWINMASK; - - if (InAddr>ReadTop-30) - if (!UnpReadBuf()) - break; - if (((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr) - { - OldUnpWriteBuf(); - if (Suspended) - return; - } - if (UnpAudioBlock) - { - int AudioNumber=DecodeNumber((struct Decode *)&MD[UnpCurChannel]); - - if (AudioNumber==256) - { - if (!ReadTables20()) - break; - continue; - } - Window[UnpPtr++]=DecodeAudio(AudioNumber); - if (++UnpCurChannel==UnpChannels) - UnpCurChannel=0; - --DestUnpSize; - continue; - } - - int Number=DecodeNumber((struct Decode *)&LD); - if (Number<256) - { - Window[UnpPtr++]=(byte)Number; - --DestUnpSize; - continue; - } - if (Number>269) - { - int Length=LDecode[Number-=270]+3; - if ((Bits=LBits[Number])>0) - { - Length+=getbits()>>(16-Bits); - addbits(Bits); - } - - int DistNumber=DecodeNumber((struct Decode *)&DD); - unsigned int Distance=DDecode[DistNumber]+1; - if ((Bits=DBits[DistNumber])>0) - { - Distance+=getbits()>>(16-Bits); - addbits(Bits); - } - - if (Distance>=0x2000) - { - Length++; - if (Distance>=0x40000L) - Length++; - } - - CopyString20(Length,Distance); - continue; - } - if (Number==269) - { - if (!ReadTables20()) - break; - continue; - } - if (Number==256) - { - CopyString20(LastLength,LastDist); - continue; - } - if (Number<261) - { - unsigned int Distance=OldDist[(OldDistPtr-(Number-256)) & 3]; - int LengthNumber=DecodeNumber((struct Decode *)&RD); - int Length=LDecode[LengthNumber]+2; - if ((Bits=LBits[LengthNumber])>0) - { - Length+=getbits()>>(16-Bits); - addbits(Bits); - } - if (Distance>=0x101) - { - Length++; - if (Distance>=0x2000) - { - Length++; - if (Distance>=0x40000) - Length++; - } - } - CopyString20(Length,Distance); - continue; - } - if (Number<270) - { - unsigned int Distance=SDDecode[Number-=261]+1; - if ((Bits=SDBits[Number])>0) - { - Distance+=getbits()>>(16-Bits); - addbits(Bits); - } - CopyString20(2,Distance); - continue; - } - } - ReadLastTables(); - OldUnpWriteBuf(); -} - - -bool Unpack::ReadTables20() -{ - byte BitLength[BC20]; - unsigned char Table[MC20*4]; - int TableSize,N,I; - if (InAddr>ReadTop-25) - if (!UnpReadBuf()) - return(false); - unsigned int BitField=getbits(); - UnpAudioBlock=(BitField & 0x8000); - - if (!(BitField & 0x4000)) - memset(UnpOldTable20,0,sizeof(UnpOldTable20)); - addbits(2); - - if (UnpAudioBlock) - { - UnpChannels=((BitField>>12) & 3)+1; - if (UnpCurChannel>=UnpChannels) - UnpCurChannel=0; - addbits(2); - TableSize=MC20*UnpChannels; - } - else - TableSize=NC20+DC20+RC20; - - for (I=0;I> 12); - addbits(4); - } - MakeDecodeTables(BitLength,(struct Decode *)&BD,BC20); - I=0; - while (IReadTop-5) - if (!UnpReadBuf()) - return(false); - int Number=DecodeNumber((struct Decode *)&BD); - if (Number<16) - { - Table[I]=(Number+UnpOldTable20[I]) & 0xf; - I++; - } - else - if (Number==16) - { - N=(getbits() >> 14)+3; - addbits(2); - while (N-- > 0 && I> 13)+3; - addbits(3); - } - else - { - N=(getbits() >> 9)+11; - addbits(7); - } - while (N-- > 0 && IReadTop) - return(true); - if (UnpAudioBlock) - for (I=0;I=InAddr+5) - { - if (UnpAudioBlock) - { - if (DecodeNumber((struct Decode *)&MD[UnpCurChannel])==256) - ReadTables20(); - } - else - if (DecodeNumber((struct Decode *)&LD)==269) - ReadTables20(); - } -} - - -void Unpack::UnpInitData20(int Solid) -{ - if (!Solid) - { - UnpAudioBlock=UnpChannelDelta=UnpCurChannel=0; - UnpChannels=1; - - memset(AudV,0,sizeof(AudV)); - memset(UnpOldTable20,0,sizeof(UnpOldTable20)); - memset(MD,0,sizeof(MD)); - } -} - - -byte Unpack::DecodeAudio(int Delta) -{ - struct AudioVariables *V=&AudV[UnpCurChannel]; - V->ByteCount++; - V->D4=V->D3; - V->D3=V->D2; - V->D2=V->LastDelta-V->D1; - V->D1=V->LastDelta; - int PCh=8*V->LastChar+V->K1*V->D1+V->K2*V->D2+V->K3*V->D3+V->K4*V->D4+V->K5*UnpChannelDelta; - PCh=(PCh>>3) & 0xFF; - - unsigned int Ch=PCh-Delta; - - int D=((signed char)Delta)<<3; - - V->Dif[0]+=abs(D); - V->Dif[1]+=abs(D-V->D1); - V->Dif[2]+=abs(D+V->D1); - V->Dif[3]+=abs(D-V->D2); - V->Dif[4]+=abs(D+V->D2); - V->Dif[5]+=abs(D-V->D3); - V->Dif[6]+=abs(D+V->D3); - V->Dif[7]+=abs(D-V->D4); - V->Dif[8]+=abs(D+V->D4); - V->Dif[9]+=abs(D-UnpChannelDelta); - V->Dif[10]+=abs(D+UnpChannelDelta); - - UnpChannelDelta=V->LastDelta=(signed char)(Ch-V->LastChar); - V->LastChar=Ch; - - if ((V->ByteCount & 0x1F)==0) - { - unsigned int MinDif=V->Dif[0],NumMinDif=0; - V->Dif[0]=0; - for (int I=1;IDif)/sizeof(V->Dif[0]);I++) - { - if (V->Dif[I]Dif[I]; - NumMinDif=I; - } - V->Dif[I]=0; - } - switch(NumMinDif) - { - case 1: - if (V->K1>=-16) - V->K1--; - break; - case 2: - if (V->K1<16) - V->K1++; - break; - case 3: - if (V->K2>=-16) - V->K2--; - break; - case 4: - if (V->K2<16) - V->K2++; - break; - case 5: - if (V->K3>=-16) - V->K3--; - break; - case 6: - if (V->K3<16) - V->K3++; - break; - case 7: - if (V->K4>=-16) - V->K4--; - break; - case 8: - if (V->K4<16) - V->K4++; - break; - case 9: - if (V->K5>=-16) - V->K5--; - break; - case 10: - if (V->K5<16) - V->K5++; - break; - } - } - return((byte)Ch); -} -#endif +#include "rar.hpp" + +void Unpack::CopyString20(uint Length,uint Distance) +{ + LastDist=OldDist[OldDistPtr++ & 3]=Distance; + LastLength=Length; + DestUnpSize-=Length; + CopyString(Length,Distance); +} + + +void Unpack::Unpack20(bool Solid) +{ + static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224}; + static unsigned char LBits[]= {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 int DDecode[]={0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040}; + static unsigned char DBits[]= {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; + static unsigned char SDDecode[]={0,4,8,16,32,64,128,192}; + static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6}; + unsigned int Bits; + + if (Suspended) + UnpPtr=WrPtr; + else + { + UnpInitData(Solid); + if (!UnpReadBuf()) + return; + if (!Solid) + if (!ReadTables20()) + return; + --DestUnpSize; + } + + while (DestUnpSize>=0) + { + UnpPtr&=MaxWinMask; + + if (Inp.InAddr>ReadTop-30) + if (!UnpReadBuf()) + break; + if (((WrPtr-UnpPtr) & MaxWinMask)<270 && WrPtr!=UnpPtr) + { + UnpWriteBuf20(); + if (Suspended) + return; + } + if (UnpAudioBlock) + { + int AudioNumber=DecodeNumber(Inp,&MD[UnpCurChannel]); + + if (AudioNumber==256) + { + if (!ReadTables20()) + break; + continue; + } + Window[UnpPtr++]=DecodeAudio(AudioNumber); + if (++UnpCurChannel==UnpChannels) + UnpCurChannel=0; + --DestUnpSize; + continue; + } + + int Number=DecodeNumber(Inp,&BlockTables.LD); + if (Number<256) + { + Window[UnpPtr++]=(byte)Number; + --DestUnpSize; + continue; + } + if (Number>269) + { + int Length=LDecode[Number-=270]+3; + if ((Bits=LBits[Number])>0) + { + Length+=Inp.getbits()>>(16-Bits); + Inp.addbits(Bits); + } + + int DistNumber=DecodeNumber(Inp,&BlockTables.DD); + unsigned int Distance=DDecode[DistNumber]+1; + if ((Bits=DBits[DistNumber])>0) + { + Distance+=Inp.getbits()>>(16-Bits); + Inp.addbits(Bits); + } + + if (Distance>=0x2000) + { + Length++; + if (Distance>=0x40000L) + Length++; + } + + CopyString20(Length,Distance); + continue; + } + if (Number==269) + { + if (!ReadTables20()) + break; + continue; + } + if (Number==256) + { + CopyString20(LastLength,LastDist); + continue; + } + if (Number<261) + { + unsigned int Distance=OldDist[(OldDistPtr-(Number-256)) & 3]; + int LengthNumber=DecodeNumber(Inp,&BlockTables.RD); + int Length=LDecode[LengthNumber]+2; + if ((Bits=LBits[LengthNumber])>0) + { + Length+=Inp.getbits()>>(16-Bits); + Inp.addbits(Bits); + } + if (Distance>=0x101) + { + Length++; + if (Distance>=0x2000) + { + Length++; + if (Distance>=0x40000) + Length++; + } + } + CopyString20(Length,Distance); + continue; + } + if (Number<270) + { + unsigned int Distance=SDDecode[Number-=261]+1; + if ((Bits=SDBits[Number])>0) + { + Distance+=Inp.getbits()>>(16-Bits); + Inp.addbits(Bits); + } + CopyString20(2,Distance); + continue; + } + } + ReadLastTables(); + UnpWriteBuf20(); +} + + +void Unpack::UnpWriteBuf20() +{ + if (UnpPtr!=WrPtr) + UnpSomeRead=true; + if (UnpPtrUnpWrite(&Window[WrPtr],-(int)WrPtr & MaxWinMask); + UnpIO->UnpWrite(Window,UnpPtr); + UnpAllBuf=true; + } + else + UnpIO->UnpWrite(&Window[WrPtr],UnpPtr-WrPtr); + WrPtr=UnpPtr; +} + + +bool Unpack::ReadTables20() +{ + byte BitLength[BC20]; + byte Table[MC20*4]; + int TableSize,N,I; + if (Inp.InAddr>ReadTop-25) + if (!UnpReadBuf()) + return(false); + uint BitField=Inp.getbits(); + UnpAudioBlock=(BitField & 0x8000); + + if (!(BitField & 0x4000)) + memset(UnpOldTable20,0,sizeof(UnpOldTable20)); + Inp.addbits(2); + + if (UnpAudioBlock) + { + UnpChannels=((BitField>>12) & 3)+1; + if (UnpCurChannel>=UnpChannels) + UnpCurChannel=0; + Inp.addbits(2); + TableSize=MC20*UnpChannels; + } + else + TableSize=NC20+DC20+RC20; + + for (I=0;I> 12); + Inp.addbits(4); + } + MakeDecodeTables(BitLength,&BlockTables.BD,BC20); + I=0; + while (IReadTop-5) + if (!UnpReadBuf()) + return false; + int Number=DecodeNumber(Inp,&BlockTables.BD); + if (Number<16) + { + Table[I]=(Number+UnpOldTable20[I]) & 0xf; + I++; + } + else + if (Number==16) + { + N=(Inp.getbits() >> 14)+3; + Inp.addbits(2); + if (I>0) + while (N-- > 0 && I> 13)+3; + Inp.addbits(3); + } + else + { + N=(Inp.getbits() >> 9)+11; + Inp.addbits(7); + } + while (N-- > 0 && IReadTop) + return(true); + if (UnpAudioBlock) + for (I=0;I=Inp.InAddr+5) + if (UnpAudioBlock) + { + if (DecodeNumber(Inp,&MD[UnpCurChannel])==256) + ReadTables20(); + } + else + if (DecodeNumber(Inp,&BlockTables.LD)==269) + ReadTables20(); +} + + +void Unpack::UnpInitData20(int Solid) +{ + if (!Solid) + { + UnpAudioBlock=UnpChannelDelta=UnpCurChannel=0; + UnpChannels=1; + + memset(AudV,0,sizeof(AudV)); + memset(UnpOldTable20,0,sizeof(UnpOldTable20)); + memset(MD,0,sizeof(MD)); + } +} + + +byte Unpack::DecodeAudio(int Delta) +{ + struct AudioVariables *V=&AudV[UnpCurChannel]; + V->ByteCount++; + V->D4=V->D3; + V->D3=V->D2; + V->D2=V->LastDelta-V->D1; + V->D1=V->LastDelta; + int PCh=8*V->LastChar+V->K1*V->D1+V->K2*V->D2+V->K3*V->D3+V->K4*V->D4+V->K5*UnpChannelDelta; + PCh=(PCh>>3) & 0xFF; + + unsigned int Ch=PCh-Delta; + + int D=((signed char)Delta)<<3; + + V->Dif[0]+=abs(D); + V->Dif[1]+=abs(D-V->D1); + V->Dif[2]+=abs(D+V->D1); + V->Dif[3]+=abs(D-V->D2); + V->Dif[4]+=abs(D+V->D2); + V->Dif[5]+=abs(D-V->D3); + V->Dif[6]+=abs(D+V->D3); + V->Dif[7]+=abs(D-V->D4); + V->Dif[8]+=abs(D+V->D4); + V->Dif[9]+=abs(D-UnpChannelDelta); + V->Dif[10]+=abs(D+UnpChannelDelta); + + UnpChannelDelta=V->LastDelta=(signed char)(Ch-V->LastChar); + V->LastChar=Ch; + + if ((V->ByteCount & 0x1F)==0) + { + unsigned int MinDif=V->Dif[0],NumMinDif=0; + V->Dif[0]=0; + for (int I=1;IDif)/sizeof(V->Dif[0]);I++) + { + if (V->Dif[I]Dif[I]; + NumMinDif=I; + } + V->Dif[I]=0; + } + switch(NumMinDif) + { + case 1: + if (V->K1>=-16) + V->K1--; + break; + case 2: + if (V->K1<16) + V->K1++; + break; + case 3: + if (V->K2>=-16) + V->K2--; + break; + case 4: + if (V->K2<16) + V->K2++; + break; + case 5: + if (V->K3>=-16) + V->K3--; + break; + case 6: + if (V->K3<16) + V->K3++; + break; + case 7: + if (V->K4>=-16) + V->K4--; + break; + case 8: + if (V->K4<16) + V->K4++; + break; + case 9: + if (V->K5>=-16) + V->K5--; + break; + case 10: + if (V->K5<16) + V->K5++; + break; + } + } + return((byte)Ch); +} diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/unpack30.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/unpack30.cpp new file mode 100644 index 000000000..980df0244 --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/unpack30.cpp @@ -0,0 +1,836 @@ +// We use it instead of direct PPM.DecodeChar call to be sure that +// we reset PPM structures in case of corrupt data. It is important, +// because these structures can be invalid after PPM.DecodeChar returned -1. +inline int Unpack::SafePPMDecodeChar() +{ + int Ch=PPM.DecodeChar(); + if (Ch==-1) // Corrupt PPM data found. + { + PPM.CleanUp(); // Reset possibly corrupt PPM data structures. + UnpBlockType=BLOCK_LZ; // Set faster and more fail proof LZ mode. + } + return(Ch); +} + + +void Unpack::Unpack29(bool Solid) +{ + static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224}; + static unsigned char LBits[]= {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 int DDecode[DC]; + static byte DBits[DC]; + static int DBitLengthCounts[]= {4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,0,12}; + static unsigned char SDDecode[]={0,4,8,16,32,64,128,192}; + static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6}; + unsigned int Bits; + + if (DDecode[1]==0) + { + int Dist=0,BitLength=0,Slot=0; + for (int I=0;IReadBorder) + { + if (!UnpReadBuf30()) + break; + } + if (((WrPtr-UnpPtr) & MaxWinMask)<260 && WrPtr!=UnpPtr) + { + UnpWriteBuf30(); + if (WrittenFileSize>DestUnpSize) + return; + if (Suspended) + { + FileExtracted=false; + return; + } + } + if (UnpBlockType==BLOCK_PPM) + { + // Here speed is critical, so we do not use SafePPMDecodeChar, + // because sometimes even the inline function can introduce + // some additional penalty. + int Ch=PPM.DecodeChar(); + if (Ch==-1) // Corrupt PPM data found. + { + PPM.CleanUp(); // Reset possibly corrupt PPM data structures. + UnpBlockType=BLOCK_LZ; // Set faster and more fail proof LZ mode. + break; + } + if (Ch==PPMEscChar) + { + int NextCh=SafePPMDecodeChar(); + if (NextCh==0) // End of PPM encoding. + { + if (!ReadTables30()) + break; + continue; + } + if (NextCh==-1) // Corrupt PPM data found. + break; + if (NextCh==2) // End of file in PPM mode. + break; + if (NextCh==3) // Read VM code. + { + if (!ReadVMCodePPM()) + break; + continue; + } + if (NextCh==4) // LZ inside of PPM. + { + unsigned int Distance=0,Length; + bool Failed=false; + for (int I=0;I<4 && !Failed;I++) + { + int Ch=SafePPMDecodeChar(); + if (Ch==-1) + Failed=true; + else + if (I==3) + Length=(byte)Ch; + else + Distance=(Distance<<8)+(byte)Ch; + } + if (Failed) + break; + + CopyString(Length+32,Distance+2); + continue; + } + if (NextCh==5) // One byte distance match (RLE) inside of PPM. + { + int Length=SafePPMDecodeChar(); + if (Length==-1) + break; + CopyString(Length+4,1); + continue; + } + // If we are here, NextCh must be 1, what means that current byte + // is equal to our 'escape' byte, so we just store it to Window. + } + Window[UnpPtr++]=Ch; + continue; + } + + int Number=DecodeNumber(Inp,&BlockTables.LD); + if (Number<256) + { + Window[UnpPtr++]=(byte)Number; + continue; + } + if (Number>=271) + { + int Length=LDecode[Number-=271]+3; + if ((Bits=LBits[Number])>0) + { + Length+=Inp.getbits()>>(16-Bits); + Inp.addbits(Bits); + } + + int DistNumber=DecodeNumber(Inp,&BlockTables.DD); + unsigned int Distance=DDecode[DistNumber]+1; + if ((Bits=DBits[DistNumber])>0) + { + if (DistNumber>9) + { + if (Bits>4) + { + Distance+=((Inp.getbits()>>(20-Bits))<<4); + Inp.addbits(Bits-4); + } + if (LowDistRepCount>0) + { + LowDistRepCount--; + Distance+=PrevLowDist; + } + else + { + int LowDist=DecodeNumber(Inp,&BlockTables.LDD); + if (LowDist==16) + { + LowDistRepCount=LOW_DIST_REP_COUNT-1; + Distance+=PrevLowDist; + } + else + { + Distance+=LowDist; + PrevLowDist=LowDist; + } + } + } + else + { + Distance+=Inp.getbits()>>(16-Bits); + Inp.addbits(Bits); + } + } + + if (Distance>=0x2000) + { + Length++; + if (Distance>=0x40000L) + Length++; + } + + InsertOldDist(Distance); + LastLength=Length; + CopyString(Length,Distance); + continue; + } + if (Number==256) + { + if (!ReadEndOfBlock()) + break; + continue; + } + if (Number==257) + { + if (!ReadVMCode()) + break; + continue; + } + if (Number==258) + { + if (LastLength!=0) + CopyString(LastLength,OldDist[0]); + continue; + } + if (Number<263) + { + int DistNum=Number-259; + unsigned int Distance=OldDist[DistNum]; + for (int I=DistNum;I>0;I--) + OldDist[I]=OldDist[I-1]; + OldDist[0]=Distance; + + int LengthNumber=DecodeNumber(Inp,&BlockTables.RD); + int Length=LDecode[LengthNumber]+2; + if ((Bits=LBits[LengthNumber])>0) + { + Length+=Inp.getbits()>>(16-Bits); + Inp.addbits(Bits); + } + LastLength=Length; + CopyString(Length,Distance); + continue; + } + if (Number<272) + { + unsigned int Distance=SDDecode[Number-=263]+1; + if ((Bits=SDBits[Number])>0) + { + Distance+=Inp.getbits()>>(16-Bits); + Inp.addbits(Bits); + } + InsertOldDist(Distance); + LastLength=2; + CopyString(2,Distance); + continue; + } + } + UnpWriteBuf30(); +} + + +// Return 'false' to quit unpacking the current file or 'true' to continue. +bool Unpack::ReadEndOfBlock() +{ + uint BitField=Inp.getbits(); + bool NewTable,NewFile=false; + + // "1" - no new file, new table just here. + // "00" - new file, no new table. + // "01" - new file, new table (in beginning of next file). + + if ((BitField & 0x8000)!=0) + { + NewTable=true; + Inp.addbits(1); + } + else + { + NewFile=true; + NewTable=(BitField & 0x4000)!=0; + Inp.addbits(2); + } + TablesRead=!NewTable; + + // Quit immediately if "new file" flag is set. If "new table" flag + // is present, we'll read the table in beginning of next file + // based on 'TablesRead' 'false' value. + if (NewFile) + return false; + return ReadTables30(); // Quit only if we failed to read tables. +} + + +bool Unpack::ReadVMCode() +{ + // Entire VM code is guaranteed to fully present in block defined + // by current Huffman table. Compressor checks that VM code does not cross + // Huffman block boundaries. + unsigned int FirstByte=Inp.getbits()>>8; + Inp.addbits(8); + int Length=(FirstByte & 7)+1; + if (Length==7) + { + Length=(Inp.getbits()>>8)+7; + Inp.addbits(8); + } + else + if (Length==8) + { + Length=Inp.getbits(); + Inp.addbits(16); + } + Array VMCode(Length); + for (int I=0;I=ReadTop-1 && !UnpReadBuf30() && I>8; + Inp.addbits(8); + } + return(AddVMCode(FirstByte,&VMCode[0],Length)); +} + + +bool Unpack::ReadVMCodePPM() +{ + unsigned int FirstByte=SafePPMDecodeChar(); + if ((int)FirstByte==-1) + return(false); + int Length=(FirstByte & 7)+1; + if (Length==7) + { + int B1=SafePPMDecodeChar(); + if (B1==-1) + return(false); + Length=B1+7; + } + else + if (Length==8) + { + int B1=SafePPMDecodeChar(); + if (B1==-1) + return(false); + int B2=SafePPMDecodeChar(); + if (B2==-1) + return(false); + Length=B1*256+B2; + } + Array VMCode(Length); + for (int I=0;IFilters30.Size() || FiltPos>OldFilterLengths.Size()) + return(false); + LastFilter=FiltPos; + bool NewFilter=(FiltPos==Filters30.Size()); + + UnpackFilter30 *StackFilter=new UnpackFilter30; // New filter for PrgStack. + + UnpackFilter30 *Filter; + if (NewFilter) // New filter code, never used before since VM reset. + { + if (FiltPos>MAX3_FILTERS) + { + // Too many different filters, corrupt archive. + delete StackFilter; + return false; + } + + Filters30.Add(1); + Filters30[Filters30.Size()-1]=Filter=new UnpackFilter30; + StackFilter->ParentFilter=(uint)(Filters30.Size()-1); + + // Reserve one item, where we store the data block length of our new + // filter entry. We'll set it to real block length below, after reading + // it. But we need to initialize it now, because when processing corrupt + // data, we can access this item even before we set it to real value. + OldFilterLengths.Push(0); + Filter->ExecCount=0; + } + else // Filter was used in the past. + { + Filter=Filters30[FiltPos]; + StackFilter->ParentFilter=FiltPos; + Filter->ExecCount++; + } + + int EmptyCount=0; + for (uint I=0;I0) + PrgStack[I]=NULL; + } + if (EmptyCount==0) + { + PrgStack.Add(1); + EmptyCount=1; + } + int StackPos=(int)(PrgStack.Size()-EmptyCount); + PrgStack[StackPos]=StackFilter; + StackFilter->ExecCount=Filter->ExecCount; + + uint BlockStart=RarVM::ReadData(VMCodeInp); + if (FirstByte & 0x40) + BlockStart+=258; + StackFilter->BlockStart=(uint)((BlockStart+UnpPtr)&MaxWinMask); + if (FirstByte & 0x20) + { + StackFilter->BlockLength=RarVM::ReadData(VMCodeInp); + + // Store the last data block length for current filter. + OldFilterLengths[FiltPos]=StackFilter->BlockLength; + } + else + { + // Set the data block size to same value as the previous block size + // for same filter. It is possible on corrupt data to access here a new + // and not filled yet item of OldFilterLengths array. This is why above + // we set new OldFilterLengths items to zero. + StackFilter->BlockLength=FiltPosNextWindow=WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<=BlockStart; + +// DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x BlockStart=%08x",UnpPtr,WrPtr,BlockStart); + + memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR)); + StackFilter->Prg.InitR[3]=VM_GLOBALMEMADDR; + StackFilter->Prg.InitR[4]=StackFilter->BlockLength; + StackFilter->Prg.InitR[5]=StackFilter->ExecCount; + + if (FirstByte & 0x10) // set registers to optional parameters if any + { + unsigned int InitMask=VMCodeInp.fgetbits()>>9; + VMCodeInp.faddbits(7); + for (int I=0;I<7;I++) + if (InitMask & (1<Prg.InitR[I]=RarVM::ReadData(VMCodeInp); + } + + if (NewFilter) + { + uint VMCodeSize=RarVM::ReadData(VMCodeInp); + if (VMCodeSize>=0x10000 || VMCodeSize==0) + return(false); + Array VMCode(VMCodeSize); + for (uint I=0;I>8; + VMCodeInp.faddbits(8); + } + VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg); + } + StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0]; + StackFilter->Prg.CmdCount=Filter->Prg.CmdCount; + + size_t StaticDataSize=Filter->Prg.StaticData.Size(); + if (StaticDataSize>0 && StaticDataSizePrg.StaticData.Add(StaticDataSize); + memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize); + } + + if (StackFilter->Prg.GlobalData.Size()Prg.GlobalData.Reset(); + StackFilter->Prg.GlobalData.Add(VM_FIXEDGLOBALSIZE); + } + byte *GlobalData=&StackFilter->Prg.GlobalData[0]; + for (int I=0;I<7;I++) + VM.SetLowEndianValue((uint *)&GlobalData[I*4],StackFilter->Prg.InitR[I]); + VM.SetLowEndianValue((uint *)&GlobalData[0x1c],StackFilter->BlockLength); + VM.SetLowEndianValue((uint *)&GlobalData[0x20],0); + VM.SetLowEndianValue((uint *)&GlobalData[0x2c],StackFilter->ExecCount); + memset(&GlobalData[0x30],0,16); + + if (FirstByte & 8) // Put the data block passed as parameter if any. + { + if (VMCodeInp.Overflow(3)) + return(false); + uint DataSize=RarVM::ReadData(VMCodeInp); + if (DataSize>VM_GLOBALMEMSIZE-VM_FIXEDGLOBALSIZE) + return(false); + size_t CurSize=StackFilter->Prg.GlobalData.Size(); + if (CurSizePrg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize); + byte *GlobalData=&StackFilter->Prg.GlobalData[VM_FIXEDGLOBALSIZE]; + for (uint I=0;I>8; + VMCodeInp.faddbits(8); + } + } + return(true); +} + + +bool Unpack::UnpReadBuf30() +{ + int DataSize=ReadTop-Inp.InAddr; // Data left to process. + if (DataSize<0) + return(false); + if (Inp.InAddr>BitInput::MAX_SIZE/2) + { + // If we already processed more than half of buffer, let's move + // remaining data into beginning to free more space for new data + // and ensure that calling function does not cross the buffer border + // even if we did not read anything here. Also it ensures that read size + // is not less than CRYPT_BLOCK_SIZE, so we can align it without risk + // to make it zero. + if (DataSize>0) + memmove(Inp.InBuf,Inp.InBuf+Inp.InAddr,DataSize); + Inp.InAddr=0; + ReadTop=DataSize; + } + else + DataSize=ReadTop; + int ReadCode=UnpIO->UnpRead(Inp.InBuf+DataSize,BitInput::MAX_SIZE-DataSize); + if (ReadCode>0) + ReadTop+=ReadCode; + ReadBorder=ReadTop-30; + return(ReadCode!=-1); +} + + +void Unpack::UnpWriteBuf30() +{ + uint WrittenBorder=(uint)WrPtr; + uint WriteSize=(uint)((UnpPtr-WrittenBorder)&MaxWinMask); + for (size_t I=0;INextWindow) + { + flt->NextWindow=false; + continue; + } + unsigned int BlockStart=flt->BlockStart; + unsigned int BlockLength=flt->BlockLength; + if (((BlockStart-WrittenBorder)&MaxWinMask)ParentFilter]->Prg; + VM_PreparedProgram *Prg=&flt->Prg; + + if (ParentPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) + { + // Copy global data from previous script execution if any. + Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); + memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + } + + ExecuteCode(Prg); + + if (Prg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) + { + // Save global data for next script execution. + if (ParentPrg->GlobalData.Size()GlobalData.Size()) + ParentPrg->GlobalData.Alloc(Prg->GlobalData.Size()); + memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + } + else + ParentPrg->GlobalData.Reset(); + + byte *FilteredData=Prg->FilteredData; + unsigned int FilteredDataSize=Prg->FilteredDataSize; + + delete PrgStack[I]; + PrgStack[I]=NULL; + while (I+1BlockStart!=BlockStart || + NextFilter->BlockLength!=FilteredDataSize || NextFilter->NextWindow) + break; + + // Apply several filters to same data block. + + VM.SetMemory(0,FilteredData,FilteredDataSize); + + VM_PreparedProgram *ParentPrg=&Filters30[NextFilter->ParentFilter]->Prg; + VM_PreparedProgram *NextPrg=&NextFilter->Prg; + + if (ParentPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) + { + // Copy global data from previous script execution if any. + NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); + memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + } + + ExecuteCode(NextPrg); + + if (NextPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) + { + // Save global data for next script execution. + if (ParentPrg->GlobalData.Size()GlobalData.Size()) + ParentPrg->GlobalData.Alloc(NextPrg->GlobalData.Size()); + memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + } + else + ParentPrg->GlobalData.Reset(); + + FilteredData=NextPrg->FilteredData; + FilteredDataSize=NextPrg->FilteredDataSize; + I++; + delete PrgStack[I]; + PrgStack[I]=NULL; + } + UnpIO->UnpWrite(FilteredData,FilteredDataSize); + UnpSomeRead=true; + WrittenFileSize+=FilteredDataSize; + WrittenBorder=BlockEnd; + WriteSize=uint((UnpPtr-WrittenBorder)&MaxWinMask); + } + else + { + // Current filter intersects the window write border, so we adjust + // the window border to process this filter next time, not now. + for (size_t J=I;JNextWindow) + flt->NextWindow=false; + } + WrPtr=WrittenBorder; + return; + } + } + } + + UnpWriteArea(WrittenBorder,UnpPtr); + WrPtr=UnpPtr; +} + + +void Unpack::ExecuteCode(VM_PreparedProgram *Prg) +{ + if (Prg->GlobalData.Size()>0) + { + Prg->InitR[6]=(uint)WrittenFileSize; + VM.SetLowEndianValue((uint *)&Prg->GlobalData[0x24],(uint)WrittenFileSize); + VM.SetLowEndianValue((uint *)&Prg->GlobalData[0x28],(uint)(WrittenFileSize>>32)); + VM.Execute(Prg); + } +} + + +bool Unpack::ReadTables30() +{ + byte BitLength[BC]; + byte Table[HUFF_TABLE_SIZE30]; + if (Inp.InAddr>ReadTop-25) + if (!UnpReadBuf30()) + return(false); + Inp.faddbits((8-Inp.InBit)&7); + uint BitField=Inp.fgetbits(); + if (BitField & 0x8000) + { + UnpBlockType=BLOCK_PPM; + return(PPM.DecodeInit(this,PPMEscChar)); + } + UnpBlockType=BLOCK_LZ; + + PrevLowDist=0; + LowDistRepCount=0; + + if (!(BitField & 0x4000)) + memset(UnpOldTable,0,sizeof(UnpOldTable)); + Inp.faddbits(2); + + for (int I=0;I> 12); + Inp.faddbits(4); + if (Length==15) + { + int ZeroCount=(byte)(Inp.fgetbits() >> 12); + Inp.faddbits(4); + if (ZeroCount==0) + BitLength[I]=15; + else + { + ZeroCount+=2; + while (ZeroCount-- > 0 && IReadTop-5) + if (!UnpReadBuf30()) + return(false); + int Number=DecodeNumber(Inp,&BlockTables.BD); + if (Number<16) + { + Table[I]=(Number+UnpOldTable[I]) & 0xf; + I++; + } + else + if (Number<18) + { + int N; + if (Number==16) + { + N=(Inp.fgetbits() >> 13)+3; + Inp.faddbits(3); + } + else + { + N=(Inp.fgetbits() >> 9)+11; + Inp.faddbits(7); + } + if (I>0) + while (N-- > 0 && I> 13)+3; + Inp.faddbits(3); + } + else + { + N=(Inp.fgetbits() >> 9)+11; + Inp.faddbits(7); + } + while (N-- > 0 && IReadTop) + return false; + MakeDecodeTables(&Table[0],&BlockTables.LD,NC30); + MakeDecodeTables(&Table[NC30],&BlockTables.DD,DC30); + MakeDecodeTables(&Table[NC30+DC30],&BlockTables.LDD,LDC30); + MakeDecodeTables(&Table[NC30+DC30+LDC30],&BlockTables.RD,RC30); + memcpy(UnpOldTable,Table,sizeof(UnpOldTable)); + return true; +} + + +void Unpack::UnpInitData30(bool Solid) +{ + if (!Solid) + { + TablesRead=false; + memset(UnpOldTable,0,sizeof(UnpOldTable)); + PPMEscChar=2; + UnpBlockType=BLOCK_LZ; + + InitFilters30(); + } +} + + +void Unpack::InitFilters30() +{ + OldFilterLengths.Reset(); + LastFilter=0; + + for (size_t I=0;I=ReadBorder) + { + bool FileDone=false; + + // We use 'while', because for empty block containing only Huffman table, + // we'll be on the block border once again just after reading the table. + while (Inp.InAddr>BlockHeader.BlockStart+BlockHeader.BlockSize-1 || + Inp.InAddr==BlockHeader.BlockStart+BlockHeader.BlockSize-1 && + Inp.InBit>=BlockHeader.BlockBitSize) + { + if (BlockHeader.LastBlockInFile) + { + FileDone=true; + break; + } + if (!ReadBlockHeader(Inp,BlockHeader) || !ReadTables(Inp,BlockHeader,BlockTables)) + return; + } + if (FileDone || !UnpReadBuf()) + break; + } + + if (((WriteBorder-UnpPtr) & MaxWinMask)DestUnpSize) + return; + if (Suspended) + { + FileExtracted=false; + return; + } + } + + uint MainSlot=DecodeNumber(Inp,&BlockTables.LD); + if (MainSlot<256) + { + if (Fragmented) + FragWindow[UnpPtr++]=(byte)MainSlot; + else + Window[UnpPtr++]=(byte)MainSlot; + continue; + } + if (MainSlot>=262) + { + uint Length=SlotToLength(Inp,MainSlot-262); + + uint DBits,Distance=1,DistSlot=DecodeNumber(Inp,&BlockTables.DD); + if (DistSlot<4) + { + DBits=0; + Distance+=DistSlot; + } + else + { + DBits=DistSlot/2 - 1; + Distance+=(2 | (DistSlot & 1)) << DBits; + } + + if (DBits>0) + { + if (DBits>=4) + { + if (DBits>4) + { + Distance+=((Inp.getbits32()>>(36-DBits))<<4); + Inp.addbits(DBits-4); + } + uint LowDist=DecodeNumber(Inp,&BlockTables.LDD); + Distance+=LowDist; + } + else + { + Distance+=Inp.getbits32()>>(32-DBits); + Inp.addbits(DBits); + } + } + + if (Distance>0x100) + { + Length++; + if (Distance>0x2000) + { + Length++; + if (Distance>0x40000) + Length++; + } + } + + InsertOldDist(Distance); + LastLength=Length; + if (Fragmented) + FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask); + else + CopyString(Length,Distance); + continue; + } + if (MainSlot==256) + { + UnpackFilter Filter; + if (!ReadFilter(Inp,Filter) || !AddFilter(Filter)) + break; + continue; + } + if (MainSlot==257) + { + if (LastLength!=0) + if (Fragmented) + FragWindow.CopyString(LastLength,OldDist[0],UnpPtr,MaxWinMask); + else + CopyString(LastLength,OldDist[0]); + continue; + } + if (MainSlot<262) + { + uint DistNum=MainSlot-258; + uint Distance=OldDist[DistNum]; + for (uint I=DistNum;I>0;I--) + OldDist[I]=OldDist[I-1]; + OldDist[0]=Distance; + + uint LengthSlot=DecodeNumber(Inp,&BlockTables.RD); + uint Length=SlotToLength(Inp,LengthSlot); + LastLength=Length; + if (Fragmented) + FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask); + else + CopyString(Length,Distance); + continue; + } + } + UnpWriteBuf(); +} + + +uint Unpack::ReadFilterData(BitInput &Inp) +{ + uint ByteCount=(Inp.fgetbits()>>14)+1; + Inp.addbits(2); + + uint Data=0; + for (uint I=0;I>8)<<(I*8); + Inp.addbits(8); + } + return Data; +} + + +bool Unpack::ReadFilter(BitInput &Inp,UnpackFilter &Filter) +{ + if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-16) + if (!UnpReadBuf()) + return false; + + Filter.BlockStart=ReadFilterData(Inp); + Filter.BlockLength=ReadFilterData(Inp); + + Filter.Type=Inp.fgetbits()>>13; + Inp.faddbits(3); + + if (Filter.Type==FILTER_DELTA) + { + Filter.Channels=(Inp.fgetbits()>>11)+1; + Inp.faddbits(5); + } + + return true; +} + + +bool Unpack::AddFilter(UnpackFilter &Filter) +{ + if (Filters.Size()>=MAX_UNPACK_FILTERS-1) + UnpWriteBuf(); // Write data, apply and flush filters. + + // If distance to filter start is that large that due to circular dictionary + // mode it points to old not written yet data, then we set 'NextWindow' + // flag and process this filter only after processing that older data. + Filter.NextWindow=WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<=Filter.BlockStart; + + Filter.BlockStart=uint((Filter.BlockStart+UnpPtr)&MaxWinMask); + Filters.Push(Filter); + return true; +} + + +bool Unpack::UnpReadBuf() +{ + int DataSize=ReadTop-Inp.InAddr; // Data left to process. + if (DataSize<0) + return false; + BlockHeader.BlockSize-=Inp.InAddr-BlockHeader.BlockStart; + if (Inp.InAddr>BitInput::MAX_SIZE/2) + { + // If we already processed more than half of buffer, let's move + // remaining data into beginning to free more space for new data + // and ensure that calling function does not cross the buffer border + // even if we did not read anything here. Also it ensures that read size + // is not less than CRYPT_BLOCK_SIZE, so we can align it without risk + // to make it zero. + if (DataSize>0) + memmove(Inp.InBuf,Inp.InBuf+Inp.InAddr,DataSize); + Inp.InAddr=0; + ReadTop=DataSize; + } + else + DataSize=ReadTop; + int ReadCode=0; + if (BitInput::MAX_SIZE!=DataSize) + ReadCode=UnpIO->UnpRead(Inp.InBuf+DataSize,BitInput::MAX_SIZE-DataSize); + if (ReadCode>0) // Can be also -1. + ReadTop+=ReadCode; + ReadBorder=ReadTop-30; + BlockHeader.BlockStart=Inp.InAddr; + if (BlockHeader.BlockSize!=-1) // '-1' means not defined yet. + { + // We may need to quit from main extraction loop and read new block header + // and trees earlier than data in input buffer ends. + ReadBorder=Min(ReadBorder,BlockHeader.BlockStart+BlockHeader.BlockSize-1); + } + return ReadCode!=-1; +} + + +void Unpack::UnpWriteBuf() +{ + size_t WrittenBorder=WrPtr; + size_t FullWriteSize=(UnpPtr-WrittenBorder)&MaxWinMask; + size_t WriteSizeLeft=FullWriteSize; + bool NotAllFiltersProcessed=false; + for (size_t I=0;IType==FILTER_NONE) + continue; + if (flt->NextWindow) + { + // Here we skip filters which have block start in current data range + // due to address warp around in circular dictionary, but actually + // belong to next dictionary block. If such filter start position + // is included to current write range, then we reset 'NextWindow' flag. + // In fact we can reset it even without such check, because current + // implementation seems to guarantee 'NextWindow' flag reset after + // buffer writing for all existing filters. But let's keep this check + // just in case. Compressor guarantees that distance between + // filter block start and filter storing position cannot exceed + // the dictionary size. So if we covered the filter block start with + // our write here, we can safely assume that filter is applicable + // to next block on no further wrap arounds is possible. + if (((flt->BlockStart-WrPtr)&MaxWinMask)<=FullWriteSize) + flt->NextWindow=false; + continue; + } + uint BlockStart=flt->BlockStart; + uint BlockLength=flt->BlockLength; + if (((BlockStart-WrittenBorder)&MaxWinMask)0) + { + uint BlockEnd=(BlockStart+BlockLength)&MaxWinMask; + + FilterSrcMemory.Alloc(BlockLength); + byte *Mem=&FilterSrcMemory[0]; + if (BlockStartUnpWrite(OutMem,BlockLength); + + UnpSomeRead=true; + WrittenFileSize+=BlockLength; + WrittenBorder=BlockEnd; + WriteSizeLeft=(UnpPtr-WrittenBorder)&MaxWinMask; + } + } + else + { + // Current filter intersects the window write border, so we adjust + // the window border to process this filter next time, not now. + WrPtr=WrittenBorder; + + // Since Filter start position can only increase, we quit processing + // all following filters for this data block and reset 'NextWindow' + // flag for them. + for (size_t J=I;JType!=FILTER_NONE) + flt->NextWindow=false; + } + + // Do not write data left after current filter now. + NotAllFiltersProcessed=true; + break; + } + } + } + + // Remove processed filters from queue. + size_t EmptyCount=0; + for (size_t I=0;I0) + Filters[I-EmptyCount]=Filters[I]; + if (Filters[I].Type==FILTER_NONE) + EmptyCount++; + } + if (EmptyCount>0) + Filters.Alloc(Filters.Size()-EmptyCount); + + if (!NotAllFiltersProcessed) // Only if all filters are processed. + { + // Write data left after last filter. + UnpWriteArea(WrittenBorder,UnpPtr); + WrPtr=UnpPtr; + } + + // We prefer to write data in blocks not exceeding UNPACK_MAX_WRITE + // instead of potentially huge MaxWinSize blocks. + WriteBorder=(UnpPtr+Min(MaxWinSize,UNPACK_MAX_WRITE))&MaxWinMask; + + // Choose the nearest among WriteBorder and WrPtr actual written border. + // If border is equal to UnpPtr, it means that we have MaxWinSize data ahead. + if (WriteBorder==UnpPtr || + WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<((WriteBorder-UnpPtr)&MaxWinMask)) + WriteBorder=WrPtr; +} + + +byte* Unpack::ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt) +{ + byte *SrcData=Data; + switch(Flt->Type) + { + case FILTER_E8: + case FILTER_E8E9: + { + uint FileOffset=(uint)WrittenFileSize; + + const int FileSize=0x1000000; + byte CmpByte2=Flt->Type==FILTER_E8E9 ? 0xe9:0xe8; + for (uint CurPos=0;(int)CurPos<(int)DataSize-4;) + { + byte CurByte=*(Data++); + CurPos++; + if (CurByte==0xe8 || CurByte==CmpByte2) + { + uint Offset=(CurPos+FileOffset)%FileSize; + uint Addr=RawGet4(Data); + + // We check 0x80000000 bit instead of '< 0' comparison + // not assuming int32 presence or uint size and endianness. + if ((Addr & 0x80000000)!=0) // Addr<0 + { + if (((Addr+Offset) & 0x80000000)==0) // Addr+Offset>=0 + RawPut4(Addr+FileSize,Data); + } + else + if (((Addr-FileSize) & 0x80000000)!=0) // Addr>8); + D[2]=(byte)(Offset>>16); + } + } + } + return SrcData; + case FILTER_DELTA: + { + uint Channels=Flt->Channels,SrcPos=0; + + FilterDstMemory.Alloc(DataSize); + byte *DstData=&FilterDstMemory[0]; + + // Bytes from same channels are grouped to continual data blocks, + // so we need to place them back to their interleaving positions. + for (uint CurChannel=0;CurChannel0) + { + size_t BlockSize=FragWindow.GetBlockSize(StartPtr,SizeToWrite); + UnpWriteData(&FragWindow[StartPtr],BlockSize); + SizeToWrite-=BlockSize; + StartPtr=(StartPtr+BlockSize) & MaxWinMask; + } + } + else + if (EndPtr=DestUnpSize) + return; + size_t WriteSize=Size; + int64 LeftToWrite=DestUnpSize-WrittenFileSize; + if ((int64)WriteSize>LeftToWrite) + WriteSize=(size_t)LeftToWrite; + UnpIO->UnpWrite(Data,WriteSize); + WrittenFileSize+=Size; +} + + +bool Unpack::ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header) +{ + Header.HeaderSize=0; + + if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-7) + if (!UnpReadBuf()) + return false; + Inp.faddbits((8-Inp.InBit)&7); + + byte BlockFlags=Inp.fgetbits()>>8; + Inp.faddbits(8); + uint ByteCount=((BlockFlags>>3)&3)+1; // Block size byte count. + + if (ByteCount==4) + return false; + + Header.HeaderSize=2+ByteCount; + + Header.BlockBitSize=(BlockFlags&7)+1; + + byte SavedCheckSum=Inp.fgetbits()>>8; + Inp.faddbits(8); + + int BlockSize=0; + for (uint I=0;I>8)<<(I*8); + Inp.addbits(8); + } + + Header.BlockSize=BlockSize; + byte CheckSum=byte(0x5a^BlockFlags^BlockSize^(BlockSize>>8)^(BlockSize>>16)); + if (CheckSum!=SavedCheckSum) + return false; + + Header.BlockStart=Inp.InAddr; + ReadBorder=Min(ReadBorder,Header.BlockStart+Header.BlockSize-1); + + Header.LastBlockInFile=(BlockFlags & 0x40)!=0; + Header.TablePresent=(BlockFlags & 0x80)!=0; + return true; +} + + +bool Unpack::ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTables &Tables) +{ + if (!Header.TablePresent) + return true; + + if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-25) + if (!UnpReadBuf()) + return false; + + byte BitLength[BC]; + for (int I=0;I> 12); + Inp.faddbits(4); + if (Length==15) + { + int ZeroCount=(byte)(Inp.fgetbits() >> 12); + Inp.faddbits(4); + if (ZeroCount==0) + BitLength[I]=15; + else + { + ZeroCount+=2; + while (ZeroCount-- > 0 && IReadTop-5) + if (!UnpReadBuf()) + return(false); + int Number=DecodeNumber(Inp,&Tables.BD); + if (Number<16) + { + Table[I]=Number; + I++; + } + else + if (Number<18) + { + int N; + if (Number==16) + { + N=(Inp.fgetbits() >> 13)+3; + Inp.faddbits(3); + } + else + { + N=(Inp.fgetbits() >> 9)+11; + Inp.faddbits(7); + } + if (I>0) + while (N-- > 0 && I> 13)+3; + Inp.faddbits(3); + } + else + { + N=(Inp.fgetbits() >> 9)+11; + Inp.faddbits(7); + } + while (N-- > 0 && IReadTop) + return(false); + MakeDecodeTables(&Table[0],&Tables.LD,NC); + MakeDecodeTables(&Table[NC],&Tables.DD,DC); + MakeDecodeTables(&Table[NC+DC],&Tables.LDD,LDC); + MakeDecodeTables(&Table[NC+DC+LDC],&Tables.RD,RC); + return(true); +} + + +void Unpack::InitFilters() +{ + Filters.Reset(); +} diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/unpack50frag.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/unpack50frag.cpp new file mode 100644 index 000000000..745b1b308 --- /dev/null +++ b/Frameworks/File_Extractor/File_Extractor/unrar/unpack50frag.cpp @@ -0,0 +1,103 @@ +FragmentedWindow::FragmentedWindow() +{ + memset(Mem,0,sizeof(Mem)); + memset(MemSize,0,sizeof(MemSize)); +} + + +FragmentedWindow::~FragmentedWindow() +{ + Reset(); +} + + +void FragmentedWindow::Reset() +{ + for (uint I=0;I=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 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=8) + { + Dest[0]=Src[0]; + Dest[1]=Src[1]; + Dest[2]=Src[2]; + Dest[3]=Src[3]; + Dest[4]=Src[4]; + Dest[5]=Src[5]; + Dest[6]=Src[6]; + Dest[7]=Src[7]; + + Src+=8; + Dest+=8; + Length-=8; + } +#ifdef FAST_MEMCPY + else + while (Length>=8) + { + // This memcpy expanded inline by MSVC. We could also use uint64 + // assignment, which seems to provide about the same speed. + memcpy(Dest,Src,8); + + Src+=8; + Dest+=8; + Length-=8; + } +#endif + + // Unroll the loop for 0 - 7 bytes left. Note that we use nested "if"s. + if (Length>0) { Dest[0]=Src[0]; + if (Length>1) { Dest[1]=Src[1]; + if (Length>2) { Dest[2]=Src[2]; + if (Length>3) { Dest[3]=Src[3]; + if (Length>4) { Dest[4]=Src[4]; + if (Length>5) { Dest[5]=Src[5]; + if (Length>6) { Dest[6]=Src[6]; } } } } } } } // Close all nested "if"s. + } + else + 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; + } +} + + +inline uint Unpack::DecodeNumber(BitInput &Inp,DecodeTable *Dec) +{ + // Left aligned 15 bit length raw bit field. + uint BitField=Inp.getbits() & 0xfffe; + + if (BitFieldDecodeLen[Dec->QuickBits]) + { + uint Code=BitField>>(16-Dec->QuickBits); + Inp.addbits(Dec->QuickLen[Code]); + return Dec->QuickNum[Code]; + } + + // Detect the real bit length for current code. + uint Bits=15; + for (uint I=Dec->QuickBits+1;I<15;I++) + if (BitFieldDecodeLen[I]) + { + Bits=I; + break; + } + + Inp.addbits(Bits); + + // Calculate the distance from the start code for current bit length. + uint Dist=BitField-Dec->DecodeLen[Bits-1]; + + // Start codes are left aligned, but we need the normal right aligned + // number. So we shift the distance to the right. + Dist>>=(16-Bits); + + // Now we can calculate the position in the code list. It is the sum + // of first position for current bit length and right aligned distance + // between our bit field and start code for current bit length. + uint Pos=Dec->DecodePos[Bits]+Dist; + + // Out of bounds safety check required for damaged archives. + if (Pos>=Dec->MaxNum) + Pos=0; + + // Convert the position in the code list to position in alphabet + // and return it. + return(Dec->DecodeNum[Pos]); +} + + +inline uint Unpack::SlotToLength(BitInput &Inp,uint Slot) +{ + uint LBits,Length=2; + if (Slot<8) + { + LBits=0; + Length+=Slot; + } + else + { + LBits=Slot/4-1; + Length+=(4 | (Slot & 3)) << LBits; + } + + if (LBits>0) + { + Length+=Inp.getbits()>>(16-LBits); + Inp.addbits(LBits); + } + return Length; +} diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/unrar.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/unrar.cpp index 66d7ab634..26eb56eae 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/unrar.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/unrar.cpp @@ -42,8 +42,7 @@ void Rar_Error_Handler::MemoryError() //// Internal -unrar_t::unrar_t() : - Buffer( &Arc ) +unrar_t::unrar_t() { Arc.user_read = NULL; Arc.user_write = NULL; @@ -74,8 +73,8 @@ unrar_t::~unrar_t() static inline bool solid_file( const unrar_t* p ) { return p->Arc.Solid && - p->Arc.NewLhd.Method != 0x30 && - p->Arc.NewLhd.FullPackSize != 0; + p->Arc.FileHead.Method != 0 && + p->Arc.FileHead.PackSize != 0; } static void update_solid_pos( unrar_t* p ) @@ -129,8 +128,9 @@ static unrar_err_t next_( unrar_t* p, bool skipping_solid ) for (;;) { + size_t ReadSize; p->Arc.SeekToNext(); - unrar_err_t const err = p->Arc.ReadHeader(); + unrar_err_t const err = p->Arc.ReadHeader(&ReadSize); if ( err != unrar_err_arc_eof ) RETURN_ERR( err ); //else @@ -138,17 +138,17 @@ static unrar_err_t next_( unrar_t* p, bool skipping_solid ) HEADER_TYPE const type = (HEADER_TYPE) p->Arc.GetHeaderType(); - if ( err != unrar_ok || type == ENDARC_HEAD ) + if ( err != unrar_ok || type == HEAD_ENDARC ) { p->done = true; break; } - if ( type != FILE_HEAD ) + if ( type != HEAD_FILE ) { // Skip non-files - /*if ( type != NEWSUB_HEAD && type != PROTECT_HEAD && type != SIGN_HEAD && type != SUB_HEAD ) - debug_printf( "unrar: Skipping unknown block type: %X\n", (unsigned) type );*/ + if ( type != HEAD_SERVICE && type != HEAD_CRYPT && type != HEAD_MARK ) + debug_printf( "unrar: Skipping unknown block type: %X\n", (unsigned) type ); update_solid_pos( p ); } @@ -162,7 +162,7 @@ static unrar_err_t next_( unrar_t* p, bool skipping_solid ) { // Ignore labels } - else if ( IsLink( p->Arc.NewLhd.FileAttr ) ) + else if ( IsLink( p->Arc.FileHead.FileAttr ) ) { // Ignore links @@ -175,12 +175,12 @@ static unrar_err_t next_( unrar_t* p, bool skipping_solid ) } else { - p->info.size = p->Arc.NewLhd.UnpSize; - p->info.name = p->Arc.NewLhd.FileName; - p->info.name_w = p->Arc.NewLhd.FileNameW; - p->info.is_unicode = (p->Arc.NewLhd.Flags & LHD_UNICODE) != 0; - p->info.dos_date = p->Arc.NewLhd.mtime.time; - p->info.crc = p->Arc.NewLhd.FileCRC; + p->info.size = p->Arc.FileHead.UnpSize; + p->info.name_w = p->Arc.FileHead.FileName; + WideToChar(p->info.name_w, p->info.name); + p->info.is_unicode = (p->Arc.FileHead.Flags & LHD_UNICODE) != 0; + p->info.dos_date = p->Arc.FileHead.mtime.GetDos(); + p->info.crc = p->Arc.FileHead.FileHash.CRC32; p->info.is_crc32 = !p->Arc.OldFormat; // Stop for files diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/unrar.h b/Frameworks/File_Extractor/File_Extractor/unrar/unrar.h index 20bab39f9..9b2255bab 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/unrar.h +++ b/Frameworks/File_Extractor/File_Extractor/unrar/unrar.h @@ -11,8 +11,10 @@ #if !defined (UNRAR_NO_LONG_LONG) && defined (LLONG_MAX) typedef long long unrar_long_long; + typedef unsigned long long unrar_ulong_long; #else typedef long unrar_long_long; + typedef unsigned long unrar_ulong_long; #endif #ifdef __cplusplus @@ -91,7 +93,7 @@ unrar_err_t unrar_seek( unrar_t*, unrar_pos_t ); typedef struct unrar_info_t { unrar_pos_t size; /**< Uncompressed size */ - const char* name; /**< Name, in Unicode if is_unicode is true */ + char name[32767]; /**< Name, in Unicode if is_unicode is true */ const blargg_wchar_t* name_w; /**< Name in Unicode, "" if unavailable */ unrar_bool is_unicode; /**< True if name is Unicode (UTF-8) */ unsigned int dos_date; /**< Date in DOS-style format, 0 if unavailable */ diff --git a/Frameworks/File_Extractor/File_Extractor/unrar/unrar_misc.cpp b/Frameworks/File_Extractor/File_Extractor/unrar/unrar_misc.cpp index 2960c6ed7..92e3f79b3 100644 --- a/Frameworks/File_Extractor/File_Extractor/unrar/unrar_misc.cpp +++ b/Frameworks/File_Extractor/File_Extractor/unrar/unrar_misc.cpp @@ -11,8 +11,8 @@ void unrar_init() { - if (CRCTab[1]==0) - InitCRC(); + if (crc_tables[0][1]==0) + InitCRCTables(); Unpack::init_tables(); } @@ -55,7 +55,7 @@ unrar_err_t unrar_extract( unrar_t* p, void* out, unrar_pos_t size ) inline static bool is_entire_file( const unrar_t* p, const void* in, int count ) { - return (count == p->Arc.NewLhd.UnpSize && p->Unp && in == p->Unp->window_wrptr()); + return (count == p->Arc.SubHead.UnpSize && p->Unp && in == p->Unp->window_wrptr()); } extern "C" { @@ -149,10 +149,7 @@ void ComprDataIO::UnpWrite( byte* out, uint count ) if ( write_error == unrar_ok ) write_error = user_write( user_write_data, out, count ); - if ( OldFormat ) - UnpFileCRC = OldCRC( (ushort) UnpFileCRC, out, count ); - else - UnpFileCRC = CRC( UnpFileCRC, out, count ); + UnpHash.Update(out,count); } } @@ -162,7 +159,7 @@ int ComprDataIO::UnpRead( byte* out, uint count ) return 0; if ( count > (uint) UnpPackedSize ) - count = (uint) UnpPackedSize; + count = UnpPackedSize; int result = Read( out, count ); UnpPackedSize -= result;