Updated unrar to version 5.1.7

CQTexperiment
Chris Moeller 2014-09-20 06:52:10 -07:00
parent 0ccc0f4dae
commit bfb319988f
54 changed files with 7869 additions and 3918 deletions

View File

@ -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 = "<group>"; };
8359FFEA17FEF40E0060F3ED /* getbits.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = getbits.hpp; sourceTree = "<group>"; };
8359FFEB17FEF40E0060F3ED /* headers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = headers.hpp; sourceTree = "<group>"; };
8359FFED17FEF40E0060F3ED /* model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = model.cpp; sourceTree = "<group>"; };
8359FFEE17FEF40E0060F3ED /* model.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = model.hpp; sourceTree = "<group>"; };
8359FFEF17FEF40E0060F3ED /* rar.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = rar.hpp; sourceTree = "<group>"; };
8359FFF017FEF40E0060F3ED /* rarvm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rarvm.cpp; sourceTree = "<group>"; };
@ -255,15 +262,24 @@
8359FFF217FEF40E0060F3ED /* rarvmtbl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rarvmtbl.cpp; sourceTree = "<group>"; };
8359FFF317FEF40E0060F3ED /* rawread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rawread.cpp; sourceTree = "<group>"; };
8359FFF417FEF40E0060F3ED /* rawread.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = rawread.hpp; sourceTree = "<group>"; };
8359FFF617FEF40E0060F3ED /* suballoc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = suballoc.cpp; sourceTree = "<group>"; };
8359FFF717FEF40E0060F3ED /* suballoc.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = suballoc.hpp; sourceTree = "<group>"; };
8359FFF917FEF40E0060F3ED /* unicode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unicode.cpp; sourceTree = "<group>"; };
8359FFFA17FEF40E0060F3ED /* unicode.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = unicode.hpp; sourceTree = "<group>"; };
8359FFFB17FEF40E0060F3ED /* unpack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unpack.cpp; sourceTree = "<group>"; };
8359FFFC17FEF40E0060F3ED /* unpack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = unpack.hpp; sourceTree = "<group>"; };
8359FFFD17FEF40E0060F3ED /* unpack15.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unpack15.cpp; sourceTree = "<group>"; };
8359FFFE17FEF40E0060F3ED /* unpack20.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unpack20.cpp; sourceTree = "<group>"; };
8359FFFF17FEF40E0060F3ED /* unrar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unrar.cpp; sourceTree = "<group>"; };
83C2108E19CD81F50093C461 /* headers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = headers.cpp; sourceTree = "<group>"; };
83C2108F19CD81F50093C461 /* headers5.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = headers5.hpp; sourceTree = "<group>"; };
83C2109A19CD88A30093C461 /* secpassword.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = secpassword.cpp; sourceTree = "<group>"; };
83C2109C19CD89C70093C461 /* hash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hash.cpp; sourceTree = "<group>"; };
83C2109E19CD89C70093C461 /* blake2s.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blake2s.cpp; sourceTree = "<group>"; };
83C2109F19CD89C70093C461 /* blake2s.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = blake2s.hpp; sourceTree = "<group>"; };
83C210A119CD89C70093C461 /* hash.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = hash.hpp; sourceTree = "<group>"; };
83C210A819CD8F8F0093C461 /* strfn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strfn.cpp; sourceTree = "<group>"; };
83C210A919CD8F8F0093C461 /* strfn.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = strfn.hpp; sourceTree = "<group>"; };
83C210AC19CD92960093C461 /* pathfn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pathfn.cpp; sourceTree = "<group>"; };
83C210AE19CD97DB0093C461 /* timefn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = timefn.cpp; sourceTree = "<group>"; };
83C210AF19CD97DB0093C461 /* timefn.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = timefn.hpp; sourceTree = "<group>"; };
/* 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;

View File

@ -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.

View File

@ -5,90 +5,87 @@
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;
memset(&MainHead,0,sizeof(MainHead));
memset(&EndArcHead,0,sizeof(EndArcHead));
HeaderCRC=0;
}
bool Archive::IsSignature(byte *D)
{
bool Valid=false;
if (D[0]==0x52)
RARFORMAT Archive::IsSignature(const byte *D,size_t Size)
{
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;
SeekToNext();
return unrar_ok;
}

View File

@ -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;

View File

@ -5,310 +5,731 @@
#include "encname.hpp"
// arcread.cpp
unrar_err_t Archive::ReadHeader()
unrar_err_t Archive::ReadHeader(size_t * ReadSize_)
{
CurBlockPos=Tell();
#ifndef SFX_MODULE
if (OldFormat)
unrar_err_t Error;
size_t ReadSize;
switch(Format)
{
ReadOldHeader();
#ifndef SFX_MODULE
case RARFMT14:
Error=ReadHeader14(&ReadSize);
break;
#endif
case RARFMT15:
Error=ReadHeader15(&ReadSize);
break;
case RARFMT50:
Error=ReadHeader50(&ReadSize);
break;
if ( Raw.Size() == 0 )
return unrar_err_arc_eof; // right at end of file
default: // unreachable
Error=unrar_err_corrupt;
break;
}
if ( Raw.PaddedSize() > 0 ) // added check
return unrar_err_corrupt; // missing data
if (Error!=unrar_ok)
return Error;
if (ReadSize>0 & NextBlockPos<=CurBlockPos)
return unrar_err_corrupt;
*ReadSize_ = ReadSize;
return unrar_ok;
}
#endif
unrar_err_t Archive::ReadHeader15(size_t *ReadSize)
{
Raw.Reset();
// (removed decryption)
Raw.Read(SIZEOF_SHORTBLOCKHEAD);
if (Raw.Size()==0)
{
return unrar_err_arc_eof; // right at end of file
}
return unrar_err_corrupt;
Raw.Get(ShortBlock.HeadCRC);
byte HeadType;
Raw.Get(HeadType);
ShortBlock.HeadType=(HEADER_TYPE)HeadType;
Raw.Get(ShortBlock.Flags);
Raw.Get(ShortBlock.HeadSize);
ShortBlock.HeadCRC=Raw.Get2();
ShortBlock.Reset();
uint HeaderType=Raw.Get1();
ShortBlock.Flags=Raw.Get2();
ShortBlock.SkipIfUnknown=(ShortBlock.Flags & SKIP_IF_UNKNOWN)!=0;
ShortBlock.HeadSize=Raw.Get2();
ShortBlock.HeaderType=(HEADER_TYPE)HeaderType;
if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
return unrar_err_corrupt;
// For simpler further processing we map header types common
// for RAR 1.5 and 5.0 formats to RAR 5.0 values. It does not include
// header types specific for RAR 1.5 - 4.x only.
switch(ShortBlock.HeaderType)
{
return unrar_err_corrupt; // invalid HeadSize
case HEAD3_MAIN: ShortBlock.HeaderType=HEAD_MAIN; break;
case HEAD3_FILE: ShortBlock.HeaderType=HEAD_FILE; break;
case HEAD3_SERVICE: ShortBlock.HeaderType=HEAD_SERVICE; break;
case HEAD3_ENDARC: ShortBlock.HeaderType=HEAD_ENDARC; break;
default: break;
}
CurHeaderType=ShortBlock.HeaderType;
// catches unknown block types and reading something that isn't even a header
check( MARK_HEAD <= ShortBlock.HeadType && ShortBlock.HeadType <= ENDARC_HEAD );
if (ShortBlock.HeadType==COMM_HEAD)
if (ShortBlock.HeaderType==HEAD3_CMT)
{
// Old style (up to RAR 2.9) comment header embedded into main
// or file header. We must not read the entire ShortBlock.HeadSize here
// to not break the comment processing logic later.
Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
}
else
if (ShortBlock.HeadType==MAIN_HEAD && (ShortBlock.Flags & MHD_COMMENT)!=0)
Raw.Read(SIZEOF_NEWMHD-SIZEOF_SHORTBLOCKHEAD);
if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0)
{
// Old style (up to RAR 2.9) main archive comment embedded into
// the main archive header found. While we can read the entire
// ShortBlock.HeadSize here and remove this part of "if", it would be
// waste of memory, because we'll read and process this comment data
// in other function anyway and we do not need them here now.
Raw.Read(SIZEOF_MAINHEAD3-SIZEOF_SHORTBLOCKHEAD);
}
else
Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);
if ( Raw.PaddedSize() > 0 ) // fewer than requested bytes read above?
return unrar_err_corrupt; // missing data
NextBlockPos=CurBlockPos+ShortBlock.HeadSize;
switch(ShortBlock.HeadType)
switch(ShortBlock.HeaderType)
{
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
case HEAD_MAIN:
MainHead.Reset();
*(BaseBlock *)&MainHead=ShortBlock;
MainHead.HighPosAV=Raw.Get2();
MainHead.PosAV=Raw.Get4();
Solid=(MainHead.Flags & MHD_SOLID)!=0;
MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0;
break;
case FILE_HEAD:
case NEWSUB_HEAD:
case HEAD_FILE:
case HEAD_SERVICE:
{
FileHeader *hd=ShortBlock.HeadType==FILE_HEAD ? &NewLhd:&SubHead;
bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
FileHeader *hd=FileBlock ? &FileHead:&SubHead;
hd->Reset();
*(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)
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->HostOS<HOST_MAX)
hd->HSType=HSYS_WINDOWS;
hd->RedirType=FSREDIR_NONE;
// RAR 4.x Unix symlink.
if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000)
{
Raw.Get(hd->HighPackSize);
Raw.Get(hd->HighUnpSize);
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
{
hd->HighPackSize=hd->HighUnpSize=0;
if (hd->UnpSize==0xffffffff)
{
// TODO: what the heck is this for anyway?
hd->UnpSize=0;
hd->HighUnpSize=0x7fffffff;
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->FullPackSize=int32to64(hd->HighPackSize,hd->PackSize);
hd->FullUnpSize=int32to64(hd->HighUnpSize,hd->UnpSize);
hd->PackSize=int32to64(HighPackSize,hd->DataSize);
hd->UnpSize=int32to64(HighUnpSize,LowUnpSize);
if (hd->UnknownUnpSize)
hd->UnpSize=INT64NDF;
if ( int32to64( 1, 0 ) == 0 && (hd->HighPackSize || hd->HighUnpSize) )
return unrar_err_huge;
char FileName[NM*4];
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
Raw.GetB((byte *)FileName,ReadNameSize);
FileName[ReadNameSize]=0;
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)
if (FileBlock)
{
// 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)
if ((hd->Flags & LHD_UNICODE)!=0)
{
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
{
size_t Length=strlen(FileName);
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;
NameSize-Length,hd->FileName,
ASIZE(hd->FileName));
}
else
*hd->FileNameW=0;
*hd->FileName=0;
ConvertUnknownHeader();
char AnsiName[NM];
IntToExt(FileName,AnsiName,ASIZE(AnsiName));
GetWideName(AnsiName,hd->FileName,hd->FileName,ASIZE(hd->FileName));
ConvertFileHeader(hd);
}
if (hd->Flags & LHD_SALT)
Raw.Get(hd->Salt,SALT_SIZE);
hd->mtime.SetDos(hd->FileTime);
if (hd->Flags & LHD_EXTTIME)
else
{
ushort Flags;
Raw.Get(Flags);
// Ignore additional time information
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)
if ((rmode & 8)==0 || CurTime==NULL)
continue;
if (I!=0)
{
uint DosTime;
Raw.Get(DosTime);
uint DosTime=Raw.Get4();
CurTime->SetDos(DosTime);
}
// skip time info
RarLocalTime rlt;
CurTime->GetLocal(&rlt);
if (rmode & 4)
rlt.Second++;
rlt.Reminder=0;
int count=rmode&3;
for (int J=0;J<count;J++)
{
byte CurByte;
Raw.Get(CurByte);
byte CurByte=Raw.Get1();
rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
}
CurTime->SetLocal(&rlt);
}
}
}
NextBlockPos+=hd->FullPackSize;
bool CRCProcessedOnly=(hd->Flags & LHD_COMMENT)!=0;
HeaderCRC=~Raw.GetCRC(CRCProcessedOnly)&0xffff;
NextBlockPos+=hd->PackSize;
bool CRCProcessedOnly=hd->CommentInHeader;
ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
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;
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;
case SUB_HEAD:
Raw.Get(SubBlockHead.DataSize);
NextBlockPos+=SubBlockHead.DataSize;
break;
#endif
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;
}
unrar_err_t Archive::ReadHeader50(size_t *ReadSize)
{
uint DataSize;
Raw.Get(DataSize);
NextBlockPos+=DataSize;
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)<FirstReadSize)
return unrar_err_arc_eof;
ShortBlock.Reset();
ShortBlock.HeadCRC=Raw.Get4();
uint SizeBytes=Raw.GetVSize(4);
uint64 BlockSize=Raw.GetV();
if (BlockSize==0 || SizeBytes==0)
return unrar_err_corrupt;
int SizeToRead=int(BlockSize);
SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
uint HeaderSize=4+SizeBytes+(uint)BlockSize;
if (SizeToRead<0 || HeaderSize<SIZEOF_SHORTBLOCKHEAD5)
return unrar_err_corrupt;
Raw.Read(SizeToRead);
if (Raw.Size()<HeaderSize)
return unrar_err_arc_eof;
uint HeaderCRC=Raw.GetCRC50();
ShortBlock.HeaderType=(HEADER_TYPE)Raw.GetV();
ShortBlock.Flags=(uint)Raw.GetV();
ShortBlock.SkipIfUnknown=(ShortBlock.Flags & HFL_SKIPIFUNKNOWN)!=0;
ShortBlock.HeadSize=HeaderSize;
CurHeaderType=ShortBlock.HeaderType;
bool BadCRC=(ShortBlock.HeadCRC!=HeaderCRC);
if (BadCRC)
return unrar_err_corrupt;
uint64 ExtraSize=0;
if ((ShortBlock.Flags & HFL_EXTRA)!=0)
{
ExtraSize=Raw.GetV();
if (ExtraSize>=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;
}
HeaderCRC=~Raw.GetCRC(false)&0xffff;
CurHeaderType=ShortBlock.HeadType;
// (removed decryption)
if (NextBlockPos<CurBlockPos+Raw.Size())
return unrar_err_corrupt; // next block isn't past end of current block's header
if (NextBlockPos<=CurBlockPos)
return unrar_err_corrupt;
// If pos went negative, then unrar_pos_t is only 32 bits and it overflowed
if ( NextBlockPos < 0 )
return unrar_err_huge;
*ReadSize=Raw.Size();
return unrar_ok;
}
// Rar.Read()s are checked by caller of ReadOldHeader() (see above)
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 (ExtraStart<Raw->GetPos())
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 (NameSize<ASIZE(UtfName)-1)
{
Raw->GetB(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
int Archive::ReadOldHeader()
unrar_err_t Archive::ReadHeader14(size_t *ReadSize)
{
Raw.Reset();
if (CurBlockPos<=SFXSize)
if (CurBlockPos<=(int64)SFXSize)
{
Raw.Read(SIZEOF_OLDMHD);
Raw.Get(OldMhd.Mark,4);
Raw.Get(OldMhd.HeadSize);
Raw.Get(OldMhd.Flags);
NextBlockPos=CurBlockPos+OldMhd.HeadSize;
CurHeaderType=MAIN_HEAD;
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
{
OldFileHeader OldLhd;
Raw.Read(SIZEOF_OLDLHD);
NewLhd.HeadType=FILE_HEAD;
Raw.Get(NewLhd.PackSize);
Raw.Get(NewLhd.UnpSize);
Raw.Get(OldLhd.FileCRC);
Raw.Get(NewLhd.HeadSize);
Raw.Get(NewLhd.FileTime);
Raw.Get(OldLhd.FileAttr);
Raw.Get(OldLhd.Flags);
Raw.Get(OldLhd.UnpVer);
Raw.Get(OldLhd.NameSize);
Raw.Get(OldLhd.Method);
Raw.Read(SIZEOF_FILEHEAD14);
FileHead.Reset();
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;
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();
NewLhd.mtime.SetDos(NewLhd.FileTime);
// (removed other times)
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;
Raw.Read(OldLhd.NameSize);
Raw.Get((byte *)NewLhd.FileName,OldLhd.NameSize);
NewLhd.FileName[OldLhd.NameSize]=0;
// (removed name case conversion)
*NewLhd.FileNameW=0;
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+NewLhd.HeadSize+NewLhd.PackSize;
CurHeaderType=FILE_HEAD;
NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize;
CurHeaderType=HEAD_FILE;
}
return(NextBlockPos>CurBlockPos ? Raw.Size():0);
*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;
if (Format==RARFMT15 && hd->UnpVer<20 && (hd->FileAttr & 0x10))
hd->Dir=true;
if (hd->HSType==HSYS_UNKNOWN)
if (hd->Dir)
hd->FileAttr=0x10;
else
NewLhd.FileAttr=0x20;
hd->FileAttr=0x20;
}
int64 Archive::GetStartPos()
{
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;
}
int64 StartPos=SFXSize+MarkHead.HeadSize;
StartPos+=MainHead.HeadSize;
return StartPos;
}

View File

@ -1,26 +1,33 @@
#ifndef _RAR_ARRAY_
#define _RAR_ARRAY_
#include <new>
template <class T> 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<T> &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 <class T> void Array<T>::CleanData()
@ -28,22 +35,30 @@ template <class T> void Array<T>::CleanData()
Buffer=NULL;
BufSize=0;
AllocSize=0;
MaxSize=0;
}
template <class T> Array<T>::Array(Rar_Error_Handler* eh) : ErrHandler( *eh )
template <class T> Array<T>::Array()
{
CleanData();
}
template <class T> Array<T>::Array(int Size, Rar_Error_Handler* eh) : ErrHandler( *eh )
template <class T> Array<T>::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 <class T> Array<T>::Array(const Array &Src)
{
CleanData();
Alloc(Src.BufSize);
if (Src.BufSize!=0)
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
}
@ -54,41 +69,46 @@ template <class T> Array<T>::~Array()
}
template <class T> inline T& Array<T>::operator [](int Item)
template <class T> inline T& Array<T>::operator [](size_t Item) const
{
return(Buffer[Item]);
return Buffer[Item];
}
template <class T> inline int Array<T>::Size()
template <class T> inline T* Array<T>::operator +(size_t Pos)
{
return(BufSize);
return Buffer+Pos;
}
template <class T> void Array<T>::Add(int Items)
template <class T> inline size_t Array<T>::Size()
{
int BufSize = this->BufSize; // don't change actual vars until alloc succeeds
T* Buffer = this->Buffer;
return BufSize;
}
BufSize+=Items;
if (BufSize>AllocSize)
template <class T> void Array<T>::Add(size_t Items)
{
int Suggested=AllocSize+AllocSize/4+32;
int NewSize=Max(BufSize,Suggested);
size_t NewBufSize=BufSize+Items;
if (NewBufSize>AllocSize)
{
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 <class T> void Array<T>::Alloc(int Items)
template <class T> void Array<T>::Alloc(size_t Items)
{
if (Items>AllocSize)
Add(Items-BufSize);
@ -117,6 +137,14 @@ template <class T> void Array<T>::Reset()
}
// Reset buffer size, but preserve already allocated memory if any,
// so we can reuse it without wasting time to allocation.
template <class T> void Array<T>::SoftReset()
{
BufSize=0;
}
template <class T> void Array<T>::operator =(Array<T> &Src)
{
Reset();
@ -132,4 +160,12 @@ template <class T> void Array<T>::Push(T Item)
(*this)[Size()-1]=Item;
}
template <class T> void Array<T>::Append(T *Items,size_t Count)
{
size_t CurSize=Size();
Add(Count);
memcpy(Buffer+CurSize,Items,Count*sizeof(T));
}
#endif

View File

@ -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 );
}

View File

@ -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

View File

@ -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;
}

View File

@ -0,0 +1,153 @@
/*
BLAKE2 reference source code package - reference C implementations
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
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 <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#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__<PARALLELISM_DEGREE;)
{
for (uint Thread=0;Thread<ThreadNumber && id__<PARALLELISM_DEGREE;Thread++)
{
Blake2ThreadData *btd=btd_array+Thread;
btd->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 );
}

View File

@ -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))<TOP || range<BOT && ((range=-low&(BOT-1)),1)) \
while ((low^(low+range))<TOP || range<BOT && ((range=-(int)low&(BOT-1)),1)) \
{ \
code=(code << 8) | read->GetChar(); \
range <<= 8; \

View File

@ -2,7 +2,6 @@
* Contents: 'Carryless rangecoder' by Dmitry Subbotin *
****************************************************************************/
const uint TOP=1 << 24, BOT=1 << 15;
class RangeCoder
{

View File

@ -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

View File

@ -1,62 +1,90 @@
// 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()
{
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)
{
// 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
// 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);
while (Size>0 && ((long)Data & 7))
{
StartCRC=CRCTab[(byte)(StartCRC^Data[0])]^(StartCRC>>8);
Size--;
Data++;
}
while (Size>=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;
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;
}
uint NextData = *(uint32 *) (Data +4);
#endif
for (size_t I=0;I<Size;I++)
StartCRC=CRCTab[(byte)(StartCRC^Data[I])]^(StartCRC>>8);
return(StartCRC);
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<Size;I++)
@ -64,6 +92,6 @@ ushort OldCRC(ushort StartCRC,const void *Addr,size_t Size)
StartCRC=(StartCRC+Data[I])&0xffff;
StartCRC=((StartCRC<<1)|(StartCRC>>15))&0xffff;
}
return(StartCRC);
return StartCRC;
}
#endif

