parent
07c6e3119e
commit
00e48e11e6
|
@ -65,7 +65,38 @@ target_sources(vbam-fex
|
|||
fex/Zip_Extractor.h
|
||||
fex/Zlib_Inflater.cpp
|
||||
fex/Zlib_Inflater.h
|
||||
|
||||
unrar/archive.cpp
|
||||
unrar/arcread.cpp
|
||||
unrar/blake2s_sse.cpp
|
||||
unrar/blake2s.cpp
|
||||
unrar/blake2sp.cpp
|
||||
unrar/coder.cpp
|
||||
unrar/crc.cpp
|
||||
unrar/encname.cpp
|
||||
unrar/extract.cpp
|
||||
unrar/getbits.cpp
|
||||
unrar/hash.cpp
|
||||
unrar/headers.cpp
|
||||
unrar/model.cpp
|
||||
unrar/pathfn.cpp
|
||||
unrar/rarvm.cpp
|
||||
unrar/rarvmtbl.cpp
|
||||
unrar/rawread.cpp
|
||||
unrar/secpassword.cpp
|
||||
unrar/strfn.cpp
|
||||
unrar/suballoc.cpp
|
||||
unrar/timefn.cpp
|
||||
unrar/unicode.cpp
|
||||
unrar/unpack.cpp
|
||||
unrar/unpack15.cpp
|
||||
unrar/unpack20.cpp
|
||||
unrar/unpack30.cpp
|
||||
unrar/unpack50.cpp
|
||||
unrar/unpack50frag.cpp
|
||||
unrar/unpackinline.cpp
|
||||
unrar/unrar_misc.cpp
|
||||
unrar/unrar_open.cpp
|
||||
unrar/unrar.cpp
|
||||
PUBLIC
|
||||
fex.h
|
||||
)
|
||||
|
|
|
@ -213,7 +213,7 @@ struct fex_type_t_ {
|
|||
blargg_err_t (*init)(); // Called by fex_init(). Can be NULL.
|
||||
};
|
||||
|
||||
extern const fex_type_t_ fex_7z_type[1], fex_gz_type[1], fex_rar_type[1], fex_zip_type[1],
|
||||
extern const fex_type_t_ fex_7z_type[1], fex_gz_type[1], fex_lz4_type[1], fex_rar_type[1], fex_zip_type[1],
|
||||
fex_bin_type[1];
|
||||
|
||||
inline blargg_err_t File_Extractor::open_v()
|
||||
|
|
|
@ -17,8 +17,11 @@
|
|||
// Enable support for as building DLL on Windows.
|
||||
//#define BLARGG_BUILD_DLL 1
|
||||
|
||||
// Support only the listed archive types. Remove any you don't need.
|
||||
#define FEX_TYPE_LIST fex_7z_type, fex_gz_type, fex_zip_type,
|
||||
#ifndef FEX_ENABLE_RAR
|
||||
#define FEX_ENABLE_RAR 1
|
||||
#endif
|
||||
|
||||
#define FEX_TYPE_LIST fex_7z_type, fex_gz_type, fex_zip_type, fex_rar_type
|
||||
|
||||
// Use standard config.h if present
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
|
|
@ -41,7 +41,7 @@ BLARGG_EXPORT const fex_type_t* fex_type_list( void )
|
|||
fex_bin_type,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
return fex_type_list_;
|
||||
}
|
||||
|
||||
|
@ -77,6 +77,7 @@ BLARGG_EXPORT const char* fex_identify_header( void const* header )
|
|||
case 0x41724301: return ".arc";
|
||||
case 0x4D534346: return ".cab";
|
||||
case 0x5A4F4F20: return ".zoo";
|
||||
case 0x04224D18: return ".lz4";
|
||||
}
|
||||
|
||||
unsigned three = four >> 8;
|
||||
|
@ -130,6 +131,7 @@ static int is_archive_extension( const char str [] )
|
|||
".dmg",
|
||||
".gz",
|
||||
".lha",
|
||||
".lz4",
|
||||
".lz",
|
||||
".lzh",
|
||||
".lzma",
|
||||
|
|
|
@ -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.
|
|
@ -0,0 +1,96 @@
|
|||
#include <stdio.h>
|
||||
#include "rar.hpp"
|
||||
|
||||
#include "unrar.h"
|
||||
|
||||
Archive::Archive() : Raw( this )
|
||||
{
|
||||
Format=RARFMT15;
|
||||
Solid=false;
|
||||
|
||||
CurBlockPos=0;
|
||||
NextBlockPos=0;
|
||||
|
||||
memset(&MainHead,0,sizeof(MainHead));
|
||||
memset(&EndArcHead,0,sizeof(EndArcHead));
|
||||
|
||||
HeaderCRC=0;
|
||||
}
|
||||
|
||||
RARFORMAT Archive::IsSignature(const byte *D,size_t Size)
|
||||
{
|
||||
RARFORMAT Type=RARFMT_NONE;
|
||||
if (Size>=1 && D[0]==0x52)
|
||||
#ifndef SFX_MODULE
|
||||
if (Size>=4 && D[1]==0x45 && D[2]==0x7e && D[3]==0x5e)
|
||||
Type=RARFMT14;
|
||||
else
|
||||
#endif
|
||||
if (Size>=7 && D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07)
|
||||
{
|
||||
// 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 Type;
|
||||
}
|
||||
|
||||
|
||||
unrar_err_t Archive::IsArchive()
|
||||
{
|
||||
if (Read(MarkHead.Mark,SIZEOF_MARKHEAD3)!=SIZEOF_MARKHEAD3)
|
||||
return unrar_err_not_arc;
|
||||
|
||||
RARFORMAT Type;
|
||||
if ((Type=IsSignature(MarkHead.Mark,SIZEOF_MARKHEAD3))!=RARFMT_NONE)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
|
||||
SeekToNext();
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
void Archive::SeekToNext()
|
||||
{
|
||||
Seek(NextBlockPos,SEEK_SET);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
#ifndef _RAR_ARCHIVE_
|
||||
#define _RAR_ARCHIVE_
|
||||
|
||||
typedef ComprDataIO File;
|
||||
#include "rawread.hpp"
|
||||
|
||||
enum RARFORMAT {RARFMT_NONE,RARFMT14,RARFMT15,RARFMT50,RARFMT_FUTURE};
|
||||
|
||||
class Archive:public File
|
||||
{
|
||||
private:
|
||||
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;
|
||||
|
||||
HEADER_TYPE CurHeaderType;
|
||||
|
||||
public:
|
||||
Archive();
|
||||
RARFORMAT IsSignature(const byte *D,size_t Size);
|
||||
unrar_err_t IsArchive();
|
||||
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();
|
||||
int64 GetStartPos();
|
||||
HEADER_TYPE GetHeaderType() {return(CurHeaderType);};
|
||||
|
||||
BaseBlock ShortBlock;
|
||||
MarkHeader MarkHead;
|
||||
MainHeader MainHead;
|
||||
FileHeader FileHead;
|
||||
EndArcHeader EndArcHead;
|
||||
SubBlockHeader SubBlockHead;
|
||||
FileHeader SubHead;
|
||||
ProtectHeader ProtectHead;
|
||||
|
||||
int64 CurBlockPos;
|
||||
int64 NextBlockPos;
|
||||
|
||||
RARFORMAT Format;
|
||||
bool Solid;
|
||||
enum { SFXSize = 0 }; // self-extracting not supported
|
||||
ushort HeaderCRC;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,735 @@
|
|||
#include "rar.hpp"
|
||||
|
||||
#include "unrar.h"
|
||||
#include "unicode.hpp"
|
||||
#include "encname.hpp"
|
||||
|
||||
// arcread.cpp
|
||||
unrar_err_t Archive::ReadHeader(size_t * ReadSize_)
|
||||
{
|
||||
CurBlockPos=Tell();
|
||||
|
||||
unrar_err_t Error;
|
||||
size_t ReadSize;
|
||||
switch(Format)
|
||||
{
|
||||
#ifndef SFX_MODULE
|
||||
case RARFMT14:
|
||||
Error=ReadHeader14(&ReadSize);
|
||||
break;
|
||||
#endif
|
||||
case RARFMT15:
|
||||
Error=ReadHeader15(&ReadSize);
|
||||
break;
|
||||
case RARFMT50:
|
||||
Error=ReadHeader50(&ReadSize);
|
||||
break;
|
||||
|
||||
default: // unreachable
|
||||
Error=unrar_err_corrupt;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Error!=unrar_ok)
|
||||
return Error;
|
||||
|
||||
if (ReadSize>0 && NextBlockPos<=CurBlockPos)
|
||||
return unrar_err_corrupt;
|
||||
|
||||
*ReadSize_ = ReadSize;
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
|
||||
unrar_err_t Archive::ReadHeader15(size_t *ReadSize)
|
||||
{
|
||||
Raw.Reset();
|
||||
|
||||
Raw.Read(SIZEOF_SHORTBLOCKHEAD);
|
||||
if (Raw.Size()==0)
|
||||
return unrar_err_corrupt;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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.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);
|
||||
|
||||
NextBlockPos=CurBlockPos+ShortBlock.HeadSize;
|
||||
|
||||
switch(ShortBlock.HeaderType)
|
||||
{
|
||||
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 HEAD_FILE:
|
||||
case HEAD_SERVICE:
|
||||
{
|
||||
bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
|
||||
FileHeader *hd=FileBlock ? &FileHead:&SubHead;
|
||||
hd->Reset();
|
||||
|
||||
*(BaseBlock *)hd=ShortBlock;
|
||||
|
||||
hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0;
|
||||
hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0;
|
||||
hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0;
|
||||
hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0;
|
||||
hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0;
|
||||
hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY;
|
||||
hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
|
||||
hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0;
|
||||
hd->Version=(hd->Flags & LHD_VERSION)!=0;
|
||||
|
||||
hd->DataSize=Raw.Get4();
|
||||
uint LowUnpSize=Raw.Get4();
|
||||
hd->HostOS=Raw.Get1();
|
||||
|
||||
hd->FileHash.Type=HASH_CRC32;
|
||||
hd->FileHash.CRC32=Raw.Get4();
|
||||
|
||||
uint FileTime=Raw.Get4();
|
||||
hd->UnpVer=Raw.Get1();
|
||||
hd->Method=Raw.Get1()-0x30;
|
||||
size_t NameSize=Raw.Get2();
|
||||
hd->FileAttr=Raw.Get4();
|
||||
|
||||
if (hd->Encrypted)
|
||||
return unrar_err_encrypted;
|
||||
|
||||
hd->HSType=HSYS_UNKNOWN;
|
||||
if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS)
|
||||
hd->HSType=HSYS_UNIX;
|
||||
else
|
||||
if (hd->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)
|
||||
{
|
||||
hd->RedirType=FSREDIR_UNIXSYMLINK;
|
||||
*hd->RedirName=0;
|
||||
}
|
||||
|
||||
hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0;
|
||||
|
||||
hd->LargeFile=(hd->Flags & LHD_LARGE)!=0;
|
||||
|
||||
uint HighPackSize,HighUnpSize;
|
||||
if (hd->LargeFile)
|
||||
{
|
||||
HighPackSize=Raw.Get4();
|
||||
HighUnpSize=Raw.Get4();
|
||||
hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff);
|
||||
}
|
||||
else
|
||||
{
|
||||
HighPackSize=HighUnpSize=0;
|
||||
// UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
|
||||
// that we do not know the unpacked file size and must unpack it
|
||||
// until we find the end of file marker in compressed data.
|
||||
hd->UnknownUnpSize=(LowUnpSize==0xffffffff);
|
||||
}
|
||||
hd->PackSize=int32to64(HighPackSize,hd->DataSize);
|
||||
hd->UnpSize=int32to64(HighUnpSize,LowUnpSize);
|
||||
if (hd->UnknownUnpSize)
|
||||
hd->UnpSize=INT64NDF;
|
||||
|
||||
char FileName[NM*4];
|
||||
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
|
||||
Raw.GetB((byte *)FileName,ReadNameSize);
|
||||
FileName[ReadNameSize]=0;
|
||||
|
||||
if (FileBlock)
|
||||
{
|
||||
if ((hd->Flags & LHD_UNICODE)!=0)
|
||||
{
|
||||
EncodeFileName NameCoder;
|
||||
size_t Length=strlen(FileName);
|
||||
Length++;
|
||||
NameCoder.Decode(FileName,(byte *)FileName+Length,
|
||||
NameSize-Length,hd->FileName,
|
||||
ASIZE(hd->FileName));
|
||||
}
|
||||
else
|
||||
*hd->FileName=0;
|
||||
|
||||
char AnsiName[NM];
|
||||
IntToExt(FileName,AnsiName,ASIZE(AnsiName));
|
||||
GetWideName(AnsiName,hd->FileName,hd->FileName,ASIZE(hd->FileName));
|
||||
|
||||
ConvertFileHeader(hd);
|
||||
}
|
||||
else
|
||||
{
|
||||
CharToWide(FileName,hd->FileName,ASIZE(hd->FileName));
|
||||
|
||||
// Calculate the size of optional data.
|
||||
int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3);
|
||||
if ((hd->Flags & LHD_SALT)!=0)
|
||||
return unrar_err_encrypted;
|
||||
|
||||
if (DataSize>0)
|
||||
{
|
||||
// Here we read optional additional fields for subheaders.
|
||||
// They are stored after the file name and before salt.
|
||||
hd->SubData.Alloc(DataSize);
|
||||
Raw.GetB(&hd->SubData[0],DataSize);
|
||||
}
|
||||
}
|
||||
if ((hd->Flags & LHD_SALT)!=0)
|
||||
return unrar_err_encrypted;
|
||||
hd->mtime.SetDos(FileTime);
|
||||
if ((hd->Flags & LHD_EXTTIME)!=0)
|
||||
{
|
||||
ushort Flags=Raw.Get2();
|
||||
RarTime *tbl[4];
|
||||
tbl[0]=&FileHead.mtime;
|
||||
tbl[1]=&FileHead.ctime;
|
||||
tbl[2]=&FileHead.atime;
|
||||
tbl[3]=NULL; // Archive time is not used now.
|
||||
for (int I=0;I<4;I++)
|
||||
{
|
||||
RarTime *CurTime=tbl[I];
|
||||
uint rmode=Flags>>(3-I)*4;
|
||||
if ((rmode & 8)==0 || CurTime==NULL)
|
||||
continue;
|
||||
if (I!=0)
|
||||
{
|
||||
uint DosTime=Raw.Get4();
|
||||
CurTime->SetDos(DosTime);
|
||||
}
|
||||
RarLocalTime rlt;
|
||||
CurTime->GetLocal(&rlt);
|
||||
if (rmode & 4)
|
||||
rlt.Second++;
|
||||
rlt.Reminder=0;
|
||||
int count=rmode&3;
|
||||
for (int J=0;J<count;J++)
|
||||
{
|
||||
byte CurByte=Raw.Get1();
|
||||
rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
|
||||
}
|
||||
CurTime->SetLocal(&rlt);
|
||||
}
|
||||
}
|
||||
NextBlockPos+=hd->PackSize;
|
||||
bool CRCProcessedOnly=hd->CommentInHeader;
|
||||
ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
|
||||
if (hd->HeadCRC!=HeaderCRC)
|
||||
return unrar_err_corrupt;
|
||||
}
|
||||
break;
|
||||
case HEAD_ENDARC:
|
||||
*(BaseBlock *)&EndArcHead=ShortBlock;
|
||||
EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0;
|
||||
EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0;
|
||||
EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0;
|
||||
EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0;
|
||||
if (EndArcHead.DataCRC)
|
||||
EndArcHead.ArcDataCRC=Raw.Get4();
|
||||
if (EndArcHead.StoreVolNumber)
|
||||
return unrar_err_segmented;
|
||||
break;
|
||||
default:
|
||||
if (ShortBlock.Flags & LONG_BLOCK)
|
||||
NextBlockPos+=Raw.Get4();
|
||||
break;
|
||||
}
|
||||
|
||||
ushort HeaderCRC=Raw.GetCRC15(false);
|
||||
|
||||
// Old AV header does not have header CRC properly set.
|
||||
if (ShortBlock.HeadCRC!=HeaderCRC && ShortBlock.HeaderType!=HEAD3_SIGN &&
|
||||
ShortBlock.HeaderType!=HEAD3_AV)
|
||||
return unrar_err_corrupt;
|
||||
|
||||
if (NextBlockPos<=CurBlockPos)
|
||||
return unrar_err_corrupt;
|
||||
|
||||
*ReadSize=Raw.Size();
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
|
||||
unrar_err_t Archive::ReadHeader50(size_t *ReadSize)
|
||||
{
|
||||
Raw.Reset();
|
||||
|
||||
// Header size must not occupy more than 3 variable length integer bytes
|
||||
// resulting in 2 MB maximum header size, so here we read 4 byte CRC32
|
||||
// followed by 3 bytes or less of header size.
|
||||
const size_t FirstReadSize=7; // Smallest possible block size.
|
||||
if (Raw.Read(FirstReadSize)<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;
|
||||
}
|
||||
|
||||
if (NextBlockPos<=CurBlockPos)
|
||||
return unrar_err_corrupt;
|
||||
|
||||
*ReadSize=Raw.Size();
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
unrar_err_t Archive::ReadHeader14(size_t *ReadSize)
|
||||
{
|
||||
Raw.Reset();
|
||||
|
||||
if (CurBlockPos<=(int64)SFXSize)
|
||||
{
|
||||
Raw.Read(SIZEOF_MAINHEAD14);
|
||||
MainHead.Reset();
|
||||
byte Mark[4];
|
||||
Raw.GetB(Mark,4);
|
||||
uint HeadSize=Raw.Get2();
|
||||
byte Flags=Raw.Get1();
|
||||
NextBlockPos=CurBlockPos+HeadSize;
|
||||
CurHeaderType=HEAD_MAIN;
|
||||
|
||||
Solid=(Flags & MHD_SOLID)!=0;
|
||||
MainHead.CommentInHeader=(Flags & MHD_COMMENT)!=0;
|
||||
MainHead.PackComment=(Flags & MHD_PACK_COMMENT)!=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Raw.Read(SIZEOF_FILEHEAD14);
|
||||
FileHead.Reset();
|
||||
|
||||
FileHead.HeaderType=HEAD_FILE;
|
||||
FileHead.DataSize=Raw.Get4();
|
||||
FileHead.UnpSize=Raw.Get4();
|
||||
FileHead.FileHash.Type=HASH_RAR14;
|
||||
FileHead.FileHash.CRC32=Raw.Get2();
|
||||
FileHead.HeadSize=Raw.Get2();
|
||||
uint FileTime=Raw.Get4();
|
||||
FileHead.FileAttr=Raw.Get1();
|
||||
FileHead.Flags=Raw.Get1()|LONG_BLOCK;
|
||||
FileHead.UnpVer=(Raw.Get1()==2) ? 13 : 10;
|
||||
size_t NameSize=Raw.Get1();
|
||||
FileHead.Method=Raw.Get1();
|
||||
|
||||
FileHead.SplitBefore=(FileHead.Flags & LHD_SPLIT_BEFORE)!=0;
|
||||
FileHead.SplitAfter=(FileHead.Flags & LHD_SPLIT_AFTER)!=0;
|
||||
FileHead.Encrypted=(FileHead.Flags & LHD_PASSWORD)!=0;
|
||||
if (FileHead.Encrypted)
|
||||
return unrar_err_encrypted;
|
||||
|
||||
FileHead.PackSize=FileHead.DataSize;
|
||||
FileHead.WinSize=0x10000;
|
||||
|
||||
FileHead.mtime.SetDos(FileTime);
|
||||
|
||||
Raw.Read(NameSize);
|
||||
|
||||
char FileName[NM];
|
||||
Raw.GetB((byte *)FileName,Min(NameSize,ASIZE(FileName)));
|
||||
FileName[NameSize]=0;
|
||||
IntToExt(FileName,FileName,ASIZE(FileName));
|
||||
CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName));
|
||||
|
||||
if (Raw.Size()!=0)
|
||||
NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize;
|
||||
CurHeaderType=HEAD_FILE;
|
||||
}
|
||||
*ReadSize=(NextBlockPos>CurBlockPos ? Raw.Size():0);
|
||||
return unrar_ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// (removed name case and attribute conversion)
|
||||
|
||||
bool Archive::IsArcDir()
|
||||
{
|
||||
return FileHead.Dir;
|
||||
}
|
||||
|
||||
|
||||
bool Archive::IsArcLabel()
|
||||
{
|
||||
return(FileHead.HostOS<=HOST_WIN32 && (FileHead.FileAttr & 8));
|
||||
}
|
||||
|
||||
|
||||
void Archive::ConvertFileHeader(FileHeader *hd)
|
||||
{
|
||||
if (Format==RARFMT15 && hd->UnpVer<20 && (hd->FileAttr & 0x10))
|
||||
hd->Dir=true;
|
||||
if (hd->HSType==HSYS_UNKNOWN)
|
||||
if (hd->Dir)
|
||||
hd->FileAttr=0x10;
|
||||
else
|
||||
hd->FileAttr=0x20;
|
||||
}
|
||||
|
||||
|
||||
int64 Archive::GetStartPos()
|
||||
{
|
||||
int64 StartPos=SFXSize+MarkHead.HeadSize;
|
||||
StartPos+=MainHead.HeadSize;
|
||||
return StartPos;
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
#ifndef _RAR_ARRAY_
|
||||
#define _RAR_ARRAY_
|
||||
|
||||
#include <new>
|
||||
|
||||
template <class T> class Array
|
||||
{
|
||||
private:
|
||||
T *Buffer;
|
||||
size_t BufSize;
|
||||
size_t AllocSize;
|
||||
size_t MaxSize;
|
||||
public:
|
||||
Array();
|
||||
Array(size_t Size);
|
||||
Array(const Array &Src); // Copy constructor.
|
||||
~Array();
|
||||
inline void CleanData();
|
||||
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);
|
||||
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()
|
||||
{
|
||||
Buffer=NULL;
|
||||
BufSize=0;
|
||||
AllocSize=0;
|
||||
MaxSize=0;
|
||||
}
|
||||
|
||||
|
||||
template <class T> Array<T>::Array()
|
||||
{
|
||||
CleanData();
|
||||
}
|
||||
|
||||
|
||||
template <class T> Array<T>::Array(size_t Size)
|
||||
{
|
||||
CleanData();
|
||||
Add(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));
|
||||
}
|
||||
|
||||
|
||||
template <class T> Array<T>::~Array()
|
||||
{
|
||||
if (Buffer!=NULL)
|
||||
rarfree(Buffer);
|
||||
}
|
||||
|
||||
|
||||
template <class T> inline T& Array<T>::operator [](size_t Item) const
|
||||
{
|
||||
return Buffer[Item];
|
||||
}
|
||||
|
||||
|
||||
template <class T> inline T* Array<T>::operator +(size_t Pos)
|
||||
{
|
||||
return Buffer+Pos;
|
||||
}
|
||||
|
||||
|
||||
template <class T> inline size_t Array<T>::Size()
|
||||
{
|
||||
return BufSize;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Add(size_t Items)
|
||||
{
|
||||
size_t NewBufSize=BufSize+Items;
|
||||
if (NewBufSize>AllocSize)
|
||||
{
|
||||
if (MaxSize!=0 && NewBufSize>MaxSize)
|
||||
throw std::bad_alloc();
|
||||
|
||||
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;
|
||||
}
|
||||
BufSize=NewBufSize;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Alloc(size_t Items)
|
||||
{
|
||||
if (Items>AllocSize)
|
||||
Add(Items-BufSize);
|
||||
else
|
||||
BufSize=Items;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Reset()
|
||||
{
|
||||
// Keep memory allocated if it's small
|
||||
// Eliminates constant reallocation when scanning archive
|
||||
if ( AllocSize < 1024/sizeof(T) )
|
||||
{
|
||||
BufSize = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Buffer!=NULL)
|
||||
{
|
||||
rarfree(Buffer);
|
||||
Buffer=NULL;
|
||||
}
|
||||
BufSize=0;
|
||||
AllocSize=0;
|
||||
}
|
||||
|
||||
|
||||
// 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();
|
||||
Alloc(Src.BufSize);
|
||||
if (Src.BufSize!=0)
|
||||
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Push(T Item)
|
||||
{
|
||||
Add(1);
|
||||
(*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
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
// Based on public domain code written in 2012 by Samuel Neves
|
||||
|
||||
#ifdef RAR_COMMON_HPP
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifdef RAR_COMMON_HPP
|
||||
|
||||
#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 );
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,141 @@
|
|||
unrar_core source code changes
|
||||
------------------------------
|
||||
Unrar_core is based on UnRAR (unrarsrc-3.8.5.tar.gz) by Alexander L.
|
||||
Roshal. The original sources have been HEAVILY modified, trimmed down,
|
||||
and purged of all OS-specific calls for file access and other
|
||||
unnecessary operations. Support for encryption, recovery records, and
|
||||
segmentation has been REMOVED. See license.txt for licensing. In
|
||||
particular, this code cannot be used to re-create the RAR compression
|
||||
algorithm, which is proprietary.
|
||||
|
||||
If you obtained this code as a part of my File_Extractor library and
|
||||
want to use it on its own, get my unrar_core library, which includes
|
||||
examples and documentation.
|
||||
|
||||
The source is as close as possible to the original, to make it simple to
|
||||
update when a new version of UnRAR comes out. In many places the
|
||||
original names and object nesting are kept, even though it's a bit
|
||||
harder to follow. See rar.hpp for the main "glue".
|
||||
|
||||
Website: http://www.slack.net/~ant/
|
||||
E-mail : Shay Green <gblargg@gmail.com>
|
||||
|
||||
|
||||
Contents
|
||||
--------
|
||||
* Diff-friendly changes
|
||||
* Removal of features
|
||||
* Error reporting changes
|
||||
* Minor tweaks
|
||||
* Unrar findings
|
||||
|
||||
|
||||
Diff-friendly changes
|
||||
---------------------
|
||||
To make my source code changes more easily visible with a line-based
|
||||
file diff, I've tried to make changes by inserting or deleting lines,
|
||||
rather than modifying them. So if the original declared a static array
|
||||
|
||||
static int array [4] = { 1, 2, 3, 4 };
|
||||
|
||||
and I want to make it const, I add the const on a line before
|
||||
|
||||
const // added
|
||||
static int array [4] = { 1, 2, 3, 4 };
|
||||
|
||||
rather than on the same line
|
||||
|
||||
static const int array [4] = { 1, 2, 3, 4 };
|
||||
|
||||
This way a diff will simply show an added line, making it clear what was
|
||||
added. If I simply inserted const on the same line, it wouldn't be as
|
||||
clear what all I had changed.
|
||||
|
||||
I've also made use of several macros rather than changing the source
|
||||
text. For example, since a class name like Unpack might easily conflict,
|
||||
I've renamed it to Rar_Unpack by using #define Unpack Rar_Unpack rather
|
||||
than changing the source text. These macros are only defined when
|
||||
compiling the library sources; the user-visible unrar.h is very clean.
|
||||
|
||||
|
||||
Removal of features
|
||||
-------------------
|
||||
This library is meant for simple access to common archives without
|
||||
having to extract them first. Encryption, segmentation, huge files, and
|
||||
self-extracting archives aren't common for things that need to be
|
||||
accessed in this manner, so I've removed support for them. Also,
|
||||
encryption adds complexity to the code that must be maintained.
|
||||
Segmentation would require a way to specify the other segments.
|
||||
|
||||
|
||||
Error reporting changes
|
||||
-----------------------
|
||||
The original used C++ exceptions to report errors. I've eliminated use
|
||||
of these through a combination of error codes and longjmp. This allows
|
||||
use of the library from C or some other language which doesn't easily
|
||||
support exceptions.
|
||||
|
||||
I tried to make as few changes as possible in the conversion. Due to the
|
||||
number of places file reads occur, propagating an error code via return
|
||||
statements would have required too many code changes. Instead, I perform
|
||||
the read, save the error code, and return 0 bytes read in case of an
|
||||
error. I also ensure that the calling code interprets this zero in an
|
||||
acceptable way. I then check this saved error code after the operation
|
||||
completes, and have it take priority over the error the RAR code
|
||||
returned. I do a similar thing for write errors.
|
||||
|
||||
|
||||
Minor tweaks
|
||||
------------
|
||||
- Eliminated as many GCC warnings as reasonably possible.
|
||||
|
||||
- Non-class array allocations now use malloc(), allowing the code to be
|
||||
linked without the standard C++ library (particularly, operator new).
|
||||
Class object allocations use a class-specific allocator that just calls
|
||||
malloc(), also avoiding calls to operator new.
|
||||
|
||||
- Made all unchanging static data const. Several pieces of static data
|
||||
in the original code weren't marked const where they could be.
|
||||
|
||||
- Initialization of some static tables was done on an as-needed basis,
|
||||
creating a problem when extracting from archives in multiple threads.
|
||||
This initialization can now be done by the user before any archives are
|
||||
opened.
|
||||
|
||||
- Tweaked CopyString, the major bottleneck during compression. I inlined
|
||||
it, cached some variables in locals in case the compiler couldn't easily
|
||||
see that the memory accesses don't modify them, and made them use
|
||||
memcpy() where possible. This improved performance by at least 20% on
|
||||
x86. Perhaps it won't work as well on files with lots of smaller string
|
||||
matches.
|
||||
|
||||
- Some .cpp files are #included by others. I've added guards to these so
|
||||
that you can simply compile all .cpp files and not get any redefinition
|
||||
errors.
|
||||
|
||||
- The current solid extraction position is kept track of, allowing the
|
||||
user to randomly extract files without regard to proper extraction
|
||||
order. The library optimizes solid extraction and only restarts it if
|
||||
the user is extracting a file earlier in the archive than the last
|
||||
solid-extracted one.
|
||||
|
||||
- Most of the time a solid file's data is already contiguously in the
|
||||
internal Unpack::Window, which unrar_extract_mem() takes advantage of.
|
||||
This avoids extra allocation in many cases.
|
||||
|
||||
- Allocation of Unpack is delayed until the first extraction, rather
|
||||
than being allocated immediately on opening the archive. This allows
|
||||
scanning with minimal memory usage.
|
||||
|
||||
|
||||
Unrar findings
|
||||
--------------
|
||||
- Apparently the LHD_SOLID flag indicates that file depends on previous
|
||||
files, rather than that later files depend on the current file's
|
||||
contents. Thus this flag can't be used to intelligently decide which
|
||||
files need to be internally extracted when skipping them, making it
|
||||
necessary to internally extract every file before the one to be
|
||||
extracted, if the archive is solid.
|
||||
|
||||
--
|
||||
Shay Green <gblargg@gmail.com>
|
|
@ -0,0 +1,50 @@
|
|||
// #included by unpack.cpp
|
||||
#ifdef RAR_COMMON_HPP
|
||||
|
||||
inline unsigned int RangeCoder::GetChar()
|
||||
{
|
||||
return(UnpackRead->GetChar());
|
||||
}
|
||||
|
||||
|
||||
void RangeCoder::InitDecoder(Unpack *UnpackRead)
|
||||
{
|
||||
RangeCoder::UnpackRead=UnpackRead;
|
||||
|
||||
low=code=0;
|
||||
range=uint(-1);
|
||||
for (int i=0;i < 4;i++)
|
||||
code=(code << 8) | GetChar();
|
||||
}
|
||||
|
||||
|
||||
// (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=-(int)low&(BOT-1)),1)) \
|
||||
{ \
|
||||
code=(code << 8) | read->GetChar(); \
|
||||
range <<= 8; \
|
||||
low <<= 8; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
inline int RangeCoder::GetCurrentCount()
|
||||
{
|
||||
return (code-low)/(range /= SubRange.scale);
|
||||
}
|
||||
|
||||
|
||||
inline uint RangeCoder::GetCurrentShiftCount(uint SHIFT)
|
||||
{
|
||||
return (code-low)/(range >>= SHIFT);
|
||||
}
|
||||
|
||||
|
||||
inline void RangeCoder::Decode()
|
||||
{
|
||||
low += range*SubRange.LowCount;
|
||||
range *= SubRange.HighCount-SubRange.LowCount;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,23 @@
|
|||
/****************************************************************************
|
||||
* Contents: 'Carryless rangecoder' by Dmitry Subbotin *
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
class RangeCoder
|
||||
{
|
||||
public:
|
||||
void InitDecoder(Unpack *UnpackRead);
|
||||
inline int GetCurrentCount();
|
||||
inline uint GetCurrentShiftCount(uint SHIFT);
|
||||
inline void Decode();
|
||||
inline void PutChar(unsigned int c);
|
||||
inline unsigned int GetChar();
|
||||
|
||||
uint low, code, range;
|
||||
struct SUBRANGE
|
||||
{
|
||||
uint LowCount, HighCount, scale;
|
||||
} SubRange;
|
||||
|
||||
Unpack *UnpackRead;
|
||||
};
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef _RAR_COMPRESS_
|
||||
#define _RAR_COMPRESS_
|
||||
|
||||
// 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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
// Largest alphabet size among all values listed above.
|
||||
static const uint LARGEST_TABLE_SIZE = 306;
|
||||
|
||||
enum {
|
||||
CODE_HUFFMAN, CODE_LZ, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE,
|
||||
CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
enum FilterType {
|
||||
// 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
|
|
@ -0,0 +1,97 @@
|
|||
// This CRC function is based on Intel Slicing-by-8 algorithm.
|
||||
//
|
||||
// Original Intel Slicing-by-8 code is available here:
|
||||
//
|
||||
// http://sourceforge.net/projects/slicing-by-8/
|
||||
//
|
||||
// Original Intel Slicing-by-8 code is licensed as:
|
||||
//
|
||||
// Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved
|
||||
//
|
||||
// This software program is licensed subject to the BSD License,
|
||||
// available at http://www.opensource.org/licenses/bsd-license.html
|
||||
|
||||
|
||||
#include "rar.hpp"
|
||||
|
||||
uint crc_tables[8][256]; // Tables for Slicing-by-8.
|
||||
|
||||
|
||||
// Build the classic CRC32 lookup table.
|
||||
// We also provide this function to legacy RAR and ZIP decryption code.
|
||||
void InitCRC32(uint *CRCTab)
|
||||
{
|
||||
if (CRCTab[1]!=0)
|
||||
return;
|
||||
for (uint I=0;I<256;I++)
|
||||
{
|
||||
uint C=I;
|
||||
for (uint J=0;J<8;J++)
|
||||
C=(C & 1) ? (C>>1)^0xEDB88320 : (C>>1);
|
||||
CRCTab[I]=C;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
byte *Data=(byte *)Addr;
|
||||
|
||||
// Align Data to 8 for better performance.
|
||||
for (;Size>0 && ((size_t)Data & 7);Size--,Data++)
|
||||
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
|
||||
|
||||
for (;Size>=8;Size-=8,Data+=8)
|
||||
{
|
||||
#ifdef BIG_ENDIAN
|
||||
StartCRC ^= Data[0]|(Data[1] << 8)|(Data[2] << 16)|(Data[3] << 24);
|
||||
uint NextData = Data[4]|(Data[5] << 8)|(Data[6] << 16)|(Data[7] << 24);
|
||||
#else
|
||||
StartCRC ^= *(uint32 *) Data;
|
||||
uint NextData = *(uint32 *) (Data +4);
|
||||
#endif
|
||||
StartCRC = crc_tables[7][(byte) StartCRC ] ^
|
||||
crc_tables[6][(byte)(StartCRC >> 8) ] ^
|
||||
crc_tables[5][(byte)(StartCRC >> 16)] ^
|
||||
crc_tables[4][(byte)(StartCRC >> 24)] ^
|
||||
crc_tables[3][(byte) NextData ] ^
|
||||
crc_tables[2][(byte)(NextData >>8 ) ] ^
|
||||
crc_tables[1][(byte)(NextData >> 16)] ^
|
||||
crc_tables[0][(byte)(NextData >> 24)];
|
||||
}
|
||||
|
||||
for (;Size>0;Size--,Data++) // Process left data.
|
||||
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
|
||||
|
||||
return StartCRC;
|
||||
}
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
// 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++)
|
||||
{
|
||||
StartCRC=(StartCRC+Data[I])&0xffff;
|
||||
StartCRC=((StartCRC<<1)|(StartCRC>>15))&0xffff;
|
||||
}
|
||||
return StartCRC;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,57 @@
|
|||
#include "rar.hpp"
|
||||
|
||||
EncodeFileName::EncodeFileName()
|
||||
{
|
||||
Flags=0;
|
||||
FlagBits=0;
|
||||
FlagsPos=0;
|
||||
DestSize=0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void EncodeFileName::Decode(char *Name,byte *EncName,size_t EncSize,wchar *NameW,
|
||||
size_t MaxDecSize)
|
||||
{
|
||||
size_t EncPos=0,DecPos=0;
|
||||
byte HighByte=EncName[EncPos++];
|
||||
while (EncPos<EncSize && DecPos<MaxDecSize)
|
||||
{
|
||||
if (FlagBits==0)
|
||||
{
|
||||
Flags=EncName[EncPos++];
|
||||
FlagBits=8;
|
||||
}
|
||||
switch(Flags>>6)
|
||||
{
|
||||
case 0:
|
||||
NameW[DecPos++]=EncName[EncPos++];
|
||||
break;
|
||||
case 1:
|
||||
NameW[DecPos++]=EncName[EncPos++]+(HighByte<<8);
|
||||
break;
|
||||
case 2:
|
||||
NameW[DecPos++]=EncName[EncPos]+(EncName[EncPos+1]<<8);
|
||||
EncPos+=2;
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
int Length=EncName[EncPos++];
|
||||
if (Length & 0x80)
|
||||
{
|
||||
byte Correction=EncName[EncPos++];
|
||||
for (Length=(Length&0x7f)+2;Length>0 && DecPos<MaxDecSize;Length--,DecPos++)
|
||||
NameW[DecPos]=((Name[DecPos]+Correction)&0xff)+(HighByte<<8);
|
||||
}
|
||||
else
|
||||
for (Length+=2;Length>0 && DecPos<MaxDecSize;Length--,DecPos++)
|
||||
NameW[DecPos]=Name[DecPos];
|
||||
}
|
||||
break;
|
||||
}
|
||||
Flags<<=2;
|
||||
FlagBits-=2;
|
||||
}
|
||||
NameW[DecPos<MaxDecSize ? DecPos:MaxDecSize-1]=0;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef _RAR_ENCNAME_
|
||||
#define _RAR_ENCNAME_
|
||||
|
||||
class EncodeFileName
|
||||
{
|
||||
private:
|
||||
void AddFlags(int Value);
|
||||
|
||||
byte *EncName;
|
||||
byte Flags;
|
||||
size_t FlagBits;
|
||||
size_t FlagsPos;
|
||||
size_t DestSize;
|
||||
public:
|
||||
EncodeFileName();
|
||||
size_t Encode(char *Name,wchar *NameW,byte *EncName);
|
||||
void Decode(char *Name,byte *EncName,size_t EncSize,wchar *NameW,size_t MaxDecSize);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,114 @@
|
|||
#include <stdio.h>
|
||||
#include "rar.hpp"
|
||||
|
||||
#include "unrar.h"
|
||||
|
||||
#define DataIO Arc
|
||||
|
||||
unrar_err_t CmdExtract::ExtractCurrentFile( bool SkipSolid, bool check_compatibility_only )
|
||||
{
|
||||
check( Arc.GetHeaderType() == FILE_HEAD );
|
||||
|
||||
if ( Arc.FileHead.SplitBefore || Arc.FileHead.SplitAfter )
|
||||
return unrar_err_segmented;
|
||||
|
||||
if ( Arc.FileHead.Encrypted )
|
||||
return unrar_err_encrypted;
|
||||
|
||||
if ( !check_compatibility_only )
|
||||
{
|
||||
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.FileHead.UnpVer!=UNP_VER && Arc.FileHead.UnpVer!=29) &&
|
||||
Arc.FileHead.Method!=0x30)
|
||||
#else
|
||||
if (Arc.FileHead.UnpVer!=VER_UNPACK5 &&
|
||||
(Arc.FileHead.UnpVer<13 || Arc.FileHead.UnpVer>VER_UNPACK))
|
||||
#endif
|
||||
{
|
||||
if (Arc.FileHead.UnpVer>VER_UNPACK)
|
||||
return unrar_err_new_algo;
|
||||
return unrar_err_old_algo;
|
||||
}
|
||||
|
||||
if ( check_compatibility_only )
|
||||
return unrar_ok;
|
||||
|
||||
// (removed lots of command-line/encryption/volume handling)
|
||||
|
||||
update_first_file_pos();
|
||||
FileCount++;
|
||||
DataIO.UnpFileCRC=Arc.OldFormat ? 0 : 0xffffffff;
|
||||
// (removed decryption)
|
||||
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.FileHead.Method==0)
|
||||
UnstoreFile(Arc.FileHead.UnpSize);
|
||||
else
|
||||
{
|
||||
// Defer creation of Unpack until first extraction
|
||||
if ( !Unp )
|
||||
{
|
||||
Unp = new Unpack( &Arc );
|
||||
if ( !Unp )
|
||||
return unrar_err_memory;
|
||||
}
|
||||
|
||||
Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid);
|
||||
Unp->SetDestSize(Arc.FileHead.UnpSize);
|
||||
#ifndef SFX_MODULE
|
||||
if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15)
|
||||
Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
|
||||
else
|
||||
#endif
|
||||
Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Solid);
|
||||
}
|
||||
|
||||
// (no need to seek to next file)
|
||||
|
||||
if (!SkipSolid)
|
||||
{
|
||||
HashValue UnpHash;
|
||||
DataIO.UnpHash.Result(&UnpHash);
|
||||
if (UnpHash==Arc.FileHead.FileHash)
|
||||
{
|
||||
// CRC is correct
|
||||
}
|
||||
else
|
||||
{
|
||||
return unrar_err_corrupt;
|
||||
}
|
||||
}
|
||||
|
||||
// (removed broken file handling)
|
||||
// (removed command-line handling)
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
|
||||
void CmdExtract::UnstoreFile(int64 DestUnpSize)
|
||||
{
|
||||
Buffer.Alloc((int)Min(DestUnpSize,0x10000));
|
||||
while (1)
|
||||
{
|
||||
unsigned int Code=DataIO.UnpRead(&Buffer[0],(uint)Buffer.Size());
|
||||
if (Code==0 || (int)Code==-1)
|
||||
break;
|
||||
Code=Code<DestUnpSize ? Code:int64to32(DestUnpSize);
|
||||
DataIO.UnpWrite(&Buffer[0],Code);
|
||||
if (DestUnpSize>=0)
|
||||
DestUnpSize-=Code;
|
||||
}
|
||||
Buffer.Reset();
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
#include "rar.hpp"
|
||||
|
||||
BitInput::BitInput(bool AllocBuffer)
|
||||
{
|
||||
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];
|
||||
|
||||
// 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()
|
||||
{
|
||||
if (!ExternalBuffer)
|
||||
delete[] InBuf;
|
||||
}
|
||||
|
||||
void BitInput::handle_mem_error( Rar_Error_Handler& ErrHandler )
|
||||
{
|
||||
if ( !InBuf )
|
||||
ErrHandler.MemoryError();
|
||||
}
|
||||
|
||||
void BitInput::faddbits(uint Bits)
|
||||
{
|
||||
// Function wrapped version of inline addbits to save code size.
|
||||
addbits(Bits);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef _RAR_GETBITS_
|
||||
#define _RAR_GETBITS_
|
||||
|
||||
class BitInput
|
||||
: public Rar_Allocator
|
||||
{
|
||||
public:
|
||||
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(bool AllocBuffer);
|
||||
~BitInput();
|
||||
void handle_mem_error( Rar_Error_Handler& );
|
||||
|
||||
byte *InBuf; // Dynamically allocated input buffer.
|
||||
|
||||
void InitBitInput()
|
||||
{
|
||||
InAddr=InBit=0;
|
||||
}
|
||||
|
||||
// Move forward by 'Bits' bits.
|
||||
void addbits(uint Bits)
|
||||
{
|
||||
Bits+=InBit;
|
||||
InAddr+=Bits>>3;
|
||||
InBit=Bits&7;
|
||||
}
|
||||
|
||||
// Return 16 bits from current position in the buffer.
|
||||
// Bit at (InAddr,InBit) has the highest position in returning data.
|
||||
uint getbits()
|
||||
{
|
||||
uint BitField=(uint)InBuf[InAddr] << 16;
|
||||
BitField|=(uint)InBuf[InAddr+1] << 8;
|
||||
BitField|=(uint)InBuf[InAddr+2];
|
||||
BitField >>= (8-InBit);
|
||||
return(BitField & 0xffff);
|
||||
}
|
||||
|
||||
// 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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,362 @@
|
|||
#ifndef _RAR_HEADERS_
|
||||
#define _RAR_HEADERS_
|
||||
|
||||
#define SIZEOF_MARKHEAD3 7 // Size of RAR 4.x archive mark header.
|
||||
#define SIZEOF_MAINHEAD14 7 // Size of RAR 1.4 main archive header.
|
||||
#define SIZEOF_MAINHEAD3 13 // Size of RAR 4.x main archive header.
|
||||
#define SIZEOF_FILEHEAD14 21 // Size of RAR 1.4 file header.
|
||||
#define SIZEOF_FILEHEAD3 32 // Size of RAR 3.0 file header.
|
||||
#define SIZEOF_SHORTBLOCKHEAD 7
|
||||
#define SIZEOF_LONGBLOCKHEAD 11
|
||||
#define SIZEOF_SUBBLOCKHEAD 14
|
||||
#define SIZEOF_COMMHEAD 13
|
||||
#define SIZEOF_PROTECTHEAD 26
|
||||
#define SIZEOF_AVHEAD 14
|
||||
#define SIZEOF_SIGNHEAD 15
|
||||
#define SIZEOF_UOHEAD 18
|
||||
#define SIZEOF_MACHEAD 22
|
||||
#define SIZEOF_EAHEAD 24
|
||||
#define SIZEOF_BEEAHEAD 24
|
||||
#define SIZEOF_STREAMHEAD 26
|
||||
|
||||
#define VER_PACK 29
|
||||
#define VER_PACK5 0
|
||||
#define VER_UNPACK 29
|
||||
#define VER_UNPACK5 0
|
||||
|
||||
#define MHD_VOLUME 0x0001U
|
||||
|
||||
// Old style main archive comment embed into main archive header. Must not
|
||||
// be used in new archives anymore.
|
||||
#define MHD_COMMENT 0x0002U
|
||||
|
||||
#define MHD_LOCK 0x0004U
|
||||
#define MHD_SOLID 0x0008U
|
||||
#define MHD_PACK_COMMENT 0x0010U
|
||||
#define MHD_NEWNUMBERING 0x0010U
|
||||
#define MHD_AV 0x0020U
|
||||
#define MHD_PROTECT 0x0040U
|
||||
#define MHD_PASSWORD 0x0080U
|
||||
#define MHD_FIRSTVOLUME 0x0100U
|
||||
|
||||
#define LHD_SPLIT_BEFORE 0x0001U
|
||||
#define LHD_SPLIT_AFTER 0x0002U
|
||||
#define LHD_PASSWORD 0x0004U
|
||||
|
||||
// Old style file comment embed into file header. Must not be used
|
||||
// in new archives anymore.
|
||||
#define LHD_COMMENT 0x0008U
|
||||
|
||||
// For non-file subheaders it denotes 'subblock having a parent file' flag.
|
||||
#define LHD_SOLID 0x0010U
|
||||
|
||||
|
||||
#define LHD_WINDOWMASK 0x00e0U
|
||||
#define LHD_WINDOW64 0x0000U
|
||||
#define LHD_WINDOW128 0x0020U
|
||||
#define LHD_WINDOW256 0x0040U
|
||||
#define LHD_WINDOW512 0x0060U
|
||||
#define LHD_WINDOW1024 0x0080U
|
||||
#define LHD_WINDOW2048 0x00a0U
|
||||
#define LHD_WINDOW4096 0x00c0U
|
||||
#define LHD_DIRECTORY 0x00e0U
|
||||
|
||||
#define LHD_LARGE 0x0100U
|
||||
#define LHD_UNICODE 0x0200U
|
||||
#define LHD_SALT 0x0400U
|
||||
#define LHD_VERSION 0x0800U
|
||||
#define LHD_EXTTIME 0x1000U
|
||||
|
||||
#define SKIP_IF_UNKNOWN 0x4000U
|
||||
#define LONG_BLOCK 0x8000U
|
||||
|
||||
#define EARC_NEXT_VOLUME 0x0001U // Not last volume.
|
||||
#define EARC_DATACRC 0x0002U // Store CRC32 of RAR archive (now is used only in volumes).
|
||||
#define EARC_REVSPACE 0x0004U // Reserve space for end of REV file 7 byte record.
|
||||
#define EARC_VOLNUMBER 0x0008U // Store a number of current volume.
|
||||
|
||||
enum HEADER_TYPE {
|
||||
// RAR 5.0 header types.
|
||||
HEAD_MARK=0x00, HEAD_MAIN=0x01, HEAD_FILE=0x02, HEAD_SERVICE=0x03,
|
||||
HEAD_CRYPT=0x04, HEAD_ENDARC=0x05, HEAD_UNKNOWN=0xff,
|
||||
|
||||
// RAR 1.5 - 4.x header types.
|
||||
HEAD3_MARK=0x72,HEAD3_MAIN=0x73,HEAD3_FILE=0x74,HEAD3_CMT=0x75,
|
||||
HEAD3_AV=0x76,HEAD3_OLDSERVICE=0x77,HEAD3_PROTECT=0x78,HEAD3_SIGN=0x79,
|
||||
HEAD3_SERVICE=0x7a,HEAD3_ENDARC=0x7b
|
||||
};
|
||||
|
||||
enum { EA_HEAD=0x100,UO_HEAD=0x101,MAC_HEAD=0x102,BEEA_HEAD=0x103,
|
||||
NTACL_HEAD=0x104,STREAM_HEAD=0x105 };
|
||||
|
||||
|
||||
// Internal implementation, depends on archive format version.
|
||||
enum HOST_SYSTEM {
|
||||
// RAR 5.0 host OS
|
||||
HOST5_WINDOWS=0,HOST5_UNIX=1,
|
||||
|
||||
// RAR 3.0 host OS.
|
||||
HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4,
|
||||
HOST_BEOS=5,HOST_MAX
|
||||
};
|
||||
|
||||
// Unified archive format independent implementation.
|
||||
enum HOST_SYSTEM_TYPE {
|
||||
HSYS_WINDOWS, HSYS_UNIX, HSYS_UNKNOWN
|
||||
};
|
||||
|
||||
|
||||
// We also use these values in extra field, so do not modify them.
|
||||
enum FILE_SYSTEM_REDIRECT {
|
||||
FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION,
|
||||
FSREDIR_HARDLINK, FSREDIR_FILECOPY
|
||||
};
|
||||
|
||||
|
||||
static const wchar SUBHEAD_TYPE_CMT[] = {'C', 'M', 'T', 0};
|
||||
static const wchar SUBHEAD_TYPE_QOPEN[] = {'Q', 'O', 0};
|
||||
static const wchar SUBHEAD_TYPE_ACL[] = {'A', 'C', 'L', 0};
|
||||
static const wchar SUBHEAD_TYPE_STREAM[] = {'S', 'T', 'M', 0};
|
||||
static const wchar SUBHEAD_TYPE_UOWNER[] = {'U', 'O', 'W', 0};
|
||||
static const wchar SUBHEAD_TYPE_AV[] = {'A', 'V', 0};
|
||||
static const wchar SUBHEAD_TYPE_RR[] = {'R', 'R', 0};
|
||||
static const wchar SUBHEAD_TYPE_OS2EA[] = {'E', 'A', '2', 0};
|
||||
|
||||
/* new file inherits a subblock when updating a host file */
|
||||
#define SUBHEAD_FLAGS_INHERITED 0x80000000
|
||||
|
||||
#define SUBHEAD_FLAGS_CMT_UNICODE 0x00000001
|
||||
|
||||
|
||||
struct MarkHeader
|
||||
{
|
||||
byte Mark[8];
|
||||
|
||||
// Following fields are virtual and not present in real blocks.
|
||||
uint HeadSize;
|
||||
};
|
||||
|
||||
|
||||
struct BaseBlock
|
||||
{
|
||||
uint HeadCRC; // 'ushort' for RAR 1.5.
|
||||
HEADER_TYPE HeaderType; // 1 byte for RAR 1.5.
|
||||
uint Flags; // 'ushort' for RAR 1.5.
|
||||
uint HeadSize; // 'ushort' for RAR 1.5, up to 2 MB for RAR 5.0.
|
||||
|
||||
bool SkipIfUnknown;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
SkipIfUnknown=false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct BlockHeader:BaseBlock
|
||||
{
|
||||
uint DataSize;
|
||||
};
|
||||
|
||||
|
||||
struct MainHeader:BaseBlock
|
||||
{
|
||||
ushort HighPosAV;
|
||||
uint PosAV;
|
||||
bool CommentInHeader;
|
||||
bool PackComment; // For RAR 1.4 archive format only.
|
||||
bool Locator;
|
||||
uint64 QOpenOffset; // Offset of quick list record.
|
||||
uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field.
|
||||
uint64 RROffset; // Offset of recovery record.
|
||||
uint64 RRMaxSize; // Maximum size of RR offset in locator extra field.
|
||||
void Reset();
|
||||
};
|
||||
|
||||
|
||||
struct FileHeader:BlockHeader
|
||||
{
|
||||
byte HostOS;
|
||||
byte UnpVer;
|
||||
byte Method;
|
||||
union {
|
||||
uint FileAttr;
|
||||
uint SubFlags;
|
||||
};
|
||||
wchar FileName[NM];
|
||||
|
||||
Array<byte> SubData;
|
||||
|
||||
RarTime mtime;
|
||||
RarTime ctime;
|
||||
RarTime atime;
|
||||
|
||||
int64 PackSize;
|
||||
int64 UnpSize;
|
||||
int64 MaxSize; // Reserve size bytes for vint of this size.
|
||||
|
||||
HashValue FileHash;
|
||||
|
||||
uint FileFlags;
|
||||
|
||||
bool SplitBefore;
|
||||
bool SplitAfter;
|
||||
|
||||
bool UnknownUnpSize;
|
||||
|
||||
bool Encrypted;
|
||||
bool UsePswCheck;
|
||||
|
||||
// Use HMAC calculated from HashKey and checksum instead of plain checksum.
|
||||
bool UseHashKey;
|
||||
|
||||
uint Lg2Count; // Log2 of PBKDF2 repetition count.
|
||||
|
||||
bool Solid;
|
||||
bool Dir;
|
||||
bool CommentInHeader; // RAR 2.0 file comment.
|
||||
bool Version; // name.ext;ver file name containing the version number.
|
||||
size_t WinSize;
|
||||
bool Inherited; // New file inherits a subblock when updating a host file (for subblocks only).
|
||||
|
||||
// 'true' if file sizes use 8 bytes instead of 4. Not used in RAR 5.0.
|
||||
bool LargeFile;
|
||||
|
||||
// 'true' for HEAD_SERVICE block, which is a child of preceding file block.
|
||||
// RAR 4.x uses 'solid' flag to indicate child subheader blocks in archives.
|
||||
bool SubBlock;
|
||||
|
||||
HOST_SYSTEM_TYPE HSType;
|
||||
|
||||
FILE_SYSTEM_REDIRECT RedirType;
|
||||
wchar RedirName[NM];
|
||||
bool DirTarget;
|
||||
|
||||
bool UnixOwnerSet,UnixOwnerNumeric,UnixGroupNumeric;
|
||||
char UnixOwnerName[256],UnixGroupName[256];
|
||||
#ifdef _UNIX
|
||||
uid_t UnixOwnerID;
|
||||
uid_t UnixGroupID;
|
||||
#else // Need these Unix fields in Windows too for 'list' command.
|
||||
uint UnixOwnerID;
|
||||
uint UnixGroupID;
|
||||
#endif
|
||||
|
||||
void Reset(size_t SubDataSize=0);
|
||||
|
||||
bool CmpName(const wchar *Name)
|
||||
{
|
||||
return(my_wcscmp(FileName,Name)==0);
|
||||
}
|
||||
|
||||
FileHeader& operator = (FileHeader &hd);
|
||||
};
|
||||
|
||||
|
||||
struct EndArcHeader:BaseBlock
|
||||
{
|
||||
// Optional CRC32 of entire archive up to start of EndArcHeader block.
|
||||
// Present in RAR 4.x archives if EARC_DATACRC flag is set.
|
||||
uint ArcDataCRC;
|
||||
|
||||
uint VolNumber; // Optional number of current volume.
|
||||
|
||||
// 7 additional zero bytes can be stored here if EARC_REVSPACE is set.
|
||||
|
||||
bool NextVolume; // Not last volume.
|
||||
bool DataCRC;
|
||||
bool RevSpace;
|
||||
bool StoreVolNumber;
|
||||
void Reset()
|
||||
{
|
||||
BaseBlock::Reset();
|
||||
NextVolume=false;
|
||||
DataCRC=false;
|
||||
RevSpace=false;
|
||||
StoreVolNumber=false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// SubBlockHeader and its successors were used in RAR 2.x format.
|
||||
// RAR 4.x uses FileHeader with HEAD_SERVICE HeaderType for subblocks.
|
||||
struct SubBlockHeader:BlockHeader
|
||||
{
|
||||
ushort SubType;
|
||||
byte Level;
|
||||
};
|
||||
|
||||
|
||||
struct CommentHeader:BaseBlock
|
||||
{
|
||||
ushort UnpSize;
|
||||
byte UnpVer;
|
||||
byte Method;
|
||||
ushort CommCRC;
|
||||
};
|
||||
|
||||
|
||||
struct ProtectHeader:BlockHeader
|
||||
{
|
||||
byte Version;
|
||||
ushort RecSectors;
|
||||
uint TotalBlocks;
|
||||
byte Mark[8];
|
||||
};
|
||||
|
||||
|
||||
struct AVHeader:BaseBlock
|
||||
{
|
||||
byte UnpVer;
|
||||
byte Method;
|
||||
byte AVVer;
|
||||
uint AVInfoCRC;
|
||||
};
|
||||
|
||||
|
||||
struct SignHeader:BaseBlock
|
||||
{
|
||||
uint CreationTime;
|
||||
ushort ArcNameSize;
|
||||
ushort UserNameSize;
|
||||
};
|
||||
|
||||
|
||||
struct UnixOwnersHeader:SubBlockHeader
|
||||
{
|
||||
ushort OwnerNameSize;
|
||||
ushort GroupNameSize;
|
||||
/* dummy */
|
||||
char OwnerName[256];
|
||||
char GroupName[256];
|
||||
};
|
||||
|
||||
|
||||
struct EAHeader:SubBlockHeader
|
||||
{
|
||||
uint UnpSize;
|
||||
byte UnpVer;
|
||||
byte Method;
|
||||
uint EACRC;
|
||||
};
|
||||
|
||||
|
||||
struct StreamHeader:SubBlockHeader
|
||||
{
|
||||
uint UnpSize;
|
||||
byte UnpVer;
|
||||
byte Method;
|
||||
uint StreamCRC;
|
||||
ushort StreamNameSize;
|
||||
char StreamName[260];
|
||||
};
|
||||
|
||||
|
||||
struct MacFInfoHeader:SubBlockHeader
|
||||
{
|
||||
uint fileType;
|
||||
uint fileCreator;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -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
|
|
@ -0,0 +1,42 @@
|
|||
****** ***** ****** UnRAR - free utility for RAR archives
|
||||
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
****** ******* ****** License for use and distribution of
|
||||
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
** ** ** ** ** ** FREE portable version
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The source code of UnRAR utility is freeware. This means:
|
||||
|
||||
1. All copyrights to RAR and the utility UnRAR are exclusively
|
||||
owned by the author - Alexander Roshal.
|
||||
|
||||
2. UnRAR source code may be used in any software to handle
|
||||
RAR archives without limitations free of charge, but cannot be
|
||||
used to develop RAR (WinRAR) compatible archiver and to
|
||||
re-create RAR compression algorithm, which is proprietary.
|
||||
Distribution of modified UnRAR source code in separate form
|
||||
or as a part of other software is permitted, provided that
|
||||
full text of this paragraph, starting from "UnRAR source code"
|
||||
words, is included in license, or in documentation if license
|
||||
is not available, and in source code comments of resulting package.
|
||||
|
||||
3. The UnRAR utility may be freely distributed. It is allowed
|
||||
to distribute UnRAR inside of other software packages.
|
||||
|
||||
4. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS".
|
||||
NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
|
||||
YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
|
||||
DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
|
||||
OR MISUSING THIS SOFTWARE.
|
||||
|
||||
5. Installing and using the UnRAR utility signifies acceptance of
|
||||
these terms and conditions of the license.
|
||||
|
||||
6. If you don't agree with terms of the license you must remove
|
||||
UnRAR files from your storage devices and cease to use the
|
||||
utility.
|
||||
|
||||
Thank you for your interest in RAR and UnRAR.
|
||||
|
||||
|
||||
Alexander L. Roshal
|
|
@ -0,0 +1,621 @@
|
|||
/****************************************************************************
|
||||
* This file is part of PPMd project *
|
||||
* Written and distributed to public domain by Dmitry Shkarin 1997, *
|
||||
* 1999-2000 *
|
||||
* Contents: model description and encoding/decoding routines *
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef RAR_COMMON_HPP
|
||||
|
||||
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)
|
||||
{
|
||||
RARPPM_CONTEXT* pc = (RARPPM_CONTEXT*) Model->SubAlloc.AllocContext();
|
||||
if ( pc )
|
||||
{
|
||||
pc->NumStats=1;
|
||||
pc->OneState=FirstState;
|
||||
pc->Suffix=this;
|
||||
pStats->Successor=pc;
|
||||
}
|
||||
return pc;
|
||||
}
|
||||
|
||||
|
||||
ModelPPM::ModelPPM()
|
||||
{
|
||||
MinContext=NULL;
|
||||
MaxContext=NULL;
|
||||
MedContext=NULL;
|
||||
}
|
||||
|
||||
|
||||
void ModelPPM::RestartModelRare()
|
||||
{
|
||||
int i, k, m;
|
||||
memset(CharMask,0,sizeof(CharMask));
|
||||
SubAlloc.InitSubAllocator();
|
||||
InitRL=-(MaxOrder < 12 ? MaxOrder:12)-1;
|
||||
MinContext = MaxContext = (RARPPM_CONTEXT*) SubAlloc.AllocContext();
|
||||
MinContext->Suffix=NULL;
|
||||
OrderFall=MaxOrder;
|
||||
MinContext->U.SummFreq=(MinContext->NumStats=256)+1;
|
||||
FoundState=MinContext->U.Stats=(RARPPM_STATE*)SubAlloc.AllocUnits(256/2);
|
||||
for (RunLength=InitRL, PrevSuccess=i=0;i < 256;i++)
|
||||
{
|
||||
MinContext->U.Stats[i].Symbol=i;
|
||||
MinContext->U.Stats[i].Freq=1;
|
||||
MinContext->U.Stats[i].Successor=NULL;
|
||||
}
|
||||
|
||||
static const ushort InitBinEsc[]={
|
||||
0x3CDD,0x1F3F,0x59BF,0x48F3,0x64A1,0x5ABC,0x6632,0x6051
|
||||
};
|
||||
|
||||
for (i=0;i < 128;i++)
|
||||
for (k=0;k < 8;k++)
|
||||
for (m=0;m < 64;m += 8)
|
||||
BinSumm[i][k+m]=BIN_SCALE-InitBinEsc[k]/(i+2);
|
||||
for (i=0;i < 25;i++)
|
||||
for (k=0;k < 16;k++)
|
||||
SEE2Cont[i][k].init(5*i+10);
|
||||
}
|
||||
|
||||
|
||||
void ModelPPM::StartModelRare(int MaxOrder)
|
||||
{
|
||||
int i, k, m ,Step;
|
||||
EscCount=1;
|
||||
/*
|
||||
if (MaxOrder < 2)
|
||||
{
|
||||
memset(CharMask,0,sizeof(CharMask));
|
||||
OrderFall=ModelPPM::MaxOrder;
|
||||
MinContext=MaxContext;
|
||||
while (MinContext->Suffix != NULL)
|
||||
{
|
||||
MinContext=MinContext->Suffix;
|
||||
OrderFall--;
|
||||
}
|
||||
FoundState=MinContext->U.Stats;
|
||||
MinContext=MaxContext;
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
ModelPPM::MaxOrder=MaxOrder;
|
||||
RestartModelRare();
|
||||
NS2BSIndx[0]=2*0;
|
||||
NS2BSIndx[1]=2*1;
|
||||
memset(NS2BSIndx+2,2*2,9);
|
||||
memset(NS2BSIndx+11,2*3,256-11);
|
||||
for (i=0;i < 3;i++)
|
||||
NS2Indx[i]=i;
|
||||
for (m=i, k=Step=1;i < 256;i++)
|
||||
{
|
||||
NS2Indx[i]=m;
|
||||
if ( !--k )
|
||||
{
|
||||
k = ++Step;
|
||||
m++;
|
||||
}
|
||||
}
|
||||
memset(HB2Flag,0,0x40);
|
||||
memset(HB2Flag+0x40,0x08,0x100-0x40);
|
||||
DummySEE2Cont.Shift=PERIOD_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RARPPM_CONTEXT::rescale(ModelPPM *Model)
|
||||
{
|
||||
int OldNS=NumStats, i=NumStats-1, Adder, EscFreq;
|
||||
RARPPM_STATE* p1, * p;
|
||||
for (p=Model->FoundState;p != U.Stats;p--)
|
||||
_PPMD_SWAP(p[0],p[-1]);
|
||||
U.Stats->Freq += 4;
|
||||
U.SummFreq += 4;
|
||||
EscFreq=U.SummFreq-p->Freq;
|
||||
Adder=(Model->OrderFall != 0);
|
||||
U.SummFreq = (p->Freq=(p->Freq+Adder) >> 1);
|
||||
do
|
||||
{
|
||||
EscFreq -= (++p)->Freq;
|
||||
U.SummFreq += (p->Freq=(p->Freq+Adder) >> 1);
|
||||
if (p[0].Freq > p[-1].Freq)
|
||||
{
|
||||
RARPPM_STATE tmp=*(p1=p);
|
||||
do
|
||||
{
|
||||
p1[0]=p1[-1];
|
||||
} while (--p1 != U.Stats && tmp.Freq > p1[-1].Freq);
|
||||
*p1=tmp;
|
||||
}
|
||||
} while ( --i );
|
||||
if (p->Freq == 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
i++;
|
||||
} while ((--p)->Freq == 0);
|
||||
EscFreq += i;
|
||||
if ((NumStats -= i) == 1)
|
||||
{
|
||||
RARPPM_STATE tmp=*U.Stats;
|
||||
do
|
||||
{
|
||||
tmp.Freq-=(tmp.Freq >> 1);
|
||||
EscFreq>>=1;
|
||||
} while (EscFreq > 1);
|
||||
Model->SubAlloc.FreeUnits(U.Stats,(OldNS+1) >> 1);
|
||||
*(Model->FoundState=&OneState)=tmp; return;
|
||||
}
|
||||
}
|
||||
U.SummFreq += (EscFreq -= (EscFreq >> 1));
|
||||
int n0=(OldNS+1) >> 1, n1=(NumStats+1) >> 1;
|
||||
if (n0 != n1)
|
||||
U.Stats = (RARPPM_STATE*) Model->SubAlloc.ShrinkUnits(U.Stats,n0,n1);
|
||||
Model->FoundState=U.Stats;
|
||||
}
|
||||
|
||||
|
||||
inline RARPPM_CONTEXT* ModelPPM::CreateSuccessors(bool Skip,RARPPM_STATE* p1)
|
||||
{
|
||||
#ifdef __ICL
|
||||
static
|
||||
#endif
|
||||
RARPPM_STATE UpState;
|
||||
RARPPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor;
|
||||
RARPPM_STATE * p, * ps[MAX_O], ** pps=ps;
|
||||
if ( !Skip )
|
||||
{
|
||||
*pps++ = FoundState;
|
||||
if ( !pc->Suffix )
|
||||
goto NO_LOOP;
|
||||
}
|
||||
if ( p1 )
|
||||
{
|
||||
p=p1;
|
||||
pc=pc->Suffix;
|
||||
goto LOOP_ENTRY;
|
||||
}
|
||||
do
|
||||
{
|
||||
pc=pc->Suffix;
|
||||
if (pc->NumStats != 1)
|
||||
{
|
||||
if ((p=pc->U.Stats)->Symbol != FoundState->Symbol)
|
||||
do
|
||||
{
|
||||
p++;
|
||||
} while (p->Symbol != FoundState->Symbol);
|
||||
}
|
||||
else
|
||||
p=&(pc->OneState);
|
||||
LOOP_ENTRY:
|
||||
if (p->Successor != UpBranch)
|
||||
{
|
||||
pc=p->Successor;
|
||||
break;
|
||||
}
|
||||
*pps++ = p;
|
||||
} while ( pc->Suffix );
|
||||
NO_LOOP:
|
||||
if (pps == ps)
|
||||
return pc;
|
||||
UpState.Symbol=*(byte*) UpBranch;
|
||||
UpState.Successor=(RARPPM_CONTEXT*) (((byte*) UpBranch)+1);
|
||||
if (pc->NumStats != 1)
|
||||
{
|
||||
if ((byte*) pc <= SubAlloc.pText)
|
||||
return(NULL);
|
||||
if ((p=pc->U.Stats)->Symbol != UpState.Symbol)
|
||||
do
|
||||
{
|
||||
p++;
|
||||
} while (p->Symbol != UpState.Symbol);
|
||||
uint cf=p->Freq-1;
|
||||
uint s0=pc->U.SummFreq-pc->NumStats-cf;
|
||||
UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0)));
|
||||
}
|
||||
else
|
||||
UpState.Freq=pc->OneState.Freq;
|
||||
do
|
||||
{
|
||||
pc = pc->createChild(this,*--pps,UpState);
|
||||
if ( !pc )
|
||||
return NULL;
|
||||
} while (pps != ps);
|
||||
return pc;
|
||||
}
|
||||
|
||||
|
||||
inline void ModelPPM::UpdateModel()
|
||||
{
|
||||
RARPPM_STATE fs = *FoundState, *p = NULL;
|
||||
RARPPM_CONTEXT *pc, *Successor;
|
||||
uint ns1, ns, cf, sf, s0;
|
||||
if (fs.Freq < MAX_FREQ/4 && (pc=MinContext->Suffix) != NULL)
|
||||
{
|
||||
if (pc->NumStats != 1)
|
||||
{
|
||||
if ((p=pc->U.Stats)->Symbol != fs.Symbol)
|
||||
{
|
||||
do
|
||||
{
|
||||
p++;
|
||||
} while (p->Symbol != fs.Symbol);
|
||||
if (p[0].Freq >= p[-1].Freq)
|
||||
{
|
||||
_PPMD_SWAP(p[0],p[-1]);
|
||||
p--;
|
||||
}
|
||||
}
|
||||
if (p->Freq < MAX_FREQ-9)
|
||||
{
|
||||
p->Freq += 2;
|
||||
pc->U.SummFreq += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p=&(pc->OneState);
|
||||
p->Freq += (p->Freq < 32);
|
||||
}
|
||||
}
|
||||
if ( !OrderFall )
|
||||
{
|
||||
MinContext=MaxContext=FoundState->Successor=CreateSuccessors(TRUE,p);
|
||||
if ( !MinContext )
|
||||
goto RESTART_MODEL;
|
||||
return;
|
||||
}
|
||||
*SubAlloc.pText++ = fs.Symbol;
|
||||
Successor = (RARPPM_CONTEXT*) SubAlloc.pText;
|
||||
if (SubAlloc.pText >= SubAlloc.FakeUnitsStart)
|
||||
goto RESTART_MODEL;
|
||||
if ( fs.Successor )
|
||||
{
|
||||
if ((byte*) fs.Successor <= SubAlloc.pText &&
|
||||
(fs.Successor=CreateSuccessors(FALSE,p)) == NULL)
|
||||
goto RESTART_MODEL;
|
||||
if ( !--OrderFall )
|
||||
{
|
||||
Successor=fs.Successor;
|
||||
SubAlloc.pText -= (MaxContext != MinContext);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FoundState->Successor=Successor;
|
||||
fs.Successor=MinContext;
|
||||
}
|
||||
s0=MinContext->U.SummFreq-(ns=MinContext->NumStats)-(fs.Freq-1);
|
||||
for (pc=MaxContext;pc != MinContext;pc=pc->Suffix)
|
||||
{
|
||||
if ((ns1=pc->NumStats) != 1)
|
||||
{
|
||||
if ((ns1 & 1) == 0)
|
||||
{
|
||||
pc->U.Stats=(RARPPM_STATE*) SubAlloc.ExpandUnits(pc->U.Stats,ns1 >> 1);
|
||||
if ( !pc->U.Stats )
|
||||
goto RESTART_MODEL;
|
||||
}
|
||||
pc->U.SummFreq += (2*ns1 < ns)+2*((4*ns1 <= ns) & (pc->U.SummFreq <= 8*ns1));
|
||||
}
|
||||
else
|
||||
{
|
||||
p=(RARPPM_STATE*) SubAlloc.AllocUnits(1);
|
||||
if ( !p )
|
||||
goto RESTART_MODEL;
|
||||
*p=pc->OneState;
|
||||
pc->U.Stats=p;
|
||||
if (p->Freq < MAX_FREQ/4-1)
|
||||
p->Freq += p->Freq;
|
||||
else
|
||||
p->Freq = MAX_FREQ-4;
|
||||
pc->U.SummFreq=p->Freq+InitEsc+(ns > 3);
|
||||
}
|
||||
cf=2*fs.Freq*(pc->U.SummFreq+6);
|
||||
sf=s0+pc->U.SummFreq;
|
||||
if (cf < 6*sf)
|
||||
{
|
||||
cf=1+(cf > sf)+(cf >= 4*sf);
|
||||
pc->U.SummFreq += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
cf=4+(cf >= 9*sf)+(cf >= 12*sf)+(cf >= 15*sf);
|
||||
pc->U.SummFreq += cf;
|
||||
}
|
||||
p=pc->U.Stats+ns1;
|
||||
p->Successor=Successor;
|
||||
p->Symbol = fs.Symbol;
|
||||
p->Freq = cf;
|
||||
pc->NumStats=++ns1;
|
||||
}
|
||||
MaxContext=MinContext=fs.Successor;
|
||||
return;
|
||||
RESTART_MODEL:
|
||||
RestartModelRare();
|
||||
EscCount=0;
|
||||
}
|
||||
|
||||
|
||||
// Tabulated escapes for exponential symbol distribution
|
||||
static const byte ExpEscape[16]={ 25,14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
|
||||
#define GET_MEAN(SUMM,SHIFT,ROUND) ((SUMM+(1 << (SHIFT-ROUND))) >> (SHIFT))
|
||||
|
||||
|
||||
|
||||
inline void RARPPM_CONTEXT::decodeBinSymbol(ModelPPM *Model)
|
||||
{
|
||||
RARPPM_STATE& rs=OneState;
|
||||
Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol];
|
||||
ushort& bs=Model->BinSumm[rs.Freq-1][Model->PrevSuccess+
|
||||
Model->NS2BSIndx[Suffix->NumStats-1]+
|
||||
Model->HiBitsFlag+2*Model->HB2Flag[rs.Symbol]+
|
||||
((Model->RunLength >> 26) & 0x20)];
|
||||
if (Model->Coder.GetCurrentShiftCount(TOT_BITS) < bs)
|
||||
{
|
||||
Model->FoundState=&rs;
|
||||
rs.Freq += (rs.Freq < 128);
|
||||
Model->Coder.SubRange.LowCount=0;
|
||||
Model->Coder.SubRange.HighCount=bs;
|
||||
bs = GET_SHORT16(bs+INTERVAL-GET_MEAN(bs,PERIOD_BITS,2));
|
||||
Model->PrevSuccess=1;
|
||||
Model->RunLength++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Model->Coder.SubRange.LowCount=bs;
|
||||
bs = GET_SHORT16(bs-GET_MEAN(bs,PERIOD_BITS,2));
|
||||
Model->Coder.SubRange.HighCount=BIN_SCALE;
|
||||
Model->InitEsc=ExpEscape[bs >> 10];
|
||||
Model->NumMasked=1;
|
||||
Model->CharMask[rs.Symbol]=Model->EscCount;
|
||||
Model->PrevSuccess=0;
|
||||
Model->FoundState=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void RARPPM_CONTEXT::update1(ModelPPM *Model,RARPPM_STATE* p)
|
||||
{
|
||||
(Model->FoundState=p)->Freq += 4;
|
||||
U.SummFreq += 4;
|
||||
if (p[0].Freq > p[-1].Freq)
|
||||
{
|
||||
_PPMD_SWAP(p[0],p[-1]);
|
||||
Model->FoundState=--p;
|
||||
if (p->Freq > MAX_FREQ)
|
||||
rescale(Model);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
inline bool RARPPM_CONTEXT::decodeSymbol1(ModelPPM *Model)
|
||||
{
|
||||
Model->Coder.SubRange.scale=U.SummFreq;
|
||||
RARPPM_STATE* p=U.Stats;
|
||||
int i, HiCnt;
|
||||
int count=Model->Coder.GetCurrentCount();
|
||||
if (count>=(int)Model->Coder.SubRange.scale)
|
||||
return(false);
|
||||
if (count < (HiCnt=p->Freq))
|
||||
{
|
||||
Model->PrevSuccess=(2*(Model->Coder.SubRange.HighCount=HiCnt) > Model->Coder.SubRange.scale);
|
||||
Model->RunLength += Model->PrevSuccess;
|
||||
(Model->FoundState=p)->Freq=(HiCnt += 4);
|
||||
U.SummFreq += 4;
|
||||
if (HiCnt > MAX_FREQ)
|
||||
rescale(Model);
|
||||
Model->Coder.SubRange.LowCount=0;
|
||||
return(true);
|
||||
}
|
||||
else
|
||||
if (Model->FoundState==NULL)
|
||||
return(false);
|
||||
Model->PrevSuccess=0;
|
||||
i=NumStats-1;
|
||||
while ((HiCnt += (++p)->Freq) <= count)
|
||||
if (--i == 0)
|
||||
{
|
||||
Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol];
|
||||
Model->Coder.SubRange.LowCount=HiCnt;
|
||||
Model->CharMask[p->Symbol]=Model->EscCount;
|
||||
i=(Model->NumMasked=NumStats)-1;
|
||||
Model->FoundState=NULL;
|
||||
do
|
||||
{
|
||||
Model->CharMask[(--p)->Symbol]=Model->EscCount;
|
||||
} while ( --i );
|
||||
Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale;
|
||||
return(true);
|
||||
}
|
||||
Model->Coder.SubRange.LowCount=(Model->Coder.SubRange.HighCount=HiCnt)-p->Freq;
|
||||
update1(Model,p);
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
inline void RARPPM_CONTEXT::update2(ModelPPM *Model,RARPPM_STATE* p)
|
||||
{
|
||||
(Model->FoundState=p)->Freq += 4;
|
||||
U.SummFreq += 4;
|
||||
if (p->Freq > MAX_FREQ)
|
||||
rescale(Model);
|
||||
Model->EscCount++;
|
||||
Model->RunLength=Model->InitRL;
|
||||
}
|
||||
|
||||
|
||||
inline RARPPM_SEE2_CONTEXT* RARPPM_CONTEXT::makeEscFreq2(ModelPPM *Model,int Diff)
|
||||
{
|
||||
RARPPM_SEE2_CONTEXT* psee2c;
|
||||
if (NumStats != 256)
|
||||
{
|
||||
psee2c=Model->SEE2Cont[Model->NS2Indx[Diff-1]]+
|
||||
(Diff < Suffix->NumStats-NumStats)+
|
||||
2*(U.SummFreq < 11*NumStats)+4*(Model->NumMasked > Diff)+
|
||||
Model->HiBitsFlag;
|
||||
Model->Coder.SubRange.scale=psee2c->getMean();
|
||||
}
|
||||
else
|
||||
{
|
||||
psee2c=&Model->DummySEE2Cont;
|
||||
Model->Coder.SubRange.scale=1;
|
||||
}
|
||||
return psee2c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
inline bool RARPPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
|
||||
{
|
||||
int count, HiCnt, i=NumStats-Model->NumMasked;
|
||||
RARPPM_SEE2_CONTEXT* psee2c=makeEscFreq2(Model,i);
|
||||
RARPPM_STATE* ps[256], ** pps=ps, * p=U.Stats-1;
|
||||
HiCnt=0;
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
p++;
|
||||
} while (Model->CharMask[p->Symbol] == Model->EscCount);
|
||||
HiCnt += p->Freq;
|
||||
*pps++ = p;
|
||||
} while ( --i );
|
||||
Model->Coder.SubRange.scale += HiCnt;
|
||||
count=Model->Coder.GetCurrentCount();
|
||||
if (count>=(int)Model->Coder.SubRange.scale)
|
||||
return(false);
|
||||
p=*(pps=ps);
|
||||
if (count < HiCnt)
|
||||
{
|
||||
HiCnt=0;
|
||||
while ((HiCnt += p->Freq) <= count)
|
||||
p=*++pps;
|
||||
Model->Coder.SubRange.LowCount = (Model->Coder.SubRange.HighCount=HiCnt)-p->Freq;
|
||||
psee2c->update();
|
||||
update2(Model,p);
|
||||
}
|
||||
else
|
||||
{
|
||||
Model->Coder.SubRange.LowCount=HiCnt;
|
||||
Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale;
|
||||
i=NumStats-Model->NumMasked;
|
||||
pps--;
|
||||
do
|
||||
{
|
||||
Model->CharMask[(*++pps)->Symbol]=Model->EscCount;
|
||||
} while ( --i );
|
||||
psee2c->Summ += Model->Coder.SubRange.scale;
|
||||
Model->NumMasked = NumStats;
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
inline void ModelPPM::ClearMask()
|
||||
{
|
||||
EscCount=1;
|
||||
memset(CharMask,0,sizeof(CharMask));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// reset PPM variables after data error allowing safe resuming
|
||||
// of further data processing
|
||||
void ModelPPM::CleanUp()
|
||||
{
|
||||
SubAlloc.StopSubAllocator();
|
||||
SubAlloc.StartSubAllocator(1);
|
||||
StartModelRare(2);
|
||||
}
|
||||
|
||||
|
||||
bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar)
|
||||
{
|
||||
int MaxOrder=UnpackRead->GetChar();
|
||||
bool Reset=(MaxOrder & 0x20)!=0;
|
||||
|
||||
int MaxMB;
|
||||
if (Reset)
|
||||
MaxMB=UnpackRead->GetChar();
|
||||
else
|
||||
if (SubAlloc.GetAllocatedMemory()==0)
|
||||
return(false);
|
||||
if (MaxOrder & 0x40)
|
||||
EscChar=UnpackRead->GetChar();
|
||||
Coder.InitDecoder(UnpackRead);
|
||||
if (Reset)
|
||||
{
|
||||
MaxOrder=(MaxOrder & 0x1f)+1;
|
||||
if (MaxOrder>16)
|
||||
MaxOrder=16+(MaxOrder-16)*3;
|
||||
if (MaxOrder==1)
|
||||
{
|
||||
SubAlloc.StopSubAllocator();
|
||||
return(false);
|
||||
}
|
||||
SubAlloc.StartSubAllocator(MaxMB+1);
|
||||
StartModelRare(MaxOrder);
|
||||
}
|
||||
return(MinContext!=NULL);
|
||||
}
|
||||
|
||||
|
||||
int ModelPPM::DecodeChar()
|
||||
{
|
||||
if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd)
|
||||
return(-1);
|
||||
if (MinContext->NumStats != 1)
|
||||
{
|
||||
if ((byte*)MinContext->U.Stats <= SubAlloc.pText || (byte*)MinContext->U.Stats>SubAlloc.HeapEnd)
|
||||
return(-1);
|
||||
if (!MinContext->decodeSymbol1(this))
|
||||
return(-1);
|
||||
}
|
||||
else
|
||||
MinContext->decodeBinSymbol(this);
|
||||
Coder.Decode();
|
||||
while ( !FoundState )
|
||||
{
|
||||
ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
|
||||
do
|
||||
{
|
||||
OrderFall++;
|
||||
MinContext=MinContext->Suffix;
|
||||
if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd)
|
||||
return(-1);
|
||||
} while (MinContext->NumStats == NumMasked);
|
||||
if (!MinContext->decodeSymbol2(this))
|
||||
return(-1);
|
||||
Coder.Decode();
|
||||
}
|
||||
int Symbol=FoundState->Symbol;
|
||||
if (!OrderFall && (byte*) FoundState->Successor > SubAlloc.pText)
|
||||
MinContext=MaxContext=FoundState->Successor;
|
||||
else
|
||||
{
|
||||
UpdateModel();
|
||||
if (EscCount == 0)
|
||||
ClearMask();
|
||||
}
|
||||
ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
|
||||
return(Symbol);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,122 @@
|
|||
#ifndef _RAR_PPMMODEL_
|
||||
#define _RAR_PPMMODEL_
|
||||
|
||||
#include "coder.hpp"
|
||||
#include "suballoc.hpp"
|
||||
|
||||
#ifdef ALLOW_MISALIGNED
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
struct RARPPM_DEF
|
||||
{
|
||||
static const int INT_BITS=7, PERIOD_BITS=7, TOT_BITS=INT_BITS+PERIOD_BITS,
|
||||
INTERVAL=1 << INT_BITS, BIN_SCALE=1 << TOT_BITS, MAX_FREQ=124;
|
||||
};
|
||||
|
||||
struct RARPPM_SEE2_CONTEXT : RARPPM_DEF
|
||||
{ // SEE-contexts for PPM-contexts with masked symbols
|
||||
ushort Summ;
|
||||
byte Shift, Count;
|
||||
void init(int InitVal)
|
||||
{
|
||||
Summ=InitVal << (Shift=PERIOD_BITS-4);
|
||||
Count=4;
|
||||
}
|
||||
uint getMean()
|
||||
{
|
||||
uint RetVal=GET_SHORT16(Summ) >> Shift;
|
||||
Summ -= RetVal;
|
||||
return RetVal+(RetVal == 0);
|
||||
}
|
||||
void update()
|
||||
{
|
||||
if (Shift < PERIOD_BITS && --Count == 0)
|
||||
{
|
||||
Summ += Summ;
|
||||
Count=3 << Shift++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ModelPPM;
|
||||
struct RARPPM_CONTEXT;
|
||||
|
||||
struct RARPPM_STATE
|
||||
{
|
||||
byte Symbol;
|
||||
byte Freq;
|
||||
RARPPM_CONTEXT* Successor;
|
||||
};
|
||||
|
||||
|
||||
struct RARPPM_CONTEXT : RARPPM_DEF
|
||||
{
|
||||
ushort NumStats;
|
||||
|
||||
struct FreqData
|
||||
{
|
||||
ushort SummFreq;
|
||||
RARPPM_STATE RARPPM_PACK_ATTR * Stats;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
FreqData U;
|
||||
RARPPM_STATE OneState;
|
||||
};
|
||||
|
||||
RARPPM_CONTEXT* Suffix;
|
||||
inline void encodeBinSymbol(ModelPPM *Model,int symbol); // MaxOrder:
|
||||
inline void encodeSymbol1(ModelPPM *Model,int symbol); // ABCD context
|
||||
inline void encodeSymbol2(ModelPPM *Model,int symbol); // BCD suffix
|
||||
inline void decodeBinSymbol(ModelPPM *Model); // BCDE successor
|
||||
inline bool decodeSymbol1(ModelPPM *Model); // other orders:
|
||||
inline bool decodeSymbol2(ModelPPM *Model); // BCD context
|
||||
inline void update1(ModelPPM *Model,RARPPM_STATE* p); // CD suffix
|
||||
inline void update2(ModelPPM *Model,RARPPM_STATE* p); // BCDE successor
|
||||
void rescale(ModelPPM *Model);
|
||||
inline RARPPM_CONTEXT* createChild(ModelPPM *Model,RARPPM_STATE* pStats,RARPPM_STATE& FirstState);
|
||||
inline RARPPM_SEE2_CONTEXT* makeEscFreq2(ModelPPM *Model,int Diff);
|
||||
};
|
||||
|
||||
#ifdef ALLOW_MISALIGNED
|
||||
#ifdef _AIX
|
||||
#pragma pack(pop)
|
||||
#else
|
||||
#pragma pack()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class ModelPPM : RARPPM_DEF
|
||||
{
|
||||
private:
|
||||
friend struct RARPPM_CONTEXT;
|
||||
|
||||
RARPPM_SEE2_CONTEXT SEE2Cont[25][16], DummySEE2Cont;
|
||||
|
||||
struct RARPPM_CONTEXT *MinContext, *MedContext, *MaxContext;
|
||||
RARPPM_STATE* FoundState; // found next state transition
|
||||
int NumMasked, InitEsc, OrderFall, MaxOrder, RunLength, InitRL;
|
||||
byte CharMask[256], NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
|
||||
byte EscCount, PrevSuccess, HiBitsFlag;
|
||||
ushort BinSumm[128][64]; // binary SEE-contexts
|
||||
|
||||
RangeCoder Coder;
|
||||
SubAllocator SubAlloc;
|
||||
|
||||
void RestartModelRare();
|
||||
void StartModelRare(int MaxOrder);
|
||||
inline RARPPM_CONTEXT* CreateSuccessors(bool Skip,RARPPM_STATE* p1);
|
||||
|
||||
inline void UpdateModel();
|
||||
inline void ClearMask();
|
||||
public:
|
||||
ModelPPM();
|
||||
void CleanUp(); // reset PPM variables after data error
|
||||
bool DecodeInit(Unpack *UnpackRead,int &EscChar);
|
||||
int DecodeChar();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,56 @@
|
|||
#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);
|
||||
}
|
||||
|
||||
void UnixSlashToDos(const char *SrcName, char *DestName, size_t MaxLength)
|
||||
{
|
||||
size_t Copied = 0;
|
||||
for (; Copied<MaxLength - 1 && SrcName[Copied] != 0; Copied++)
|
||||
DestName[Copied] = SrcName[Copied] == '/' ? '\\' : SrcName[Copied];
|
||||
DestName[Copied] = 0;
|
||||
}
|
||||
|
||||
|
||||
void DosSlashToUnix(const char *SrcName, char *DestName, size_t MaxLength)
|
||||
{
|
||||
size_t Copied = 0;
|
||||
for (; Copied<MaxLength - 1 && SrcName[Copied] != 0; Copied++)
|
||||
DestName[Copied] = SrcName[Copied] == '\\' ? '/' : SrcName[Copied];
|
||||
DestName[Copied] = 0;
|
||||
}
|
||||
|
||||
|
||||
void UnixSlashToDos(const wchar *SrcName, wchar *DestName, size_t MaxLength)
|
||||
{
|
||||
size_t Copied = 0;
|
||||
for (; Copied<MaxLength - 1 && SrcName[Copied] != 0; Copied++)
|
||||
DestName[Copied] = SrcName[Copied] == '/' ? '\\' : SrcName[Copied];
|
||||
DestName[Copied] = 0;
|
||||
}
|
||||
|
||||
|
||||
void DosSlashToUnix(const wchar *SrcName, wchar *DestName, size_t MaxLength)
|
||||
{
|
||||
size_t Copied = 0;
|
||||
for (; Copied<MaxLength - 1 && SrcName[Copied] != 0; Copied++)
|
||||
DestName[Copied] = SrcName[Copied] == '\\' ? '/' : SrcName[Copied];
|
||||
DestName[Copied] = 0;
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
// This source code is a heavily modified version based on the unrar package.
|
||||
// It may NOT be used to develop a RAR (WinRAR) compatible archiver.
|
||||
// See license.txt for copyright and licensing.
|
||||
|
||||
// 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>
|
||||
#include <limits.h>
|
||||
|
||||
//// Glue
|
||||
|
||||
// One goal is to keep source code as close to original as possible, so
|
||||
// that changes to the original can be found and merged more easily.
|
||||
|
||||
// These names are too generic and might clash (or have already, hmpf)
|
||||
#define Array Rar_Array
|
||||
#define uint32 rar_uint32
|
||||
#define int32 rar_int32
|
||||
#define Unpack Rar_Unpack
|
||||
#define Archive Rar_Archive
|
||||
#define RawRead Rar_RawRead
|
||||
#define BitInput Rar_BitInput
|
||||
#define ModelPPM Rar_ModelPPM
|
||||
#define RangeCoder Rar_RangeCoder
|
||||
#define SubAllocator Rar_SubAllocator
|
||||
#define UnpackFilter Rar_UnpackFilter
|
||||
#define VM_PreparedProgram Rar_VM_PreparedProgram
|
||||
#define CRCTab Rar_CRCTab
|
||||
|
||||
// original source used rar* names for these as well
|
||||
#define rarmalloc malloc
|
||||
#define rarrealloc realloc
|
||||
#define rarfree free
|
||||
|
||||
// Internal flags, possibly set later
|
||||
#undef SFX_MODULE
|
||||
#undef VM_OPTIMIZE
|
||||
#undef VM_STANDARDFILTERS
|
||||
#undef NORARVM
|
||||
|
||||
// During debugging if expr is false, prints message then continues execution
|
||||
#ifndef check
|
||||
#define check( expr ) ((void) 0)
|
||||
#endif
|
||||
|
||||
struct Rar_Error_Handler
|
||||
{
|
||||
jmp_buf jmp_env;
|
||||
|
||||
void MemoryError();
|
||||
void ReportError( unrar_err_t );
|
||||
};
|
||||
|
||||
// throw spec is mandatory in ISO C++ if operator new can return NULL
|
||||
#if __cplusplus >= 199711 || __GNUC__ >= 3
|
||||
#define UNRAR_NOTHROW throw ()
|
||||
#else
|
||||
#define UNRAR_NOTHROW
|
||||
#endif
|
||||
|
||||
struct Rar_Allocator
|
||||
{
|
||||
// provides allocator that doesn't throw an exception on failure
|
||||
static void operator delete ( void* p ) { free( p ); }
|
||||
static void* operator new ( size_t s ) UNRAR_NOTHROW { return malloc( s ); }
|
||||
static void* operator new ( size_t, void* p ) UNRAR_NOTHROW { return p; }
|
||||
};
|
||||
|
||||
//// os.hpp
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
#undef STRICT_ALIGNMENT_REQUIRED
|
||||
#undef LITTLE_ENDIAN
|
||||
#define NM 1024
|
||||
|
||||
#if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64)
|
||||
// Optimizations mostly only apply to x86
|
||||
#define LITTLE_ENDIAN
|
||||
#define ALLOW_NOT_ALIGNED_INT
|
||||
#endif
|
||||
|
||||
#if defined(__sparc) || defined(sparc) || defined(__sparcv9)
|
||||
/* prohibit not aligned access to data structures in text comression
|
||||
algorithm, increases memory requirements */
|
||||
#define STRICT_ALIGNMENT_REQUIRED
|
||||
#endif
|
||||
|
||||
//// rartypes.hpp
|
||||
#if INT_MAX == 0x7FFFFFFF && UINT_MAX == 0xFFFFFFFF
|
||||
typedef unsigned int uint32; //32 bits exactly
|
||||
typedef int int32; //signed 32 bits exactly
|
||||
#define PRESENT_INT32
|
||||
#endif
|
||||
|
||||
typedef unsigned char byte; //8 bits
|
||||
typedef unsigned short ushort; //preferably 16 bits, but can be more
|
||||
typedef unsigned int uint; //32 bits or more
|
||||
|
||||
typedef wchar_t wchar;
|
||||
|
||||
#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_ulong_long uint64;
|
||||
|
||||
#define int64to32(x) ((uint)(x))
|
||||
#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 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);
|
||||
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
#include "blake2s.hpp"
|
||||
#include "hash.hpp"
|
||||
|
||||
//// rdwrfn.hpp
|
||||
class ComprDataIO
|
||||
: public Rar_Error_Handler
|
||||
{
|
||||
public:
|
||||
unrar_read_func user_read;
|
||||
unrar_write_func user_write;
|
||||
void* user_read_data;
|
||||
void* user_write_data;
|
||||
unrar_err_t write_error; // once write error occurs, no more writes are made
|
||||
int64 Tell_;
|
||||
bool OldFormat;
|
||||
|
||||
private:
|
||||
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; }
|
||||
|
||||
uint UnpFileCRC;
|
||||
|
||||
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);
|
||||
void UnixSlashToDos(const char *SrcName, char *DestName, size_t MaxLength);
|
||||
void DosSlashToUnix(const char *SrcName, char *DestName, size_t MaxLength);
|
||||
void UnixSlashToDos(const wchar *SrcName, wchar *DestName, size_t MaxLength);
|
||||
void DosSlashToUnix(const wchar *SrcName, wchar *DestName, size_t MaxLength);
|
||||
|
||||
//// 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"
|
||||
#include "encname.hpp"
|
||||
#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
|
||||
: public Rar_Allocator
|
||||
{
|
||||
unrar_info_t info;
|
||||
unrar_pos_t begin_pos;
|
||||
unrar_pos_t solid_pos;
|
||||
unrar_pos_t first_file_pos;
|
||||
void const* data_;
|
||||
void* own_data_;
|
||||
void (*close_file)( void* ); // func ptr to avoid linking fclose() in unnecessarily
|
||||
bool done;
|
||||
long FileCount;
|
||||
Unpack* Unp;
|
||||
Array<byte> Buffer;
|
||||
// large items last
|
||||
Archive Arc;
|
||||
|
||||
unrar_t();
|
||||
~unrar_t();
|
||||
void UnstoreFile( int64 );
|
||||
unrar_err_t ExtractCurrentFile( bool SkipSolid = false, bool check_compatibility_only = false );
|
||||
void update_first_file_pos()
|
||||
{
|
||||
if ( FileCount == 0 )
|
||||
first_file_pos = Arc.CurBlockPos;
|
||||
}
|
||||
};
|
||||
|
||||
typedef unrar_t CmdExtract;
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,115 @@
|
|||
#ifndef _RAR_VM_
|
||||
#define _RAR_VM_
|
||||
|
||||
#define VM_STANDARDFILTERS
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
#define VM_OPTIMIZE
|
||||
#endif
|
||||
|
||||
|
||||
#define VM_MEMSIZE 0x40000
|
||||
#define VM_MEMMASK (VM_MEMSIZE-1)
|
||||
#define VM_GLOBALMEMADDR 0x3C000
|
||||
#define VM_GLOBALMEMSIZE 0x2000
|
||||
#define VM_FIXEDGLOBALSIZE 64
|
||||
|
||||
enum VM_Commands
|
||||
{
|
||||
VM_MOV, VM_CMP, VM_ADD, VM_SUB, VM_JZ, VM_JNZ, VM_INC, VM_DEC,
|
||||
VM_JMP, VM_XOR, VM_AND, VM_OR, VM_TEST, VM_JS, VM_JNS, VM_JB,
|
||||
VM_JBE, VM_JA, VM_JAE, VM_PUSH, VM_POP, VM_CALL, VM_RET, VM_NOT,
|
||||
VM_SHL, VM_SHR, VM_SAR, VM_NEG, VM_PUSHA,VM_POPA, VM_PUSHF,VM_POPF,
|
||||
VM_MOVZX,VM_MOVSX,VM_XCHG, VM_MUL, VM_DIV, VM_ADC, VM_SBB, VM_PRINT,
|
||||
|
||||
#ifdef VM_OPTIMIZE
|
||||
VM_MOVB, VM_MOVD, VM_CMPB, VM_CMPD,
|
||||
|
||||
VM_ADDB, VM_ADDD, VM_SUBB, VM_SUBD, VM_INCB, VM_INCD, VM_DECB, VM_DECD,
|
||||
VM_NEGB, VM_NEGD,
|
||||
#endif
|
||||
|
||||
VM_STANDARD
|
||||
};
|
||||
|
||||
enum VM_StandardFilters {
|
||||
VMSF_NONE, VMSF_E8, VMSF_E8E9, VMSF_ITANIUM, VMSF_RGB, VMSF_AUDIO,
|
||||
VMSF_DELTA
|
||||
};
|
||||
|
||||
enum VM_Flags {VM_FC=1,VM_FZ=2,VM_FS=0x80000000};
|
||||
|
||||
enum VM_OpType {VM_OPREG,VM_OPINT,VM_OPREGMEM,VM_OPNONE};
|
||||
|
||||
struct VM_PreparedOperand
|
||||
{
|
||||
VM_OpType Type;
|
||||
uint Data;
|
||||
uint Base;
|
||||
uint *Addr;
|
||||
};
|
||||
|
||||
struct VM_PreparedCommand
|
||||
{
|
||||
VM_Commands OpCode;
|
||||
bool ByteMode;
|
||||
VM_PreparedOperand Op1,Op2;
|
||||
};
|
||||
|
||||
|
||||
struct VM_PreparedProgram
|
||||
{
|
||||
VM_PreparedProgram()
|
||||
{
|
||||
AltCmd=NULL;
|
||||
FilteredDataSize=0;
|
||||
CmdCount=0;
|
||||
}
|
||||
|
||||
Array<VM_PreparedCommand> Cmd;
|
||||
VM_PreparedCommand *AltCmd;
|
||||
int CmdCount;
|
||||
|
||||
Array<byte> GlobalData;
|
||||
Array<byte> StaticData; // static data contained in DB operators
|
||||
uint InitR[7];
|
||||
|
||||
byte *FilteredData;
|
||||
uint FilteredDataSize;
|
||||
};
|
||||
|
||||
class RarVM:private BitInput
|
||||
{
|
||||
private:
|
||||
inline uint GetValue(bool ByteMode,uint *Addr);
|
||||
inline void SetValue(bool ByteMode,uint *Addr,uint Value);
|
||||
inline uint* GetOperand(VM_PreparedOperand *CmdOp);
|
||||
void DecodeArg(VM_PreparedOperand &Op,bool ByteMode);
|
||||
#ifdef VM_OPTIMIZE
|
||||
void Optimize(VM_PreparedProgram *Prg);
|
||||
#endif
|
||||
bool ExecuteCode(VM_PreparedCommand *PreparedCode,uint CodeSize);
|
||||
#ifdef VM_STANDARDFILTERS
|
||||
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,uint BitField,int BitPos,int BitCount);
|
||||
#endif
|
||||
|
||||
byte *Mem;
|
||||
uint R[8];
|
||||
uint Flags;
|
||||
public:
|
||||
RarVM();
|
||||
~RarVM();
|
||||
void Init();
|
||||
void handle_mem_error( Rar_Error_Handler& );
|
||||
friend class Unpack;
|
||||
void Prepare(byte *Code,uint CodeSize,VM_PreparedProgram *Prg);
|
||||
void Execute(VM_PreparedProgram *Prg);
|
||||
void SetLowEndianValue(uint *Addr,uint Value);
|
||||
void SetMemory(size_t Pos,byte *Data,size_t DataSize);
|
||||
static uint ReadData(BitInput &Inp);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,57 @@
|
|||
// #included by rarvm.cpp
|
||||
#ifdef RAR_COMMON_HPP
|
||||
#define VMCF_OP0 0
|
||||
#define VMCF_OP1 1
|
||||
#define VMCF_OP2 2
|
||||
#define VMCF_OPMASK 3
|
||||
#define VMCF_BYTEMODE 4
|
||||
#define VMCF_JUMP 8
|
||||
#define VMCF_PROC 16
|
||||
#define VMCF_USEFLAGS 32
|
||||
#define VMCF_CHFLAGS 64
|
||||
|
||||
const
|
||||
static byte VM_CmdFlags[]=
|
||||
{
|
||||
/* VM_MOV */ VMCF_OP2 | VMCF_BYTEMODE ,
|
||||
/* VM_CMP */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_ADD */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_SUB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_JZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_JNZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_INC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_DEC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_JMP */ VMCF_OP1 | VMCF_JUMP ,
|
||||
/* VM_XOR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_AND */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_OR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_TEST */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_JS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_JNS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_JB */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_JBE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_JA */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_JAE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_PUSH */ VMCF_OP1 ,
|
||||
/* VM_POP */ VMCF_OP1 ,
|
||||
/* VM_CALL */ VMCF_OP1 | VMCF_PROC ,
|
||||
/* VM_RET */ VMCF_OP0 | VMCF_PROC ,
|
||||
/* VM_NOT */ VMCF_OP1 | VMCF_BYTEMODE ,
|
||||
/* VM_SHL */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_SHR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_SAR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_NEG */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_PUSHA */ VMCF_OP0 ,
|
||||
/* VM_POPA */ VMCF_OP0 ,
|
||||
/* VM_PUSHF */ VMCF_OP0 | VMCF_USEFLAGS ,
|
||||
/* VM_POPF */ VMCF_OP0 | VMCF_CHFLAGS ,
|
||||
/* VM_MOVZX */ VMCF_OP2 ,
|
||||
/* VM_MOVSX */ VMCF_OP2 ,
|
||||
/* VM_XCHG */ VMCF_OP2 | VMCF_BYTEMODE ,
|
||||
/* VM_MUL */ VMCF_OP2 | VMCF_BYTEMODE ,
|
||||
/* VM_DIV */ VMCF_OP2 | VMCF_BYTEMODE ,
|
||||
/* VM_ADC */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS ,
|
||||
/* VM_SBB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS ,
|
||||
/* VM_PRINT */ VMCF_OP0
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,159 @@
|
|||
#include "rar.hpp"
|
||||
|
||||
RawRead::RawRead(ComprDataIO *SrcFile)
|
||||
{
|
||||
RawRead::SrcFile=SrcFile;
|
||||
Reset();
|
||||
}
|
||||
|
||||
void RawRead::Reset()
|
||||
{
|
||||
ReadPos=0;
|
||||
DataSize=0;
|
||||
Data.Reset();
|
||||
}
|
||||
|
||||
size_t RawRead::Read(size_t Size)
|
||||
{
|
||||
size_t ReadSize=0;
|
||||
// (removed decryption)
|
||||
if (Size!=0)
|
||||
{
|
||||
Data.Add(Size);
|
||||
ReadSize=SrcFile->Read(&Data[DataSize],Size);
|
||||
DataSize+=ReadSize;
|
||||
}
|
||||
return ReadSize;
|
||||
}
|
||||
|
||||
|
||||
void RawRead::Read(byte *SrcData,size_t Size)
|
||||
{
|
||||
if (Size!=0)
|
||||
{
|
||||
Data.Add(Size);
|
||||
memcpy(&Data[DataSize],SrcData,Size);
|
||||
DataSize+=Size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
byte RawRead::Get1()
|
||||
{
|
||||
return ReadPos<DataSize ? Data[ReadPos++]:0;
|
||||
}
|
||||
|
||||
|
||||
ushort RawRead::Get2()
|
||||
{
|
||||
if (ReadPos+1<DataSize)
|
||||
{
|
||||
ushort Result=Data[ReadPos]+(Data[ReadPos+1]<<8);
|
||||
ReadPos+=2;
|
||||
return Result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint RawRead::Get4()
|
||||
{
|
||||
if (ReadPos+3<DataSize)
|
||||
{
|
||||
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
|
||||
memset(Field,0,sizeof(wchar)*Size);
|
||||
}
|
||||
|
||||
|
||||
uint RawRead::GetCRC15(bool ProcessedOnly) // RAR 1.5 block CRC.
|
||||
{
|
||||
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.
|
||||
{
|
||||
if (DataSize<=4)
|
||||
return 0xffffffff;
|
||||
return CRC32(0xffffffff,&Data[4],DataSize-4) ^ 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
// Read vint from arbitrary byte array.
|
||||
uint64 RawGetV(const byte *Data,uint &ReadPos,uint DataSize,bool &Overflow)
|
||||
{
|
||||
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.
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
#ifndef _RAR_RAWREAD_
|
||||
#define _RAR_RAWREAD_
|
||||
|
||||
class RawRead
|
||||
{
|
||||
private:
|
||||
Array<byte> Data;
|
||||
File *SrcFile;
|
||||
size_t DataSize;
|
||||
size_t ReadPos;
|
||||
public:
|
||||
RawRead(File *SrcFile);
|
||||
void Reset();
|
||||
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
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
Portable UnRAR version
|
||||
|
||||
|
||||
1. General
|
||||
|
||||
This package includes freeware Unrar C++ source and makefile for
|
||||
several Unix compilers.
|
||||
|
||||
Unrar source is subset of RAR and generated from RAR source automatically,
|
||||
by a small program removing blocks like '#ifndef UNRAR ... #endif'.
|
||||
Such method is not perfect and you may find some RAR related stuff
|
||||
unnecessary in Unrar, especially in header files.
|
||||
|
||||
If you wish to port Unrar to a new platform, you may need to edit
|
||||
'#define LITTLE_ENDIAN' in os.hpp and data type definitions
|
||||
in rartypes.hpp.
|
||||
|
||||
if computer architecture does not allow not aligned data access,
|
||||
you need to undefine ALLOW_NOT_ALIGNED_INT and define
|
||||
STRICT_ALIGNMENT_REQUIRED in os.h.
|
||||
|
||||
UnRAR.vcproj and UnRARDll.vcproj are projects for Microsoft Visual C++.
|
||||
UnRARDll.vcproj lets to build unrar.dll library.
|
||||
|
||||
|
||||
2. Unrar binaries
|
||||
|
||||
If you compiled Unrar for OS, which is not present in "Downloads"
|
||||
and "RAR extras" on www.rarlab.com, we will appreciate if you send
|
||||
us the compiled executable to place it to our site.
|
||||
|
||||
|
||||
3. Acknowledgements
|
||||
|
||||
This source includes parts of code written by other authors.
|
||||
Please see acknow.txt file for details.
|
||||
|
||||
|
||||
4. Legal stuff
|
||||
|
||||
Unrar source may be used in any software to handle RAR archives
|
||||
without limitations free of charge, but cannot be used to re-create
|
||||
the RAR compression algorithm, which is proprietary. Distribution
|
||||
of modified Unrar source in separate form or as a part of other
|
||||
software is permitted, provided that it is clearly stated in
|
||||
the documentation and source comments that the code may not be used
|
||||
to develop a RAR (WinRAR) compatible archiver.
|
||||
|
||||
More detailed license text is available in license.txt.
|
|
@ -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
|
||||
}
|
||||
|
|
@ -0,0 +1,419 @@
|
|||
#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');
|
||||
#if defined(__APPLE__) || defined(_MSC_VER)
|
||||
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) || defined(_MSC_VER) || defined(__APPLE__)
|
||||
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)
|
||||
{
|
||||
#if _MSC_VER >= 1300
|
||||
strcpy_s(dest,maxlen-1,src);
|
||||
#else
|
||||
strncpy(dest,src,maxlen-1);
|
||||
#endif
|
||||
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)
|
||||
#if _MSC_VER >= 1300
|
||||
strcat_s(dest, maxlen - Length - 1, src);
|
||||
#else
|
||||
strncat(dest, src, maxlen - Length - 1);
|
||||
#endif
|
||||
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
|
|
@ -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
|
|
@ -0,0 +1,264 @@
|
|||
/****************************************************************************
|
||||
* This file is part of PPMd project *
|
||||
* Written and distributed to public domain by Dmitry Shkarin 1997, *
|
||||
* 1999-2000 *
|
||||
* Contents: memory allocation routines *
|
||||
****************************************************************************/
|
||||
|
||||
// #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();
|
||||
}
|
||||
|
||||
|
||||
void SubAllocator::Clean()
|
||||
{
|
||||
SubAllocatorSize=0;
|
||||
}
|
||||
|
||||
|
||||
inline void SubAllocator::InsertNode(void* p,int indx)
|
||||
{
|
||||
((RAR_NODE*) p)->next=FreeList[indx].next;
|
||||
FreeList[indx].next=(RAR_NODE*) p;
|
||||
}
|
||||
|
||||
|
||||
inline void* SubAllocator::RemoveNode(int indx)
|
||||
{
|
||||
RAR_NODE* RetVal=FreeList[indx].next;
|
||||
FreeList[indx].next=RetVal->next;
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
|
||||
inline uint SubAllocator::U2B(int NU)
|
||||
{
|
||||
return /*8*NU+4*NU*/UNIT_SIZE*NU;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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 RARPPM_MEM_BLK* SubAllocator::MBPtr(RARPPM_MEM_BLK *BasePtr,int Items)
|
||||
{
|
||||
return((RARPPM_MEM_BLK*)( ((byte *)(BasePtr))+U2B(Items) ));
|
||||
}
|
||||
|
||||
|
||||
inline void SubAllocator::SplitBlock(void* pv,int OldIndx,int NewIndx)
|
||||
{
|
||||
int i, UDiff=Indx2Units[OldIndx]-Indx2Units[NewIndx];
|
||||
byte* p=((byte*) pv)+U2B(Indx2Units[NewIndx]);
|
||||
if (Indx2Units[i=Units2Indx[UDiff-1]] != UDiff)
|
||||
{
|
||||
InsertNode(p,--i);
|
||||
p += U2B(i=Indx2Units[i]);
|
||||
UDiff -= i;
|
||||
}
|
||||
InsertNode(p,Units2Indx[UDiff-1]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SubAllocator::StopSubAllocator()
|
||||
{
|
||||
if ( SubAllocatorSize )
|
||||
{
|
||||
SubAllocatorSize=0;
|
||||
rarfree(HeapStart);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SubAllocator::StartSubAllocator(int SASize)
|
||||
{
|
||||
uint t=SASize << 20;
|
||||
if (SubAllocatorSize == t)
|
||||
return true;
|
||||
StopSubAllocator();
|
||||
uint AllocSize=t/FIXED_UNIT_SIZE*UNIT_SIZE+UNIT_SIZE;
|
||||
#ifdef STRICT_ALIGNMENT_REQUIRED
|
||||
AllocSize+=UNIT_SIZE;
|
||||
#endif
|
||||
if ((HeapStart=(byte *)rarmalloc(AllocSize)) == NULL)
|
||||
{
|
||||
ErrHandler->MemoryError();
|
||||
return false;
|
||||
}
|
||||
HeapEnd=HeapStart+AllocSize-UNIT_SIZE;
|
||||
SubAllocatorSize=t;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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 RealSize2=Size2/FIXED_UNIT_SIZE*UNIT_SIZE;
|
||||
uint Size1=(uint)(SubAllocatorSize-Size2);
|
||||
uint RealSize1=Size1/FIXED_UNIT_SIZE*UNIT_SIZE+Size1%FIXED_UNIT_SIZE;
|
||||
#ifdef STRICT_ALIGNMENT_REQUIRED
|
||||
if (Size1%FIXED_UNIT_SIZE!=0)
|
||||
RealSize1+=UNIT_SIZE-Size1%FIXED_UNIT_SIZE;
|
||||
#endif
|
||||
HiUnit=HeapStart+SubAllocatorSize;
|
||||
LoUnit=UnitsStart=HeapStart+RealSize1;
|
||||
FakeUnitsStart=HeapStart+Size1;
|
||||
HiUnit=LoUnit+RealSize2;
|
||||
for (i=0,k=1;i < N1 ;i++,k += 1)
|
||||
Indx2Units[i]=k;
|
||||
for (k++;i < N1+N2 ;i++,k += 2)
|
||||
Indx2Units[i]=k;
|
||||
for (k++;i < N1+N2+N3 ;i++,k += 3)
|
||||
Indx2Units[i]=k;
|
||||
for (k++;i < N1+N2+N3+N4;i++,k += 4)
|
||||
Indx2Units[i]=k;
|
||||
for (GlueCount=k=i=0;k < 128;k++)
|
||||
{
|
||||
i += (Indx2Units[i] < k+1);
|
||||
Units2Indx[k]=i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void SubAllocator::GlueFreeBlocks()
|
||||
{
|
||||
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=(RARPPM_MEM_BLK*)RemoveNode(i);
|
||||
p->insertAt(&s0);
|
||||
p->Stamp=0xFFFF;
|
||||
p->NU=Indx2Units[i];
|
||||
}
|
||||
for (p=s0.next;p != &s0;p=p->next)
|
||||
while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU < 0x10000)
|
||||
{
|
||||
p1->remove();
|
||||
p->NU += p1->NU;
|
||||
}
|
||||
while ((p=s0.next) != &s0)
|
||||
{
|
||||
for (p->remove(), sz=p->NU;sz > 128;sz -= 128, p=MBPtr(p,128))
|
||||
InsertNode(p,N_INDEXES-1);
|
||||
if (Indx2Units[i=Units2Indx[sz-1]] != sz)
|
||||
{
|
||||
k=sz-Indx2Units[--i];
|
||||
InsertNode(MBPtr(p,sz-k),k-1);
|
||||
}
|
||||
InsertNode(p,i);
|
||||
}
|
||||
}
|
||||
|
||||
void* SubAllocator::AllocUnitsRare(int indx)
|
||||
{
|
||||
if ( !GlueCount )
|
||||
{
|
||||
GlueCount = 255;
|
||||
GlueFreeBlocks();
|
||||
if ( FreeList[indx].next )
|
||||
return RemoveNode(indx);
|
||||
}
|
||||
int i=indx;
|
||||
do
|
||||
{
|
||||
if (++i == N_INDEXES)
|
||||
{
|
||||
GlueCount--;
|
||||
i=U2B(Indx2Units[indx]);
|
||||
int j=FIXED_UNIT_SIZE*Indx2Units[indx];
|
||||
if (FakeUnitsStart-pText > j)
|
||||
{
|
||||
FakeUnitsStart-=j;
|
||||
UnitsStart -= i;
|
||||
return(UnitsStart);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
} while ( !FreeList[i].next );
|
||||
void* RetVal=RemoveNode(i);
|
||||
SplitBlock(RetVal,i,indx);
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
|
||||
inline void* SubAllocator::AllocUnits(int NU)
|
||||
{
|
||||
int indx=Units2Indx[NU-1];
|
||||
if ( FreeList[indx].next )
|
||||
return RemoveNode(indx);
|
||||
void* RetVal=LoUnit;
|
||||
LoUnit += U2B(Indx2Units[indx]);
|
||||
if (LoUnit <= HiUnit)
|
||||
return RetVal;
|
||||
LoUnit -= U2B(Indx2Units[indx]);
|
||||
return AllocUnitsRare(indx);
|
||||
}
|
||||
|
||||
|
||||
void* SubAllocator::AllocContext()
|
||||
{
|
||||
if (HiUnit != LoUnit)
|
||||
return (HiUnit -= UNIT_SIZE);
|
||||
if ( FreeList->next )
|
||||
return RemoveNode(0);
|
||||
return AllocUnitsRare(0);
|
||||
}
|
||||
|
||||
|
||||
void* SubAllocator::ExpandUnits(void* OldPtr,int OldNU)
|
||||
{
|
||||
int i0=Units2Indx[OldNU-1], i1=Units2Indx[OldNU-1+1];
|
||||
if (i0 == i1)
|
||||
return OldPtr;
|
||||
void* ptr=AllocUnits(OldNU+1);
|
||||
if ( ptr )
|
||||
{
|
||||
memcpy(ptr,OldPtr,U2B(OldNU));
|
||||
InsertNode(OldPtr,i0);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void* SubAllocator::ShrinkUnits(void* OldPtr,int OldNU,int NewNU)
|
||||
{
|
||||
int i0=Units2Indx[OldNU-1], i1=Units2Indx[NewNU-1];
|
||||
if (i0 == i1)
|
||||
return OldPtr;
|
||||
if ( FreeList[i1].next )
|
||||
{
|
||||
void* ptr=RemoveNode(i1);
|
||||
memcpy(ptr,OldPtr,U2B(NewNU));
|
||||
InsertNode(OldPtr,i0);
|
||||
return ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitBlock(OldPtr,i0,i1);
|
||||
return OldPtr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SubAllocator::FreeUnits(void* ptr,int OldNU)
|
||||
{
|
||||
InsertNode(ptr,Units2Indx[OldNU-1]);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,88 @@
|
|||
/****************************************************************************
|
||||
* This file is part of PPMd project *
|
||||
* Written and distributed to public domain by Dmitry Shkarin 1997, *
|
||||
* 1999-2000 *
|
||||
* Contents: interface to memory allocation routines *
|
||||
****************************************************************************/
|
||||
#if !defined(_SUBALLOC_H_)
|
||||
#define _SUBALLOC_H_
|
||||
|
||||
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(ALLOW_MISALIGNED)
|
||||
#define RARPPM_PACK_ATTR __attribute__ ((packed))
|
||||
#else
|
||||
#define RARPPM_PACK_ATTR
|
||||
#endif /* defined(__GNUC__) */
|
||||
|
||||
#ifdef ALLOW_MISALIGNED
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
struct RARPPM_MEM_BLK
|
||||
{
|
||||
ushort Stamp, NU;
|
||||
RARPPM_MEM_BLK* next, * prev;
|
||||
void insertAt(RARPPM_MEM_BLK* p)
|
||||
{
|
||||
next=(prev=p)->next;
|
||||
p->next=next->prev=this;
|
||||
}
|
||||
void remove()
|
||||
{
|
||||
prev->next=next;
|
||||
next->prev=prev;
|
||||
}
|
||||
} RARPPM_PACK_ATTR;
|
||||
|
||||
#ifndef ALLOW_MISALIGNED
|
||||
#ifdef _AIX
|
||||
#pragma pack(pop)
|
||||
#else
|
||||
#pragma pack()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
struct RAR_NODE
|
||||
{
|
||||
RAR_NODE* next;
|
||||
};
|
||||
|
||||
class SubAllocator
|
||||
{
|
||||
private:
|
||||
inline void InsertNode(void* p,int indx);
|
||||
inline void* RemoveNode(int indx);
|
||||
inline uint U2B(int NU);
|
||||
inline void SplitBlock(void* pv,int OldIndx,int NewIndx);
|
||||
uint GetUsedMemory();
|
||||
inline void GlueFreeBlocks();
|
||||
void* AllocUnitsRare(int indx);
|
||||
inline RARPPM_MEM_BLK* MBPtr(RARPPM_MEM_BLK *BasePtr,int Items);
|
||||
|
||||
long SubAllocatorSize;
|
||||
byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount;
|
||||
byte *HeapStart,*LoUnit, *HiUnit;
|
||||
struct RAR_NODE FreeList[N_INDEXES];
|
||||
public:
|
||||
Rar_Error_Handler* ErrHandler;
|
||||
SubAllocator();
|
||||
~SubAllocator() {StopSubAllocator();}
|
||||
void Clean();
|
||||
bool StartSubAllocator(int SASize);
|
||||
void StopSubAllocator();
|
||||
void InitSubAllocator();
|
||||
inline void* AllocContext();
|
||||
inline void* AllocUnits(int NU);
|
||||
inline void* ExpandUnits(void* ptr,int OldNU);
|
||||
inline void* ShrinkUnits(void* ptr,int OldNU,int NewNU);
|
||||
inline void FreeUnits(void* ptr,int OldNU);
|
||||
long GetAllocatedMemory() {return(SubAllocatorSize);};
|
||||
|
||||
byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart;
|
||||
};
|
||||
|
||||
|
||||
#endif /* !defined(_SUBALLOC_H_) */
|
|
@ -0,0 +1,275 @@
|
|||
|
||||
RAR version 3.80 - Technical information
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
THE ARCHIVE FORMAT DESCRIBED BELOW IS ONLY VALID FOR VERSIONS SINCE 1.50
|
||||
|
||||
==========================================================================
|
||||
RAR archive file format
|
||||
==========================================================================
|
||||
|
||||
Archive file consists of variable length blocks. The order of these
|
||||
blocks may vary, but the first block must be a marker block followed by
|
||||
an archive header block.
|
||||
|
||||
Each block begins with the following fields:
|
||||
|
||||
HEAD_CRC 2 bytes CRC of total block or block part
|
||||
HEAD_TYPE 1 byte Block type
|
||||
HEAD_FLAGS 2 bytes Block flags
|
||||
HEAD_SIZE 2 bytes Block size
|
||||
ADD_SIZE 4 bytes Optional field - added block size
|
||||
|
||||
Field ADD_SIZE present only if (HEAD_FLAGS & 0x8000) != 0
|
||||
|
||||
Total block size is HEAD_SIZE if (HEAD_FLAGS & 0x8000) == 0
|
||||
and HEAD_SIZE+ADD_SIZE if the field ADD_SIZE is present - when
|
||||
(HEAD_FLAGS & 0x8000) != 0.
|
||||
|
||||
In each block the followings bits in HEAD_FLAGS have the same meaning:
|
||||
|
||||
0x4000 - if set, older RAR versions will ignore the block
|
||||
and remove it when the archive is updated.
|
||||
if clear, the block is copied to the new archive
|
||||
file when the archive is updated;
|
||||
|
||||
0x8000 - if set, ADD_SIZE field is present and the full block
|
||||
size is HEAD_SIZE+ADD_SIZE.
|
||||
|
||||
Declared block types:
|
||||
|
||||
HEAD_TYPE=0x72 marker block
|
||||
HEAD_TYPE=0x73 archive header
|
||||
HEAD_TYPE=0x74 file header
|
||||
HEAD_TYPE=0x75 old style comment header
|
||||
HEAD_TYPE=0x76 old style authenticity information
|
||||
HEAD_TYPE=0x77 old style subblock
|
||||
HEAD_TYPE=0x78 old style recovery record
|
||||
HEAD_TYPE=0x79 old style authenticity information
|
||||
HEAD_TYPE=0x7a subblock
|
||||
|
||||
Comment block is actually used only within other blocks and doesn't
|
||||
exist separately.
|
||||
|
||||
Archive processing is made in the following manner:
|
||||
|
||||
1. Read and check marker block
|
||||
2. Read archive header
|
||||
3. Read or skip HEAD_SIZE-sizeof(MAIN_HEAD) bytes
|
||||
4. If end of archive encountered then terminate archive processing,
|
||||
else read 7 bytes into fields HEAD_CRC, HEAD_TYPE, HEAD_FLAGS,
|
||||
HEAD_SIZE.
|
||||
5. Check HEAD_TYPE.
|
||||
if HEAD_TYPE==0x74
|
||||
read file header ( first 7 bytes already read )
|
||||
read or skip HEAD_SIZE-sizeof(FILE_HEAD) bytes
|
||||
if (HEAD_FLAGS & 0x100)
|
||||
read or skip HIGH_PACK_SIZE*0x100000000+PACK_SIZE bytes
|
||||
else
|
||||
read or skip PACK_SIZE bytes
|
||||
else
|
||||
read corresponding HEAD_TYPE block:
|
||||
read HEAD_SIZE-7 bytes
|
||||
if (HEAD_FLAGS & 0x8000)
|
||||
read ADD_SIZE bytes
|
||||
6. go to 4.
|
||||
|
||||
|
||||
==========================================================================
|
||||
Block Formats
|
||||
==========================================================================
|
||||
|
||||
|
||||
Marker block ( MARK_HEAD )
|
||||
|
||||
|
||||
HEAD_CRC Always 0x6152
|
||||
2 bytes
|
||||
|
||||
HEAD_TYPE Header type: 0x72
|
||||
1 byte
|
||||
|
||||
HEAD_FLAGS Always 0x1a21
|
||||
2 bytes
|
||||
|
||||
HEAD_SIZE Block size = 0x0007
|
||||
2 bytes
|
||||
|
||||
The marker block is actually considered as a fixed byte
|
||||
sequence: 0x52 0x61 0x72 0x21 0x1a 0x07 0x00
|
||||
|
||||
|
||||
|
||||
Archive header ( MAIN_HEAD )
|
||||
|
||||
|
||||
HEAD_CRC CRC of fields HEAD_TYPE to RESERVED2
|
||||
2 bytes
|
||||
|
||||
HEAD_TYPE Header type: 0x73
|
||||
1 byte
|
||||
|
||||
HEAD_FLAGS Bit flags:
|
||||
2 bytes
|
||||
0x0001 - Volume attribute (archive volume)
|
||||
0x0002 - Archive comment present
|
||||
RAR 3.x uses the separate comment block
|
||||
and does not set this flag.
|
||||
|
||||
0x0004 - Archive lock attribute
|
||||
0x0008 - Solid attribute (solid archive)
|
||||
0x0010 - New volume naming scheme ('volname.partN.rar')
|
||||
0x0020 - Authenticity information present
|
||||
RAR 3.x does not set this flag.
|
||||
|
||||
0x0040 - Recovery record present
|
||||
0x0080 - Block headers are encrypted
|
||||
0x0100 - First volume (set only by RAR 3.0 and later)
|
||||
|
||||
other bits in HEAD_FLAGS are reserved for
|
||||
internal use
|
||||
|
||||
HEAD_SIZE Archive header total size including archive comments
|
||||
2 bytes
|
||||
|
||||
RESERVED1 Reserved
|
||||
2 bytes
|
||||
|
||||
RESERVED2 Reserved
|
||||
4 bytes
|
||||
|
||||
|
||||
|
||||
File header (File in archive)
|
||||
|
||||
|
||||
HEAD_CRC CRC of fields from HEAD_TYPE to FILEATTR
|
||||
2 bytes and file name
|
||||
|
||||
HEAD_TYPE Header type: 0x74
|
||||
1 byte
|
||||
|
||||
HEAD_FLAGS Bit flags:
|
||||
2 bytes
|
||||
0x01 - file continued from previous volume
|
||||
0x02 - file continued in next volume
|
||||
0x04 - file encrypted with password
|
||||
|
||||
0x08 - file comment present
|
||||
RAR 3.x uses the separate comment block
|
||||
and does not set this flag.
|
||||
|
||||
0x10 - information from previous files is used (solid flag)
|
||||
(for RAR 2.0 and later)
|
||||
|
||||
bits 7 6 5 (for RAR 2.0 and later)
|
||||
|
||||
0 0 0 - dictionary size 64 KB
|
||||
0 0 1 - dictionary size 128 KB
|
||||
0 1 0 - dictionary size 256 KB
|
||||
0 1 1 - dictionary size 512 KB
|
||||
1 0 0 - dictionary size 1024 KB
|
||||
1 0 1 - dictionary size 2048 KB
|
||||
1 1 0 - dictionary size 4096 KB
|
||||
1 1 1 - file is directory
|
||||
|
||||
0x100 - HIGH_PACK_SIZE and HIGH_UNP_SIZE fields
|
||||
are present. These fields are used to archive
|
||||
only very large files (larger than 2Gb),
|
||||
for smaller files these fields are absent.
|
||||
|
||||
0x200 - FILE_NAME contains both usual and encoded
|
||||
Unicode name separated by zero. In this case
|
||||
NAME_SIZE field is equal to the length
|
||||
of usual name plus encoded Unicode name plus 1.
|
||||
|
||||
If this flag is present, but FILE_NAME does not
|
||||
contain zero bytes, it means that file name
|
||||
is encoded using UTF-8.
|
||||
|
||||
0x400 - the header contains additional 8 bytes
|
||||
after the file name, which are required to
|
||||
increase encryption security (so called 'salt').
|
||||
|
||||
0x800 - Version flag. It is an old file version,
|
||||
a version number is appended to file name as ';n'.
|
||||
|
||||
0x1000 - Extended time field present.
|
||||
|
||||
0x8000 - this bit always is set, so the complete
|
||||
block size is HEAD_SIZE + PACK_SIZE
|
||||
(and plus HIGH_PACK_SIZE, if bit 0x100 is set)
|
||||
|
||||
HEAD_SIZE File header full size including file name and comments
|
||||
2 bytes
|
||||
|
||||
PACK_SIZE Compressed file size
|
||||
4 bytes
|
||||
|
||||
UNP_SIZE Uncompressed file size
|
||||
4 bytes
|
||||
|
||||
HOST_OS Operating system used for archiving
|
||||
1 byte 0 - MS DOS
|
||||
1 - OS/2
|
||||
2 - Win32
|
||||
3 - Unix
|
||||
4 - Mac OS
|
||||
5 - BeOS
|
||||
|
||||
FILE_CRC File CRC
|
||||
4 bytes
|
||||
|
||||
FTIME Date and time in standard MS DOS format
|
||||
4 bytes
|
||||
|
||||
UNP_VER RAR version needed to extract file
|
||||
1 byte
|
||||
Version number is encoded as
|
||||
10 * Major version + minor version.
|
||||
|
||||
METHOD Packing method
|
||||
1 byte
|
||||
0x30 - storing
|
||||
0x31 - fastest compression
|
||||
0x32 - fast compression
|
||||
0x33 - normal compression
|
||||
0x34 - good compression
|
||||
0x35 - best compression
|
||||
|
||||
NAME_SIZE File name size
|
||||
2 bytes
|
||||
|
||||
ATTR File attributes
|
||||
4 bytes
|
||||
|
||||
HIGH_PACK_SIZE High 4 bytes of 64 bit value of compressed file size.
|
||||
4 bytes Optional value, presents only if bit 0x100 in HEAD_FLAGS
|
||||
is set.
|
||||
|
||||
HIGH_UNP_SIZE High 4 bytes of 64 bit value of uncompressed file size.
|
||||
4 bytes Optional value, presents only if bit 0x100 in HEAD_FLAGS
|
||||
is set.
|
||||
|
||||
FILE_NAME File name - string of NAME_SIZE bytes size
|
||||
|
||||
SALT present if (HEAD_FLAGS & 0x400) != 0
|
||||
8 bytes
|
||||
|
||||
EXT_TIME present if (HEAD_FLAGS & 0x1000) != 0
|
||||
variable size
|
||||
|
||||
other new fields may appear here.
|
||||
|
||||
|
||||
==========================================================================
|
||||
Application notes
|
||||
==========================================================================
|
||||
|
||||
1. To process an SFX archive you need to skip the SFX module searching
|
||||
for the marker block in the archive. There is no marker block sequence (0x52
|
||||
0x61 0x72 0x21 0x1a 0x07 0x00) in the SFX module itself.
|
||||
|
||||
2. The CRC is calculated using the standard polynomial 0xEDB88320. In
|
||||
case the size of the CRC is less than 4 bytes, only the low order bytes
|
||||
are used.
|
|
@ -0,0 +1,257 @@
|
|||
#include "rar.hpp"
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
#include <Windows.h>
|
||||
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;
|
||||
|
||||
// SystemTimeToTzSpecificLocalTime based code produces 1 hour error on XP.
|
||||
FileTimeToLocalFileTime(&ft,&lft);
|
||||
|
||||
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;
|
||||
|
||||
// TzSpecificLocalTimeToSystemTime based code produces 1 hour error on XP.
|
||||
LocalFileTimeToFileTime(&lft,&ft);
|
||||
|
||||
*this=ft;
|
||||
}
|
||||
else
|
||||
Reset();
|
||||
#else
|
||||
struct tm t;
|
||||
|
||||
t.tm_sec=lt->Second;
|
||||
t.tm_min=lt->Minute;
|
||||
t.tm_hour=lt->Hour;
|
||||
t.tm_mday=lt->Day;
|
||||
t.tm_mon=lt->Month-1;
|
||||
t.tm_year=lt->Year-1900;
|
||||
t.tm_isdst=-1;
|
||||
*this=mktime(&t);
|
||||
itime+=lt->Reminder;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Return the stored time as 64-bit number of 100-nanosecond intervals since
|
||||
// 01.01.1601. Actually we do not care since which date this time starts from
|
||||
// as long as this date is the same for GetRaw and SetRaw. We use the value
|
||||
// returned by GetRaw() for time comparisons, for relative operations
|
||||
// like SetRaw(GetRaw()-C) and for compact time storage when necessary.
|
||||
uint64 RarTime::GetRaw()
|
||||
{
|
||||
return itime;
|
||||
}
|
||||
|
||||
|
||||
void RarTime::SetRaw(uint64 RawTime)
|
||||
{
|
||||
itime=RawTime;
|
||||
}
|
||||
|
||||
|
||||
uint RarTime::GetDos()
|
||||
{
|
||||
RarLocalTime lt;
|
||||
GetLocal(<);
|
||||
uint DosTime=(lt.Second/2)|(lt.Minute<<5)|(lt.Hour<<11)|
|
||||
(lt.Day<<16)|(lt.Month<<21)|((lt.Year-1980)<<25);
|
||||
return DosTime;
|
||||
}
|
||||
|
||||
|
||||
void RarTime::SetDos(uint DosTime)
|
||||
{
|
||||
RarLocalTime lt;
|
||||
lt.Second=(DosTime & 0x1f)*2;
|
||||
lt.Minute=(DosTime>>5) & 0x3f;
|
||||
lt.Hour=(DosTime>>11) & 0x1f;
|
||||
lt.Day=(DosTime>>16) & 0x1f;
|
||||
lt.Month=(DosTime>>21) & 0x0f;
|
||||
lt.Year=(DosTime>>25)+1980;
|
||||
lt.Reminder=0;
|
||||
SetLocal(<);
|
||||
}
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
void RarTime::SetIsoText(const wchar *TimeText)
|
||||
{
|
||||
int Field[6];
|
||||
memset(Field,0,sizeof(Field));
|
||||
for (uint DigitCount=0;*TimeText!=0;TimeText++)
|
||||
if (IsDigit(*TimeText))
|
||||
{
|
||||
int FieldPos=DigitCount<4 ? 0:(DigitCount-4)/2+1;
|
||||
if (FieldPos<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(<);
|
||||
}
|
||||
#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);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef _RAR_TIMEFN_
|
||||
#define _RAR_TIMEFN_
|
||||
|
||||
#include <time.h>
|
||||
#ifdef _WIN_ALL
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
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
|
|
@ -0,0 +1,198 @@
|
|||
#include "rar.hpp"
|
||||
|
||||
#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;
|
||||
#ifdef _WIN_32
|
||||
if (WideCharToMultiByte(CP_ACP,0,Src,-1,Dest,DestSize,NULL,NULL)==0)
|
||||
RetCode=false;
|
||||
#else
|
||||
#ifdef _APPLE
|
||||
WideToUtf(Src,Dest,DestSize);
|
||||
#else
|
||||
#ifdef MBFUNCTIONS
|
||||
|
||||
size_t ResultingSize=wcstombs(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 && strlenw(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(WideToChar(Src,Dest,NM));
|
||||
}
|
||||
|
||||
#else
|
||||
// TODO: convert to UTF-8? Would need conversion routine. Ugh.
|
||||
for (int I=0;I<DestSize;I++)
|
||||
{
|
||||
Dest[I]=(char)Src[I];
|
||||
if (Src[I]==0)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
return(RetCode);
|
||||
}
|
||||
|
||||
void UtfToWide(const char *Src,wchar *Dest,int DestSize)
|
||||
{
|
||||
DestSize--;
|
||||
while (*Src!=0)
|
||||
{
|
||||
uint c=(byte)*(Src++),d;
|
||||
if (c<0x80)
|
||||
d=c;
|
||||
else
|
||||
if ((c>>5)==6)
|
||||
{
|
||||
if ((*Src&0xc0)!=0x80)
|
||||
break;
|
||||
d=((c&0x1f)<<6)|(*Src&0x3f);
|
||||
Src++;
|
||||
}
|
||||
else
|
||||
if ((c>>4)==14)
|
||||
{
|
||||
if ((Src[0]&0xc0)!=0x80 || (Src[1]&0xc0)!=0x80)
|
||||
break;
|
||||
d=((c&0xf)<<12)|((Src[0]&0x3f)<<6)|(Src[1]&0x3f);
|
||||
Src+=2;
|
||||
}
|
||||
else
|
||||
if ((c>>3)==30)
|
||||
{
|
||||
if ((Src[0]&0xc0)!=0x80 || (Src[1]&0xc0)!=0x80 || (Src[2]&0xc0)!=0x80)
|
||||
break;
|
||||
d=((c&7)<<18)|((Src[0]&0x3f)<<12)|((Src[1]&0x3f)<<6)|(Src[2]&0x3f);
|
||||
Src+=3;
|
||||
}
|
||||
else
|
||||
break;
|
||||
if (--DestSize<0)
|
||||
break;
|
||||
if (d>0xffff)
|
||||
{
|
||||
if (--DestSize<0 || d>0x10ffff)
|
||||
break;
|
||||
*(Dest++)=((d-0x10000)>>10)+0xd800;
|
||||
*(Dest++)=(d&0x3ff)+0xdc00;
|
||||
}
|
||||
else
|
||||
*(Dest++)=d;
|
||||
}
|
||||
*Dest=0;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
#if defined(_WIN_32)
|
||||
CharToOem(Src,Dest);
|
||||
#else
|
||||
if (Dest!=Src)
|
||||
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;
|
||||
}
|
|
@ -0,0 +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
|
|
@ -0,0 +1,321 @@
|
|||
#include "rar.hpp"
|
||||
|
||||
#define _RAR_UNPACK_CPP_
|
||||
|
||||
#include "coder.cpp"
|
||||
#include "suballoc.cpp"
|
||||
#include "model.cpp"
|
||||
#include "unpackinline.cpp"
|
||||
#ifndef SFX_MODULE
|
||||
#include "unpack15.cpp"
|
||||
#include "unpack20.cpp"
|
||||
#endif
|
||||
#include "unpack30.cpp"
|
||||
#include "unpack50.cpp"
|
||||
#include "unpack50frag.cpp"
|
||||
|
||||
Unpack::Unpack(ComprDataIO *DataIO)
|
||||
: Inp(true), VMCodeInp(true)
|
||||
{
|
||||
LastFilter = 0;
|
||||
UnpIO=DataIO;
|
||||
Window=NULL;
|
||||
Fragmented=false;
|
||||
Suspended=false;
|
||||
UnpAllBuf=false;
|
||||
UnpSomeRead=false;
|
||||
MaxWinSize=0;
|
||||
MaxWinMask=0;
|
||||
}
|
||||
|
||||
void Unpack::init_tables()
|
||||
{
|
||||
ComprDataIO IOTemp;
|
||||
Unpack Temp(&IOTemp);
|
||||
// Perform initialization, which should be done only once for all files.
|
||||
// It prevents crash if first DoUnpack call is later made with wrong
|
||||
// (true) 'Solid' value.
|
||||
Temp.UnpInitData(false);
|
||||
#ifndef SFX_MODULE
|
||||
// RAR 1.5 decompression initialization
|
||||
Temp.UnpInitData15(false);
|
||||
Temp.InitHuff();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Unpack::~Unpack()
|
||||
{
|
||||
if (Window!=NULL)
|
||||
rarfree( Window );
|
||||
InitFilters30();
|
||||
}
|
||||
|
||||
|
||||
void Unpack::Init(size_t WinSize,bool Solid)
|
||||
{
|
||||
// If 32-bit RAR unpacks an archive with 4 GB dictionary, the window size
|
||||
// will be 0 because of size_t overflow. Let's issue the memory error.
|
||||
if (WinSize==0)
|
||||
throw std::bad_alloc();
|
||||
|
||||
// Minimum window size must be at least twice more than maximum possible
|
||||
// size of filter block, which is 0x10000 in RAR now. If window size is
|
||||
// smaller, we can have a block with never cleared flt->NextWindow flag
|
||||
// in UnpWriteBuf(). Minimum window size 0x20000 would be enough, but let's
|
||||
// use 0x40000 for extra safety and possible filter area size expansion.
|
||||
const size_t MinAllocSize=0x40000;
|
||||
if (WinSize<MinAllocSize)
|
||||
WinSize=MinAllocSize;
|
||||
|
||||
if (WinSize<=MaxWinSize) // Use the already allocated window.
|
||||
return;
|
||||
if ((WinSize>>16)>0x10000) // Window size must not exceed 4 GB.
|
||||
return;
|
||||
|
||||
// Archiving code guarantees that window size does not grow in the same
|
||||
// solid stream. So if we are here, we are either creating a new window
|
||||
// or increasing the size of non-solid window. So we could safely reject
|
||||
// current window data without copying them to a new window, though being
|
||||
// extra cautious, we still handle the solid window grow case below.
|
||||
bool Grow=Solid && (Window!=NULL || Fragmented);
|
||||
|
||||
// We do not handle growth for existing fragmented window.
|
||||
if (Grow && Fragmented)
|
||||
throw std::bad_alloc();
|
||||
|
||||
byte *NewWindow=Fragmented ? NULL : (byte *)malloc(WinSize);
|
||||
|
||||
if (NewWindow==NULL) {
|
||||
if (Grow || WinSize<0x1000000)
|
||||
{
|
||||
// We do not support growth for new fragmented window.
|
||||
// Also exclude RAR4 and small dictionaries.
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Window!=NULL) // If allocated by preceding files.
|
||||
{
|
||||
free(Window);
|
||||
Window=NULL;
|
||||
}
|
||||
FragWindow.Init(WinSize);
|
||||
Fragmented=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Fragmented)
|
||||
{
|
||||
// Clean the window to generate the same output when unpacking corrupt
|
||||
// RAR files, which may access to unused areas of sliding dictionary.
|
||||
memset(NewWindow,0,WinSize);
|
||||
|
||||
// If Window is not NULL, it means that window size has grown.
|
||||
// In solid streams we need to copy data to a new window in such case.
|
||||
// RAR archiving code does not allow it in solid streams now,
|
||||
// but let's implement it anyway just in case we'll change it sometimes.
|
||||
if (Grow)
|
||||
for (size_t I=1;I<MaxWinSize;I++)
|
||||
NewWindow[(UnpPtr-I)&(WinSize-1)]=Window[(UnpPtr-I)&(MaxWinSize-1)];
|
||||
|
||||
if (Window!=NULL)
|
||||
free(Window);
|
||||
Window=NewWindow;
|
||||
}
|
||||
|
||||
MaxWinSize=WinSize;
|
||||
MaxWinMask=MaxWinSize-1;
|
||||
}
|
||||
|
||||
|
||||
void Unpack::DoUnpack(int Method,bool Solid)
|
||||
{
|
||||
switch(Method)
|
||||
{
|
||||
#ifndef SFX_MODULE
|
||||
case 15: // rar 1.5 compression
|
||||
Unpack15(Solid);
|
||||
break;
|
||||
case 20: // rar 2.x compression
|
||||
case 26: // files larger than 2GB
|
||||
Unpack20(Solid);
|
||||
break;
|
||||
#endif
|
||||
case 29: // rar 3.x compression
|
||||
Unpack29(Solid);
|
||||
break;
|
||||
case 0: // RAR 5.0 compression algorithm 0.
|
||||
Unpack5(Solid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Unpack::UnpInitData(bool Solid)
|
||||
{
|
||||
if (!Solid)
|
||||
{
|
||||
memset(OldDist,0,sizeof(OldDist));
|
||||
OldDistPtr=0;
|
||||
LastDist=LastLength=0;
|
||||
// memset(Window,0,MaxWinSize);
|
||||
memset(&BlockTables,0,sizeof(BlockTables));
|
||||
UnpPtr=WrPtr=0;
|
||||
WriteBorder=Min(MaxWinSize,UNPACK_MAX_WRITE)&MaxWinMask;
|
||||
|
||||
InitFilters();
|
||||
}
|
||||
Inp.InitBitInput();
|
||||
WrittenFileSize=0;
|
||||
ReadTop=0;
|
||||
ReadBorder=0;
|
||||
|
||||
memset(&BlockHeader,0,sizeof(BlockHeader));
|
||||
BlockHeader.BlockSize=-1; // '-1' means not defined yet.
|
||||
#ifndef SFX_MODULE
|
||||
UnpInitData20(Solid);
|
||||
#endif
|
||||
UnpInitData30(Solid);
|
||||
}
|
||||
|
||||
|
||||
// LengthTable contains the length in bits for every element of alphabet.
|
||||
// Dec is the structure to decode Huffman code/
|
||||
// Size is size of length table and DecodeNum field in Dec structure,
|
||||
void Unpack::MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size)
|
||||
{
|
||||
// Size of alphabet and DecodePos array.
|
||||
Dec->MaxNum=Size;
|
||||
|
||||
// Calculate how many entries for every bit length in LengthTable we have.
|
||||
uint LengthCount[16];
|
||||
memset(LengthCount,0,sizeof(LengthCount));
|
||||
for (size_t I=0;I<Size;I++)
|
||||
LengthCount[LengthTable[I] & 0xf]++;
|
||||
|
||||
// We must not calculate the number of zero length codes.
|
||||
LengthCount[0]=0;
|
||||
|
||||
// Set the entire DecodeNum to zero.
|
||||
memset(Dec->DecodeNum,0,Size*sizeof(*Dec->DecodeNum));
|
||||
|
||||
// Initialize not really used entry for zero length code.
|
||||
Dec->DecodePos[0]=0;
|
||||
|
||||
// Start code for bit length 1 is 0.
|
||||
Dec->DecodeLen[0]=0;
|
||||
|
||||
// Right aligned upper limit code for current bit length.
|
||||
uint UpperLimit=0;
|
||||
|
||||
for (size_t I=1;I<16;I++)
|
||||
{
|
||||
// Adjust the upper limit code.
|
||||
UpperLimit+=LengthCount[I];
|
||||
|
||||
// Left aligned upper limit code.
|
||||
uint LeftAligned=UpperLimit<<(16-I);
|
||||
|
||||
// Prepare the upper limit code for next bit length.
|
||||
UpperLimit*=2;
|
||||
|
||||
// Store the left aligned upper limit code.
|
||||
Dec->DecodeLen[I]=(uint)LeftAligned;
|
||||
|
||||
// Every item of this array contains the sum of all preceding items.
|
||||
// So it contains the start position in code list for every bit length.
|
||||
Dec->DecodePos[I]=Dec->DecodePos[I-1]+LengthCount[I-1];
|
||||
}
|
||||
|
||||
// Prepare the copy of DecodePos. We'll modify this copy below,
|
||||
// so we cannot use the original DecodePos.
|
||||
uint CopyDecodePos[16];
|
||||
memcpy(CopyDecodePos,Dec->DecodePos,sizeof(CopyDecodePos));
|
||||
|
||||
// For every bit length in the bit length table and so for every item
|
||||
// of alphabet.
|
||||
for (uint I=0;I<Size;I++)
|
||||
{
|
||||
// Get the current bit length.
|
||||
byte CurBitLength=LengthTable[I] & 0xf;
|
||||
|
||||
if (CurBitLength!=0)
|
||||
{
|
||||
// Last position in code list for current bit length.
|
||||
uint LastPos=CopyDecodePos[CurBitLength];
|
||||
|
||||
// Prepare the decode table, so this position in code list will be
|
||||
// decoded to current alphabet item number.
|
||||
Dec->DecodeNum[LastPos]=(ushort)I;
|
||||
|
||||
// We'll use next position number for this bit length next time.
|
||||
// So we pass through the entire range of positions available
|
||||
// for every bit length.
|
||||
CopyDecodePos[CurBitLength]++;
|
||||
}
|
||||
}
|
||||
|
||||
// Define the number of bits to process in quick mode. We use more bits
|
||||
// for larger alphabets. More bits means that more codes will be processed
|
||||
// in quick mode, but also that more time will be spent to preparation
|
||||
// of tables for quick decode.
|
||||
switch (Size)
|
||||
{
|
||||
case NC:
|
||||
case NC20:
|
||||
case NC30:
|
||||
Dec->QuickBits=MAX_QUICK_DECODE_BITS;
|
||||
break;
|
||||
default:
|
||||
Dec->QuickBits=MAX_QUICK_DECODE_BITS-3;
|
||||
break;
|
||||
}
|
||||
|
||||
// Size of tables for quick mode.
|
||||
uint QuickDataSize=1<<Dec->QuickBits;
|
||||
|
||||
// Bit length for current code, start from 1 bit codes. It is important
|
||||
// to use 1 bit instead of 0 for minimum code length, so we are moving
|
||||
// forward even when processing a corrupt archive.
|
||||
uint CurBitLength=1;
|
||||
|
||||
// For every right aligned bit string which supports the quick decoding.
|
||||
for (uint Code=0;Code<QuickDataSize;Code++)
|
||||
{
|
||||
// Left align the current code, so it will be in usual bit field format.
|
||||
uint BitField=Code<<(16-Dec->QuickBits);
|
||||
|
||||
// Prepare the table for quick decoding of bit lengths.
|
||||
|
||||
// Find the upper limit for current bit field and adjust the bit length
|
||||
// accordingly if necessary.
|
||||
while (BitField>=Dec->DecodeLen[CurBitLength] && CurBitLength<ASIZE(Dec->DecodeLen))
|
||||
CurBitLength++;
|
||||
|
||||
// Translation of right aligned bit string to bit length.
|
||||
Dec->QuickLen[Code]=CurBitLength;
|
||||
|
||||
// Prepare the table for quick translation of position in code list
|
||||
// to position in alphabet.
|
||||
|
||||
// Calculate the distance from the start code for current bit length.
|
||||
uint Dist=BitField-Dec->DecodeLen[CurBitLength-1];
|
||||
|
||||
// Right align the distance.
|
||||
Dist>>=(16-CurBitLength);
|
||||
|
||||
// Now we can calculate the position in the code list. It is the sum
|
||||
// of first position for current bit length and right aligned distance
|
||||
// between our bit field and start code for current bit length.
|
||||
uint Pos=Dec->DecodePos[CurBitLength]+Dist;
|
||||
|
||||
if (Pos<Size) // Safety check for damaged archives.
|
||||
{
|
||||
// Define the code to alphabet number translation.
|
||||
Dec->QuickNum[Code]=Dec->DecodeNum[Pos];
|
||||
}
|
||||
else
|
||||
Dec->QuickNum[Code]=0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,369 @@
|
|||
#ifndef _RAR_UNPACK_
|
||||
#define _RAR_UNPACK_
|
||||
|
||||
// Maximum allowed number of compressed bits processed in quick mode.
|
||||
#define MAX_QUICK_DECODE_BITS 10
|
||||
|
||||
// Maximum number of filters per entire data block.
|
||||
#define MAX_UNPACK_FILTERS 8192
|
||||
|
||||
// Maximum number of filters per entire data block for RAR3 unpack.
|
||||
#define MAX3_FILTERS 1024
|
||||
|
||||
// Write data in 4 MB or smaller blocks.
|
||||
#define UNPACK_MAX_WRITE 0x400000
|
||||
|
||||
// Decode compressed bit fields to alphabet numbers.
|
||||
struct DecodeTable:PackDef
|
||||
{
|
||||
// Real size of DecodeNum table.
|
||||
uint MaxNum;
|
||||
|
||||
// Left aligned start and upper limit codes defining code space
|
||||
// ranges for bit lengths. DecodeLen[BitLength-1] defines the start of
|
||||
// range for bit length and DecodeLen[BitLength] defines next code
|
||||
// after the end of range or in other words the upper limit code
|
||||
// for specified bit length.
|
||||
uint DecodeLen[16];
|
||||
|
||||
// Every item of this array contains the sum of all preceding items.
|
||||
// So it contains the start position in code list for every bit length.
|
||||
uint DecodePos[16];
|
||||
|
||||
// Number of compressed bits processed in quick mode.
|
||||
// Must not exceed MAX_QUICK_DECODE_BITS.
|
||||
uint QuickBits;
|
||||
|
||||
// Translates compressed bits (up to QuickBits length)
|
||||
// to bit length in quick mode.
|
||||
byte QuickLen[1<<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 UnpackBlockHeader
|
||||
{
|
||||
int BlockSize;
|
||||
int BlockBitSize;
|
||||
int BlockStart;
|
||||
int HeaderSize;
|
||||
bool LastBlockInFile;
|
||||
bool TablePresent;
|
||||
};
|
||||
|
||||
|
||||
struct UnpackBlockTables
|
||||
{
|
||||
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.
|
||||
};
|
||||
|
||||
|
||||
#ifdef RAR_SMP
|
||||
enum UNP_DEC_TYPE {
|
||||
UNPDT_LITERAL,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER
|
||||
};
|
||||
|
||||
struct UnpackDecodedItem
|
||||
{
|
||||
UNP_DEC_TYPE Type;
|
||||
ushort Length;
|
||||
union
|
||||
{
|
||||
uint Distance;
|
||||
byte Literal[4];
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
struct UnpackThreadData
|
||||
{
|
||||
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
|
||||
{
|
||||
byte Type;
|
||||
uint BlockStart;
|
||||
uint BlockLength;
|
||||
byte Channels;
|
||||
// uint Width;
|
||||
// byte PosR;
|
||||
bool NextWindow;
|
||||
};
|
||||
|
||||
|
||||
struct UnpackFilter30
|
||||
{
|
||||
unsigned int BlockStart;
|
||||
unsigned int BlockLength;
|
||||
unsigned int ExecCount;
|
||||
bool NextWindow;
|
||||
|
||||
// position of parent filter in Filters array used as prototype for filter
|
||||
// in PrgStack array. Not defined for filters in Filters array.
|
||||
unsigned int ParentFilter;
|
||||
|
||||
VM_PreparedProgram Prg;
|
||||
};
|
||||
|
||||
|
||||
struct AudioVariables // For RAR 2.0 archives only.
|
||||
{
|
||||
int K1,K2,K3,K4,K5;
|
||||
int D1,D2,D3,D4;
|
||||
int LastDelta;
|
||||
unsigned int Dif[11];
|
||||
unsigned int ByteCount;
|
||||
int LastChar;
|
||||
};
|
||||
|
||||
|
||||
// We can use the fragmented dictionary in case heap does not have the single
|
||||
// large enough memory block. It is slower than normal dictionary.
|
||||
class FragmentedWindow
|
||||
{
|
||||
private:
|
||||
enum {MAX_MEM_BLOCKS=32};
|
||||
|
||||
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();
|
||||
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);
|
||||
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;
|
||||
BitInput Inp;
|
||||
|
||||
Array<byte> FilterSrcMemory;
|
||||
Array<byte> FilterDstMemory;
|
||||
|
||||
// Filters code, one entry per filter.
|
||||
Array<UnpackFilter> Filters;
|
||||
|
||||
uint OldDist[4],OldDistPtr;
|
||||
uint LastLength;
|
||||
|
||||
// LastDist is necessary only for RAR2 and older with circular OldDist
|
||||
// array. In RAR3 last distance is always stored in OldDist[0].
|
||||
uint LastDist;
|
||||
|
||||
size_t UnpPtr,WrPtr;
|
||||
|
||||
// Top border of read packed data.
|
||||
int ReadTop;
|
||||
|
||||
// Border to call UnpReadBuf. We use it instead of (ReadTop-C)
|
||||
// for optimization reasons. Ensures that we have C bytes in buffer
|
||||
// unless we are at the end of file.
|
||||
int ReadBorder;
|
||||
|
||||
UnpackBlockHeader BlockHeader;
|
||||
UnpackBlockTables BlockTables;
|
||||
|
||||
size_t WriteBorder;
|
||||
|
||||
byte *Window;
|
||||
|
||||
FragmentedWindow FragWindow;
|
||||
bool Fragmented;
|
||||
|
||||
|
||||
int64 DestUnpSize;
|
||||
|
||||
bool Suspended;
|
||||
bool UnpAllBuf;
|
||||
bool UnpSomeRead;
|
||||
int64 WrittenFileSize;
|
||||
bool FileExtracted;
|
||||
|
||||
|
||||
/***************************** Unpack v 1.5 *********************************/
|
||||
void Unpack15(bool Solid);
|
||||
void ShortLZ();
|
||||
void LongLZ();
|
||||
void HuffDecode();
|
||||
void GetFlagsBuf();
|
||||
void UnpInitData15(int Solid);
|
||||
void InitHuff();
|
||||
void CorrHuff(ushort *CharSet,byte *NumToPlace);
|
||||
void CopyString15(uint Distance,uint Length);
|
||||
uint DecodeNum(uint Num,uint StartPos,uint *DecTab,uint *PosTab);
|
||||
|
||||
ushort ChSet[256],ChSetA[256],ChSetB[256],ChSetC[256];
|
||||
byte NToPl[256],NToPlB[256],NToPlC[256];
|
||||
uint FlagBuf,AvrPlc,AvrPlcB,AvrLn1,AvrLn2,AvrLn3;
|
||||
int Buf60,NumHuf,StMode,LCount,FlagsCnt;
|
||||
uint Nhfb,Nlzb,MaxDist3;
|
||||
/***************************** Unpack v 1.5 *********************************/
|
||||
|
||||
/***************************** Unpack v 2.0 *********************************/
|
||||
void Unpack20(bool Solid);
|
||||
|
||||
DecodeTable MD[4]; // Decode multimedia data, up to 4 channels.
|
||||
|
||||
unsigned char UnpOldTable20[MC20*4];
|
||||
uint UnpAudioBlock,UnpChannels,UnpCurChannel;
|
||||
int UnpChannelDelta;
|
||||
void CopyString20(uint Length,uint Distance);
|
||||
bool ReadTables20();
|
||||
void UnpWriteBuf20();
|
||||
void UnpInitData20(int Solid);
|
||||
void ReadLastTables();
|
||||
byte DecodeAudio(int Delta);
|
||||
struct AudioVariables AudV[4];
|
||||
/***************************** Unpack v 2.0 *********************************/
|
||||
|
||||
/***************************** Unpack v 3.0 *********************************/
|
||||
enum BLOCK_TYPES {BLOCK_LZ,BLOCK_PPM};
|
||||
|
||||
void UnpInitData30(bool Solid);
|
||||
void Unpack29(bool Solid);
|
||||
void InitFilters30();
|
||||
bool ReadEndOfBlock();
|
||||
bool ReadVMCode();
|
||||
bool ReadVMCodePPM();
|
||||
bool AddVMCode(uint FirstByte,byte *Code,int CodeSize);
|
||||
int SafePPMDecodeChar();
|
||||
bool ReadTables30();
|
||||
bool UnpReadBuf30();
|
||||
void UnpWriteBuf30();
|
||||
void ExecuteCode(VM_PreparedProgram *Prg);
|
||||
|
||||
int PrevLowDist,LowDistRepCount;
|
||||
|
||||
ModelPPM PPM;
|
||||
int PPMEscChar;
|
||||
|
||||
byte UnpOldTable[HUFF_TABLE_SIZE30];
|
||||
int UnpBlockType;
|
||||
|
||||
bool TablesRead;
|
||||
|
||||
// Virtual machine to execute filters code.
|
||||
RarVM VM;
|
||||
|
||||
// Buffer to read VM filters code. We moved it here from AddVMCode
|
||||
// function to reduce time spent in BitInput constructor.
|
||||
BitInput VMCodeInp;
|
||||
|
||||
// Filters code, one entry per filter.
|
||||
Array<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(size_t WinSize,bool Solid);
|
||||
void DoUnpack(int Method,bool Solid);
|
||||
bool IsFileExtracted() {return(FileExtracted);}
|
||||
void SetDestSize(int64 DestSize) {DestUnpSize=DestSize;FileExtracted=false;}
|
||||
void SetSuspended(bool Suspended) {Unpack::Suspended=Suspended;}
|
||||
|
||||
byte const* window_wrptr() const { return &Window [WrPtr & MaxWinMask]; }
|
||||
|
||||
size_t MaxWinSize;
|
||||
size_t MaxWinMask;
|
||||
|
||||
uint GetChar()
|
||||
{
|
||||
if (Inp.InAddr>BitInput::MAX_SIZE-30)
|
||||
UnpReadBuf();
|
||||
return(Inp.InBuf[Inp.InAddr++]);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,487 @@
|
|||
#ifdef RAR_COMMON_HPP
|
||||
|
||||
#define STARTL1 2
|
||||
static unsigned int DecL1[]={0x8000,0xa000,0xc000,0xd000,0xe000,0xea00,
|
||||
0xee00,0xf000,0xf200,0xf200,0xffff};
|
||||
static unsigned int PosL1[]={0,0,0,2,3,5,7,11,16,20,24,32,32};
|
||||
|
||||
#define STARTL2 3
|
||||
static unsigned int DecL2[]={0xa000,0xc000,0xd000,0xe000,0xea00,0xee00,
|
||||
0xf000,0xf200,0xf240,0xffff};
|
||||
static unsigned int PosL2[]={0,0,0,0,5,7,9,13,18,22,26,34,36};
|
||||
|
||||
#define STARTHF0 4
|
||||
static unsigned int DecHf0[]={0x8000,0xc000,0xe000,0xf200,0xf200,0xf200,
|
||||
0xf200,0xf200,0xffff};
|
||||
static unsigned int PosHf0[]={0,0,0,0,0,8,16,24,33,33,33,33,33};
|
||||
|
||||
|
||||
#define STARTHF1 5
|
||||
static unsigned int DecHf1[]={0x2000,0xc000,0xe000,0xf000,0xf200,0xf200,
|
||||
0xf7e0,0xffff};
|
||||
static unsigned int PosHf1[]={0,0,0,0,0,0,4,44,60,76,80,80,127};
|
||||
|
||||
|
||||
#define STARTHF2 5
|
||||
static unsigned int DecHf2[]={0x1000,0x2400,0x8000,0xc000,0xfa00,0xffff,
|
||||
0xffff,0xffff};
|
||||
static unsigned int PosHf2[]={0,0,0,0,0,0,2,7,53,117,233,0,0};
|
||||
|
||||
|
||||
#define STARTHF3 6
|
||||
static unsigned int DecHf3[]={0x800,0x2400,0xee00,0xfe80,0xffff,0xffff,
|
||||
0xffff};
|
||||
static unsigned int PosHf3[]={0,0,0,0,0,0,0,2,16,218,251,0,0};
|
||||
|
||||
|
||||
#define STARTHF4 8
|
||||
static unsigned int DecHf4[]={0xff00,0xffff,0xffff,0xffff,0xffff,0xffff};
|
||||
static unsigned int PosHf4[]={0,0,0,0,0,0,0,0,0,255,0,0,0};
|
||||
|
||||
|
||||
void Unpack::Unpack15(bool Solid)
|
||||
{
|
||||
UnpInitData(Solid);
|
||||
UnpInitData15(Solid);
|
||||
UnpReadBuf();
|
||||
if (!Solid)
|
||||
{
|
||||
InitHuff();
|
||||
UnpPtr=0;
|
||||
}
|
||||
else
|
||||
UnpPtr=WrPtr;
|
||||
--DestUnpSize;
|
||||
if (DestUnpSize>=0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt=8;
|
||||
}
|
||||
|
||||
while (DestUnpSize>=0)
|
||||
{
|
||||
UnpPtr&=MaxWinMask;
|
||||
|
||||
if (Inp.InAddr>ReadTop-30 && !UnpReadBuf())
|
||||
break;
|
||||
if (((WrPtr-UnpPtr) & MaxWinMask)<270 && WrPtr!=UnpPtr)
|
||||
UnpWriteBuf20();
|
||||
if (StMode)
|
||||
{
|
||||
HuffDecode();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt=7;
|
||||
}
|
||||
|
||||
if (FlagBuf & 0x80)
|
||||
{
|
||||
FlagBuf<<=1;
|
||||
if (Nlzb > Nhfb)
|
||||
LongLZ();
|
||||
else
|
||||
HuffDecode();
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf<<=1;
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt=7;
|
||||
}
|
||||
if (FlagBuf & 0x80)
|
||||
{
|
||||
FlagBuf<<=1;
|
||||
if (Nlzb > Nhfb)
|
||||
HuffDecode();
|
||||
else
|
||||
LongLZ();
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf<<=1;
|
||||
ShortLZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
UnpWriteBuf20();
|
||||
}
|
||||
|
||||
|
||||
#define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos])
|
||||
#define GetShortLen2(pos) ((pos)==3 ? Buf60+3:ShortLen2[pos])
|
||||
|
||||
void Unpack::ShortLZ()
|
||||
{
|
||||
static unsigned int ShortLen1[]={1,3,4,4,5,6,7,8,8,4,4,5,6,6,4,0};
|
||||
static unsigned int ShortXor1[]={0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,
|
||||
0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0};
|
||||
static unsigned int ShortLen2[]={2,3,3,3,4,4,5,6,6,4,4,5,6,6,4,0};
|
||||
static unsigned int ShortXor2[]={0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,
|
||||
0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0};
|
||||
|
||||
|
||||
unsigned int Length,SaveLength;
|
||||
unsigned int LastDistance;
|
||||
unsigned int Distance;
|
||||
int DistancePlace;
|
||||
NumHuf=0;
|
||||
|
||||
unsigned int BitField=Inp.fgetbits();
|
||||
if (LCount==2)
|
||||
{
|
||||
Inp.faddbits(1);
|
||||
if (BitField >= 0x8000)
|
||||
{
|
||||
CopyString15((unsigned int)LastDist,LastLength);
|
||||
return;
|
||||
}
|
||||
BitField <<= 1;
|
||||
LCount=0;
|
||||
}
|
||||
|
||||
BitField>>=8;
|
||||
|
||||
// not thread safe, replaced by GetShortLen1 and GetShortLen2 macro
|
||||
// ShortLen1[1]=ShortLen2[3]=Buf60+3;
|
||||
|
||||
if (AvrLn1<37)
|
||||
{
|
||||
for (Length=0;;Length++)
|
||||
if (((BitField^ShortXor1[Length]) & (~(0xff>>GetShortLen1(Length))))==0)
|
||||
break;
|
||||
Inp.faddbits(GetShortLen1(Length));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Length=0;;Length++)
|
||||
if (((BitField^ShortXor2[Length]) & (~(0xff>>GetShortLen2(Length))))==0)
|
||||
break;
|
||||
Inp.faddbits(GetShortLen2(Length));
|
||||
}
|
||||
|
||||
if (Length >= 9)
|
||||
{
|
||||
if (Length == 9)
|
||||
{
|
||||
LCount++;
|
||||
CopyString15((unsigned int)LastDist,LastLength);
|
||||
return;
|
||||
}
|
||||
if (Length == 14)
|
||||
{
|
||||
LCount=0;
|
||||
Length=DecodeNum(Inp.fgetbits(),STARTL2,DecL2,PosL2)+5;
|
||||
Distance=(Inp.fgetbits()>>1) | 0x8000;
|
||||
Inp.faddbits(15);
|
||||
LastLength=Length;
|
||||
LastDist=Distance;
|
||||
CopyString15(Distance,Length);
|
||||
return;
|
||||
}
|
||||
|
||||
LCount=0;
|
||||
SaveLength=Length;
|
||||
Distance=OldDist[(OldDistPtr-(Length-9)) & 3];
|
||||
Length=DecodeNum(Inp.fgetbits(),STARTL1,DecL1,PosL1)+2;
|
||||
if (Length==0x101 && SaveLength==10)
|
||||
{
|
||||
Buf60 ^= 1;
|
||||
return;
|
||||
}
|
||||
if (Distance > 256)
|
||||
Length++;
|
||||
if (Distance >= MaxDist3)
|
||||
Length++;
|
||||
|
||||
OldDist[OldDistPtr++]=Distance;
|
||||
OldDistPtr = OldDistPtr & 3;
|
||||
LastLength=Length;
|
||||
LastDist=Distance;
|
||||
CopyString15(Distance,Length);
|
||||
return;
|
||||
}
|
||||
|
||||
LCount=0;
|
||||
AvrLn1 += Length;
|
||||
AvrLn1 -= AvrLn1 >> 4;
|
||||
|
||||
DistancePlace=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2) & 0xff;
|
||||
Distance=ChSetA[DistancePlace];
|
||||
if (--DistancePlace != -1)
|
||||
{
|
||||
LastDistance=ChSetA[DistancePlace];
|
||||
ChSetA[DistancePlace+1]=LastDistance;
|
||||
ChSetA[DistancePlace]=Distance;
|
||||
}
|
||||
Length+=2;
|
||||
OldDist[OldDistPtr++] = ++Distance;
|
||||
OldDistPtr = OldDistPtr & 3;
|
||||
LastLength=Length;
|
||||
LastDist=Distance;
|
||||
CopyString15(Distance,Length);
|
||||
}
|
||||
|
||||
|
||||
void Unpack::LongLZ()
|
||||
{
|
||||
unsigned int Length;
|
||||
unsigned int Distance;
|
||||
unsigned int DistancePlace,NewDistancePlace;
|
||||
unsigned int OldAvr2,OldAvr3;
|
||||
|
||||
NumHuf=0;
|
||||
Nlzb+=16;
|
||||
if (Nlzb > 0xff)
|
||||
{
|
||||
Nlzb=0x90;
|
||||
Nhfb >>= 1;
|
||||
}
|
||||
OldAvr2=AvrLn2;
|
||||
|
||||
unsigned int BitField=Inp.fgetbits();
|
||||
if (AvrLn2 >= 122)
|
||||
Length=DecodeNum(BitField,STARTL2,DecL2,PosL2);
|
||||
else
|
||||
if (AvrLn2 >= 64)
|
||||
Length=DecodeNum(BitField,STARTL1,DecL1,PosL1);
|
||||
else
|
||||
if (BitField < 0x100)
|
||||
{
|
||||
Length=BitField;
|
||||
Inp.faddbits(16);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Length=0;((BitField<<Length)&0x8000)==0;Length++)
|
||||
;
|
||||
Inp.faddbits(Length+1);
|
||||
}
|
||||
|
||||
AvrLn2 += Length;
|
||||
AvrLn2 -= AvrLn2 >> 5;
|
||||
|
||||
BitField=Inp.fgetbits();
|
||||
if (AvrPlcB > 0x28ff)
|
||||
DistancePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2);
|
||||
else
|
||||
if (AvrPlcB > 0x6ff)
|
||||
DistancePlace=DecodeNum(BitField,STARTHF1,DecHf1,PosHf1);
|
||||
else
|
||||
DistancePlace=DecodeNum(BitField,STARTHF0,DecHf0,PosHf0);
|
||||
|
||||
AvrPlcB += DistancePlace;
|
||||
AvrPlcB -= AvrPlcB >> 8;
|
||||
while (1)
|
||||
{
|
||||
Distance = ChSetB[DistancePlace & 0xff];
|
||||
NewDistancePlace = NToPlB[Distance++ & 0xff]++;
|
||||
if (!(Distance & 0xff))
|
||||
CorrHuff(ChSetB,NToPlB);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
ChSetB[DistancePlace]=ChSetB[NewDistancePlace];
|
||||
ChSetB[NewDistancePlace]=Distance;
|
||||
|
||||
Distance=((Distance & 0xff00) | (Inp.fgetbits() >> 8)) >> 1;
|
||||
Inp.faddbits(7);
|
||||
|
||||
OldAvr3=AvrLn3;
|
||||
if (Length!=1 && Length!=4) {
|
||||
if (Length==0 && Distance <= MaxDist3)
|
||||
{
|
||||
AvrLn3++;
|
||||
AvrLn3 -= AvrLn3 >> 8;
|
||||
} else {
|
||||
if (AvrLn3 > 0) {
|
||||
AvrLn3--;
|
||||
}
|
||||
}
|
||||
}
|
||||
Length+=3;
|
||||
if (Distance >= MaxDist3)
|
||||
Length++;
|
||||
if (Distance <= 256)
|
||||
Length+=8;
|
||||
if (OldAvr3 > 0xb0 || (AvrPlc >= 0x2a00 && OldAvr2 < 0x40))
|
||||
MaxDist3=0x7f00;
|
||||
else
|
||||
MaxDist3=0x2001;
|
||||
OldDist[OldDistPtr++]=Distance;
|
||||
OldDistPtr = OldDistPtr & 3;
|
||||
LastLength=Length;
|
||||
LastDist=Distance;
|
||||
CopyString15(Distance,Length);
|
||||
}
|
||||
|
||||
|
||||
void Unpack::HuffDecode()
|
||||
{
|
||||
unsigned int CurByte,NewBytePlace;
|
||||
unsigned int Length;
|
||||
unsigned int Distance;
|
||||
int BytePlace;
|
||||
|
||||
unsigned int BitField=Inp.fgetbits();
|
||||
|
||||
if (AvrPlc > 0x75ff)
|
||||
BytePlace=DecodeNum(BitField,STARTHF4,DecHf4,PosHf4);
|
||||
else
|
||||
if (AvrPlc > 0x5dff)
|
||||
BytePlace=DecodeNum(BitField,STARTHF3,DecHf3,PosHf3);
|
||||
else
|
||||
if (AvrPlc > 0x35ff)
|
||||
BytePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2);
|
||||
else
|
||||
if (AvrPlc > 0x0dff)
|
||||
BytePlace=DecodeNum(BitField,STARTHF1,DecHf1,PosHf1);
|
||||
else
|
||||
BytePlace=DecodeNum(BitField,STARTHF0,DecHf0,PosHf0);
|
||||
BytePlace&=0xff;
|
||||
if (StMode)
|
||||
{
|
||||
if (BytePlace==0 && BitField > 0xfff)
|
||||
BytePlace=0x100;
|
||||
if (--BytePlace==-1)
|
||||
{
|
||||
BitField=Inp.fgetbits();
|
||||
Inp.faddbits(1);
|
||||
if (BitField & 0x8000)
|
||||
{
|
||||
NumHuf=StMode=0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Length = (BitField & 0x4000) ? 4 : 3;
|
||||
Inp.faddbits(1);
|
||||
Distance=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2);
|
||||
Distance = (Distance << 5) | (Inp.fgetbits() >> 11);
|
||||
Inp.faddbits(5);
|
||||
CopyString15(Distance,Length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (NumHuf++ >= 16 && FlagsCnt==0)
|
||||
StMode=1;
|
||||
AvrPlc += BytePlace;
|
||||
AvrPlc -= AvrPlc >> 8;
|
||||
Nhfb+=16;
|
||||
if (Nhfb > 0xff)
|
||||
{
|
||||
Nhfb=0x90;
|
||||
Nlzb >>= 1;
|
||||
}
|
||||
|
||||
Window[UnpPtr++]=(byte)(ChSet[BytePlace]>>8);
|
||||
--DestUnpSize;
|
||||
|
||||
while (1)
|
||||
{
|
||||
CurByte=ChSet[BytePlace];
|
||||
NewBytePlace=NToPl[CurByte++ & 0xff]++;
|
||||
if ((CurByte & 0xff) > 0xa1)
|
||||
CorrHuff(ChSet,NToPl);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
ChSet[BytePlace]=ChSet[NewBytePlace];
|
||||
ChSet[NewBytePlace]=CurByte;
|
||||
}
|
||||
|
||||
|
||||
void Unpack::GetFlagsBuf()
|
||||
{
|
||||
unsigned int Flags,NewFlagsPlace;
|
||||
unsigned int FlagsPlace=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2);
|
||||
|
||||
while (1)
|
||||
{
|
||||
Flags=ChSetC[FlagsPlace];
|
||||
FlagBuf=Flags>>8;
|
||||
NewFlagsPlace=NToPlC[Flags++ & 0xff]++;
|
||||
if ((Flags & 0xff) != 0)
|
||||
break;
|
||||
CorrHuff(ChSetC,NToPlC);
|
||||
}
|
||||
|
||||
ChSetC[FlagsPlace]=ChSetC[NewFlagsPlace];
|
||||
ChSetC[NewFlagsPlace]=Flags;
|
||||
}
|
||||
|
||||
|
||||
void Unpack::UnpInitData15(int Solid)
|
||||
{
|
||||
if (!Solid)
|
||||
{
|
||||
AvrPlcB=AvrLn1=AvrLn2=AvrLn3=NumHuf=Buf60=0;
|
||||
AvrPlc=0x3500;
|
||||
MaxDist3=0x2001;
|
||||
Nhfb=Nlzb=0x80;
|
||||
}
|
||||
FlagsCnt=0;
|
||||
FlagBuf=0;
|
||||
StMode=0;
|
||||
LCount=0;
|
||||
ReadTop=0;
|
||||
}
|
||||
|
||||
|
||||
void Unpack::InitHuff()
|
||||
{
|
||||
for (unsigned int I=0;I<256;I++)
|
||||
{
|
||||
ChSet[I]=ChSetB[I]=I<<8;
|
||||
ChSetA[I]=I;
|
||||
ChSetC[I]=((~I+1) & 0xff)<<8;
|
||||
}
|
||||
memset(NToPl,0,sizeof(NToPl));
|
||||
memset(NToPlB,0,sizeof(NToPlB));
|
||||
memset(NToPlC,0,sizeof(NToPlC));
|
||||
CorrHuff(ChSetB,NToPlB);
|
||||
}
|
||||
|
||||
|
||||
void Unpack::CorrHuff(ushort *CharSet,byte *NumToPlace)
|
||||
{
|
||||
int I,J;
|
||||
for (I=7;I>=0;I--)
|
||||
for (J=0;J<32;J++,CharSet++)
|
||||
*CharSet=(*CharSet & ~0xff) | I;
|
||||
memset(NumToPlace,0,sizeof(NToPl));
|
||||
for (I=6;I>=0;I--)
|
||||
NumToPlace[I]=(7-I)*32;
|
||||
}
|
||||
|
||||
|
||||
void Unpack::CopyString15(uint Distance,uint Length)
|
||||
{
|
||||
DestUnpSize-=Length;
|
||||
while (Length--)
|
||||
{
|
||||
Window[UnpPtr]=Window[(UnpPtr-Distance) & MaxWinMask];
|
||||
UnpPtr=(UnpPtr+1) & MaxWinMask;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint Unpack::DecodeNum(uint Num,uint StartPos,uint *DecTab,uint *PosTab)
|
||||
{
|
||||
int I;
|
||||
for (Num&=0xfff0,I=0;DecTab[I]<=Num;I++)
|
||||
StartPos++;
|
||||
Inp.faddbits(StartPos);
|
||||
return(((Num-(I ? DecTab[I-1]:0))>>(16-StartPos))+PosTab[StartPos]);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,373 @@
|
|||
#ifdef RAR_COMMON_HPP
|
||||
|
||||
void Unpack::CopyString20(uint Length,uint Distance)
|
||||
{
|
||||
LastDist=OldDist[OldDistPtr++ & 3]=Distance;
|
||||
LastLength=Length;
|
||||
DestUnpSize-=Length;
|
||||
CopyString(Length,Distance);
|
||||
}
|
||||
|
||||
|
||||
void Unpack::Unpack20(bool Solid)
|
||||
{
|
||||
static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224};
|
||||
static unsigned char LBits[]= {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
|
||||
static int DDecode[]={0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040};
|
||||
static unsigned char DBits[]= {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16};
|
||||
static unsigned char SDDecode[]={0,4,8,16,32,64,128,192};
|
||||
static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6};
|
||||
unsigned int Bits;
|
||||
|
||||
if (Suspended)
|
||||
UnpPtr=WrPtr;
|
||||
else
|
||||
{
|
||||
UnpInitData(Solid);
|
||||
if (!UnpReadBuf())
|
||||
return;
|
||||
if (!Solid)
|
||||
if (!ReadTables20())
|
||||
return;
|
||||
--DestUnpSize;
|
||||
}
|
||||
|
||||
while (DestUnpSize>=0)
|
||||
{
|
||||
UnpPtr&=MaxWinMask;
|
||||
|
||||
if (Inp.InAddr>ReadTop-30)
|
||||
if (!UnpReadBuf())
|
||||
break;
|
||||
if (((WrPtr-UnpPtr) & MaxWinMask)<270 && WrPtr!=UnpPtr)
|
||||
{
|
||||
UnpWriteBuf20();
|
||||
if (Suspended)
|
||||
return;
|
||||
}
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
int AudioNumber=DecodeNumber(Inp,&MD[UnpCurChannel]);
|
||||
|
||||
if (AudioNumber==256)
|
||||
{
|
||||
if (!ReadTables20())
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
Window[UnpPtr++]=DecodeAudio(AudioNumber);
|
||||
if (++UnpCurChannel==UnpChannels)
|
||||
UnpCurChannel=0;
|
||||
--DestUnpSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
int Number=DecodeNumber(Inp,&BlockTables.LD);
|
||||
if (Number<256)
|
||||
{
|
||||
Window[UnpPtr++]=(byte)Number;
|
||||
--DestUnpSize;
|
||||
continue;
|
||||
}
|
||||
if (Number>269)
|
||||
{
|
||||
int Length=LDecode[Number-=270]+3;
|
||||
if ((Bits=LBits[Number])>0)
|
||||
{
|
||||
Length+=Inp.getbits()>>(16-Bits);
|
||||
Inp.addbits(Bits);
|
||||
}
|
||||
|
||||
int DistNumber=DecodeNumber(Inp,&BlockTables.DD);
|
||||
unsigned int Distance=DDecode[DistNumber]+1;
|
||||
if ((Bits=DBits[DistNumber])>0)
|
||||
{
|
||||
Distance+=Inp.getbits()>>(16-Bits);
|
||||
Inp.addbits(Bits);
|
||||
}
|
||||
|
||||
if (Distance>=0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance>=0x40000L)
|
||||
Length++;
|
||||
}
|
||||
|
||||
CopyString20(Length,Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number==269)
|
||||
{
|
||||
if (!ReadTables20())
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (Number==256)
|
||||
{
|
||||
CopyString20(LastLength,LastDist);
|
||||
continue;
|
||||
}
|
||||
if (Number<261)
|
||||
{
|
||||
unsigned int Distance=OldDist[(OldDistPtr-(Number-256)) & 3];
|
||||
int LengthNumber=DecodeNumber(Inp,&BlockTables.RD);
|
||||
int Length=LDecode[LengthNumber]+2;
|
||||
if ((Bits=LBits[LengthNumber])>0)
|
||||
{
|
||||
Length+=Inp.getbits()>>(16-Bits);
|
||||
Inp.addbits(Bits);
|
||||
}
|
||||
if (Distance>=0x101)
|
||||
{
|
||||
Length++;
|
||||
if (Distance>=0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance>=0x40000)
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
CopyString20(Length,Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number<270)
|
||||
{
|
||||
unsigned int Distance=SDDecode[Number-=261]+1;
|
||||
if ((Bits=SDBits[Number])>0)
|
||||
{
|
||||
Distance+=Inp.getbits()>>(16-Bits);
|
||||
Inp.addbits(Bits);
|
||||
}
|
||||
CopyString20(2,Distance);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ReadLastTables();
|
||||
UnpWriteBuf20();
|
||||
}
|
||||
|
||||
|
||||
void Unpack::UnpWriteBuf20()
|
||||
{
|
||||
if (UnpPtr!=WrPtr)
|
||||
UnpSomeRead=true;
|
||||
if (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];
|
||||
byte Table[MC20*4];
|
||||
int TableSize,N,I;
|
||||
if (Inp.InAddr>ReadTop-25)
|
||||
if (!UnpReadBuf())
|
||||
return(false);
|
||||
uint BitField=Inp.getbits();
|
||||
UnpAudioBlock=(BitField & 0x8000);
|
||||
|
||||
if (!(BitField & 0x4000))
|
||||
memset(UnpOldTable20,0,sizeof(UnpOldTable20));
|
||||
Inp.addbits(2);
|
||||
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
UnpChannels=((BitField>>12) & 3)+1;
|
||||
if (UnpCurChannel>=UnpChannels)
|
||||
UnpCurChannel=0;
|
||||
Inp.addbits(2);
|
||||
TableSize=MC20*UnpChannels;
|
||||
}
|
||||
else
|
||||
TableSize=NC20+DC20+RC20;
|
||||
|
||||
for (I=0;I<BC20;I++)
|
||||
{
|
||||
BitLength[I]=(byte)(Inp.getbits() >> 12);
|
||||
Inp.addbits(4);
|
||||
}
|
||||
MakeDecodeTables(BitLength,&BlockTables.BD,BC20);
|
||||
I=0;
|
||||
while (I<TableSize)
|
||||
{
|
||||
if (Inp.InAddr>ReadTop-5)
|
||||
if (!UnpReadBuf())
|
||||
return false;
|
||||
int Number=DecodeNumber(Inp,&BlockTables.BD);
|
||||
if (Number<16)
|
||||
{
|
||||
Table[I]=(Number+UnpOldTable20[I]) & 0xf;
|
||||
I++;
|
||||
}
|
||||
else
|
||||
if (Number==16)
|
||||
{
|
||||
N=(Inp.getbits() >> 14)+3;
|
||||
Inp.addbits(2);
|
||||
if (I>0)
|
||||
while (N-- > 0 && I<TableSize)
|
||||
{
|
||||
Table[I]=Table[I-1];
|
||||
I++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Number==17)
|
||||
{
|
||||
N=(Inp.getbits() >> 13)+3;
|
||||
Inp.addbits(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
N=(Inp.getbits() >> 9)+11;
|
||||
Inp.addbits(7);
|
||||
}
|
||||
while (N-- > 0 && I<TableSize)
|
||||
Table[I++]=0;
|
||||
}
|
||||
}
|
||||
if (Inp.InAddr>ReadTop)
|
||||
return(true);
|
||||
if (UnpAudioBlock)
|
||||
for (I=0;I<UnpChannels;I++)
|
||||
MakeDecodeTables(&Table[I*MC20],&MD[I],MC20);
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void Unpack::ReadLastTables()
|
||||
{
|
||||
if (ReadTop>=Inp.InAddr+5) {
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
if (DecodeNumber(Inp,&MD[UnpCurChannel])==256)
|
||||
ReadTables20();
|
||||
} else {
|
||||
if (DecodeNumber(Inp,&BlockTables.LD)==269)
|
||||
ReadTables20();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Unpack::UnpInitData20(int Solid)
|
||||
{
|
||||
if (!Solid)
|
||||
{
|
||||
UnpAudioBlock=UnpChannelDelta=UnpCurChannel=0;
|
||||
UnpChannels=1;
|
||||
|
||||
memset(AudV,0,sizeof(AudV));
|
||||
memset(UnpOldTable20,0,sizeof(UnpOldTable20));
|
||||
memset(MD,0,sizeof(MD));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
byte Unpack::DecodeAudio(int Delta)
|
||||
{
|
||||
struct AudioVariables *V=&AudV[UnpCurChannel];
|
||||
V->ByteCount++;
|
||||
V->D4=V->D3;
|
||||
V->D3=V->D2;
|
||||
V->D2=V->LastDelta-V->D1;
|
||||
V->D1=V->LastDelta;
|
||||
int PCh=8*V->LastChar+V->K1*V->D1+V->K2*V->D2+V->K3*V->D3+V->K4*V->D4+V->K5*UnpChannelDelta;
|
||||
PCh=(PCh>>3) & 0xFF;
|
||||
|
||||
unsigned int Ch=PCh-Delta;
|
||||
|
||||
int D=((signed char)Delta)<<3;
|
||||
|
||||
V->Dif[0]+=abs(D);
|
||||
V->Dif[1]+=abs(D-V->D1);
|
||||
V->Dif[2]+=abs(D+V->D1);
|
||||
V->Dif[3]+=abs(D-V->D2);
|
||||
V->Dif[4]+=abs(D+V->D2);
|
||||
V->Dif[5]+=abs(D-V->D3);
|
||||
V->Dif[6]+=abs(D+V->D3);
|
||||
V->Dif[7]+=abs(D-V->D4);
|
||||
V->Dif[8]+=abs(D+V->D4);
|
||||
V->Dif[9]+=abs(D-UnpChannelDelta);
|
||||
V->Dif[10]+=abs(D+UnpChannelDelta);
|
||||
|
||||
UnpChannelDelta=V->LastDelta=(signed char)(Ch-V->LastChar);
|
||||
V->LastChar=Ch;
|
||||
|
||||
if ((V->ByteCount & 0x1F)==0)
|
||||
{
|
||||
unsigned int MinDif=V->Dif[0],NumMinDif=0;
|
||||
V->Dif[0]=0;
|
||||
for (int I=1;I<sizeof(V->Dif)/sizeof(V->Dif[0]);I++)
|
||||
{
|
||||
if (V->Dif[I]<MinDif)
|
||||
{
|
||||
MinDif=V->Dif[I];
|
||||
NumMinDif=I;
|
||||
}
|
||||
V->Dif[I]=0;
|
||||
}
|
||||
switch(NumMinDif)
|
||||
{
|
||||
case 1:
|
||||
if (V->K1>=-16)
|
||||
V->K1--;
|
||||
break;
|
||||
case 2:
|
||||
if (V->K1<16)
|
||||
V->K1++;
|
||||
break;
|
||||
case 3:
|
||||
if (V->K2>=-16)
|
||||
V->K2--;
|
||||
break;
|
||||
case 4:
|
||||
if (V->K2<16)
|
||||
V->K2++;
|
||||
break;
|
||||
case 5:
|
||||
if (V->K3>=-16)
|
||||
V->K3--;
|
||||
break;
|
||||
case 6:
|
||||
if (V->K3<16)
|
||||
V->K3++;
|
||||
break;
|
||||
case 7:
|
||||
if (V->K4>=-16)
|
||||
V->K4--;
|
||||
break;
|
||||
case 8:
|
||||
if (V->K4<16)
|
||||
V->K4++;
|
||||
break;
|
||||
case 9:
|
||||
if (V->K5>=-16)
|
||||
V->K5--;
|
||||
break;
|
||||
case 10:
|
||||
if (V->K5<16)
|
||||
V->K5++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return((byte)Ch);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,840 @@
|
|||
#ifdef RAR_COMMON_HPP
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,654 @@
|
|||
#ifdef RAR_COMMON_HPP
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,107 @@
|
|||
#ifdef RAR_COMMON_HPP
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,146 @@
|
|||
#ifdef RAR_COMMON_HPP
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,352 @@
|
|||
// unrar_core 3.8.5. http://www.slack.net/~ant/
|
||||
|
||||
#include "unrar.h"
|
||||
|
||||
#include "rar.hpp"
|
||||
#include <assert.h>
|
||||
|
||||
// This source code is a heavily modified version based on the unrar package.
|
||||
// It may not be used to develop a RAR (WinRAR) compatible archiver.
|
||||
// See unrar/license.txt for copyright and licensing.
|
||||
|
||||
// Same as printf when debugging, otherwise 0
|
||||
#ifndef debug_printf
|
||||
#define debug_printf 1 ? (void)0 : (void)
|
||||
#endif
|
||||
|
||||
// If expr != unrar_ok, returns its value
|
||||
#define RETURN_ERR( expr ) \
|
||||
do {\
|
||||
unrar_err_t err_;\
|
||||
if ( (err_ = (expr)) != unrar_ok )\
|
||||
return err_;\
|
||||
} while ( 0 )
|
||||
|
||||
|
||||
// Receives errors reported from deep within library.
|
||||
// MUST be macro.
|
||||
#define NONLOCAL_ERROR( p ) \
|
||||
setjmp( p->Arc.jmp_env )
|
||||
|
||||
void Rar_Error_Handler::ReportError( unrar_err_t err )
|
||||
{
|
||||
if ( err )
|
||||
longjmp( jmp_env, err );
|
||||
}
|
||||
|
||||
void Rar_Error_Handler::MemoryError()
|
||||
{
|
||||
ReportError( unrar_err_memory );
|
||||
}
|
||||
|
||||
|
||||
//// Internal
|
||||
|
||||
unrar_t::unrar_t()
|
||||
{
|
||||
Arc.user_read = NULL;
|
||||
Arc.user_write = NULL;
|
||||
Arc.Tell_ = 0;
|
||||
Arc.write_error = unrar_ok;
|
||||
data_ = NULL;
|
||||
own_data_ = NULL;
|
||||
close_file = NULL;
|
||||
FileCount = 0;
|
||||
Unp = NULL;
|
||||
|
||||
unrar_init();
|
||||
}
|
||||
|
||||
unrar_t::~unrar_t()
|
||||
{
|
||||
if ( Arc.write_error ) { }
|
||||
|
||||
if ( close_file )
|
||||
close_file( Arc.user_read_data );
|
||||
|
||||
delete Unp;
|
||||
|
||||
free( own_data_ );
|
||||
}
|
||||
|
||||
// True if current file is compressed in way that affects solid extraction state
|
||||
static inline bool solid_file( const unrar_t* p )
|
||||
{
|
||||
return p->Arc.Solid &&
|
||||
p->Arc.FileHead.Method != 0 &&
|
||||
p->Arc.FileHead.PackSize != 0;
|
||||
}
|
||||
|
||||
static void update_solid_pos( unrar_t* p )
|
||||
{
|
||||
if ( p->solid_pos == p->Arc.CurBlockPos )
|
||||
p->solid_pos = p->Arc.NextBlockPos;
|
||||
}
|
||||
|
||||
static unrar_err_t extract_( unrar_t* p, unrar_write_func user_write, void* user_data )
|
||||
{
|
||||
assert( !p->done );
|
||||
assert( !solid_file( p ) || p->solid_pos == p->Arc.CurBlockPos );
|
||||
|
||||
if ( p->Arc.write_error ) { }
|
||||
p->Arc.write_error = unrar_ok;
|
||||
p->Arc.user_write = user_write;
|
||||
p->Arc.user_write_data = user_data;
|
||||
RETURN_ERR( p->ExtractCurrentFile( user_write == NULL ) );
|
||||
p->Arc.user_write = NULL;
|
||||
RETURN_ERR( p->Arc.write_error );
|
||||
|
||||
update_solid_pos( p );
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
static unrar_err_t skip_solid( unrar_t* p )
|
||||
{
|
||||
if ( !solid_file( p ) )
|
||||
{
|
||||
update_solid_pos( p );
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
return extract_( p, NULL, NULL );
|
||||
}
|
||||
|
||||
static inline bool IsLink(uint Attr)
|
||||
{
|
||||
return((Attr & 0xF000)==0xA000);
|
||||
}
|
||||
|
||||
static unrar_err_t next_( unrar_t* p, bool skipping_solid )
|
||||
{
|
||||
if ( p->done )
|
||||
return unrar_err_arc_eof;
|
||||
|
||||
free( p->own_data_ );
|
||||
p->own_data_ = NULL;
|
||||
p->data_ = NULL;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
size_t ReadSize;
|
||||
p->Arc.SeekToNext();
|
||||
unrar_err_t const err = p->Arc.ReadHeader(&ReadSize);
|
||||
if ( err != unrar_err_arc_eof )
|
||||
RETURN_ERR( err );
|
||||
//else
|
||||
// debug_printf( "unrar: Didn't end with ENDARC_HEAD\n" ); // rar -en causes this
|
||||
|
||||
HEADER_TYPE const type = (HEADER_TYPE) p->Arc.GetHeaderType();
|
||||
|
||||
if ( err != unrar_ok || type == HEAD_ENDARC )
|
||||
{
|
||||
p->done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( type != HEAD_FILE )
|
||||
{
|
||||
// Skip non-files
|
||||
#if 0
|
||||
if ( type != HEAD_SERVICE && type != HEAD_CRYPT && type != HEAD_MARK )
|
||||
debug_printf( "unrar: Skipping unknown block type: %X\n", (unsigned) type );
|
||||
#endif
|
||||
|
||||
update_solid_pos( p );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update even for non-solid files, in case it's not extracted
|
||||
if ( !solid_file( p ) )
|
||||
update_solid_pos( p );
|
||||
|
||||
if ( p->Arc.IsArcLabel() )
|
||||
{
|
||||
// Ignore labels
|
||||
}
|
||||
else if ( IsLink( p->Arc.FileHead.FileAttr ) )
|
||||
{
|
||||
// Ignore links
|
||||
|
||||
p->update_first_file_pos();
|
||||
p->FileCount++; // Links are treated as files
|
||||
}
|
||||
else if ( p->Arc.IsArcDir() )
|
||||
{
|
||||
// Ignore directories
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
break;
|
||||
}
|
||||
|
||||
// Original code assumed that non-file items were never solid compressed
|
||||
check( !solid_file( p ) );
|
||||
|
||||
// Skip non-file solid-compressed items (original code assumed there were none)
|
||||
if ( skipping_solid )
|
||||
RETURN_ERR( skip_solid( p ) );
|
||||
}
|
||||
}
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
static unrar_err_t open_( unrar_t* p, unrar_read_func read, void* user_data )
|
||||
{
|
||||
p->Arc.user_read = read;
|
||||
p->Arc.user_read_data = user_data;
|
||||
|
||||
RETURN_ERR( p->Arc.IsArchive() );
|
||||
|
||||
p->begin_pos = p->Arc.NextBlockPos;
|
||||
p->solid_pos = p->Arc.NextBlockPos;
|
||||
p->first_file_pos = INT_MAX;
|
||||
p->done = false;
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
|
||||
//// Interface
|
||||
|
||||
// Needed when user read throws exception
|
||||
struct unrar_ptr {
|
||||
unrar_t* p;
|
||||
unrar_ptr() { p = NULL; }
|
||||
~unrar_ptr() { delete p; }
|
||||
};
|
||||
|
||||
unrar_err_t unrar_open_custom( unrar_t** impl_out, unrar_read_func read, void* user_data )
|
||||
{
|
||||
*impl_out = NULL;
|
||||
|
||||
unrar_ptr ptr;
|
||||
ptr.p = new unrar_t;
|
||||
if ( !ptr.p )
|
||||
return unrar_err_memory;
|
||||
|
||||
RETURN_ERR( NONLOCAL_ERROR( ptr.p ) );
|
||||
RETURN_ERR( open_( ptr.p, read, user_data ) );
|
||||
RETURN_ERR( next_( ptr.p, false ) );
|
||||
|
||||
*impl_out = ptr.p;
|
||||
ptr.p = NULL;
|
||||
|
||||
//delete ptr.p; // done automatically at end of function
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
void unrar_close( unrar_t* ar )
|
||||
{
|
||||
delete ar;
|
||||
}
|
||||
|
||||
unrar_bool unrar_done( const unrar_t* p )
|
||||
{
|
||||
return p->done;
|
||||
}
|
||||
|
||||
unrar_err_t unrar_next( unrar_t* p )
|
||||
{
|
||||
assert( !unrar_done( p ) );
|
||||
|
||||
RETURN_ERR( NONLOCAL_ERROR( p ) );
|
||||
return next_( p, false );
|
||||
}
|
||||
|
||||
const unrar_info_t* unrar_info( unrar_t const* p )
|
||||
{
|
||||
assert( !unrar_done( p ) );
|
||||
|
||||
return &p->info;
|
||||
}
|
||||
|
||||
unrar_pos_t unrar_tell( const unrar_t* p )
|
||||
{
|
||||
return p->Arc.CurBlockPos;
|
||||
}
|
||||
|
||||
unrar_err_t unrar_seek( unrar_t* p, unrar_pos_t n )
|
||||
{
|
||||
p->Arc.NextBlockPos = n;
|
||||
p->done = false;
|
||||
p->FileCount = (n <= p->first_file_pos ? 0 : 1);
|
||||
|
||||
return unrar_next( p );
|
||||
}
|
||||
|
||||
unrar_err_t unrar_rewind( unrar_t* p )
|
||||
{
|
||||
return unrar_seek( p, p->begin_pos );
|
||||
}
|
||||
|
||||
unrar_err_t unrar_try_extract( const unrar_t* p )
|
||||
{
|
||||
assert( !unrar_done( p ) );
|
||||
|
||||
return ((unrar_t*) p)->ExtractCurrentFile( true, true );
|
||||
}
|
||||
|
||||
static unrar_err_t reopen( unrar_t* p )
|
||||
{
|
||||
// Save and restore archive reader
|
||||
unrar_read_func read = p->Arc.user_read;
|
||||
void* user_data = p->Arc.user_read_data;
|
||||
|
||||
void (*close_file)( void* ) = p->close_file;
|
||||
p->close_file = NULL;
|
||||
|
||||
p->~unrar_t();
|
||||
new (p) unrar_t;
|
||||
|
||||
p->close_file = close_file;
|
||||
|
||||
return open_( p, read, user_data );
|
||||
}
|
||||
|
||||
unrar_err_t unrar_extract_custom( unrar_t* p, unrar_write_func user_write, void* user_data )
|
||||
{
|
||||
assert( !unrar_done( p ) );
|
||||
|
||||
RETURN_ERR( NONLOCAL_ERROR( p ) );
|
||||
|
||||
if ( solid_file( p ) )
|
||||
{
|
||||
unrar_pos_t pos = p->Arc.CurBlockPos;
|
||||
if ( p->solid_pos != pos )
|
||||
{
|
||||
// Next file to solid extract isn't current one
|
||||
|
||||
if ( p->solid_pos > pos )
|
||||
RETURN_ERR( reopen( p ) );
|
||||
else
|
||||
p->Arc.NextBlockPos = p->solid_pos;
|
||||
|
||||
RETURN_ERR( next_( p, true ) );
|
||||
|
||||
// Keep extracting until solid position is at desired file
|
||||
while ( !p->done && p->solid_pos < pos )
|
||||
{
|
||||
RETURN_ERR( skip_solid( p ) );
|
||||
RETURN_ERR( next_( p, true ) );
|
||||
}
|
||||
|
||||
// Be sure we're at right file
|
||||
if ( p->solid_pos != pos || p->Arc.CurBlockPos != pos )
|
||||
return unrar_err_corrupt;
|
||||
}
|
||||
}
|
||||
|
||||
return extract_( p, user_write, user_data );
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
/** RAR archive scanning and extraction \file */
|
||||
|
||||
/* unrar_core 3.8.5 */
|
||||
#ifndef UNRAR_H
|
||||
#define UNRAR_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "../fex/blargg_common.h"
|
||||
|
||||
#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
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** Error code, or 0 if function was successful. See Errors for more. Except
|
||||
where noted, once an operation returns an error, that archive should not be
|
||||
used any further, other than with unrar_close(). */
|
||||
#ifndef unrar_err_t /* (#ifndef allows better testing of library) */
|
||||
typedef int unrar_err_t;
|
||||
#endif
|
||||
|
||||
/** First parameter of most functions is unrar_t*, or const unrar_t* if nothing
|
||||
is changed. */
|
||||
typedef struct unrar_t unrar_t;
|
||||
|
||||
/** File position */
|
||||
typedef unrar_long_long unrar_pos_t;
|
||||
|
||||
/** Boolean, where 0 is false and 1 is true */
|
||||
typedef int unrar_bool;
|
||||
|
||||
|
||||
/******** Open/close ********/
|
||||
|
||||
/** Initializes static tables used by library. Automatically called by
|
||||
unrar_open(). OK to call more than once. */
|
||||
void unrar_init( void );
|
||||
|
||||
/** Opens archive and points *out at it. If error, sets *out to NULL. */
|
||||
unrar_err_t unrar_open( unrar_t** out, const char path [] );
|
||||
|
||||
/** User archive read callback. When called, user_data is a copy of that passed
|
||||
to unrar_open_custom(). Callback must do the following: Read avail bytes from
|
||||
file at offset pos and set *count to avail, where avail is the lesser of *count
|
||||
and file_size-pos. Put read bytes into *out and return unrar_ok. If fewer than
|
||||
avail bytes could be read successfully, return a non-zero error code. */
|
||||
typedef unrar_err_t (*unrar_read_func)( void* user_data,
|
||||
void* out, int* count, unrar_pos_t pos );
|
||||
|
||||
/** Same as unrar_open(), except data is read using supplied function rather
|
||||
than from file. */
|
||||
unrar_err_t unrar_open_custom( unrar_t** unrar_out,
|
||||
unrar_read_func, void* user_data );
|
||||
|
||||
/** Closes archive and frees memory. OK to pass NULL. */
|
||||
void unrar_close( unrar_t* );
|
||||
|
||||
|
||||
/******** Scanning ********/
|
||||
|
||||
/** True if at end of archive. Must be called after unrar_open() or
|
||||
unrar_rewind(), as an archive might contain no files. */
|
||||
unrar_bool unrar_done( const unrar_t* );
|
||||
|
||||
/** Goes to next file in archive. If there are no more files, unrar_done() will
|
||||
now return true. */
|
||||
unrar_err_t unrar_next( unrar_t* );
|
||||
|
||||
/** Goes back to first file in archive, as if it were just opened with
|
||||
unrar_open(). */
|
||||
unrar_err_t unrar_rewind( unrar_t* );
|
||||
|
||||
/** Position of current file in archive. Will never return zero. */
|
||||
unrar_pos_t unrar_tell( const unrar_t* );
|
||||
|
||||
/** Returns to file at previously-saved position. */
|
||||
unrar_err_t unrar_seek( unrar_t*, unrar_pos_t );
|
||||
|
||||
|
||||
/**** Info ****/
|
||||
|
||||
/** Information about current file */
|
||||
typedef struct unrar_info_t
|
||||
{
|
||||
unrar_pos_t size; /**< Uncompressed size */
|
||||
char name[32767]; /**< Name, in Unicode if is_unicode is true */
|
||||
const 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 */
|
||||
unsigned int crc; /**< Checksum; algorithm depends on archive */
|
||||
unrar_bool is_crc32; /**< True if crc is CRC-32 */
|
||||
} unrar_info_t;
|
||||
|
||||
/** Information about current file. Pointer is valid until unrar_next(),
|
||||
unrar_rewind(), unrar_seek(), or unrar_close(). */
|
||||
const unrar_info_t* unrar_info( const unrar_t* );
|
||||
|
||||
|
||||
/**** Extraction ****/
|
||||
|
||||
/** Returns unrar_ok if current file can be extracted, otherwise error
|
||||
indicating why it can't be extracted (too new/old compression algorithm,
|
||||
encrypted, segmented). Archive is still usable if this returns error,
|
||||
just the current file can't be extracted. */
|
||||
unrar_err_t unrar_try_extract( const unrar_t* );
|
||||
|
||||
/** Extracts at most size bytes from current file into out. If file is larger,
|
||||
discards excess bytes. If file is smaller, only writes unrar_size() bytes. */
|
||||
unrar_err_t unrar_extract( unrar_t*, void* out, unrar_pos_t size );
|
||||
|
||||
/** Extracts data to memory and returns pointer to it in *out. Pointer is
|
||||
valid until unrar_next(), unrar_rewind(), unrar_seek(), or unrar_close(). OK to
|
||||
call more than once for same file. Optimized to avoid allocating memory when
|
||||
entire file will already be kept in internal window. */
|
||||
unrar_err_t unrar_extract_mem( unrar_t* p, void const** out );
|
||||
|
||||
/** User extracted data write callback. When called, user_data is a copy of
|
||||
that passed to unrar_extract_custom(). Callback must do the following: Write
|
||||
count bytes from *in to wherever extracted data goes and return unrar_ok. If
|
||||
data cannot be written successfully, return a non-zero error code. */
|
||||
typedef unrar_err_t (*unrar_write_func)( void* user_data,
|
||||
const void* in, int count );
|
||||
|
||||
/** Extracts current file and writes data using supplied function. Any error
|
||||
it returns will be returned by this function, and archive will still be
|
||||
usable. */
|
||||
unrar_err_t unrar_extract_custom( unrar_t*,
|
||||
unrar_write_func, void* user_data );
|
||||
|
||||
|
||||
/******** Errors ********/
|
||||
|
||||
/** Error string associated with unrar error code. Always returns valid
|
||||
pointer to a C string; never returns NULL. Returns "" for unrar_ok. */
|
||||
const char* unrar_err_str( unrar_err_t );
|
||||
|
||||
enum {
|
||||
unrar_ok = 0,/**< No error; success. Guaranteed to be zero. */
|
||||
unrar_err_memory = 1,/**< Out of memory */
|
||||
unrar_err_open = 2,/**< Couldn't open file (not found/permissions) */
|
||||
unrar_err_not_arc = 3,/**< Not a RAR archive */
|
||||
unrar_err_corrupt = 4,/**< Archive is corrupt */
|
||||
unrar_err_io = 5,/**< Read failed */
|
||||
unrar_err_arc_eof = 6,/**< At end of archive; no more files */
|
||||
unrar_err_encrypted = 7,/**< Encryption not supported */
|
||||
unrar_err_segmented = 8,/**< Segmentation not supported */
|
||||
unrar_err_huge = 9,/**< Huge (2GB+) archives not supported */
|
||||
unrar_err_old_algo = 10,/**< Compressed with unsupported old algorithm */
|
||||
unrar_err_new_algo = 11,/**< Compressed with unsupported new algorithm */
|
||||
unrar_next_err = 100/**< Errors range from 0 to unrar_next_err-1 */
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,167 @@
|
|||
// Misc functions outside the core interface
|
||||
|
||||
#include "unrar.h"
|
||||
|
||||
#include "rar.hpp"
|
||||
#include <assert.h>
|
||||
|
||||
// This source code is a heavily modified version based on the unrar package.
|
||||
// It may not be used to develop a RAR (WinRAR) compatible archiver.
|
||||
// See unrar/license.txt for copyright and licensing.
|
||||
|
||||
void unrar_init()
|
||||
{
|
||||
if (crc_tables[0][1]==0)
|
||||
InitCRCTables();
|
||||
|
||||
Unpack::init_tables();
|
||||
}
|
||||
|
||||
struct unrar_extract_mem_t
|
||||
{
|
||||
char* out;
|
||||
char* end;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
static unrar_err_t extract_write( void* user_data, const void* in, int count )
|
||||
{
|
||||
unrar_extract_mem_t* p = (unrar_extract_mem_t*) user_data;
|
||||
|
||||
unrar_pos_t remain = p->end - p->out;
|
||||
if ( remain > 0 )
|
||||
{
|
||||
if ( count > remain )
|
||||
count = (int)remain;
|
||||
|
||||
memcpy( p->out, in, count );
|
||||
p->out += count;
|
||||
}
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
}
|
||||
|
||||
unrar_err_t unrar_extract( unrar_t* p, void* out, unrar_pos_t size )
|
||||
{
|
||||
assert( !unrar_done( p ) );
|
||||
|
||||
unrar_extract_mem_t m;
|
||||
m.out = (char*) out;
|
||||
m.end = m.out + size;
|
||||
return unrar_extract_custom( p, &extract_write, &m );
|
||||
}
|
||||
|
||||
inline
|
||||
static bool is_entire_file( const unrar_t* p, const void* in, int count )
|
||||
{
|
||||
return (count == p->Arc.SubHead.UnpSize && p->Unp && in == p->Unp->window_wrptr());
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
static unrar_err_t extract_mem( void* data, void const* in, int count )
|
||||
{
|
||||
unrar_t* p = (unrar_t*) data;
|
||||
|
||||
// We might have pointer to entire file
|
||||
if ( !p->data_ && is_entire_file( p, in, count ) )
|
||||
{
|
||||
p->data_ = in;
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
// We don't have it, so allocate memory to read entire file into
|
||||
if ( !p->own_data_ )
|
||||
{
|
||||
assert( !p->data_ );
|
||||
|
||||
unrar_pos_t size = unrar_info( p )->size;
|
||||
p->own_data_ = malloc( size ? (size_t)size : 1 );
|
||||
if ( !p->own_data_ )
|
||||
return unrar_err_memory;
|
||||
|
||||
p->data_ = p->own_data_;
|
||||
}
|
||||
|
||||
memcpy( (void*) p->data_, in, count );
|
||||
p->data_ = (char*) p->data_ + count;
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
}
|
||||
|
||||
unrar_err_t unrar_extract_mem( unrar_t* p, void const** out )
|
||||
{
|
||||
assert( !unrar_done( p ) );
|
||||
|
||||
*out = NULL;
|
||||
|
||||
if ( !p->data_ )
|
||||
{
|
||||
unrar_err_t err = unrar_extract_custom( p, &extract_mem, p );
|
||||
if ( err )
|
||||
return err;
|
||||
}
|
||||
|
||||
*out = (p->own_data_ ? p->own_data_ : p->data_);
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
const char* unrar_err_str( unrar_err_t err )
|
||||
{
|
||||
switch ( err )
|
||||
{
|
||||
case unrar_ok: return "";
|
||||
case unrar_err_memory: return "out of memory";
|
||||
case unrar_err_open: return "couldn't open RAR archive";
|
||||
case unrar_err_not_arc: return "not a RAR archive";
|
||||
case unrar_err_corrupt: return "RAR archive is corrupt";
|
||||
case unrar_err_io: return "couldn't read/write";
|
||||
case unrar_err_arc_eof: return "unexpected end of archive";
|
||||
case unrar_err_encrypted: return "encryption not supported";
|
||||
case unrar_err_segmented: return "segmentation not supported";
|
||||
case unrar_err_huge: return "huge (2GB+) archives are not supported";
|
||||
case unrar_err_old_algo: return "compressed using older algorithm than supported";
|
||||
case unrar_err_new_algo: return "compressed using newer algorithm than supported";
|
||||
}
|
||||
|
||||
assert( false );
|
||||
return "problem with RAR";
|
||||
}
|
||||
|
||||
int ComprDataIO::Read( void* p, int n )
|
||||
{
|
||||
unrar_err_t err = user_read( user_read_data, p, &n, Tell_ );
|
||||
if ( err )
|
||||
ReportError( err );
|
||||
|
||||
Tell_ += n;
|
||||
if ( Tell_ < 0 )
|
||||
ReportError( unrar_err_huge );
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void ComprDataIO::UnpWrite( byte* out, uint count )
|
||||
{
|
||||
if ( !SkipUnpCRC )
|
||||
{
|
||||
if ( write_error == unrar_ok )
|
||||
write_error = user_write( user_write_data, out, count );
|
||||
|
||||
UnpHash.Update(out,count);
|
||||
}
|
||||
}
|
||||
|
||||
int ComprDataIO::UnpRead( byte* out, uint count )
|
||||
{
|
||||
if ( count <= 0 )
|
||||
return 0;
|
||||
|
||||
if ( count > (uint) UnpPackedSize )
|
||||
count = (uint) UnpPackedSize;
|
||||
|
||||
int result = Read( out, count );
|
||||
UnpPackedSize -= result;
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// Separate file to avoid linking to f* functions unless user calls unrar_open_file()
|
||||
|
||||
#include "unrar.h"
|
||||
#include "rar.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" {
|
||||
static unrar_err_t unrar_read_file( void* user_data, void* out, int* count, unrar_pos_t pos )
|
||||
{
|
||||
FILE* file = (FILE*) user_data;
|
||||
|
||||
// most of the time, seeking won't be necessary
|
||||
if ( pos != ftell( file ) && fseek( file, (long)pos, SEEK_SET ) != 0 )
|
||||
return unrar_err_corrupt;
|
||||
|
||||
*count = (int) fread( out, 1, *count, file );
|
||||
|
||||
if ( ferror( file ) != 0 )
|
||||
return unrar_err_io;
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
}
|
||||
|
||||
static void unrar_close_file( void* user_data )
|
||||
{
|
||||
fclose( (FILE*) user_data );
|
||||
}
|
||||
|
||||
unrar_err_t unrar_open( unrar_t** arc_out, const char path [] )
|
||||
{
|
||||
*arc_out = NULL;
|
||||
|
||||
#if _MSC_VER >= 1300
|
||||
FILE* file = NULL;
|
||||
fopen_s(&file, path, "rb");
|
||||
#else
|
||||
FILE* file = fopen( path, "rb" );
|
||||
#endif
|
||||
if ( file == NULL )
|
||||
return unrar_err_open;
|
||||
|
||||
unrar_err_t err = unrar_open_custom( arc_out, &unrar_read_file, file );
|
||||
if ( err != unrar_ok )
|
||||
fclose( file );
|
||||
else
|
||||
(*arc_out)->close_file = &unrar_close_file;
|
||||
|
||||
return err;
|
||||
}
|
|
@ -0,0 +1,267 @@
|
|||
|
||||
|
||||
WinRAR - What's new in the latest version
|
||||
|
||||
|
||||
Version 3.80
|
||||
|
||||
1. Added support for ZIP archives containing Unicode file names
|
||||
in UTF-8 format. When creating ZIP archive, WinRAR stores
|
||||
names in Unicode only if they cannot be stored correctly using
|
||||
the current single byte character set.
|
||||
|
||||
2. Added decompression support for WinZip AES encrypted ZIP archives.
|
||||
|
||||
3. Improved Unicode support for RAR and ZIP archive names.
|
||||
|
||||
4. "Ask before overwrite" and "Skip existing files" update modes
|
||||
are now available in archiving dialog. They allow to specify
|
||||
WinRAR behavior when updating already existing files in archive.
|
||||
Unlike already available "Fresh existing files only" and
|
||||
"Add and update files", these new modes ignore file date
|
||||
and compare only file names.
|
||||
|
||||
Command line equivalents of these modes are:
|
||||
|
||||
a) switch -o enables "Ask before overwrite" archiving mode;
|
||||
|
||||
b) switch -o- enables "Skip existing files" archiving mode;
|
||||
|
||||
c) switch -o+ enables "Overwrite all" mode (default for archiving).
|
||||
|
||||
5. New "Add to context menu" option in "Profile parameters" dialog.
|
||||
If this option is on, the profile name will be displayed in Explorer
|
||||
context menus allowing to activate a profile from context menu.
|
||||
|
||||
6. New -cp<profile name> switch allows to select a compression profile
|
||||
in command line mode. It is supported only by GUI WinRAR.exe,
|
||||
not by rar.exe.
|
||||
|
||||
7. New "Options" page of archiving dialog contains the group of
|
||||
settings modifying the behavior of "Delete files after archiving"
|
||||
option from "General" page:
|
||||
|
||||
a) Delete files. Delete files normally like in previous WinRAR
|
||||
versions.
|
||||
|
||||
b) Move files to Recycle Bin. Deleted files are placed to
|
||||
Recycle Bin.
|
||||
|
||||
Command line equivalent of this option is -dr switch.
|
||||
|
||||
c) Wipe files. Before deleting file data are overwritten by
|
||||
zero bytes to prevent recovery of deleted files.
|
||||
|
||||
Command line equivalent of this option is -dw switch.
|
||||
|
||||
All these options have an effect only if "Delete files
|
||||
after archiving" is on. You can enable any of these options
|
||||
in the default compression profile to change the default
|
||||
behavior of "Delete files after archiving".
|
||||
|
||||
8. WinRAR "Extraction path and options" dialog is now resizable.
|
||||
You can use the mouse to drag its border to the desired size
|
||||
and provide more space for folder tree pane. WinRAR will store
|
||||
new dimensions of this dialog.
|
||||
|
||||
9. New "Update" SFX script command and "Update mode" group
|
||||
of options in "Update" page of "Advanced SFX options" dialog.
|
||||
These command and options allow to check time and implement
|
||||
file time based updating;
|
||||
|
||||
10. SFX script "Shortcut" command and "Add shortcut..." command
|
||||
in "Advanced SFX options" dialog now allow to specify
|
||||
an icon file containing an icon associated with shortcut.
|
||||
|
||||
11. New "Wipe temporary files" option in "Settings/Security" dialog
|
||||
provides more secure, though slower, way to delete temporary
|
||||
WinRAR files.
|
||||
|
||||
12. WinRAR and RAR display the total progress bar when unpacking
|
||||
a multivolume RAR archive if all volumes are present
|
||||
in the same folder.
|
||||
|
||||
13. WinRAR and RAR automatically expand names of environment
|
||||
variables in list files. For example, a list file can contain
|
||||
lines like:
|
||||
|
||||
%windir%\*.exe
|
||||
%USERPROFILE%\Desktop
|
||||
|
||||
This feature is available only in Windows RAR version.
|
||||
|
||||
14. Added support of TAR archives with non-zero "extra field" data.
|
||||
|
||||
15. Added support of TAR archives, which does not contain
|
||||
the end of archive entry consisting of 512 zero bytes.
|
||||
|
||||
16. Improved Unicode support when dragging files from WinRAR window.
|
||||
|
||||
17. Shift+Tab key combination can be used in main WinRAR window to
|
||||
switch the input focus between interface elements (files, comment,
|
||||
tree, address) in reverse order. In previous versions Shift+Tab
|
||||
used the same order as Tab.
|
||||
|
||||
18. Corrected a possible WinRAR crash when opening truncated
|
||||
UDF ISO files.
|
||||
|
||||
|
||||
Version 3.71
|
||||
|
||||
1. Archive names in rar.log error log file always include
|
||||
the full path.
|
||||
|
||||
2. WinRAR tray icon is compatible with high DPI display modes.
|
||||
|
||||
3. If you modified a file in archive with encrypted names using
|
||||
an external editor, WinRAR will not ask for archive password again
|
||||
when prompting to update a file. It will use a password which
|
||||
you entered when opening an archive,
|
||||
|
||||
4. Bugs fixed:
|
||||
|
||||
a) switch -tl and "Set archive time to latest file time" option
|
||||
could fail in previous version. Sometimes they set archive time
|
||||
to current system time instead of latest file time;
|
||||
|
||||
b) if -ag switch mask contained archive number, month and minute
|
||||
characters, WinRAR placed 'I' character instead of minute value
|
||||
into generated archive name for archive numbers exceeding 1;
|
||||
|
||||
c) high ASCII names in ISO files using ISO 9660 format without
|
||||
Joliet format extension were displayed incorrectly;
|
||||
|
||||
d) WinRAR could crash when decompressing some of corrupt RAR archives;
|
||||
|
||||
e) if "Turn PC off when done" option was set in "Convert archives"
|
||||
command, WinRAR turned PC off after converting the first archive
|
||||
in selected group instead of after converting the entire group;
|
||||
|
||||
f) if user specified a non-existent destination path in SFX archive
|
||||
in Vista, SFX could enter into infinite "create new SFX window"
|
||||
loop;
|
||||
|
||||
g) WinRAR could fail to unpack an individual file from subfolder
|
||||
of ACE archive using the drag and drop.
|
||||
|
||||
|
||||
Version 3.70
|
||||
|
||||
1. Numerous Windows Vista compatibility changes:
|
||||
|
||||
a) help format changed from old HLP to newer HTML based CHM;
|
||||
|
||||
b) GUI self-extracting modules attempt to request for
|
||||
administrator permissions if they cannot create destination
|
||||
folder under current user account;
|
||||
|
||||
c) Log file rar.log and WinRAR theme files are stored
|
||||
in %APPDATA%\WinRAR folder instead of WinRAR program files folder.
|
||||
|
||||
Exported settings file settings.reg is also stored
|
||||
in %APPDATA%\WinRAR folder by default, but it is possible to
|
||||
select another folder in "Save WinRAR settings" and "Load WinRAR
|
||||
settings" dialogs.
|
||||
|
||||
WinRAR searches for registration key and settings.reg
|
||||
both in its program files folder and in %APPDATA%\WinRAR;
|
||||
|
||||
It is possible to set the string value "AppData" in Registry key
|
||||
HKEY_CURRENT_USER\Software\WinRAR\Paths to override the default
|
||||
%appdata%\WinRAR path for WinRAR settings.
|
||||
|
||||
For example, if you wish to store theme files in WinRAR folder,
|
||||
set this value to "c:\Program Files\WinRAR".
|
||||
|
||||
d) Vista compatibility changes in WinRAR shell integration;
|
||||
|
||||
e) New "Request administrative access" option in "Advanced" page
|
||||
of "Advanced SFX options" allows to create SFX archive,
|
||||
which will request the administrative access when started
|
||||
in Windows Vista.
|
||||
|
||||
Command line equivalent of this option is -iadm switch.
|
||||
|
||||
2. Added support for ISO 13346 (UDF) file format. This format
|
||||
is frequently used in ISO images of DVD disks.
|
||||
|
||||
3. Added Unicode support for ISO 9660 files, so WinRAR should
|
||||
handle non-English file names in .iso files better.
|
||||
|
||||
4. Design changes in window displaying archiving and extraction
|
||||
progress:
|
||||
|
||||
a) it provides more space for file names, allowing lengthy names;
|
||||
|
||||
b) it displays the current archive name in separate line,
|
||||
allowing much longer archive names than before;
|
||||
|
||||
c) when archiving, it displays the current compression ratio
|
||||
in separate line;
|
||||
|
||||
d) it can use both standard Windows and classic WinRAR progress bars.
|
||||
Turn on "Windows progress bars" option in WinRAR "Settings/General"
|
||||
dialog to use standard progress bars. By default this option is
|
||||
on if some Windows visual style is active and off if Windows Classic
|
||||
theme is selected.
|
||||
|
||||
Windows progress bars are two color only, so they do not indicate
|
||||
the current compression ratio. But now the ratio is displayed
|
||||
in separate line;
|
||||
|
||||
e) "Mode..." button moved to bottom of window.
|
||||
|
||||
5. GUI self-extracting modules support following command line
|
||||
switches:
|
||||
|
||||
-d<path> set the destination path
|
||||
-p<pwd> specify a password
|
||||
-s silent mode, hide all
|
||||
-s1 same as -s
|
||||
-s2 silent mode, hide start dialog
|
||||
-sp<par> specify parameters for setup program
|
||||
|
||||
6. GUI self-extracting modules do not pass the entire command line
|
||||
to setup program like they did in previous versions.
|
||||
If you need to get access to entire command line of SFX archive,
|
||||
parse sfxcmd environment variable which contains this command line.
|
||||
|
||||
7. New switch -sc<charset>[objects] allowing to select character
|
||||
sets for archive comments and list files. It replaces -fcu switch
|
||||
introduced in RAR 3.60, which was removed from list of supported
|
||||
switches. Now you need to specify -scuc instead of -fcu to use
|
||||
Unicode comments. Unlike -fcu, -sc also supports OEM and ANSI charset.
|
||||
|
||||
8. New "Save archive copy as..." command in "File" menu.
|
||||
This command may be useful if you opened an archive from Internet
|
||||
directly in WinRAR and then decided to save it on local disk.
|
||||
|
||||
9. "Word wrap" command added to "View" menu of WinRAR internal viewer,
|
||||
so you can change the wrapping mode of already opened viewer window.
|
||||
|
||||
State of this option is not stored between viewing sessions.
|
||||
If you need to change the default word wrap mode, use WinRAR
|
||||
"Settings/Viewer" dialog.
|
||||
|
||||
10. Buttons "Up" and "Down" added to "Organize profiles" dialog.
|
||||
Using these buttons you can change position of selected profile
|
||||
in the list.
|
||||
|
||||
11. Operation progress is displayed when adding the recovery record.
|
||||
|
||||
12. If WinRAR is minimized to tray and mouse is over its icon,
|
||||
WinRAR diplays a message about the current operation progress.
|
||||
In previous versions it included only percent done, now it also
|
||||
contains the time left information.
|
||||
|
||||
13. Console RAR displays "Calculating the control sum" message
|
||||
when calculating CRC32 control sum for newly created RAR volume.
|
||||
Previous versions also calculated the volume control sum,
|
||||
but did it silently.
|
||||
|
||||
14. Archives history list in "File" menu allows Unicode names,
|
||||
providing more reliable support for non-English archive names.
|
||||
|
||||
15. Stack overflow vulnerability has been corrected in password
|
||||
processing module of console RAR and UnRAR. GUI WinRAR is not
|
||||
affected. We are thankful to the iDEFENSE LABS for reporting this bug.
|
Loading…
Reference in New Issue