View File

@ -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 (EncPos<EncSize && DecPos<MaxDecSize)
{

View File

@ -8,13 +8,13 @@ class EncodeFileName
byte *EncName;
byte Flags;
int FlagBits;
int FlagsPos;
int DestSize;
size_t FlagBits;
size_t FlagsPos;
size_t DestSize;
public:
EncodeFileName();
int Encode(char *Name,wchar *NameW,byte *EncName);
void Decode(char *Name,byte *EncName,int EncSize,wchar *NameW,int MaxDecSize);
size_t Encode(char *Name,wchar *NameW,byte *EncName);
void Decode(char *Name,byte *EncName,size_t EncSize,wchar *NameW,size_t MaxDecSize);
};
#endif

View File

@ -9,28 +9,29 @@ unrar_err_t CmdExtract::ExtractCurrentFile( bool SkipSolid, bool check_compatibi
{
check( Arc.GetHeaderType() == FILE_HEAD );
if ( Arc.NewLhd.Flags & (LHD_SPLIT_AFTER | LHD_SPLIT_BEFORE) )
if ( Arc.FileHead.SplitBefore || Arc.FileHead.SplitAfter )
return unrar_err_segmented;
if ( Arc.NewLhd.Flags & LHD_PASSWORD )
if ( Arc.FileHead.Encrypted )
return unrar_err_encrypted;
if ( !check_compatibility_only )
{
check( Arc.NextBlockPos-Arc.NewLhd.FullPackSize == Arc.Tell() );
Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET);
check( Arc.NextBlockPos-Arc.FileHead.PackSize == Arc.Tell() );
Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET);
}
// (removed lots of command-line handling)
#ifdef SFX_MODULE
if ((Arc.NewLhd.UnpVer!=UNP_VER && Arc.NewLhd.UnpVer!=29) &&
Arc.NewLhd.Method!=0x30)
if ((Arc.FileHead.UnpVer!=UNP_VER && Arc.FileHead.UnpVer!=29) &&
Arc.FileHead.Method!=0x30)
#else
if (Arc.NewLhd.UnpVer<13 || Arc.NewLhd.UnpVer>UNP_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,24 +63,25 @@ 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
}
@ -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<DestUnpSize ? Code:int64to32(DestUnpSize);

View File

@ -1,19 +1,29 @@
#include "rar.hpp"
BitInput::BitInput()
BitInput::BitInput(bool AllocBuffer)
{
InBuf = (byte*) rarmalloc( MAX_SIZE );
ExternalBuffer=false;
if (AllocBuffer)
{
// getbits32 attempts to read data from InAddr, ... InAddr+3 positions.
// So let's allocate 3 additional bytes for situation, when we need to
// read only 1 byte from the last position of buffer and avoid a crash
// from access to next 3 bytes, which contents we do not need.
size_t BufSize=MAX_SIZE+3;
InBuf=new byte[BufSize];
// Otherwise getbits() reads uninitialized memory
// TODO: instead of clearing entire block, just clear last two
// bytes after reading from file
if ( InBuf )
memset( InBuf, 0, MAX_SIZE );
// Ensure that we get predictable results when accessing bytes in area
// not filled with read data.
memset(InBuf,0,BufSize);
}
else
InBuf=NULL;
}
BitInput::~BitInput()
{
rarfree( InBuf );
if (!ExternalBuffer)
delete[] InBuf;
}
void BitInput::handle_mem_error( Rar_Error_Handler& ErrHandler )
@ -22,13 +32,25 @@ void BitInput::handle_mem_error( Rar_Error_Handler& ErrHandler )
ErrHandler.MemoryError();
}
void BitInput::faddbits(int Bits)
void BitInput::faddbits(uint Bits)
{
// Function wrapped version of inline addbits to save code size.
addbits(Bits);
}
unsigned int BitInput::fgetbits()
uint BitInput::fgetbits()
{
// Function wrapped version of inline getbits to save code size.
return(getbits());
}
void BitInput::SetExternalBuffer(byte *Buf)
{
if (InBuf!=NULL && !ExternalBuffer)
delete[] InBuf;
InBuf=Buf;
ExternalBuffer=true;
}

View File

@ -5,36 +5,66 @@ class BitInput
: public Rar_Allocator
{
public:
enum BufferSize {MAX_SIZE=0x8000};
protected:
int InAddr,InBit;
enum BufferSize {MAX_SIZE=0x8000}; // Size of input buffer.
int InAddr; // Curent byte position in the buffer.
int InBit; // Current bit position in the current byte.
bool ExternalBuffer;
public:
BitInput();
BitInput(bool AllocBuffer);
~BitInput();
void handle_mem_error( Rar_Error_Handler& );
byte *InBuf;
byte *InBuf; // Dynamically allocated input buffer.
void InitBitInput()
{
InAddr=InBit=0;
}
void addbits(int Bits)
// Move forward by 'Bits' bits.
void addbits(uint Bits)
{
Bits+=InBit;
InAddr+=Bits>>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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -1,92 +1,161 @@
#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_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 UNP_VER 36
#define VER_PACK 29
#define VER_PACK5 0
#define VER_UNPACK 29
#define VER_UNPACK5 0
#define MHD_VOLUME 0x0001
#define MHD_COMMENT 0x0002
#define MHD_SOLID 0x0008
#define MHD_PASSWORD 0x0080
#define MHD_VOLUME 0x0001U
#define LHD_SPLIT_BEFORE 0x0001
#define LHD_SPLIT_AFTER 0x0002
#define LHD_PASSWORD 0x0004
#define LHD_COMMENT 0x0008
#define LHD_SOLID 0x0010
// Old style main archive comment embed into main archive header. Must not
// be used in new archives anymore.
#define MHD_COMMENT 0x0002U
#define LHD_WINDOWMASK 0x00e0
#define LHD_DIRECTORY 0x00e0
#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_LARGE 0x0100
#define LHD_UNICODE 0x0200
#define LHD_SALT 0x0400
#define LHD_EXTTIME 0x1000
#define LHD_SPLIT_BEFORE 0x0001U
#define LHD_SPLIT_AFTER 0x0002U
#define LHD_PASSWORD 0x0004U
#define LONG_BLOCK 0x8000
// 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 {
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
// 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
};
struct OldMainHeader
{
byte Mark[4];
ushort HeadSize;
byte Flags;
// Unified archive format independent implementation.
enum HOST_SYSTEM_TYPE {
HSYS_WINDOWS, HSYS_UNIX, HSYS_UNKNOWN
};
struct OldFileHeader
{
uint PackSize;
uint UnpSize;
ushort FileCRC;
ushort HeadSize;
uint FileTime;
byte FileAttr;
byte Flags;
byte UnpVer;
byte NameSize;
byte Method;
// 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[7];
byte Mark[8];
// Following fields are virtual and not present in real blocks.
uint HeadSize;
};
struct BaseBlock
{
ushort HeadCRC;
HEADER_TYPE HeadType;//byte
ushort Flags;
ushort HeadSize;
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
{
union {
uint DataSize;
uint PackSize;
};
};
@ -94,46 +163,139 @@ 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();
};
#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];
wchar FileName[NM];
Array<byte> SubData;
RarTime mtime;
/* dummy */
Int64 FullPackSize;
Int64 FullUnpSize;
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 3.x uses FileHeader with NEWSUB_HEAD HeadType for subblocks.
// 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;
@ -142,4 +304,59 @@ struct ProtectHeader:BlockHeader
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

View File

@ -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

View File

@ -10,13 +10,15 @@
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.
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.

View File

@ -1,5 +1,3 @@
// #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, *
@ -7,10 +5,17 @@
* Contents: model description and encoding/decoding routines *
****************************************************************************/
inline PPM_CONTEXT* PPM_CONTEXT::createChild(ModelPPM *Model,STATE* pStats,
STATE& FirstState)
static const int MAX_O=64; /* maximum allowed model order */
const uint TOP=1 << 24, BOT=1 << 15;
template <class T>
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)
{
PPM_CONTEXT* pc = (PPM_CONTEXT*) Model->SubAlloc.AllocContext();
RARPPM_CONTEXT* pc = (RARPPM_CONTEXT*) Model->SubAlloc.AllocContext();
if ( pc )
{
pc->NumStats=1;
@ -36,11 +41,11 @@ void ModelPPM::RestartModelRare()
memset(CharMask,0,sizeof(CharMask));
SubAlloc.InitSubAllocator();
InitRL=-(MaxOrder < 12 ? MaxOrder:12)-1;
MinContext = MaxContext = (PPM_CONTEXT*) SubAlloc.AllocContext();
MinContext = MaxContext = (RARPPM_CONTEXT*) SubAlloc.AllocContext();
MinContext->Suffix=NULL;
OrderFall=MaxOrder;
MinContext->U.SummFreq=(MinContext->NumStats=256)+1;
FoundState=MinContext->U.Stats=(STATE*)SubAlloc.AllocUnits(256/2);
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;
@ -107,10 +112,10 @@ void ModelPPM::StartModelRare(int MaxOrder)
}
void PPM_CONTEXT::rescale(ModelPPM *Model)
void RARPPM_CONTEXT::rescale(ModelPPM *Model)
{
int OldNS=NumStats, i=NumStats-1, Adder, EscFreq;
STATE* p1, * p;
RARPPM_STATE* p1, * p;
for (p=Model->FoundState;p != U.Stats;p--)
_PPMD_SWAP(p[0],p[-1]);
U.Stats->Freq += 4;
@ -124,7 +129,7 @@ void PPM_CONTEXT::rescale(ModelPPM *Model)
U.SummFreq += (p->Freq=(p->Freq+Adder) >> 1);
if (p[0].Freq > p[-1].Freq)
{
STATE tmp=*(p1=p);
RARPPM_STATE tmp=*(p1=p);
do
{
p1[0]=p1[-1];
@ -141,7 +146,7 @@ void PPM_CONTEXT::rescale(ModelPPM *Model)
EscFreq += i;
if ((NumStats -= i) == 1)
{
STATE tmp=*U.Stats;
RARPPM_STATE tmp=*U.Stats;
do
{
tmp.Freq-=(tmp.Freq >> 1);
@ -154,17 +159,19 @@ void PPM_CONTEXT::rescale(ModelPPM *Model)
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);
U.Stats = (RARPPM_STATE*) Model->SubAlloc.ShrinkUnits(U.Stats,n0,n1);
Model->FoundState=U.Stats;
}
inline PPM_CONTEXT* ModelPPM::CreateSuccessors(bool Skip,STATE* p1)
inline RARPPM_CONTEXT* ModelPPM::CreateSuccessors(bool Skip,RARPPM_STATE* p1)
{
// (removed conditional static)
STATE UpState;
PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor;
STATE * p, * ps[MAX_O], ** pps=ps;
#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;
@ -202,7 +209,7 @@ NO_LOOP:
if (pps == ps)
return pc;
UpState.Symbol=*(byte*) UpBranch;
UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1);
UpState.Successor=(RARPPM_CONTEXT*) (((byte*) UpBranch)+1);
if (pc->NumStats != 1)
{
if ((byte*) pc <= SubAlloc.pText)
@ -230,8 +237,8 @@ NO_LOOP:
inline void ModelPPM::UpdateModel()
{
STATE fs = *FoundState, *p = NULL;
PPM_CONTEXT *pc, *Successor;
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)
{
@ -263,19 +270,19 @@ inline void ModelPPM::UpdateModel()
}
if ( !OrderFall )
{
MinContext=MaxContext=FoundState->Successor=CreateSuccessors(true,p);
MinContext=MaxContext=FoundState->Successor=CreateSuccessors(TRUE,p);
if ( !MinContext )
goto RESTART_MODEL;
return;
}
*SubAlloc.pText++ = fs.Symbol;
Successor = (PPM_CONTEXT*) SubAlloc.pText;
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)
(fs.Successor=CreateSuccessors(FALSE,p)) == NULL)
goto RESTART_MODEL;
if ( !--OrderFall )
{
@ -295,7 +302,7 @@ inline void ModelPPM::UpdateModel()
{
if ((ns1 & 1) == 0)
{
pc->U.Stats=(STATE*) SubAlloc.ExpandUnits(pc->U.Stats,ns1 >> 1);
pc->U.Stats=(RARPPM_STATE*) SubAlloc.ExpandUnits(pc->U.Stats,ns1 >> 1);
if ( !pc->U.Stats )
goto RESTART_MODEL;
}
@ -303,7 +310,7 @@ inline void ModelPPM::UpdateModel()
}
else
{
p=(STATE*) SubAlloc.AllocUnits(1);
p=(RARPPM_STATE*) SubAlloc.AllocUnits(1);
if ( !p )
goto RESTART_MODEL;
*p=pc->OneState;
@ -346,9 +353,9 @@ static const byte ExpEscape[16]={ 25,14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2,
inline void PPM_CONTEXT::decodeBinSymbol(ModelPPM *Model)
inline void RARPPM_CONTEXT::decodeBinSymbol(ModelPPM *Model)
{
STATE& rs=OneState;
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]+
@ -360,14 +367,14 @@ inline void PPM_CONTEXT::decodeBinSymbol(ModelPPM *Model)
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));
bs = GET_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));
bs = GET_SHORT16(bs-GET_MEAN(bs,PERIOD_BITS,2));
Model->Coder.SubRange.HighCount=BIN_SCALE;
Model->InitEsc=ExpEscape[bs >> 10];
Model->NumMasked=1;
@ -378,7 +385,7 @@ inline void PPM_CONTEXT::decodeBinSymbol(ModelPPM *Model)
}
inline void PPM_CONTEXT::update1(ModelPPM *Model,STATE* p)
inline void RARPPM_CONTEXT::update1(ModelPPM *Model,RARPPM_STATE* p)
{
(Model->FoundState=p)->Freq += 4;
U.SummFreq += 4;
@ -394,13 +401,13 @@ inline void PPM_CONTEXT::update1(ModelPPM *Model,STATE* p)
inline bool PPM_CONTEXT::decodeSymbol1(ModelPPM *Model)
inline bool RARPPM_CONTEXT::decodeSymbol1(ModelPPM *Model)
{
Model->Coder.SubRange.scale=U.SummFreq;
STATE* p=U.Stats;
RARPPM_STATE* p=U.Stats;
int i, HiCnt;
int count=Model->Coder.GetCurrentCount();
if (count>=Model->Coder.SubRange.scale)
if (count>=(int)Model->Coder.SubRange.scale)
return(false);
if (count < (HiCnt=p->Freq))
{
@ -439,7 +446,7 @@ inline bool PPM_CONTEXT::decodeSymbol1(ModelPPM *Model)
}
inline void PPM_CONTEXT::update2(ModelPPM *Model,STATE* p)
inline void RARPPM_CONTEXT::update2(ModelPPM *Model,RARPPM_STATE* p)
{
(Model->FoundState=p)->Freq += 4;
U.SummFreq += 4;
@ -450,9 +457,9 @@ inline void PPM_CONTEXT::update2(ModelPPM *Model,STATE* p)
}
inline SEE2_CONTEXT* PPM_CONTEXT::makeEscFreq2(ModelPPM *Model,int Diff)
inline RARPPM_SEE2_CONTEXT* RARPPM_CONTEXT::makeEscFreq2(ModelPPM *Model,int Diff)
{
SEE2_CONTEXT* psee2c;
RARPPM_SEE2_CONTEXT* psee2c;
if (NumStats != 256)
{
psee2c=Model->SEE2Cont[Model->NS2Indx[Diff-1]]+
@ -472,11 +479,11 @@ inline SEE2_CONTEXT* PPM_CONTEXT::makeEscFreq2(ModelPPM *Model,int Diff)
inline bool PPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
inline bool RARPPM_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;
RARPPM_SEE2_CONTEXT* psee2c=makeEscFreq2(Model,i);
RARPPM_STATE* ps[256], ** pps=ps, * p=U.Stats-1;
HiCnt=0;
do
{
@ -489,7 +496,7 @@ inline bool PPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
} while ( --i );
Model->Coder.SubRange.scale += HiCnt;
count=Model->Coder.GetCurrentCount();
if (count>=Model->Coder.SubRange.scale)
if (count>=(int)Model->Coder.SubRange.scale)
return(false);
p=*(pps=ps);
if (count < HiCnt)
@ -540,10 +547,9 @@ void ModelPPM::CleanUp()
bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar)
{
int MaxOrder=UnpackRead->GetChar();
bool Reset=MaxOrder & 0x20;
bool Reset=(MaxOrder & 0x20)!=0;
int MaxMB;
MaxMB = 0; // avoids warning of being uninitialized
if (Reset)
MaxMB=UnpackRead->GetChar();
else
@ -609,4 +615,3 @@ int ModelPPM::DecodeChar()
ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
return(Symbol);
}
#endif

View File

@ -4,16 +4,17 @@
#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
#ifdef ALLOW_MISALIGNED
#pragma pack(1)
#endif
struct SEE2_CONTEXT
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;
@ -24,7 +25,7 @@ struct SEE2_CONTEXT
}
uint getMean()
{
uint RetVal=SHORT16(Summ) >> Shift;
uint RetVal=GET_SHORT16(Summ) >> Shift;
Summ -= RetVal;
return RetVal+(RetVal == 0);
}
@ -40,45 +41,47 @@ struct SEE2_CONTEXT
class ModelPPM;
struct PPM_CONTEXT;
struct RARPPM_CONTEXT;
struct STATE
struct RARPPM_STATE
{
byte Symbol;
byte Freq;
PPM_CONTEXT* Successor;
RARPPM_CONTEXT* Successor;
};
struct RARPPM_CONTEXT : RARPPM_DEF
{
ushort NumStats;
struct FreqData
{
ushort SummFreq;
STATE _PACK_ATTR * Stats;
RARPPM_STATE RARPPM_PACK_ATTR * Stats;
};
struct PPM_CONTEXT
{
ushort NumStats;
union
{
FreqData U;
STATE OneState;
RARPPM_STATE OneState;
};
PPM_CONTEXT* Suffix;
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,STATE* p); // CD suffix
inline void update2(ModelPPM *Model,STATE* p); // BCDE successor
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 PPM_CONTEXT* createChild(ModelPPM *Model,STATE* pStats,STATE& FirstState);
inline SEE2_CONTEXT* makeEscFreq2(ModelPPM *Model,int Diff);
inline RARPPM_CONTEXT* createChild(ModelPPM *Model,RARPPM_STATE* pStats,RARPPM_STATE& FirstState);
inline RARPPM_SEE2_CONTEXT* makeEscFreq2(ModelPPM *Model,int Diff);
};
#ifndef STRICT_ALIGNMENT_REQUIRED
#ifdef ALLOW_MISALIGNED
#ifdef _AIX
#pragma pack(pop)
#else
@ -86,28 +89,15 @@ struct PPM_CONTEXT
#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 <class T>
inline void _PPMD_SWAP(T& t1,T& t2) { T tmp=t1; t1=t2; t2=tmp; }
class ModelPPM
class ModelPPM : RARPPM_DEF
{
private:
friend struct PPM_CONTEXT;
friend struct RARPPM_CONTEXT;
/*_PACK_ATTR*/ SEE2_CONTEXT SEE2Cont[25][16], DummySEE2Cont;
RARPPM_SEE2_CONTEXT SEE2Cont[25][16], DummySEE2Cont;
struct PPM_CONTEXT *MinContext, *MedContext, *MaxContext;
STATE* FoundState; // found next state transition
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;
@ -118,11 +108,10 @@ class ModelPPM
void RestartModelRare();
void StartModelRare(int MaxOrder);
inline PPM_CONTEXT* CreateSuccessors(bool Skip,STATE* p1);
inline RARPPM_CONTEXT* CreateSuccessors(bool Skip,RARPPM_STATE* p1);
inline void UpdateModel();
inline void ClearMask();
friend class Unpack;
public:
ModelPPM();
void CleanUp(); // reset PPM variables after data error

View File

@ -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);
}

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
@ -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()
{

View File

@ -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)
#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)
#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))
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<<Value2);
uint Result=GET_UINT32(Value1<<Value2);
Flags=(Result==0 ? VM_FZ:(Result&VM_FS))|((Value1<<(Value2-1))&0x80000000 ? VM_FC:0);
SET_VALUE(Cmd->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=(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;
@ -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;I<CodeSize;I++)
for (uint I=1;I<CodeSize;I++)
XorSum^=Code[I];
}
faddbits(8);
@ -573,6 +579,7 @@ void RarVM::Prepare(byte *Code,int CodeSize,VM_PreparedProgram *Prg)
CurCmd->Op2.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;InAddr<CodeSize && I<DataSize;I++)
uint DataSize=ReadData(*this)+1;
for (uint I=0;(uint)InAddr<CodeSize && I<DataSize;I++)
{
Prg->StaticData.Add(1);
Prg->StaticData[I]=fgetbits()>>8;
@ -592,7 +599,7 @@ void RarVM::Prepare(byte *Code,int CodeSize,VM_PreparedProgram *Prg)
}
}
while (InAddr<CodeSize)
while ((uint)InAddr<CodeSize)
{
Prg->Cmd.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 (Pos<VM_MEMSIZE && Data!=Mem+Pos)
memmove(Mem+Pos,Data,Min(DataSize,VM_MEMSIZE-Pos));
@ -784,9 +791,9 @@ void RarVM::SetMemory(unsigned int Pos,byte *Data,unsigned int DataSize)
void RarVM::Optimize(VM_PreparedProgram *Prg)
{
VM_PreparedCommand *Code=&Prg->Cmd[0];
int CodeSize=Prg->CmdCount;
uint CodeSize=Prg->CmdCount;
for (int I=0;I<CodeSize;I++)
for (uint I=0;I<CodeSize;I++)
{
VM_PreparedCommand *Cmd=Code+I;
@ -800,8 +807,6 @@ void RarVM::Optimize(VM_PreparedProgram *Prg)
case VM_CMP:
Cmd->OpCode=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;J<CodeSize;J++)
for (uint J=I+1;J<CodeSize;J++)
{
int Flags=VM_CmdFlags[Code[J].OpCode];
if (Flags & (VMCF_JUMP|VMCF_PROC|VMCF_USEFLAGS))
@ -845,8 +850,6 @@ void RarVM::Optimize(VM_PreparedProgram *Prg)
case VM_NEG:
Cmd->OpCode=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<sizeof(StdList)/sizeof(StdList[0]);I++)
uint CodeCRC=CRC32(0xffffffff,Code,CodeSize)^0xffffffff;
for (uint I=0;I<ASIZE(StdList);I++)
if (StdList[I].CRC==CodeCRC && StdList[I].Length==CodeSize)
return(StdList[I].Type);
return(VMSF_NONE);
@ -898,7 +899,7 @@ void RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType)
int DataSize=R[4];
uint FileOffset=R[6];
if (DataSize>=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<Channels;CurChannel++)
{
unsigned int PrevByte=0;
uint PrevByte=0;
for (int I=CurChannel;I<DataSize;I+=Channels)
{
unsigned int Predicted;
uint Predicted;
int UpperPos=I-Width;
if (UpperPos>=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<Channels;CurChannel++)
{
unsigned int PrevByte=0,PrevDelta=0,Dif[7];
uint PrevByte=0,PrevDelta=0,Dif[7];
int D1=0,D2=0,D3;
int K1=0,K2=0,K3=0;
memset(Dif,0,sizeof(Dif));
@ -1061,10 +1062,10 @@ void RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType)
D2=PrevDelta-D1;
D1=PrevDelta;
unsigned int Predicted=8*PrevByte+K1*D1+K2*D2+K3*D3;
uint Predicted=8*PrevByte+K1*D1+K2*D2+K3*D3;
Predicted=(Predicted>>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<sizeof(Dif)/sizeof(Dif[0]);J++)
{
@ -1108,33 +1109,15 @@ void RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType)
}
}
break;
case VMSF_UPCASE:
{
int DataSize=R[4],SrcPos=0,DestPos=DataSize;
if (DataSize>=VM_GLOBALMEMADDR/2)
break;
while (SrcPos<DataSize)
{
byte CurByte=Mem[SrcPos++];
if (CurByte==2 && (CurByte=Mem[SrcPos++])!=2)
CurByte-=32;
Mem[DestPos++]=CurByte;
}
SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x1c],DestPos-DataSize);
SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20],DataSize);
}
break;
default: break;
}
}
unsigned int RarVM::FilterItanium_GetBits(byte *Data,int BitPos,int BitCount)
uint RarVM::FilterItanium_GetBits(byte *Data,int BitPos,int BitCount)
{
int InAddr=BitPos/8;
int InBit=BitPos&7;
unsigned int BitField=(uint)Data[InAddr++];
uint BitField=(uint)Data[InAddr++];
BitField|=(uint)Data[InAddr++] << 8;
BitField|=(uint)Data[InAddr++] << 16;
BitField|=(uint)Data[InAddr] << 24;
@ -1143,17 +1126,16 @@ unsigned int RarVM::FilterItanium_GetBits(byte *Data,int BitPos,int BitCount)
}
void RarVM::FilterItanium_SetBits(byte *Data,unsigned int BitField,int BitPos,
int BitCount)
void RarVM::FilterItanium_SetBits(byte *Data,uint BitField,int BitPos,int BitCount)
{
int InAddr=BitPos/8;
int InBit=BitPos&7;
unsigned int AndMask=0xffffffff>>(32-BitCount);
uint AndMask=0xffffffff>>(32-BitCount);
AndMask=~(AndMask<<InBit);
BitField<<=InBit;
for (int I=0;I<4;I++)
for (uint I=0;I<4;I++)
{
Data[InAddr+I]&=AndMask;
Data[InAddr+I]|=BitField;

View File

@ -34,7 +34,7 @@ enum VM_Commands
enum VM_StandardFilters {
VMSF_NONE, VMSF_E8, VMSF_E8E9, VMSF_ITANIUM, VMSF_RGB, VMSF_AUDIO,
VMSF_DELTA, VMSF_UPCASE
VMSF_DELTA
};
enum VM_Flags {VM_FC=1,VM_FZ=2,VM_FS=0x80000000};
@ -59,8 +59,12 @@ struct VM_PreparedCommand
struct VM_PreparedProgram
{
VM_PreparedProgram( Rar_Error_Handler* eh ) : Cmd( eh ), GlobalData( eh ), StaticData( eh )
{AltCmd=NULL;}
VM_PreparedProgram()
{
AltCmd=NULL;
FilteredDataSize=0;
CmdCount=0;
}
Array<VM_PreparedCommand> 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);
};

View File

@ -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);
ReadSize=SrcFile->Read(&Data[DataSize],Size);
DataSize+=ReadSize;
}
return ReadSize;
}
void RawRead::Get(byte &Field)
void RawRead::Read(byte *SrcData,size_t Size)
{
if (ReadPos<DataSize)
if (Size!=0)
{
Field=Data[ReadPos];
ReadPos++;
Data.Add(Size);
memcpy(&Data[DataSize],SrcData,Size);
DataSize+=Size;
}
else
Field=0;
}
void RawRead::Get(ushort &Field)
byte RawRead::Get1()
{
return ReadPos<DataSize ? Data[ReadPos++]:0;
}
ushort RawRead::Get2()
{
if (ReadPos+1<DataSize)
{
Field=Data[ReadPos]+(Data[ReadPos+1]<<8);
ushort Result=Data[ReadPos]+(Data[ReadPos+1]<<8);
ReadPos+=2;
return Result;
}
else
Field=0;
return 0;
}
void RawRead::Get(uint &Field)
uint RawRead::Get4()
{
if (ReadPos+3<DataSize)
{
Field=Data[ReadPos]+(Data[ReadPos+1]<<8)+(Data[ReadPos+2]<<16)+
uint Result=Data[ReadPos]+(Data[ReadPos+1]<<8)+(Data[ReadPos+2]<<16)+
(Data[ReadPos+3]<<24);
ReadPos+=4;
return Result;
}
return 0;
}
uint64 RawRead::Get8()
{
uint Low=Get4(),High=Get4();
return int32to64(High,Low);
}
uint64 RawRead::GetV()
{
uint64 Result=0;
for (uint Shift=0;ReadPos<DataSize;Shift+=7)
{
byte CurByte=Data[ReadPos++];
Result+=uint64(CurByte & 0x7f)<<Shift;
if ((CurByte & 0x80)==0)
return Result; // Decoded successfully.
}
return 0; // Out of buffer border.
}
// Return a number of bytes in current variable length integer.
uint RawRead::GetVSize(size_t Pos)
{
for (size_t CurPos=Pos;CurPos<DataSize;CurPos++)
if ((Data[CurPos] & 0x80)==0)
return int(CurPos-Pos+1);
return 0; // Buffer overflow.
}
size_t RawRead::GetB(void *Field,size_t Size)
{
byte *F=(byte *)Field;
size_t CopySize=Min(DataSize-ReadPos,Size);
if (CopySize>0)
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<DataSize)
{
RawToWide(&Data[ReadPos],Field,Size);
ReadPos+=sizeof(wchar)*Size;
}
else
Field=0;
memset(Field,0,sizeof(wchar)*Size);
}
void RawRead::Get(byte *Field,int Size)
uint RawRead::GetCRC15(bool ProcessedOnly) // RAR 1.5 block CRC.
{
if (ReadPos+Size-1<DataSize)
if (DataSize<=2)
return 0;
uint HeaderCRC=CRC32(0xffffffff,&Data[2],(ProcessedOnly ? ReadPos:DataSize)-2);
return ~HeaderCRC & 0xffff;
}
uint RawRead::GetCRC50() // RAR 5.0 block CRC.
{
memcpy(Field,&Data[ReadPos],Size);
ReadPos+=Size;
}
else
memset(Field,0,Size);
if (DataSize<=4)
return 0xffffffff;
return CRC32(0xffffffff,&Data[4],DataSize-4) ^ 0xffffffff;
}
uint RawRead::GetCRC(bool ProcessedOnly)
// Read vint from arbitrary byte array.
uint64 RawGetV(const byte *Data,uint &ReadPos,uint DataSize,bool &Overflow)
{
return(DataSize>2 ? CRC(0xffffffff,&Data[2],(ProcessedOnly ? ReadPos:DataSize)-2):0xffffffff);
Overflow=false;
uint64 Result=0;
for (uint Shift=0;ReadPos<DataSize;Shift+=7)
{
byte CurByte=Data[ReadPos++];
Result+=uint64(CurByte & 0x7f)<<Shift;
if ((CurByte & 0x80)==0)
return Result; // Decoded successfully.
}
Overflow=true;
return 0; // Out of buffer border.
}

View File

@ -6,20 +6,93 @@ class RawRead
private:
Array<byte> 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

View File

@ -4,12 +4,13 @@
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,
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.
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
@ -17,16 +18,10 @@
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.
STRICT_ALIGNMENT_REQUIRED in os.h.
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.
UnRAR.vcproj and UnRARDll.vcproj are projects for Microsoft Visual C++.
UnRARDll.vcproj lets to build unrar.dll library.
2. Unrar binaries
@ -38,16 +33,8 @@
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
This source includes parts of code written by other authors.
Please see acknow.txt file for details.
4. Legal stuff

View File

@ -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<size;i++)
d[i]=0;
#endif
}

View File

@ -0,0 +1,411 @@
#include "rar.hpp"
#include <ctype.h>
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<BinSize;I++)
{
uint High=Bin[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 && A<HexSize-2) // Need space for 2 chars and final zero.
{
HexA[A++]=(char)HighHex;
HexA[A++]=(char)LowHex;
}
if (HexW!=NULL && W<HexSize-2) // Need space for 2 chars and final zero.
{
HexW[W++]=HighHex;
HexW[W++]=LowHex;
}
}
if (HexA!=NULL && HexSize>0)
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<Pos;I++)
Str[I]=NumStr[Pos-I-1];
Str[Pos]=0;
}
void itoa(int64 n,wchar *Str)
{
wchar NumStr[50];
size_t Pos=0;
do
{
NumStr[Pos++]=wchar(n%10)+'0';
n=n/10;
} while (n!=0);
for (size_t I=0;I<Pos;I++)
Str[I]=NumStr[Pos-I-1];
Str[Pos]=0;
}
const wchar* GetWide(const char *Src)
{
const size_t MaxLength=NM;
static wchar StrTable[4][MaxLength];
static uint StrNum=0;
if (++StrNum >= 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 && ParamSize<MaxSize-1)
Param[ParamSize++]='\"';
CmdLine++;
}
else
Quote=!Quote;
}
else
if (Param!=NULL && ParamSize<MaxSize-1)
Param[ParamSize++]=*CmdLine;
CmdLine++;
}
if (Param!=NULL)
Param[ParamSize]=0;
return CmdLine;
}
#ifndef SILENT
// For compatibility with existing translations we use %s to print Unicode
// strings in format strings and convert them to %ls here. %s could work
// without such conversion in Windows, but not in Unix wprintf.
void PrintfPrepareFmt(const wchar *Org,wchar *Cvt,size_t MaxSize)
{
uint Src=0,Dest=0;
while (Org[Src]!=0 && Dest<MaxSize-1)
{
if (Org[Src]=='%' && (Src==0 || Org[Src-1]!='%'))
{
uint SPos=Src+1;
// Skipping a possible width specifier like %-50s.
while (IsDigit(Org[SPos]) || Org[SPos]=='-')
SPos++;
if (Org[SPos]=='s' && Dest<MaxSize-(SPos-Src+1))
{
while (Src<SPos)
Cvt[Dest++]=Org[Src++];
Cvt[Dest++]='l';
}
}
#ifdef _WIN_ALL
// Convert \n to \r\n in Windows. Important when writing to log,
// so other tools like Notebook can view resulting log properly.
if (Org[Src]=='\n' && (Src==0 || Org[Src-1]!='\r'))
Cvt[Dest++]='\r';
#endif
Cvt[Dest++]=Org[Src++];
}
Cvt[Dest]=0;
}
#endif

View File

@ -0,0 +1,45 @@
#ifndef _RAR_STRFN_
#define _RAR_STRFN_
const char* NullToEmpty(const char *Str);
const wchar* NullToEmpty(const wchar *Str);
void IntToExt(const char *Src,char *Dest,size_t DestSize);
int stricomp(const char *s1,const char *s2);
int strnicomp(const char *s1,const char *s2,size_t n);
wchar* RemoveEOL(wchar *Str);
wchar* RemoveLF(wchar *Str);
unsigned char loctolower(unsigned char ch);
unsigned char loctoupper(unsigned char ch);
char* strncpyz(char *dest, const char *src, size_t maxlen);
wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen);
char* strncatz(char* dest, const char* src, size_t maxlen);
wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen);
unsigned char etoupper(unsigned char ch);
wchar etoupperw(wchar ch);
bool IsDigit(int ch);
bool IsSpace(int ch);
bool IsAlpha(int ch);
void BinToHex(const byte *Bin,size_t BinSize,char *Hex,wchar *HexW,size_t HexSize);
#ifndef SFX_MODULE
uint GetDigits(uint Number);
#endif
bool LowAscii(const char *Str);
bool LowAscii(const wchar *Str);
int wcsicompc(const wchar *Str1,const wchar *Str2);
void itoa(int64 n,char *Str);
void itoa(int64 n,wchar *Str);
const wchar* GetWide(const char *Src);
const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize);
#ifndef SILENT
void PrintfPrepareFmt(const wchar *Org,wchar *Cvt,size_t MaxSize);
#endif
#endif

View File

@ -7,6 +7,9 @@
// #included by unpack.cpp
#ifdef RAR_COMMON_HPP
static const uint UNIT_SIZE=Max(sizeof(RARPPM_CONTEXT),sizeof(RARPPM_MEM_BLK));
static const uint FIXED_UNIT_SIZE=12;
SubAllocator::SubAllocator()
{
Clean();
@ -41,12 +44,12 @@ inline uint SubAllocator::U2B(int NU)
/*
calculate RAR_MEM_BLK + Items address. Real RAR_MEM_BLK size must be
equal to UNIT_SIZE, so we cannot just add Items to RAR_MEM_BLK address
calculate RARPPM_MEM_BLK + Items address. Real RARPPM_MEM_BLK size must be
equal to UNIT_SIZE, so we cannot just add Items to RARPPM_MEM_BLK address
*/
inline RAR_MEM_BLK* SubAllocator::MBPtr(RAR_MEM_BLK *BasePtr,int Items)
inline RARPPM_MEM_BLK* SubAllocator::MBPtr(RARPPM_MEM_BLK *BasePtr,int Items)
{
return((RAR_MEM_BLK*)( ((byte *)(BasePtr))+U2B(Items) ));
return((RARPPM_MEM_BLK*)( ((byte *)(BasePtr))+U2B(Items) ));
}
@ -102,9 +105,9 @@ void SubAllocator::InitSubAllocator()
int i, k;
memset(FreeList,0,sizeof(FreeList));
pText=HeapStart;
uint Size2=(uint)(FIXED_UNIT_SIZE*(SubAllocatorSize/8/FIXED_UNIT_SIZE*7));
uint Size2=FIXED_UNIT_SIZE*(SubAllocatorSize/8/FIXED_UNIT_SIZE*7);
uint RealSize2=Size2/FIXED_UNIT_SIZE*UNIT_SIZE;
uint Size1=(uint)(SubAllocatorSize-Size2);
uint Size1=SubAllocatorSize-Size2;
uint RealSize1=Size1/FIXED_UNIT_SIZE*UNIT_SIZE+Size1%FIXED_UNIT_SIZE;
#ifdef STRICT_ALIGNMENT_REQUIRED
if (Size1%FIXED_UNIT_SIZE!=0)
@ -132,14 +135,14 @@ void SubAllocator::InitSubAllocator()
inline void SubAllocator::GlueFreeBlocks()
{
RAR_MEM_BLK s0, * p, * p1;
RARPPM_MEM_BLK s0, * p, * p1;
int i, k, sz;
if (LoUnit != HiUnit)
*LoUnit=0;
for (i=0, s0.next=s0.prev=&s0;i < N_INDEXES;i++)
while ( FreeList[i].next )
{
p=(RAR_MEM_BLK*)RemoveNode(i);
p=(RARPPM_MEM_BLK*)RemoveNode(i);
p->insertAt(&s0);
p->Stamp=0xFFFF;
p->NU=Indx2Units[i];

View File

@ -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;

View File

@ -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;I<lt->Month && 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.dwLowDateTime<lt->Reminder)
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(&lt);
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(&lt);
}
#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<ASIZE(Field))
Field[FieldPos]=Field[FieldPos]*10+*TimeText-'0';
DigitCount++;
}
RarLocalTime lt;
lt.Second=Field[5];
lt.Minute=Field[4];
lt.Hour=Field[3];
lt.Day=Field[2]==0 ? 1:Field[2];
lt.Month=Field[1]==0 ? 1:Field[1];
lt.Year=Field[0];
lt.Reminder=0;
SetLocal(&lt);
}
#endif
#ifndef SFX_MODULE
void RarTime::SetAgeText(const wchar *TimeText)
{
uint Seconds=0,Value=0;
for (int I=0;TimeText[I]!=0;I++)
{
int Ch=TimeText[I];
if (IsDigit(Ch))
Value=Value*10+Ch-'0';
else
{
switch(etoupper(Ch))
{
case 'D':
Seconds+=Value*24*3600;
break;
case 'H':
Seconds+=Value*3600;
break;
case 'M':
Seconds+=Value*60;
break;
case 'S':
Seconds+=Value;
break;
}
Value=0;
}
}
SetCurrentTime();
SetRaw(itime-uint64(Seconds)*10000000);
}
#endif
void RarTime::SetCurrentTime()
{
#ifdef _WIN_ALL
FILETIME ft;
SYSTEMTIME st;
GetSystemTime(&st);
SystemTimeToFileTime(&st,&ft);
*this=ft;
#else
time_t st;
time(&st);
*this=st;
#endif
}
bool IsLeapYear(int Year)
{
return (Year&3)==0 && (Year%100!=0 || Year%400==0);
}

View File

@ -0,0 +1,56 @@
#ifndef _RAR_TIMEFN_
#define _RAR_TIMEFN_
#include <time.h>
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<rt.itime;}
bool operator <= (RarTime &rt) {return itime<rt.itime || itime==rt.itime;}
bool operator > (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

View File

@ -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)<NM)
{
/* Workaround for strange Linux Unicode functions bug.
Some of wcstombs and mbstowcs implementations in some situations
(we are yet to find out what it depends on) can return an empty
string and success code if buffer size value is too large.
*/
return(CharToWide(Src,Dest,NM));
}
#else
// TODO: convert to UTF-8? Would need conversion routine. Ugh.
for (int I=0;I<DestSize;I++)
{
Dest[I]=(wchar)Src[I];
if (Src[I]==0)
break;
}
#endif
#endif
#endif
return(RetCode);
}
bool WideToChar(const wchar *Src,char *Dest,int DestSize)
{
bool RetCode=true;
@ -94,6 +136,15 @@ void UtfToWide(const char *Src,wchar *Dest,int DestSize)
}
wchar* RawToWide(const byte *Src,wchar *Dest,size_t DestSize)
{
for (size_t I=0;I<DestSize;I++)
if ((Dest[I]=Src[I*2]+(Src[I*2+1]<<8))==0)
break;
return Dest;
}
// strfn.cpp
void ExtToInt(const char *Src,char *Dest)
{
@ -104,3 +155,44 @@ void ExtToInt(const char *Src,char *Dest)
strcpy(Dest,Src);
#endif
}
size_t my_wcslen(const wchar *a)
{
size_t I;
for (I=0; a[I]; ++I);
return I;
}
int my_wcsncmp(const wchar *a, const wchar *b, size_t Max)
{
for (size_t I=0; I<Max && (a[I] || b[I]); ++I)
{
if (a[I] != b[I])
return a[I] - b[I];
}
return 0;
}
int my_wcscmp(const wchar *a, const wchar *b)
{
return my_wcsncmp(a, b, ~0UL);
}
void my_wcsncpy(wchar *Dest, const wchar *Src, size_t DestSize)
{
size_t I;
for (I=0; I<DestSize && Src[I]; ++I)
Dest[I] = Src[I];
if (I<DestSize)
Dest[I] = 0;
}
void my_wcsncat(wchar *Dest, const wchar *Src, size_t DestSize)
{
size_t I, J;
for (I=0; I<DestSize && Dest[I]; ++I);
for (J=0; I<DestSize && Src[J]; ++I, ++J)
Dest[I] = Src[J];
if (I<DestSize)
Dest[I] = 0;
}

View File

@ -1,10 +1,18 @@
#ifndef _RAR_UNICODE_
#define _RAR_UNICODE_
bool CharToWide(const char *Src,wchar *Dest,int DestSize);
bool WideToChar(const wchar *Src,char *Dest,int DestSize=0x1000000);
void UtfToWide(const char *Src,wchar *Dest,int DestSize);
wchar* RawToWide(const byte *Src,wchar *Dest,size_t DestSize);
// strfn.cpp
void ExtToInt(const char *Src,char *Dest);
size_t my_wcslen(const wchar *a);
int my_wcscmp(const wchar *a, const wchar *b);
int my_wcsncmp(const wchar *a, const wchar *b, size_t DestSize);
void my_wcsncpy(wchar *Dest, const wchar *Src, size_t DestSize);
void my_wcsncat(wchar *Dest, const wchar *Src, size_t DestSize);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,58 +1,145 @@
#ifndef _RAR_UNPACK_
#define _RAR_UNPACK_
enum BLOCK_TYPES {BLOCK_LZ,BLOCK_PPM};
// Maximum allowed number of compressed bits processed in quick mode.
#define MAX_QUICK_DECODE_BITS 10
struct Decode
// 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
{
unsigned int MaxNum;
unsigned int DecodeLen[16];
unsigned int DecodePos[16];
unsigned int DecodeNum[2];
// 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<<MAX_QUICK_DECODE_BITS];
// Translates compressed bits (up to QuickBits length)
// to position in alphabet in quick mode.
// 'ushort' saves some memory and even provides a little speed gain
// comparting to 'uint' here.
ushort QuickNum[1<<MAX_QUICK_DECODE_BITS];
// Translate the position in code list to position in alphabet.
// We do not allocate it dynamically to avoid performance overhead
// introduced by pointer, so we use the largest possible table size
// as array dimension. Real size of this array is defined in MaxNum.
// We use this array if compressed bit field is too lengthy
// for QuickLen based translation.
// 'ushort' saves some memory and even provides a little speed gain
// comparting to 'uint' here.
ushort DecodeNum[LARGEST_TABLE_SIZE];
};
struct LitDecode
struct UnpackBlockHeader
{
unsigned int MaxNum;
unsigned int DecodeLen[16];
unsigned int DecodePos[16];
unsigned int DecodeNum[NC];
int BlockSize;
int BlockBitSize;
int BlockStart;
int HeaderSize;
bool LastBlockInFile;
bool TablePresent;
};
struct DistDecode
struct UnpackBlockTables
{
unsigned int MaxNum;
unsigned int DecodeLen[16];
unsigned int DecodePos[16];
unsigned int DecodeNum[DC];
DecodeTable LD; // Decode literals.
DecodeTable DD; // Decode distances.
DecodeTable LDD; // Decode lower bits of distances.
DecodeTable RD; // Decode repeating distances.
DecodeTable BD; // Decode bit lengths in Huffman table.
};
struct LowDistDecode
{
unsigned int MaxNum;
unsigned int DecodeLen[16];
unsigned int DecodePos[16];
unsigned int DecodeNum[LDC];
#ifdef RAR_SMP
enum UNP_DEC_TYPE {
UNPDT_LITERAL,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER
};
struct RepDecode
struct UnpackDecodedItem
{
unsigned int MaxNum;
unsigned int DecodeLen[16];
unsigned int DecodePos[16];
unsigned int DecodeNum[RC];
UNP_DEC_TYPE Type;
ushort Length;
union
{
uint Distance;
byte Literal[4];
};
};
struct BitDecode
struct UnpackThreadData
{
unsigned int MaxNum;
unsigned int DecodeLen[16];
unsigned int DecodePos[16];
unsigned int DecodeNum[BC];
Unpack *UnpackPtr;
BitInput Inp;
bool HeaderRead;
UnpackBlockHeader BlockHeader;
bool TableRead;
UnpackBlockTables BlockTables;
int DataSize; // Data left in buffer. Can be less than block size.
bool DamagedData;
bool LargeBlock;
bool NoDataLeft; // 'true' if file is read completely.
bool Incomplete; // Not entire block was processed, need to read more data.
UnpackDecodedItem *Decoded;
uint DecodedSize;
uint DecodedAllocated;
uint ThreadNumber; // For debugging.
UnpackThreadData()
:Inp(false)
{
Decoded=NULL;
}
~UnpackThreadData()
{
if (Decoded!=NULL)
free(Decoded);
}
};
#endif
struct UnpackFilter
: Rar_Allocator
{
byte Type;
uint BlockStart;
uint BlockLength;
byte Channels;
// uint Width;
// byte PosR;
bool NextWindow;
};
struct UnpackFilter30
{
unsigned int BlockStart;
unsigned int BlockLength;
@ -64,19 +151,10 @@ struct UnpackFilter
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
struct AudioVariables // For RAR 2.0 archives only.
{
int K1,K2,K3,K4,K5;
int D1,D2,D3,D4;
@ -85,90 +163,103 @@ struct AudioVariables
unsigned int ByteCount;
int LastChar;
};
/***************************** Unpack v 2.0 *********************************/
// public so operator new/delete will be accessible, argh
class Unpack:public BitInput
// We can use the fragmented dictionary in case heap does not have the single
// large enough memory block. It is slower than normal dictionary.
class FragmentedWindow
{
private:
friend class Pack;
enum {MAX_MEM_BLOCKS=32};
void Unpack29(bool Solid);
void Reset();
byte *Mem[MAX_MEM_BLOCKS];
size_t MemSize[MAX_MEM_BLOCKS];
public:
FragmentedWindow();
~FragmentedWindow();
void Init(size_t WinSize);
byte& operator [](size_t Item);
void CopyString(uint Length,uint Distance,size_t &UnpPtr,size_t MaxWinMask);
void CopyData(byte *Dest,size_t WinPos,size_t Size);
size_t GetBlockSize(size_t StartPos,size_t RequiredSize);
};
class Unpack:PackDef
{
public:
static void init_tables();
private:
void Unpack5(bool Solid);
void Unpack5MT(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);
byte* ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt);
void UnpWriteArea(size_t StartPtr,size_t EndPtr);
void UnpWriteData(byte *Data,size_t Size);
uint SlotToLength(BitInput &Inp,uint Slot);
bool ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header);
bool ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTables &Tables);
void MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size);
uint DecodeNumber(BitInput &Inp,DecodeTable *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 UnpInitData(bool Solid);
void CopyString(uint Length,uint Distance);
uint ReadFilterData(BitInput &Inp);
bool ReadFilter(BitInput &Inp,UnpackFilter &Filter);
bool AddFilter(UnpackFilter &Filter);
bool AddFilter();
void InitFilters();
ComprDataIO *UnpIO;
ModelPPM PPM;
int PPMEscChar;
BitInput Inp;
Array<byte> VMCode; // here to avoid leaks
BitInput Inp; // here to avoid leaks
Array<byte> FilterSrcMemory;
Array<byte> FilterDstMemory;
RarVM VM;
// Filters code, one entry per filter.
Array<UnpackFilter> Filters;
UnpackFilter* LastStackFilter; // avoids leak for stack-based filter
uint OldDist[4],OldDistPtr;
uint LastLength;
/* Filters code, one entry per filter */
Array<UnpackFilter*> Filters;
// LastDist is necessary only for RAR2 and older with circular OldDist
// array. In RAR3 last distance is always stored in OldDist[0].
uint LastDist;
/* Filters stack, several entrances of same filter are possible */
Array<UnpackFilter*> PrgStack;
/* lengths of preceding blocks, one length per filter. Used to reduce
size required to write block length if lengths are repeating */
Array<int> 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;
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;
unsigned char UnpOldTable[HUFF_TABLE_SIZE];
UnpackBlockHeader BlockHeader;
UnpackBlockTables BlockTables;
int UnpBlockType;
size_t WriteBorder;
byte *Window;
bool ExternalWindow;
FragmentedWindow FragWindow;
bool Fragmented;
Int64 DestUnpSize;
int64 DestUnpSize;
enum { Suspended = false }; // original source could never set to true
bool Suspended;
bool UnpAllBuf;
bool UnpSomeRead;
Int64 WrittenFileSize;
int64 WrittenFileSize;
bool FileExtracted;
int PrevLowDist,LowDistRepCount;
/***************************** Unpack v 1.5 *********************************/
void Unpack15(bool Solid);
@ -176,51 +267,102 @@ private:
void LongLZ();
void HuffDecode();
void GetFlagsBuf();
void OldUnpInitData(int Solid);
void UnpInitData15(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();
void CorrHuff(ushort *CharSet,byte *NumToPlace);
void CopyString15(uint Distance,uint Length);
uint DecodeNum(uint Num,uint StartPos,uint *DecTab,uint *PosTab);
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;
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;
unsigned int Nhfb,Nlzb,MaxDist3;
uint Nhfb,Nlzb,MaxDist3;
/***************************** Unpack v 1.5 *********************************/
/***************************** Unpack v 2.0 *********************************/
void Unpack20(bool Solid);
struct MultDecode MD[4];
DecodeTable MD[4]; // Decode multimedia data, up to 4 channels.
unsigned char UnpOldTable20[MC20*4];
int UnpAudioBlock,UnpChannels,UnpCurChannel,UnpChannelDelta;
void CopyString20(unsigned int Length,unsigned int Distance);
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 *********************************/
public:
Rar_Error_Handler& ErrHandler;
byte const* window_wrptr() const { return &Window [WrPtr & MAXWINMASK]; }
/***************************** Unpack v 3.0 *********************************/
enum BLOCK_TYPES {BLOCK_LZ,BLOCK_PPM};
static void init_tables();
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<UnpackFilter30 *> Filters30;
// Filters stack, several entrances of same filter are possible.
Array<UnpackFilter30 *> 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<int> OldFilterLengths;
int LastFilter;
/***************************** Unpack v 3.0 *********************************/
public:
Unpack(ComprDataIO *DataIO);
~Unpack();
void Init(byte *Window=NULL);
void Init(size_t WinSize,bool Solid);
void DoUnpack(int Method,bool Solid);
void SetDestSize(Int64 DestSize) {DestUnpSize=DestSize;FileExtracted=false;}
bool IsFileExtracted() {return(FileExtracted);}
void SetDestSize(int64 DestSize) {DestUnpSize=DestSize;FileExtracted=false;}
void SetSuspended(bool Suspended) {Unpack::Suspended=Suspended;}
unsigned int GetChar()
byte const* window_wrptr() const { return &Window [WrPtr & MaxWinMask]; }
size_t MaxWinSize;
size_t MaxWinMask;
uint GetChar()
{
if (InAddr>BitInput::MAX_SIZE-30)
if (Inp.InAddr>BitInput::MAX_SIZE-30)
UnpReadBuf();
return(InBuf[InAddr++]);
return(Inp.InBuf[Inp.InAddr++]);
}
};

View File

@ -1,66 +1,46 @@
// #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);
UnpInitData15(Solid);
UnpReadBuf();
if (!Solid)
{
@ -70,7 +50,6 @@ void Unpack::Unpack15(bool Solid)
else
UnpPtr=WrPtr;
--DestUnpSize;
}
if (DestUnpSize>=0)
{
GetFlagsBuf();
@ -79,16 +58,12 @@ void Unpack::Unpack15(bool Solid)
while (DestUnpSize>=0)
{
UnpPtr&=MAXWINMASK;
UnpPtr&=MaxWinMask;
if (InAddr>ReadTop-30 && !UnpReadBuf())
if (Inp.InAddr>ReadTop-30 && !UnpReadBuf())
break;
if (((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr)
{
OldUnpWriteBuf();
if (Suspended)
return;
}
if (((WrPtr-UnpPtr) & MaxWinMask)<270 && WrPtr!=UnpPtr)
UnpWriteBuf20();
if (StMode)
{
HuffDecode();
@ -132,23 +107,7 @@ void Unpack::Unpack15(bool Solid)
}
}
}
OldUnpWriteBuf();
}
void Unpack::OldUnpWriteBuf()
{
if (UnpPtr!=WrPtr)
UnpSomeRead=true;
if (UnpPtr<WrPtr)
{
UnpIO->UnpWrite(&Window[WrPtr],-WrPtr & MAXWINMASK);
UnpIO->UnpWrite(Window,UnpPtr);
UnpAllBuf=true;
}
else
UnpIO->UnpWrite(&Window[WrPtr],UnpPtr-WrPtr);
WrPtr=UnpPtr;
UnpWriteBuf20();
}
@ -157,14 +116,10 @@ void Unpack::OldUnpWriteBuf()
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};
@ -175,13 +130,13 @@ void Unpack::ShortLZ()
int DistancePlace;
NumHuf=0;
unsigned int BitField=fgetbits();
unsigned int BitField=Inp.fgetbits();
if (LCount==2)
{
faddbits(1);
Inp.faddbits(1);
if (BitField >= 0x8000)
{
OldCopyString((unsigned int)LastDist,LastLength);
CopyString15((unsigned int)LastDist,LastLength);
return;
}
BitField <<= 1;
@ -198,14 +153,14 @@ void Unpack::ShortLZ()
for (Length=0;;Length++)
if (((BitField^ShortXor1[Length]) & (~(0xff>>GetShortLen1(Length))))==0)
break;
faddbits(GetShortLen1(Length));
Inp.faddbits(GetShortLen1(Length));
}
else
{
for (Length=0;;Length++)
if (((BitField^ShortXor2[Length]) & (~(0xff>>GetShortLen2(Length))))==0)
break;
faddbits(GetShortLen2(Length));
Inp.faddbits(GetShortLen2(Length));
}
if (Length >= 9)
@ -213,25 +168,25 @@ void Unpack::ShortLZ()
if (Length == 9)
{
LCount++;
OldCopyString((unsigned int)LastDist,LastLength);
CopyString15((unsigned int)LastDist,LastLength);
return;
}
if (Length == 14)
{
LCount=0;
Length=DecodeNum(fgetbits(),STARTL2,DecL2,PosL2)+5;
Distance=(fgetbits()>>1) | 0x8000;
faddbits(15);
Length=DecodeNum(Inp.fgetbits(),STARTL2,DecL2,PosL2)+5;
Distance=(Inp.fgetbits()>>1) | 0x8000;
Inp.faddbits(15);
LastLength=Length;
LastDist=Distance;
OldCopyString(Distance,Length);
CopyString15(Distance,Length);
return;
}
LCount=0;
SaveLength=Length;
Distance=OldDist[(OldDistPtr-(Length-9)) & 3];
Length=DecodeNum(fgetbits(),STARTL1,DecL1,PosL1)+2;
Length=DecodeNum(Inp.fgetbits(),STARTL1,DecL1,PosL1)+2;
if (Length==0x101 && SaveLength==10)
{
Buf60 ^= 1;
@ -246,7 +201,7 @@ void Unpack::ShortLZ()
OldDistPtr = OldDistPtr & 3;
LastLength=Length;
LastDist=Distance;
OldCopyString(Distance,Length);
CopyString15(Distance,Length);
return;
}
@ -254,13 +209,11 @@ void Unpack::ShortLZ()
AvrLn1 += Length;
AvrLn1 -= AvrLn1 >> 4;
DistancePlace=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2) & 0xff;
DistancePlace=DecodeNum(Inp.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;
}
@ -269,7 +222,7 @@ void Unpack::ShortLZ()
OldDistPtr = OldDistPtr & 3;
LastLength=Length;
LastDist=Distance;
OldCopyString(Distance,Length);
CopyString15(Distance,Length);
}
@ -289,7 +242,7 @@ void Unpack::LongLZ()
}
OldAvr2=AvrLn2;
unsigned int BitField=fgetbits();
unsigned int BitField=Inp.fgetbits();
if (AvrLn2 >= 122)
Length=DecodeNum(BitField,STARTL2,DecL2,PosL2);
else
@ -299,19 +252,19 @@ void Unpack::LongLZ()
if (BitField < 0x100)
{
Length=BitField;
faddbits(16);
Inp.faddbits(16);
}
else
{
for (Length=0;((BitField<<Length)&0x8000)==0;Length++)
;
faddbits(Length+1);
Inp.faddbits(Length+1);
}
AvrLn2 += Length;
AvrLn2 -= AvrLn2 >> 5;
BitField=fgetbits();
BitField=Inp.fgetbits();
if (AvrPlcB > 0x28ff)
DistancePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2);
else
@ -335,12 +288,11 @@ void Unpack::LongLZ()
ChSetB[DistancePlace]=ChSetB[NewDistancePlace];
ChSetB[NewDistancePlace]=Distance;
Distance=((Distance & 0xff00) | (fgetbits() >> 8)) >> 1;
faddbits(7);
Distance=((Distance & 0xff00) | (Inp.fgetbits() >> 8)) >> 1;
Inp.faddbits(7);
OldAvr3=AvrLn3;
if (Length!=1 && Length!=4)
{
if (Length==0 && Distance <= MaxDist3)
{
AvrLn3++;
@ -349,7 +301,6 @@ void Unpack::LongLZ()
else
if (AvrLn3 > 0)
AvrLn3--;
}
Length+=3;
if (Distance >= MaxDist3)
Length++;
@ -363,7 +314,7 @@ void Unpack::LongLZ()
OldDistPtr = OldDistPtr & 3;
LastLength=Length;
LastDist=Distance;
OldCopyString(Distance,Length);
CopyString15(Distance,Length);
}
@ -374,7 +325,7 @@ void Unpack::HuffDecode()
unsigned int Distance;
int BytePlace;
unsigned int BitField=fgetbits();
unsigned int BitField=Inp.fgetbits();
if (AvrPlc > 0x75ff)
BytePlace=DecodeNum(BitField,STARTHF4,DecHf4,PosHf4);
@ -396,8 +347,8 @@ void Unpack::HuffDecode()
BytePlace=0x100;
if (--BytePlace==-1)
{
BitField=fgetbits();
faddbits(1);
BitField=Inp.fgetbits();
Inp.faddbits(1);
if (BitField & 0x8000)
{
NumHuf=StMode=0;
@ -406,11 +357,11 @@ void Unpack::HuffDecode()
else
{
Length = (BitField & 0x4000) ? 4 : 3;
faddbits(1);
Distance=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2);
Distance = (Distance << 5) | (fgetbits() >> 11);
faddbits(5);
OldCopyString(Distance,Length);
Inp.faddbits(1);
Distance=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2);
Distance = (Distance << 5) | (Inp.fgetbits() >> 11);
Inp.faddbits(5);
CopyString15(Distance,Length);
return;
}
}
@ -448,7 +399,7 @@ void Unpack::HuffDecode()
void Unpack::GetFlagsBuf()
{
unsigned int Flags,NewFlagsPlace;
unsigned int FlagsPlace=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2);
unsigned int FlagsPlace=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2);
while (1)
{
@ -465,7 +416,7 @@ void Unpack::GetFlagsBuf()
}
void Unpack::OldUnpInitData(int Solid)
void Unpack::UnpInitData15(int Solid)
{
if (!Solid)
{
@ -486,8 +437,6 @@ 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;
@ -499,7 +448,7 @@ void Unpack::InitHuff()
}
void Unpack::CorrHuff(unsigned int *CharSet,unsigned int *NumToPlace)
void Unpack::CorrHuff(ushort *CharSet,byte *NumToPlace)
{
int I,J;
for (I=7;I>=0;I--)
@ -511,24 +460,22 @@ void Unpack::CorrHuff(unsigned int *CharSet,unsigned int *NumToPlace)
}
void Unpack::OldCopyString(unsigned int Distance,unsigned int Length)
void Unpack::CopyString15(uint Distance,uint Length)
{
DestUnpSize-=Length;
while (Length--)
{
Window[UnpPtr]=Window[(UnpPtr-Distance) & MAXWINMASK];
UnpPtr=(UnpPtr+1) & MAXWINMASK;
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)
uint Unpack::DecodeNum(uint Num,uint StartPos,uint *DecTab,uint *PosTab)
{
int I;
for (Num&=0xfff0,I=0;DecTab[I]<=Num;I++)
StartPos++;
faddbits(StartPos);
Inp.faddbits(StartPos);
return(((Num-(I ? DecTab[I-1]:0))>>(16-StartPos))+PosTab[StartPos]);
}
#endif

View File

@ -1,61 +1,21 @@
// #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)
void Unpack::CopyString20(uint Length,uint 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 (UnpPtr<MAXWINSIZE-300 && DestPtr<MAXWINSIZE-300)
{
this->UnpPtr += 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;
}
CopyString(Length,Distance);
}
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;
@ -72,22 +32,22 @@ void Unpack::Unpack20(bool Solid)
--DestUnpSize;
}
while (is64plus(DestUnpSize))
while (DestUnpSize>=0)
{
UnpPtr&=MAXWINMASK;
UnpPtr&=MaxWinMask;
if (InAddr>ReadTop-30)
if (Inp.InAddr>ReadTop-30)
if (!UnpReadBuf())
break;
if (((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr)
if (((WrPtr-UnpPtr) & MaxWinMask)<270 && WrPtr!=UnpPtr)
{
OldUnpWriteBuf();
UnpWriteBuf20();
if (Suspended)
return;
}
if (UnpAudioBlock)
{
int AudioNumber=DecodeNumber((struct Decode *)&MD[UnpCurChannel]);
int AudioNumber=DecodeNumber(Inp,&MD[UnpCurChannel]);
if (AudioNumber==256)
{
@ -102,7 +62,7 @@ void Unpack::Unpack20(bool Solid)
continue;
}
int Number=DecodeNumber((struct Decode *)&LD);
int Number=DecodeNumber(Inp,&BlockTables.LD);
if (Number<256)
{
Window[UnpPtr++]=(byte)Number;
@ -114,16 +74,16 @@ void Unpack::Unpack20(bool Solid)
int Length=LDecode[Number-=270]+3;
if ((Bits=LBits[Number])>0)
{
Length+=getbits()>>(16-Bits);
addbits(Bits);
Length+=Inp.getbits()>>(16-Bits);
Inp.addbits(Bits);
}
int DistNumber=DecodeNumber((struct Decode *)&DD);
int DistNumber=DecodeNumber(Inp,&BlockTables.DD);
unsigned int Distance=DDecode[DistNumber]+1;
if ((Bits=DBits[DistNumber])>0)
{
Distance+=getbits()>>(16-Bits);
addbits(Bits);
Distance+=Inp.getbits()>>(16-Bits);
Inp.addbits(Bits);
}
if (Distance>=0x2000)
@ -150,12 +110,12 @@ void Unpack::Unpack20(bool Solid)
if (Number<261)
{
unsigned int Distance=OldDist[(OldDistPtr-(Number-256)) & 3];
int LengthNumber=DecodeNumber((struct Decode *)&RD);
int LengthNumber=DecodeNumber(Inp,&BlockTables.RD);
int Length=LDecode[LengthNumber]+2;
if ((Bits=LBits[LengthNumber])>0)
{
Length+=getbits()>>(16-Bits);
addbits(Bits);
Length+=Inp.getbits()>>(16-Bits);
Inp.addbits(Bits);
}
if (Distance>=0x101)
{
@ -175,39 +135,55 @@ void Unpack::Unpack20(bool Solid)
unsigned int Distance=SDDecode[Number-=261]+1;
if ((Bits=SDBits[Number])>0)
{
Distance+=getbits()>>(16-Bits);
addbits(Bits);
Distance+=Inp.getbits()>>(16-Bits);
Inp.addbits(Bits);
}
CopyString20(2,Distance);
continue;
}
}
ReadLastTables();
OldUnpWriteBuf();
UnpWriteBuf20();
}
void Unpack::UnpWriteBuf20()
{
if (UnpPtr!=WrPtr)
UnpSomeRead=true;
if (UnpPtr<WrPtr)
{
UnpIO->UnpWrite(&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];
unsigned char Table[MC20*4];
byte Table[MC20*4];
int TableSize,N,I;
if (InAddr>ReadTop-25)
if (Inp.InAddr>ReadTop-25)
if (!UnpReadBuf())
return(false);
unsigned int BitField=getbits();
uint BitField=Inp.getbits();
UnpAudioBlock=(BitField & 0x8000);
if (!(BitField & 0x4000))
memset(UnpOldTable20,0,sizeof(UnpOldTable20));
addbits(2);
Inp.addbits(2);
if (UnpAudioBlock)
{
UnpChannels=((BitField>>12) & 3)+1;
if (UnpCurChannel>=UnpChannels)
UnpCurChannel=0;
addbits(2);
Inp.addbits(2);
TableSize=MC20*UnpChannels;
}
else
@ -215,17 +191,17 @@ bool Unpack::ReadTables20()
for (I=0;I<BC20;I++)
{
BitLength[I]=(byte)(getbits() >> 12);
addbits(4);
BitLength[I]=(byte)(Inp.getbits() >> 12);
Inp.addbits(4);
}
MakeDecodeTables(BitLength,(struct Decode *)&BD,BC20);
MakeDecodeTables(BitLength,&BlockTables.BD,BC20);
I=0;
while (I<TableSize)
{
if (InAddr>ReadTop-5)
if (Inp.InAddr>ReadTop-5)
if (!UnpReadBuf())
return(false);
int Number=DecodeNumber((struct Decode *)&BD);
return false;
int Number=DecodeNumber(Inp,&BlockTables.BD);
if (Number<16)
{
Table[I]=(Number+UnpOldTable20[I]) & 0xf;
@ -234,8 +210,9 @@ bool Unpack::ReadTables20()
else
if (Number==16)
{
N=(getbits() >> 14)+3;
addbits(2);
N=(Inp.getbits() >> 14)+3;
Inp.addbits(2);
if (I>0)
while (N-- > 0 && I<TableSize)
{
Table[I]=Table[I-1];
@ -246,28 +223,28 @@ bool Unpack::ReadTables20()
{
if (Number==17)
{
N=(getbits() >> 13)+3;
addbits(3);
N=(Inp.getbits() >> 13)+3;
Inp.addbits(3);
}
else
{
N=(getbits() >> 9)+11;
addbits(7);
N=(Inp.getbits() >> 9)+11;
Inp.addbits(7);
}
while (N-- > 0 && I<TableSize)
Table[I++]=0;
}
}
if (InAddr>ReadTop)
if (Inp.InAddr>ReadTop)
return(true);
if (UnpAudioBlock)
for (I=0;I<UnpChannels;I++)
MakeDecodeTables(&Table[I*MC20],(struct Decode *)&MD[I],MC20);
MakeDecodeTables(&Table[I*MC20],&MD[I],MC20);
else
{
MakeDecodeTables(&Table[0],(struct Decode *)&LD,NC20);
MakeDecodeTables(&Table[NC20],(struct Decode *)&DD,DC20);
MakeDecodeTables(&Table[NC20+DC20],(struct Decode *)&RD,RC20);
MakeDecodeTables(&Table[0],&BlockTables.LD,NC20);
MakeDecodeTables(&Table[NC20],&BlockTables.DD,DC20);
MakeDecodeTables(&Table[NC20+DC20],&BlockTables.RD,RC20);
}
memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20));
return(true);
@ -276,18 +253,16 @@ bool Unpack::ReadTables20()
void Unpack::ReadLastTables()
{
if (ReadTop>=InAddr+5)
{
if (ReadTop>=Inp.InAddr+5)
if (UnpAudioBlock)
{
if (DecodeNumber((struct Decode *)&MD[UnpCurChannel])==256)
if (DecodeNumber(Inp,&MD[UnpCurChannel])==256)
ReadTables20();
}
else
if (DecodeNumber((struct Decode *)&LD)==269)
if (DecodeNumber(Inp,&BlockTables.LD)==269)
ReadTables20();
}
}
void Unpack::UnpInitData20(int Solid)
@ -393,4 +368,3 @@ byte Unpack::DecodeAudio(int Delta)
}
return((byte)Ch);
}
#endif

View File

@ -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;I<ASIZE(DBitLengthCounts);I++,BitLength++)
for (int J=0;J<DBitLengthCounts[I];J++,Slot++,Dist+=(1<<BitLength))
{
DDecode[Slot]=Dist;
DBits[Slot]=BitLength;
}
}
FileExtracted=true;
if (!Suspended)
{
UnpInitData(Solid);
if (!UnpReadBuf30())
return;
if ((!Solid || !TablesRead) && !ReadTables30())
return;
}
while (true)
{
UnpPtr&=MaxWinMask;
if (Inp.InAddr>ReadBorder)
{
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<byte> VMCode(Length);
for (int I=0;I<Length;I++)
{
// Try to read the new buffer if only one byte is left.
// But if we read all bytes except the last, one byte is enough.
if (Inp.InAddr>=ReadTop-1 && !UnpReadBuf30() && I<Length-1)
return(false);
VMCode[I]=Inp.getbits()>>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<byte> VMCode(Length);
for (int I=0;I<Length;I++)
{
int Ch=SafePPMDecodeChar();
if (Ch==-1)
return(false);
VMCode[I]=Ch;
}
return(AddVMCode(FirstByte,&VMCode[0],Length));
}
bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize)
{
VMCodeInp.InitBitInput();
memcpy(VMCodeInp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize));
VM.Init();
uint FiltPos;
if (FirstByte & 0x80)
{
FiltPos=RarVM::ReadData(VMCodeInp);
if (FiltPos==0)
InitFilters30();
else
FiltPos--;
}
else
FiltPos=LastFilter; // Use the same filter as last time.
if (FiltPos>Filters30.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;I<PrgStack.Size();I++)
{
PrgStack[I-EmptyCount]=PrgStack[I];
if (PrgStack[I]==NULL)
EmptyCount++;
if (EmptyCount>0)
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=FiltPos<OldFilterLengths.Size() ? OldFilterLengths[FiltPos]:0;
}
StackFilter->NextWindow=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<<I))
StackFilter->Prg.InitR[I]=RarVM::ReadData(VMCodeInp);
}
if (NewFilter)
{
uint VMCodeSize=RarVM::ReadData(VMCodeInp);
if (VMCodeSize>=0x10000 || VMCodeSize==0)
return(false);
Array<byte> VMCode(VMCodeSize);
for (uint I=0;I<VMCodeSize;I++)
{
if (VMCodeInp.Overflow(3))
return(false);
VMCode[I]=VMCodeInp.fgetbits()>>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 && StaticDataSize<VM_GLOBALMEMSIZE)
{
// read statically defined data contained in DB commands
StackFilter->Prg.StaticData.Add(StaticDataSize);
memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize);
}
if (StackFilter->Prg.GlobalData.Size()<VM_FIXEDGLOBALSIZE)
{
StackFilter->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 (CurSize<DataSize+VM_FIXEDGLOBALSIZE)
StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize);
byte *GlobalData=&StackFilter->Prg.GlobalData[VM_FIXEDGLOBALSIZE];
for (uint I=0;I<DataSize;I++)
{
if (VMCodeInp.Overflow(3))
return(false);
GlobalData[I]=VMCodeInp.fgetbits()>>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;I<PrgStack.Size();I++)
{
// Here we apply filters to data which we need to write.
// We always copy data to virtual machine memory before processing.
// We cannot process them just in place in Window buffer, because
// these data can be used for future string matches, so we must
// preserve them in original form.
UnpackFilter30 *flt=PrgStack[I];
if (flt==NULL)
continue;
if (flt->NextWindow)
{
flt->NextWindow=false;
continue;
}
unsigned int BlockStart=flt->BlockStart;
unsigned int BlockLength=flt->BlockLength;
if (((BlockStart-WrittenBorder)&MaxWinMask)<WriteSize)
{
if (WrittenBorder!=BlockStart)
{
UnpWriteArea(WrittenBorder,BlockStart);
WrittenBorder=BlockStart;
WriteSize=(uint)((UnpPtr-WrittenBorder)&MaxWinMask);
}
if (BlockLength<=WriteSize)
{
uint BlockEnd=(BlockStart+BlockLength)&MaxWinMask;
if (BlockStart<BlockEnd || BlockEnd==0)
VM.SetMemory(0,Window+BlockStart,BlockLength);
else
{
uint FirstPartLength=uint(MaxWinSize-BlockStart);
VM.SetMemory(0,Window+BlockStart,FirstPartLength);
VM.SetMemory(FirstPartLength,Window,BlockEnd);
}
VM_PreparedProgram *ParentPrg=&Filters30[flt->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()<Prg->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+1<PrgStack.Size())
{
UnpackFilter30 *NextFilter=PrgStack[I+1];
if (NextFilter==NULL || NextFilter->BlockStart!=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()<NextPrg->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;J<PrgStack.Size();J++)
{
UnpackFilter30 *flt=PrgStack[J];
if (flt!=NULL && flt->NextWindow)
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<BC;I++)
{
int Length=(byte)(Inp.fgetbits() >> 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 && I<ASIZE(BitLength))
BitLength[I++]=0;
I--;
}
}
else
BitLength[I]=Length;
}
MakeDecodeTables(BitLength,&BlockTables.BD,BC30);
const int TableSize=HUFF_TABLE_SIZE30;
for (int I=0;I<TableSize;)
{
if (Inp.InAddr>ReadTop-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<TableSize)
{
Table[I]=Table[I-1];
I++;
}
}
else
{
int N;
if (Number==18)
{
N=(Inp.fgetbits() >> 13)+3;
Inp.faddbits(3);
}
else
{
N=(Inp.fgetbits() >> 9)+11;
Inp.faddbits(7);
}
while (N-- > 0 && I<TableSize)
Table[I++]=0;
}
}
TablesRead=true;
if (Inp.InAddr>ReadTop)
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<Filters30.Size();I++)
delete Filters30[I];
Filters30.Reset();
for (size_t I=0;I<PrgStack.Size();I++)
delete PrgStack[I];
PrgStack.Reset();
}

View File

@ -0,0 +1,648 @@
void Unpack::Unpack5(bool Solid)
{
FileExtracted=true;
if (!Suspended)
{
UnpInitData(Solid);
if (!UnpReadBuf())
return;
if (!ReadBlockHeader(Inp,BlockHeader) || !ReadTables(Inp,BlockHeader,BlockTables))
return;
}
while (true)
{
UnpPtr&=MaxWinMask;
if (Inp.InAddr>=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)<MAX_LZ_MATCH+3 && WriteBorder!=UnpPtr)
{
UnpWriteBuf();
if (WrittenFileSize>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<ByteCount;I++)
{
Data+=(Inp.fgetbits()>>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;I<Filters.Size();I++)
{
// Here we apply filters to data which we need to write.
// We always copy data to virtual machine memory before processing.
// We cannot process them just in place in Window buffer, because
// these data can be used for future string matches, so we must
// preserve them in original form.
UnpackFilter *flt=&Filters[I];
if (flt->Type==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)<WriteSizeLeft)
{
if (WrittenBorder!=BlockStart)
{
UnpWriteArea(WrittenBorder,BlockStart);
WrittenBorder=BlockStart;
WriteSizeLeft=(UnpPtr-WrittenBorder)&MaxWinMask;
}
if (BlockLength<=WriteSizeLeft)
{
if (BlockLength>0)
{
uint BlockEnd=(BlockStart+BlockLength)&MaxWinMask;
FilterSrcMemory.Alloc(BlockLength);
byte *Mem=&FilterSrcMemory[0];
if (BlockStart<BlockEnd || BlockEnd==0)
{
if (Fragmented)
FragWindow.CopyData(Mem,BlockStart,BlockLength);
else
memcpy(Mem,Window+BlockStart,BlockLength);
}
else
{
size_t FirstPartLength=size_t(MaxWinSize-BlockStart);
if (Fragmented)
{
FragWindow.CopyData(Mem,BlockStart,FirstPartLength);
FragWindow.CopyData(Mem+FirstPartLength,0,BlockEnd);
}
else
{
memcpy(Mem,Window+BlockStart,FirstPartLength);
memcpy(Mem+FirstPartLength,Window,BlockEnd);
}
}
byte *OutMem=ApplyFilter(Mem,BlockLength,flt);
Filters[I].Type=FILTER_NONE;
if (OutMem!=NULL)
UnpIO->UnpWrite(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;J<Filters.Size();J++)
{
UnpackFilter *flt=&Filters[J];
if (flt->Type!=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;I<Filters.Size();I++)
{
if (EmptyCount>0)
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<FileSize
RawPut4(Addr-Offset,Data);
Data+=4;
CurPos+=4;
}
}
}
return SrcData;
case FILTER_ARM:
{
uint FileOffset=(uint)WrittenFileSize;
for (uint CurPos=0;(int)CurPos<(int)DataSize-3;CurPos+=4)
{
byte *D=Data+CurPos;
if (D[3]==0xeb) // BL command with '1110' (Always) condition.
{
uint Offset=D[0]+uint(D[1])*0x100+uint(D[2])*0x10000;
Offset-=(FileOffset+CurPos)/4;
D[0]=(byte)Offset;
D[1]=(byte)(Offset>>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;CurChannel<Channels;CurChannel++)
{
byte PrevByte=0;
for (uint DestPos=CurChannel;DestPos<DataSize;DestPos+=Channels)
DstData[DestPos]=(PrevByte-=Data[SrcPos++]);
}
return DstData;
}
}
return NULL;
}
void Unpack::UnpWriteArea(size_t StartPtr,size_t EndPtr)
{
if (EndPtr!=StartPtr)
UnpSomeRead=true;
if (EndPtr<StartPtr)
UnpAllBuf=true;
if (Fragmented)
{
size_t SizeToWrite=(EndPtr-StartPtr) & MaxWinMask;
while (SizeToWrite>0)
{
size_t BlockSize=FragWindow.GetBlockSize(StartPtr,SizeToWrite);
UnpWriteData(&FragWindow[StartPtr],BlockSize);
SizeToWrite-=BlockSize;
StartPtr=(StartPtr+BlockSize) & MaxWinMask;
}
}
else
if (EndPtr<StartPtr)
{
UnpWriteData(Window+StartPtr,MaxWinSize-StartPtr);
UnpWriteData(Window,EndPtr);
}
else
UnpWriteData(Window+StartPtr,EndPtr-StartPtr);
}
void Unpack::UnpWriteData(byte *Data,size_t Size)
{
if (WrittenFileSize>=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<ByteCount;I++)
{
BlockSize+=(Inp.fgetbits()>>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<BC;I++)
{
int Length=(byte)(Inp.fgetbits() >> 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 && I<sizeof(BitLength)/sizeof(BitLength[0]))
BitLength[I++]=0;
I--;
}
}
else
BitLength[I]=Length;
}
MakeDecodeTables(BitLength,&Tables.BD,BC);
byte Table[HUFF_TABLE_SIZE];
const int TableSize=HUFF_TABLE_SIZE;
for (int I=0;I<TableSize;)
{
if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-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<TableSize)
{
Table[I]=Table[I-1];
I++;
}
}
else
{
int N;
if (Number==18)
{
N=(Inp.fgetbits() >> 13)+3;
Inp.faddbits(3);
}
else
{
N=(Inp.fgetbits() >> 9)+11;
Inp.faddbits(7);
}
while (N-- > 0 && I<TableSize)
Table[I++]=0;
}
}
if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop)
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();
}

View File

@ -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<ASIZE(Mem);I++)
if (Mem[I]!=NULL)
{
free(Mem[I]);
Mem[I]=NULL;
}
}
void FragmentedWindow::Init(size_t WinSize)
{
Reset();
uint BlockNum=0;
size_t TotalSize=0; // Already allocated.
while (TotalSize<WinSize && BlockNum<ASIZE(Mem))
{
size_t Size=WinSize-TotalSize; // Size needed to allocate.
// Minimum still acceptable block size. Next allocations cannot be larger
// than current, so we do not need blocks if they are smaller than
// "size left / attempts left". Also we do not waste time to blocks
// smaller than some arbitrary constant.
size_t MinSize=Max(Size/(ASIZE(Mem)-BlockNum), 0x400000);
byte *NewMem=NULL;
while (Size>=MinSize)
{
NewMem=(byte *)malloc(Size);
if (NewMem!=NULL)
break;
Size-=Size/32;
}
if (NewMem==NULL)
throw std::bad_alloc();
// Clean the window to generate the same output when unpacking corrupt
// RAR files, which may access to unused areas of sliding dictionary.
memset(NewMem,0,Size);
Mem[BlockNum]=NewMem;
TotalSize+=Size;
MemSize[BlockNum]=TotalSize;
BlockNum++;
}
if (TotalSize<WinSize) // Not found enough free blocks.
throw std::bad_alloc();
}
byte& FragmentedWindow::operator [](size_t Item)
{
if (Item<MemSize[0])
return Mem[0][Item];
for (uint I=1;I<ASIZE(MemSize);I++)
if (Item<MemSize[I])
return Mem[I][Item-MemSize[I-1]];
return Mem[0][0]; // Must never happen;
}
void FragmentedWindow::CopyString(uint Length,uint Distance,size_t &UnpPtr,size_t MaxWinMask)
{
size_t SrcPtr=UnpPtr-Distance;
while (Length-- > 0)
{
(*this)[UnpPtr]=(*this)[SrcPtr++ & MaxWinMask];
// We need to have masked UnpPtr after quit from loop, so it must not
// be replaced with '(*this)[UnpPtr++ & MaxWinMask]'
UnpPtr=(UnpPtr+1) & MaxWinMask;
}
}
void FragmentedWindow::CopyData(byte *Dest,size_t WinPos,size_t Size)
{
for (size_t I=0;I<Size;I++)
Dest[I]=(*this)[WinPos+I];
}
size_t FragmentedWindow::GetBlockSize(size_t StartPos,size_t RequiredSize)
{
for (uint I=0;I<ASIZE(MemSize);I++)
if (StartPos<MemSize[I])
return Min(MemSize[I]-StartPos,RequiredSize);
return 0; // Must never be here.
}

View File

@ -0,0 +1,142 @@
inline void Unpack::InsertOldDist(uint Distance)
{
OldDist[3]=OldDist[2];
OldDist[2]=OldDist[1];
OldDist[1]=OldDist[0];
OldDist[0]=Distance;
}
#ifdef _MSC_VER
#define FAST_MEMCPY
#endif
inline void Unpack::CopyString(uint Length,uint Distance)
{
size_t SrcPtr=UnpPtr-Distance;
if (SrcPtr<MaxWinSize-MAX_LZ_MATCH && UnpPtr<MaxWinSize-MAX_LZ_MATCH)
{
// If we are not close to end of window, we do not need to waste time
// to "& MaxWinMask" pointer protection.
byte *Src=Window+SrcPtr;
byte *Dest=Window+UnpPtr;
UnpPtr+=Length;
#ifdef FAST_MEMCPY
if (Distance<Length) // Overlapping strings
#endif
while (Length>=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 (BitField<Dec->DecodeLen[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 (BitField<Dec->DecodeLen[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;
}

View File

@ -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

View File

@ -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 */

View File

@ -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;