#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#include "unrarlib.h"
#include "others.h"
#ifdef _WIN_32
#include <windows.h>
#include <stdio.h>
#include <string.h>
#define ENABLE_ACCESS
#define HOST_OS WIN_32
#define FM_NORMAL 0x00
#define FM_RDONLY 0x01
#define FM_HIDDEN 0x02
#define FM_SYSTEM 0x04
#define FM_LABEL 0x08
#define FM_DIREC 0x10
#define FM_ARCH 0x20
#define PATHDIVIDER "\\"
#define CPATHDIVIDER '\\'
#define MASKALL "*.*"
#define READBINARY "rb"
#define READTEXT "rt"
#define UPDATEBINARY "r+b"
#define CREATEBINARY "w+b"
#define CREATETEXT "w"
#define APPENDTEXT "at"
#endif
#ifdef _UNIX
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#define ENABLE_ACCESS
#define HOST_OS UNIX
#define FM_LABEL 0x0000
#define FM_DIREC 0x4000
#define PATHDIVIDER "/"
#define CPATHDIVIDER '/'
#define MASKALL "*.*"
#define READBINARY "r"
#define READTEXT "r"
#define UPDATEBINARY "r+"
#define CREATEBINARY "w+"
#define CREATETEXT "w"
#define APPENDTEXT "a"
typedef long DWORD;
typedef short BOOL;
#define TRUE 1
#define FALSE 0
#ifdef _DEBUG_LOG
#include <unistd.h>
#include <sys/time.h>
DWORD GetTickCount()
{
struct timeval tv;
gettimeofday( &tv, 0 );
return (tv.tv_usec / 1000);
}
#endif
#endif
#ifdef _DEBUG_LOG
BOOL debug_log_first_start = TRUE;
#define debug_log(a); debug_log_proc(a, __FILE__, __LINE__);
#define debug_init(a); debug_init_proc(a);
void debug_log_proc(char *text, char *sourcefile, int sourceline);
void debug_init_proc(char *file_name);
#else
#define debug_log(a); cli_dbgmsg("%s:%d %s\n", __FILE__, __LINE__, a);
#define debug_init(a);
#endif
#define MAXWINSIZE 0x100000
#define MAXWINMASK (MAXWINSIZE-1)
#define UNP_MEMORY MAXWINSIZE
#define Min(x,y) (((x)<(y)) ? (x):(y))
#define Max(x,y) (((x)>(y)) ? (x):(y))
#define NM 260
#define SIZEOF_MARKHEAD 7
#define SIZEOF_OLDMHD 7
#define SIZEOF_NEWMHD 13
#define SIZEOF_OLDLHD 21
#define SIZEOF_NEWLHD 32
#define SIZEOF_SHORTBLOCKHEAD 7
#define SIZEOF_LONGBLOCKHEAD 11
#define SIZEOF_COMMHEAD 13
#define SIZEOF_PROTECTHEAD 26
#define PACK_VER 20
#define UNP_VER 20
#define PROTECT_VER 20
enum { M_DENYREAD,M_DENYWRITE,M_DENYNONE,M_DENYALL };
enum { FILE_EMPTY,FILE_ADD,FILE_UPDATE,FILE_COPYOLD,FILE_COPYBLOCK };
enum { SUCCESS,WARNING,FATAL_ERROR,CRC_ERROR,LOCK_ERROR,WRITE_ERROR,
OPEN_ERROR,USER_ERROR,MEMORY_ERROR,USER_BREAK=255,IMM_ABORT=0x8000 };
enum { EN_LOCK=1,EN_VOL=2 };
enum { SD_MEMORY=1,SD_FILES=2 };
enum { NAMES_DONTCHANGE };
enum { LOG_ARC=1,LOG_FILE=2 };
enum { OLD_DECODE=0,OLD_ENCODE=1,NEW_CRYPT=2 };
enum { OLD_UNPACK,NEW_UNPACK };
#define MHD_COMMENT 2
#define MHD_LOCK 4
#define MHD_PACK_COMMENT 16
#define MHD_AV 32
#define MHD_PROTECT 64
#define LHD_SPLIT_BEFORE 1
#define LHD_SPLIT_AFTER 2
#define LHD_PASSWORD 4
#define LHD_COMMENT 8
#define LHD_SOLID 16
#define LHD_WINDOWMASK 0x00e0
#define LHD_WINDOW64 0
#define LHD_WINDOW128 32
#define LHD_WINDOW256 64
#define LHD_WINDOW512 96
#define LHD_WINDOW1024 128
#define LHD_DIRECTORY 0x00e0
#define LONG_BLOCK 0x8000
#define READSUBBLOCK 0x8000
enum { ALL_HEAD=0,MARK_HEAD=0x72,MAIN_HEAD=0x73,FILE_HEAD=0x74,
COMM_HEAD=0x75,AV_HEAD=0x76,SUB_HEAD=0x77,PROTECT_HEAD=0x78};
enum { EA_HEAD=0x100 };
enum { MS_DOS=0,OS2=1,WIN_32=2,UNIX=3 };
struct MarkHeader
{
UBYTE Mark[7];
};
struct NewMainArchiveHeader
{
UWORD HeadCRC;
UBYTE HeadType;
UWORD Flags;
UWORD HeadSize;
UWORD Reserved;
UDWORD Reserved1;
};
struct NewFileHeader
{
UWORD HeadCRC;
UBYTE HeadType;
UWORD Flags;
UWORD HeadSize;
UDWORD PackSize;
UDWORD UnpSize;
UBYTE HostOS;
UDWORD FileCRC;
UDWORD FileTime;
UBYTE UnpVer;
UBYTE Method;
UWORD NameSize;
UDWORD FileAttr;
};
struct BlockHeader
{
UWORD HeadCRC;
UBYTE HeadType;
UWORD Flags;
UWORD HeadSize;
UDWORD DataSize;
};
struct Decode
{
unsigned int MaxNum;
unsigned int DecodeLen[16];
unsigned int DecodePos[16];
unsigned int DecodeNum[2];
};
static struct MarkHeader MarkHead;
static struct NewMainArchiveHeader NewMhd;
static struct NewFileHeader NewLhd;
static struct BlockHeader BlockHead;
static UBYTE *TempMemory = NULL;
static char *CommMemory = NULL;
static UBYTE *UnpMemory = NULL;
static char ArgName[NM];
static char ArcFileName[NM];
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
static MemoryFile *MemRARFile;
#else
static FILE *ArcPtr;
#endif
static char Password[255];
static unsigned char *temp_output_buffer;
static unsigned long *temp_output_buffer_offset;
static int MainHeadSize;
static long CurBlockPos,NextBlockPos;
static unsigned long CurUnpRead, CurUnpWrite;
static long UnpPackedSize;
static long DestUnpSize;
static UDWORD HeaderCRC;
static int Encryption;
static unsigned int UnpPtr,WrPtr;
static unsigned char PN1,PN2,PN3;
static unsigned short OldKey[4];
static int ReadHeader(int BlockType);
static BOOL ExtrFile(int desc);
static int tread(void *stream,void *buf,unsigned len);
static int tseek(void *stream,long offset,int fromwhere);
static int IsArchive(void);
static int ReadBlock(int BlockType);
static unsigned int UnpRead(unsigned char *Addr,unsigned int Count);
static void UnpInitData(void);
static void Unpack(unsigned char *UnpAddr, BOOL FileFound);
static UBYTE DecodeAudio(int Delta);
static void DecodeNumber(struct Decode *Dec);
static void UpdKeys(UBYTE *Buf);
static void SetCryptKeys(char* NewPassword);
static void SetOldKeys(char *NewPassword);
static void DecryptBlock(unsigned char *Buf);
static void InitCRC(void);
static UDWORD CalcCRC32(UDWORD StartCRC,UBYTE *Addr,UDWORD Size);
static void UnpReadBuf(int FirstBuf);
static void ReadTables(void);
static void ReadLastTables(void);
static void MakeDecodeTables(unsigned char *LenTab,
struct Decode *Dec,
int Size);
static int stricomp(char *Str1,char *Str2);
int urarlib_get(void *output,
unsigned long *size,
char *filename,
int desc,
char *libpassword)
{
BOOL retcode = FALSE;
#ifdef _DEBUG_LOG
int str_offs;
char DebugMsg[500];
if(debug_log_first_start)
{
debug_log_first_start=FALSE;
debug_init(_DEBUG_LOG_FILE);
}
#endif
InitCRC();
strcpy(ArgName, filename);
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
MemRARFile = rarfile;
#endif
if(libpassword != NULL)
strcpy(Password, libpassword);
temp_output_buffer = NULL;
temp_output_buffer_offset=size;
retcode = ExtrFile(desc);
memset(Password,0,sizeof(Password));
#ifndef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
if (ArcPtr!=NULL){
cli_dbgmsg("%s:%d NOT Close ArcPtr from fd %d\n", __FILE__, __LINE__, desc);
}
#endif
if(UnpMemory)
free(UnpMemory);
if(TempMemory)
free(TempMemory);
if(CommMemory)
free(CommMemory);
UnpMemory=NULL;
TempMemory=NULL;
CommMemory=NULL;
if(retcode == FALSE)
{
if(temp_output_buffer)
free(temp_output_buffer);
temp_output_buffer=NULL;
*(DWORD*)output=0;
*size=0;
#ifdef _DEBUG_LOG
str_offs = sprintf(DebugMsg, "Error - couldn't extract ");
str_offs += sprintf(DebugMsg + str_offs, ">%s<", filename);
str_offs += sprintf(DebugMsg + str_offs, " and allocated ");
str_offs += sprintf(DebugMsg + str_offs, "%u Bytes", (unsigned int)*size);
str_offs += sprintf(DebugMsg + str_offs, " of unused memory!");
} else
{
sprintf(DebugMsg, "Extracted %u Bytes.", (unsigned int)*size);
}
debug_log(DebugMsg);
#else
}
#endif
*(DWORD*)output=(DWORD)temp_output_buffer;
return retcode;
}
int urarlib_list(int desc, ArchiveList_struct *list)
{
ArchiveList_struct *tmp_List = NULL;
int NoOfFilesInArchive = 0;
int newdesc;
#ifdef _DEBUG_LOG
if(debug_log_first_start)
{
debug_log_first_start=FALSE;
debug_init(_DEBUG_LOG_FILE);
}
#endif
InitCRC();
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
MemRARFile = rarfile;
MemRARFile->offset = 0;
if (!IsArchive())
{
debug_log("Not a RAR file");
return NoOfFilesInArchive;
}
#else
newdesc = dup(desc);
cli_dbgmsg("ExtrFile(): dup(%d) = %d\n", desc, newdesc);
if ((ArcPtr=fdopen(newdesc,READBINARY))!=NULL)
{
if (!IsArchive())
{
cli_dbgmsg("urarlib_list(): Not a valid archive.");
debug_log("Not a RAR file");
fclose(ArcPtr);
lseek(desc, 0, SEEK_SET);
ArcPtr = NULL;
return NoOfFilesInArchive;
}
}
else {
cli_dbgmsg("urarlib_list(): Error opening file: %s", strerror(errno));
debug_log("Error opening file.");
cli_dbgmsg("%s:%d Close fd %d\n", __FILE__, __LINE__, newdesc);
close(newdesc);
return NoOfFilesInArchive;
}
#endif
if ((UnpMemory=malloc(UNP_MEMORY))==NULL)
{
cli_dbgmsg("urarlib_list(): out of memory.");
debug_log("Can't allocate memory for decompression!");
fclose(ArcPtr);
return NoOfFilesInArchive;
}
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
MemRARFile->offset+=NewMhd.HeadSize-MainHeadSize;
#else
tseek(ArcPtr,NewMhd.HeadSize-MainHeadSize,SEEK_CUR);
#endif
(*(DWORD*)list) = (DWORD)NULL;
while (TRUE)
{
int ReadBlockResult;
if ((ReadBlockResult = ReadBlock(FILE_HEAD | READSUBBLOCK)) <= 0)
{
cli_dbgmsg("Couldn't read next filename from archive (I/O error): %d\n", ReadBlockResult);
break;
}
if (BlockHead.HeadType==SUB_HEAD)
{
debug_log("Sorry, sub-headers not supported.");
NoOfFilesInArchive = 0;
break;
}
if((void*)(*(DWORD*)list) == NULL)
{
tmp_List = malloc(sizeof(ArchiveList_struct));
tmp_List->next = NULL;
(*(DWORD*)list) = (DWORD)tmp_List;
} else
{
tmp_List->next = malloc(sizeof(ArchiveList_struct));
tmp_List = (ArchiveList_struct*) tmp_List->next;
tmp_List->next = NULL;
}
tmp_List->item.Name = malloc(NewLhd.NameSize + 1);
strcpy(tmp_List->item.Name, ArcFileName);
tmp_List->item.NameSize = NewLhd.NameSize;
tmp_List->item.PackSize = NewLhd.PackSize;
tmp_List->item.UnpSize = NewLhd.UnpSize;
tmp_List->item.HostOS = NewLhd.HostOS;
tmp_List->item.FileCRC = NewLhd.FileCRC;
tmp_List->item.FileTime = NewLhd.FileTime;
tmp_List->item.UnpVer = NewLhd.UnpVer;
tmp_List->item.Method = NewLhd.Method;
tmp_List->item.FileAttr = NewLhd.FileAttr;
tmp_List->item.Flags = NewLhd.Flags;
NoOfFilesInArchive++;
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
MemRARFile->offset = NextBlockPos;
#else
if (ArcPtr!=NULL) tseek(ArcPtr,NextBlockPos,SEEK_SET);
#endif
};
memset(Password,0,sizeof(Password));
#ifndef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
if (ArcPtr!=NULL){
fclose(ArcPtr);
ArcPtr = NULL;
lseek(desc, 0, SEEK_SET);
}
#endif
if(UnpMemory)
free(UnpMemory);
if(TempMemory)
free(TempMemory);
if(CommMemory)
free(CommMemory);
UnpMemory=NULL;
TempMemory=NULL;
CommMemory=NULL;
return NoOfFilesInArchive;
}
void urarlib_freelist(ArchiveList_struct *list)
{
ArchiveList_struct* tmp = list;
while ( list ) {
tmp = list->next;
free( list->item.Name );
free( list );
list = tmp;
}
}
#define GetHeaderByte(N) Header[N]
#define GetHeaderWord(N) (Header[N]+((UWORD)Header[N+1]<<8))
#define GetHeaderDword(N) (Header[N]+((UWORD)Header[N+1]<<8)+\
((UDWORD)Header[N+2]<<16)+\
((UDWORD)Header[N+3]<<24))
int ReadBlock(int BlockType)
{
struct NewFileHeader SaveFileHead;
int Size=0,ReadSubBlock=0;
static int LastBlock;
memcpy(&SaveFileHead,&NewLhd,sizeof(SaveFileHead));
if (BlockType & READSUBBLOCK) {
ReadSubBlock=1;
BlockType &= 0xff;
}
{
while (1)
{
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
CurBlockPos=MemRARFile->offset;
#else
CurBlockPos=ftell(ArcPtr);
#endif
Size=ReadHeader(FILE_HEAD);
if (Size!=0)
{
if (NewLhd.HeadSize<SIZEOF_SHORTBLOCKHEAD)
return(0);
NextBlockPos=CurBlockPos+NewLhd.HeadSize;
if (NewLhd.Flags & LONG_BLOCK)
NextBlockPos+=NewLhd.PackSize;
if (NextBlockPos<=CurBlockPos)
return(0);
}
if (Size > 0 && BlockType!=SUB_HEAD)
LastBlock=BlockType;
if (Size==0 || BlockType==ALL_HEAD || NewLhd.HeadType==BlockType ||
(NewLhd.HeadType==SUB_HEAD && ReadSubBlock && LastBlock==BlockType))
break;
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
MemRARFile->offset = NextBlockPos;
#else
tseek(ArcPtr, NextBlockPos, SEEK_SET);
#endif
}
}
BlockHead.HeadCRC=NewLhd.HeadCRC;
BlockHead.HeadType=NewLhd.HeadType;
BlockHead.Flags=NewLhd.Flags;
BlockHead.HeadSize=NewLhd.HeadSize;
BlockHead.DataSize=NewLhd.PackSize;
if (BlockType!=NewLhd.HeadType) BlockType=ALL_HEAD;
if((FILE_HEAD == BlockType) && (Size>0))
{
NewLhd.NameSize=Min(NewLhd.NameSize,sizeof(ArcFileName)-1);
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
tread(MemRARFile, ArcFileName, NewLhd.NameSize);
#else
tread(ArcPtr,ArcFileName,NewLhd.NameSize);
#endif
ArcFileName[NewLhd.NameSize]=0;
#ifdef _DEBUG_LOG
if (NewLhd.HeadCRC!=(UWORD)~CalcCRC32(HeaderCRC,(UBYTE*)&ArcFileName[0],
NewLhd.NameSize))
{
debug_log("file header broken");
}
#endif
Size+=NewLhd.NameSize;
} else
{
memcpy(&NewLhd,&SaveFileHead,sizeof(NewLhd));
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
MemRARFile->offset = CurBlockPos;
#else
tseek(ArcPtr,CurBlockPos,SEEK_SET);
#endif
}
return(Size);
}
int ReadHeader(int BlockType)
{
int Size = 0;
unsigned char Header[64];
memset(Header, 0, sizeof(Header));
switch(BlockType)
{
case MAIN_HEAD:
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
Size=tread(MemRARFile, Header, SIZEOF_NEWMHD);
#else
Size=tread(ArcPtr,Header,SIZEOF_NEWMHD);
#endif
NewMhd.HeadCRC=(unsigned short)GetHeaderWord(0);
NewMhd.HeadType=GetHeaderByte(2);
NewMhd.Flags=(unsigned short)GetHeaderWord(3);
NewMhd.HeadSize=(unsigned short)GetHeaderWord(5);
NewMhd.Reserved=(unsigned short)GetHeaderWord(7);
NewMhd.Reserved1=GetHeaderDword(9);
HeaderCRC=CalcCRC32(0xFFFFFFFFL,&Header[2],SIZEOF_NEWMHD-2);
break;
case FILE_HEAD:
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
Size=tread(MemRARFile, Header, SIZEOF_NEWLHD);
#else
Size=tread(ArcPtr,Header,SIZEOF_NEWLHD);
#endif
NewLhd.HeadCRC=(unsigned short)GetHeaderWord(0);
NewLhd.HeadType=GetHeaderByte(2);
NewLhd.Flags=(unsigned short)GetHeaderWord(3);
NewLhd.HeadSize=(unsigned short)GetHeaderWord(5);
NewLhd.PackSize=GetHeaderDword(7);
NewLhd.UnpSize=GetHeaderDword(11);
NewLhd.HostOS=GetHeaderByte(15);
NewLhd.FileCRC=GetHeaderDword(16);
NewLhd.FileTime=GetHeaderDword(20);
NewLhd.UnpVer=GetHeaderByte(24);
NewLhd.Method=GetHeaderByte(25);
NewLhd.NameSize=(unsigned short)GetHeaderWord(26);
NewLhd.FileAttr=GetHeaderDword(28);
HeaderCRC=CalcCRC32(0xFFFFFFFFL,Header+2,SIZEOF_NEWLHD-2);
break;
#ifdef _DEBUG_LOG
case COMM_HEAD:
debug_log("Comment headers not supported! "\
"Please create archives without comments.");
break;
case PROTECT_HEAD:
debug_log("Protected headers not supported!");
break;
case ALL_HEAD:
debug_log("ShortBlockHeader not supported!");
break;
default:
debug_log("Unknown//unsupported !");
#else
default:
break;
#endif
}
return(Size);
}
int IsArchive(void)
{
#ifdef _DEBUG_LOG
int str_offs;
char DebugMsg[500];
#endif
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
if (tread(MemRARFile, MarkHead.Mark, SIZEOF_MARKHEAD) != SIZEOF_MARKHEAD) {
debug_log("IsArchive(): short read: FALSE");
return(FALSE);
}
#else
if (tread(ArcPtr,MarkHead.Mark,SIZEOF_MARKHEAD)!=SIZEOF_MARKHEAD) {
debug_log("IsArchive(): short read: FALSE");
return(FALSE);
}
#endif
if (MarkHead.Mark[0]==0x52 && MarkHead.Mark[1]==0x45 &&
MarkHead.Mark[2]==0x7e && MarkHead.Mark[3]==0x5e)
{
debug_log("Attention: format as OLD detected! Can't handle archive!");
}
else
if ((MarkHead.Mark[0]==0x52 && MarkHead.Mark[1]==0x61 &&
MarkHead.Mark[2]==0x72 && MarkHead.Mark[3]==0x21 &&
MarkHead.Mark[4]==0x1a && MarkHead.Mark[5]==0x07 &&
MarkHead.Mark[6]==0x00) ||
(MarkHead.Mark[0]=='U' && MarkHead.Mark[1]=='n' &&
MarkHead.Mark[2]=='i' && MarkHead.Mark[3]=='q' &&
MarkHead.Mark[4]=='u' && MarkHead.Mark[5]=='E' &&
MarkHead.Mark[6]=='!'))
{
if (ReadHeader(MAIN_HEAD)!=SIZEOF_NEWMHD) {
debug_log("IsArchive(): ReadHeader() failed");
return(FALSE);
}
} else
{
#ifdef _DEBUG_LOG
str_offs = sprintf(DebugMsg, "unknown archive type (only plain RAR ");
str_offs += sprintf(DebugMsg + str_offs, "supported (normal and solid ");
str_offs += sprintf(DebugMsg + str_offs, "archives), SFX and Volumes ");
str_offs += sprintf(DebugMsg + str_offs, "are NOT supported!)");
debug_log(DebugMsg);
#endif
}
MainHeadSize=SIZEOF_NEWMHD;
return(TRUE);
}
BOOL ExtrFile(int desc)
{
BOOL ReturnCode=TRUE;
BOOL FileFound=FALSE;
int newdesc;
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
MemRARFile->offset = 0;
if (!IsArchive())
{
debug_log("Not a RAR file");
return FALSE;
}
#else
newdesc = dup(desc);
cli_dbgmsg("ExtrFile(): dup(%d) = %d\n", desc, newdesc);
if ((ArcPtr=fdopen(newdesc,READBINARY))!=NULL)
{
if (!IsArchive())
{
debug_log("Not a RAR file");
fclose(ArcPtr);
ArcPtr = NULL;
return FALSE;
}
} else
{
debug_log("Error opening file.");
return FALSE;
}
#endif
if ((UnpMemory=malloc(UNP_MEMORY))==NULL)
{
cli_dbgmsg("unrarlib: Can't allocate memory for decompression!");
return FALSE;
} else cli_dbgmsg("unrarlib: Allocated %d bytes.\n", UNP_MEMORY);
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
MemRARFile->offset+=NewMhd.HeadSize-MainHeadSize;
#else
tseek(ArcPtr,NewMhd.HeadSize-MainHeadSize,SEEK_CUR);
#endif
do
{
if (ReadBlock(FILE_HEAD | READSUBBLOCK) <= 0)
{
ReturnCode=FALSE;
break;
}
if (BlockHead.HeadType==SUB_HEAD)
{
debug_log("Sorry, sub-headers not supported.");
ReturnCode=FALSE;
break;
}
if(TRUE == (FileFound=(stricomp(ArgName, ArcFileName) == 0)))
{
{
cli_dbgmsg("unrarlib: Allocating %d bytes\n", NewLhd.UnpSize);
if((temp_output_buffer=malloc(NewLhd.UnpSize)) == NULL) { ;
cli_errmsg("unrarlib: Can't malloc %d bytes\n", NewLhd.UnpSize);
ReturnCode = FALSE;
break;
}
}
*temp_output_buffer_offset=0;
}
if((NewMhd.Flags & 0x08) || FileFound)
{
if (NewLhd.UnpVer<13 || NewLhd.UnpVer>UNP_VER)
{
cli_dbgmsg("unknown compression method: %d (min=13 max=%d)\n", NewLhd.UnpVer, UNP_VER);
ReturnCode=FALSE;
break;
}
CurUnpRead=CurUnpWrite=0;
if ((*Password!=0) && (NewLhd.Flags & LHD_PASSWORD))
Encryption=NewLhd.UnpVer;
else
Encryption=0;
if (Encryption) SetCryptKeys(Password);
UnpPackedSize=NewLhd.PackSize;
DestUnpSize=NewLhd.UnpSize;
if (NewLhd.Method==0x30)
{
cli_dbgmsg("unrarlib: Unstore method temporarily not supported\n");
ReturnCode=FALSE;
break;
} else
{
cli_dbgmsg("unrarlib: Unpack()\n");
Unpack(UnpMemory, FileFound);
}
#ifdef _DO_CRC32_CHECK
if((UBYTE*)temp_output_buffer != NULL)
{
if(NewLhd.FileCRC!=~CalcCRC32(0xFFFFFFFFL,
(UBYTE*)temp_output_buffer,
NewLhd.UnpSize))
{
debug_log("CRC32 error - file couldn't be decompressed correctly!");
ReturnCode=FALSE;
break;
}
}
#endif
}
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
MemRARFile->offset = NextBlockPos;
#else
if (ArcPtr!=NULL) tseek(ArcPtr,NextBlockPos,SEEK_SET);
#endif
} while(stricomp(ArgName, ArcFileName) != 0);
if(UnpMemory)
free(UnpMemory);
UnpMemory=NULL;
#ifndef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
if (ArcPtr!=NULL){
fclose(ArcPtr);
lseek(desc, 0, SEEK_SET);
ArcPtr = NULL;
}
#endif
return ReturnCode;
}
int tread(void *stream,void *buf,unsigned len)
{
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
if(((MemRARFile->offset + len) > MemRARFile->size) || (len == 0))
return 0;
memcpy(buf,
(BYTE*)(((MemoryFile*)stream)->data)+((MemoryFile*)stream)->offset,
len % ((((MemoryFile*)stream)->size) - 1));
MemRARFile->offset+=len;
return len % ((((MemoryFile*)stream)->size) - 1);
#else
return(fread(buf,1,len,(FILE*)stream));
#endif
}
#ifndef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
int tseek(void *stream,long offset,int fromwhere)
{
return(fseek((FILE*)stream,offset,fromwhere));
}
#endif
static char* strupper(char *Str)
{
char *ChPtr;
for (ChPtr=Str;*ChPtr;ChPtr++)
*ChPtr=(char)toupper(*ChPtr);
return(Str);
}
int stricomp(char *Str1,char *Str2)
{
char S1[512],S2[512];
char *chptr;
strncpy(S1,Str1,sizeof(S1));
strncpy(S2,Str2,sizeof(S2));
while((chptr = strchr(S1, '\\')) != NULL)
{
*chptr = '_';
}
while((chptr = strchr(S2, '\\')) != NULL)
{
*chptr = '_';
}
while((chptr = strchr(S1, '/')) != NULL)
{
*chptr = '_';
}
while((chptr = strchr(S2, '/')) != NULL)
{
*chptr = '_';
}
return(strcmp(strupper(S1),strupper(S2)));
}
#define NC 298
#define DC 48
#define RC 28
#define BC 19
#define MC 257
enum {CODE_HUFFMAN=0,CODE_LZ=1,CODE_LZ2=2,CODE_REPEATLZ=3,CODE_CACHELZ=4,
CODE_STARTFILE=5,CODE_ENDFILE=6,CODE_STARTMM=8,CODE_ENDMM=7,
CODE_MMDELTA=9};
struct AudioVariables
{
int K1,K2,K3,K4,K5;
int D1,D2,D3,D4;
int LastDelta;
unsigned int Dif[11];
unsigned int ByteCount;
int LastChar;
};
#define NC 298
#define DC 48
#define RC 28
#define BC 19
#define MC 257
static struct AudioVariables AudV[4];
#define GetBits() \
BitField = ( ( ( (UDWORD)InBuf[InAddr] << 16 ) | \
( (UWORD) InBuf[InAddr+1] << 8 ) | \
( InBuf[InAddr+2] ) ) \
>> (8-InBit) ) & 0xffff;
#define AddBits(Bits) \
InAddr += ( InBit + (Bits) ) >> 3; \
InBit = ( InBit + (Bits) ) & 7;
static unsigned char *UnpBuf;
static unsigned int BitField;
static unsigned int Number;
static unsigned char InBuf[8192];
static unsigned char UnpOldTable[MC*4];
static unsigned int InAddr,InBit,ReadTop;
static unsigned int LastDist,LastLength;
static unsigned int Length,Distance;
static unsigned int OldDist[4],OldDistPtr;
static struct LitDecode
{
unsigned int MaxNum;
unsigned int DecodeLen[16];
unsigned int DecodePos[16];
unsigned int DecodeNum[NC];
} LD;
static struct DistDecode
{
unsigned int MaxNum;
unsigned int DecodeLen[16];
unsigned int DecodePos[16];
unsigned int DecodeNum[DC];
} DD;
static struct RepDecode
{
unsigned int MaxNum;
unsigned int DecodeLen[16];
unsigned int DecodePos[16];
unsigned int DecodeNum[RC];
} RD;
static struct MultDecode
{
unsigned int MaxNum;
unsigned int DecodeLen[16];
unsigned int DecodePos[16];
unsigned int DecodeNum[MC];
} MD[4];
static struct BitDecode
{
unsigned int MaxNum;
unsigned int DecodeLen[16];
unsigned int DecodePos[16];
unsigned int DecodeNum[BC];
} BD;
static struct MultDecode *MDPtr[4]={&MD[0],&MD[1],&MD[2],&MD[3]};
static int UnpAudioBlock,UnpChannels,CurChannel,ChannelDelta;
void Unpack(unsigned char *UnpAddr, BOOL FileFound)
{
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;
UnpBuf=UnpAddr;
UnpInitData();
UnpReadBuf(1);
if (!(NewLhd.Flags & LHD_SOLID))
ReadTables();
DestUnpSize--;
while (DestUnpSize>=0)
{
UnpPtr&=MAXWINMASK;
if (InAddr>sizeof(InBuf)-30)
UnpReadBuf(0);
if (((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr)
{
if (FileFound)
{
if (UnpPtr<WrPtr)
{
if((*temp_output_buffer_offset + ((0-WrPtr) & MAXWINMASK) + UnpPtr) > NewLhd.UnpSize)
{
debug_log("Fatal! Buffer overrun during decompression!");
DestUnpSize=-1;
} else
{
memcpy(temp_output_buffer + *temp_output_buffer_offset,
&UnpBuf[WrPtr], (0-WrPtr) & MAXWINMASK);
*temp_output_buffer_offset+= (0-WrPtr) & MAXWINMASK;
memcpy(temp_output_buffer + *temp_output_buffer_offset, UnpBuf,
UnpPtr);
*temp_output_buffer_offset+=UnpPtr;
}
} else
{
if((*temp_output_buffer_offset + (UnpPtr-WrPtr)) > NewLhd.UnpSize)
{
debug_log("Fatal! Buffer overrun during decompression!");
DestUnpSize=-1;
} else
{
memcpy(temp_output_buffer + *temp_output_buffer_offset,
&UnpBuf[WrPtr], UnpPtr-WrPtr);
*temp_output_buffer_offset+=UnpPtr-WrPtr;
}
}
}
WrPtr=UnpPtr;
}
if (UnpAudioBlock)
{
DecodeNumber((struct Decode *)MDPtr[CurChannel]);
if (Number==256)
{
ReadTables();
continue;
}
UnpBuf[UnpPtr++]=DecodeAudio(Number);
if (++CurChannel==UnpChannels)
CurChannel=0;
DestUnpSize--;
continue;
}
DecodeNumber((struct Decode *)&LD);
if (Number<256)
{
UnpBuf[UnpPtr++]=(UBYTE)Number;
DestUnpSize--;
continue;
}
if (Number>269)
{
Length=LDecode[Number-=270]+3;
if ((Bits=LBits[Number])>0)
{
GetBits();
Length+=BitField>>(16-Bits);
AddBits(Bits);
}
DecodeNumber((struct Decode *)&DD);
Distance=DDecode[Number]+1;
if ((Bits=DBits[Number])>0)
{
GetBits();
Distance+=BitField>>(16-Bits);
AddBits(Bits);
}
if (Distance>=0x40000L)
Length++;
if (Distance>=0x2000)
Length++;
LastDist=OldDist[OldDistPtr++ & 3]=Distance;
DestUnpSize-=(LastLength=Length);
while (Length--)
{
UnpBuf[UnpPtr]=UnpBuf[(UnpPtr-Distance) & MAXWINMASK];
UnpPtr=(UnpPtr+1) & MAXWINMASK;
}
continue;
}
if (Number==269)
{
ReadTables();
continue;
}
if (Number==256)
{
Length=LastLength;
Distance=LastDist;
LastDist=OldDist[OldDistPtr++ & 3]=Distance;
DestUnpSize-=(LastLength=Length);
while (Length--)
{
UnpBuf[UnpPtr]=UnpBuf[(UnpPtr-Distance) & MAXWINMASK];
UnpPtr=(UnpPtr+1) & MAXWINMASK;
}
continue;
}
if (Number<261)
{
Distance=OldDist[(OldDistPtr-(Number-256)) & 3];
DecodeNumber((struct Decode *)&RD);
Length=LDecode[Number]+2;
if ((Bits=LBits[Number])>0)
{
GetBits();
Length+=BitField>>(16-Bits);
AddBits(Bits);
}
if (Distance>=0x40000)
Length++;
if (Distance>=0x2000)
Length++;
if (Distance>=0x101)
Length++;
LastDist=OldDist[OldDistPtr++ & 3]=Distance;
DestUnpSize-=(LastLength=Length);
while (Length--)
{
UnpBuf[UnpPtr]=UnpBuf[(UnpPtr-Distance) & MAXWINMASK];
UnpPtr=(UnpPtr+1) & MAXWINMASK;
}
continue;
}
if (Number<270)
{
Distance=SDDecode[Number-=261]+1;
if ((Bits=SDBits[Number])>0)
{
GetBits();
Distance+=BitField>>(16-Bits);
AddBits(Bits);
}
Length=2;
LastDist=OldDist[OldDistPtr++ & 3]=Distance;
DestUnpSize-=(LastLength=Length);
while (Length--)
{
UnpBuf[UnpPtr]=UnpBuf[(UnpPtr-Distance) & MAXWINMASK];
UnpPtr=(UnpPtr+1) & MAXWINMASK;
}
continue;
}
}
ReadLastTables();
if (FileFound)
{
if (UnpPtr<WrPtr)
{
if((*temp_output_buffer_offset + ((0-WrPtr) & MAXWINMASK) + UnpPtr) > NewLhd.UnpSize)
{
debug_log("Fatal! Buffer overrun during decompression!");
DestUnpSize=-1;
} else
{
memcpy(temp_output_buffer + *temp_output_buffer_offset, &UnpBuf[WrPtr],
(0-WrPtr) & MAXWINMASK);
*temp_output_buffer_offset+= (0-WrPtr) & MAXWINMASK;
memcpy(temp_output_buffer + *temp_output_buffer_offset, UnpBuf, UnpPtr);
*temp_output_buffer_offset+=UnpPtr;
}
} else
{
if((*temp_output_buffer_offset + (UnpPtr-WrPtr)) > NewLhd.UnpSize)
{
debug_log("Fatal! Buffer overrun during decompression!");
DestUnpSize=-1;
} else
{
memcpy(temp_output_buffer + *temp_output_buffer_offset, &UnpBuf[WrPtr],
UnpPtr-WrPtr);
*temp_output_buffer_offset+=UnpPtr-WrPtr;
}
}
}
WrPtr=UnpPtr;
}
unsigned int UnpRead(unsigned char *Addr,unsigned int Count)
{
int RetCode=0;
unsigned int I,ReadSize,TotalRead=0;
unsigned char *ReadAddr;
ReadAddr=Addr;
while (Count > 0)
{
ReadSize=(unsigned int)((Count>(unsigned long)UnpPackedSize) ?
UnpPackedSize : Count);
#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION
cli_dbgmsg("unrarlib: UnpREAD: Using memory->memory decompression\n");
if(MemRARFile->data == NULL)
return(0);
RetCode=tread(MemRARFile, ReadAddr, ReadSize);
#else
if (ArcPtr==NULL)
return(0);
RetCode=tread(ArcPtr,ReadAddr,ReadSize);
#endif
CurUnpRead+=RetCode;
ReadAddr+=RetCode;
TotalRead+=RetCode;
Count-=RetCode;
UnpPackedSize-=RetCode;
break;
}
cli_dbgmsg("CurUnpRead == %d, TotalRead == %d, Count == %d, UnpPackedSize == %d\n", CurUnpRead, TotalRead, Count, UnpPackedSize);
if (RetCode!= -1)
{
RetCode=TotalRead;
if (Encryption)
{
if (Encryption<20)
{
cli_dbgmsg("unrarlib: Old Crypt() not supported!");
}
else
{
for (I=0;I<(unsigned int)RetCode;I+=16)
DecryptBlock(&Addr[I]);
}
}
}
return(RetCode);
}
void UnpReadBuf(int FirstBuf)
{
int RetCode;
if (FirstBuf)
{
ReadTop=UnpRead(InBuf,sizeof(InBuf));
InAddr=0;
}
else
{
memcpy(InBuf,&InBuf[sizeof(InBuf)-32],32);
InAddr&=0x1f;
RetCode=UnpRead(&InBuf[32],sizeof(InBuf)-32);
if (RetCode>0)
ReadTop=RetCode+32;
else
ReadTop=InAddr;
}
}
void ReadTables(void)
{
UBYTE BitLength[BC];
unsigned char Table[MC*4];
int TableSize,N,I;
if (InAddr>sizeof(InBuf)-25)
UnpReadBuf(0);
GetBits();
UnpAudioBlock=(BitField & 0x8000);
if (!(BitField & 0x4000))
memset(UnpOldTable,0,sizeof(UnpOldTable));
AddBits(2);
if (UnpAudioBlock)
{
UnpChannels=((BitField>>12) & 3)+1;
if (CurChannel>=UnpChannels)
CurChannel=0;
AddBits(2);
TableSize=MC*UnpChannels;
}
else
TableSize=NC+DC+RC;
for (I=0;I<BC;I++)
{
GetBits();
BitLength[I]=(UBYTE)(BitField >> 12);
AddBits(4);
}
MakeDecodeTables(BitLength,(struct Decode *)&BD,BC);
I=0;
while (I<TableSize)
{
if (InAddr>sizeof(InBuf)-5)
UnpReadBuf(0);
DecodeNumber((struct Decode *)&BD);
if (Number<16) {
Table[I]=(Number+UnpOldTable[I]) & 0xf;
I++;
}
else
if (Number==16)
{
GetBits();
N=(BitField >> 14)+3;
AddBits(2);
while (N-- > 0 && I<TableSize)
{
Table[I]=Table[I-1];
I++;
}
}
else
{
if (Number==17)
{
GetBits();
N=(BitField >> 13)+3;
AddBits(3);
}
else
{
GetBits();
N=(BitField >> 9)+11;
AddBits(7);
}
while (N-- > 0 && I<TableSize)
Table[I++]=0;
}
}
if (UnpAudioBlock)
for (I=0;I<UnpChannels;I++)
MakeDecodeTables(&Table[I*MC],(struct Decode *)MDPtr[I],MC);
else
{
MakeDecodeTables(&Table[0],(struct Decode *)&LD,NC);
MakeDecodeTables(&Table[NC],(struct Decode *)&DD,DC);
MakeDecodeTables(&Table[NC+DC],(struct Decode *)&RD,RC);
}
memcpy(UnpOldTable,Table,sizeof(UnpOldTable));
}
static void ReadLastTables(void)
{
if (ReadTop>=InAddr+5)
{
if (UnpAudioBlock)
{
DecodeNumber((struct Decode *)MDPtr[CurChannel]);
if (Number==256)
ReadTables();
}
else
{
DecodeNumber((struct Decode *)&LD);
if (Number==269)
ReadTables();
}
}
}
static void MakeDecodeTables(unsigned char *LenTab,
struct Decode *Dec,
int Size)
{
int LenCount[16],TmpPos[16],I;
long M,N;
memset(LenCount,0,sizeof(LenCount));
for (I=0;I<Size;I++)
LenCount[LenTab[I] & 0xF]++;
LenCount[0]=0;
for (TmpPos[0]=Dec->DecodePos[0]=Dec->DecodeLen[0]=0,N=0,I=1;I<16;I++)
{
N=2*(N+LenCount[I]);
M=N<<(15-I);
if (M>0xFFFF)
M=0xFFFF;
Dec->DecodeLen[I]=(unsigned int)M;
TmpPos[I]=Dec->DecodePos[I]=Dec->DecodePos[I-1]+LenCount[I-1];
}
for (I=0;I<Size;I++)
if (LenTab[I]!=0)
Dec->DecodeNum[TmpPos[LenTab[I] & 0xF]++]=I;
Dec->MaxNum=Size;
}
static void DecodeNumber(struct Decode *Deco)
{
unsigned int I;
register unsigned int N;
GetBits();
#ifdef _USE_ASM
#ifdef _WIN_32
__asm {
xor eax, eax
mov eax, BitField
and eax, 0xFFFFFFFE
mov [N], eax
mov edx, [Deco]
cmp eax, dword ptr[edx + 8*4 + 4]
jae else_G
cmp eax, dword ptr[edx + 4*4 + 4]
jae else_F
cmp eax, dword ptr[edx + 2*4 + 4]
jae else_C
cmp eax, dword ptr[edx + 1*4 + 4]
jae else_1
mov I, 1
jmp next_1
else_1:
mov I, 2
next_1:
jmp next_C
else_C:
cmp eax, dword ptr[edx + 3*4 + 4]
jae else_2
mov I, 3
jmp next_2
else_2:
mov I, 4
next_2:
next_C:
jmp next_F
else_F:
cmp eax, dword ptr[edx + 6*4 + 4]
jae else_E
cmp eax, dword ptr[edx + 5*4 + 4]
jae else_3
mov I, 5
jmp next_3
else_3:
mov I, 6
next_3:
jmp next_E
else_E:
cmp eax, dword ptr[edx + 7*4 + 4]
jae else_4
mov I, 7
jmp next_4
else_4:
mov I, 8
next_4:
next_E:
next_F:
jmp next_G
else_G:
cmp eax, dword ptr[edx + 12*4 + 4]
jae else_D
cmp eax, dword ptr[edx + 10*4 + 4]
jae else_B
cmp eax, dword ptr[edx + 9*4 + 4]
jae else_5
mov I, 9
jmp next_5
else_5:
mov I, 10
next_5:
jmp next_B
else_B:
cmp eax, dword ptr[edx + 11*4 + 4]
jae else_6
mov I, 11
jmp next_6
else_6:
mov I, 12
next_6:
next_B:
jmp next_D
else_D:
cmp eax, dword ptr[edx + 14*4 + 4]
jae else_A
cmp eax, dword ptr[edx + 13*4 + 4]
jae else_7
mov I, 13
jmp next_7
else_7:
mov I, 14
next_7:
jmp next_A
else_A:
mov I, 15
next_A:
next_D:
next_G:
}
#else
__asm__ __volatile__ (
"andl $0xFFFFFFFE, %%eax"
" movl %%eax, %1"
" cmpl 8*4(%%edx), %%eax /* 5379 */"
" jae else_G"
""
" cmpl 4*4(%%edx), %%eax"
" jae else_F"
""
" cmpl 2*4(%%edx), %%eax"
" jae else_C"
""
" cmpl 1*4(%%edx), %%eax"
""
" jae else_1"
" movl $1, %0"
" jmp next_1"
" else_1: "
" movl $2, %0"
" next_1:"
" "
" jmp next_C"
" else_C: "
""
" cmpl 3*4(%%edx), %%eax "
" jae else_2"
" movl $3, %0"
" jmp next_2"
" else_2: "
" movl $4, %0"
" next_2:"
""
" next_C: "
""
" jmp next_F"
" else_F:"
""
" cmpl 6*4(%%edx), %%eax"
" jae else_E"
""
" cmpl 5*4(%%edx), %%eax"
" jae else_3"
" movl $5, %0 "
" jmp next_3"
" else_3: "
" movl $6, %0 "
" next_3:"
""
" jmp next_E"
" else_E: "
""
" cmpl 7*4(%%edx), %%eax"
" jae else_4"
" movl $7, %0 "
" jmp next_4"
" else_4: "
" movl $8, %0 "
" next_4:"
""
" next_E:"
""
" next_F:"
""
" jmp next_G"
" else_G:"
""
" cmpl 12*4(%%edx), %%eax"
" jae else_D"
""
" cmpl 10*4(%%edx), %%eax"
" jae else_B"
""
" cmpl 9*4(%%edx), %%eax"
" jae else_5"
" movl $9, %0 "
" jmp next_5"
" else_5: "
" movl $10, %0 "
" next_5:"
""
" jmp next_B"
" else_B: "
""
" cmpl 11*4(%%edx), %%eax"
" "
" jae else_6"
" movl $11, %0 "
" jmp next_6"
" else_6: "
" movl $12, %0 "
" next_6:"
""
" next_B:"
" "
" "
" jmp next_D"
" else_D: "
""
" cmpl 14*4(%%edx), %%eax"
" jae else_A"
""
" cmpl 13*4(%%edx), %%eax"
" jae else_7"
" movl $13, %0"
" jmp next_7"
" else_7: "
" movl $14, %0"
" next_7:"
""
" jmp next_A"
" else_A: "
" movl $15, %0 "
" next_A:"
" "
" next_D: "
" next_G:"
: "=g" (I), "=r"(N)
: "eax" ((long)BitField), "edx"((long)Deco->DecodeLen)
: "memory"
);
#endif
#else
N=BitField & 0xFFFE;
if (N<Deco->DecodeLen[8]) {
if (N<Deco->DecodeLen[4]) {
if (N<Deco->DecodeLen[2]) {
if (N<Deco->DecodeLen[1])
I=1;
else
I=2;
} else {
if (N<Deco->DecodeLen[3])
I=3;
else
I=4;
}
} else {
if (N<Deco->DecodeLen[6]) {
if (N<Deco->DecodeLen[5])
I=5;
else
I=6;
} else {
if (N<Deco->DecodeLen[7])
I=7;
else
I=8;
}
}
} else {
if (N<Deco->DecodeLen[12]) {
if (N<Deco->DecodeLen[10]) {
if (N<Deco->DecodeLen[9])
I=9;
else
I=10;
} else {
if (N<Deco->DecodeLen[11])
I=11;
else
I=12;
}
} else {
if (N<Deco->DecodeLen[14]) {
if (N<Deco->DecodeLen[13])
I=13;
else
I=14;
} else {
I=15;
}
}
}
#endif
AddBits(I);
if ((N=Deco->DecodePos[I]+((N-Deco->DecodeLen[I-1])>>(16-I)))>=Deco->MaxNum)
N=0;
Number=Deco->DecodeNum[N];
}
void UnpInitData()
{
InAddr=InBit=0;
if (!(NewLhd.Flags & LHD_SOLID))
{
ChannelDelta=CurChannel=0;
#ifdef _USE_ASM
#ifdef _WIN_32
__asm {
push edi
push eax
push ecx
cld
mov al, 0x00
mov ecx, SIZE AudV
mov edi, Offset AudV
rep stosb
mov ecx, SIZE OldDist
mov edi, Offset OldDist
rep stosb
mov ecx, SIZE UnpOldTable
mov edi, Offset UnpOldTable
rep stosb
pop ecx
pop eax
pop edi
mov [OldDistPtr], 0
mov [LastDist], 0
mov [LastLength], 0
mov [UnpPtr], 0
mov [WrPtr], 0
mov [OldDistPtr], 0
mov [LastLength], 0
mov [LastDist], 0
mov [UnpPtr], 0
mov [WrPtr], 0
}
memset(UnpBuf,0,MAXWINSIZE);
#else
__asm__ __volatile (
" cld /* increment EDI and ESI */"
" movb $0x00, %%al"
" movl %0, %%ecx"
" movl %1, %%edi"
" rep "
" stosb /* clear memory */"
""
" movl %2, %%ecx"
" mov %3, %%edi"
" rep "
" stosb /* clear memory */"
""
" movl %4, %%ecx"
" movl %5, %%edi"
" rep "
" stosb /* clear memory */"
""
" movl $0, (OldDistPtr)"
" movl $0, (LastDist)"
" movl $0, (LastLength)"
" movl $0, (UnpPtr)"
" movl $0, (WrPtr)"
" movl $0, (OldDistPtr)"
" movl $0, (LastLength)"
" movl $0, (LastDist)"
" movl $0, (UnpPtr)"
" movl $0, (WrPtr)"
:
: "m" ((long)sizeof(AudV)),
"m" ((long)AudV),
"m" ((long)sizeof(OldDist)),
"m" ((long)OldDist),
"m" ((long)sizeof(UnpOldTable)),
"m" ((long)UnpOldTable)
: "memory", "edi", "eax", "ecx"
);
memset(UnpBuf,0,MAXWINSIZE);
#endif
#else
memset(AudV,0,sizeof(AudV));
memset(OldDist,0,sizeof(OldDist));
OldDistPtr=0;
LastDist=LastLength=0;
memset(UnpBuf,0,MAXWINSIZE);
memset(UnpOldTable,0,sizeof(UnpOldTable));
UnpPtr=WrPtr=0;
#endif
}
}
UBYTE DecodeAudio(int Delta)
{
struct AudioVariables *V;
unsigned int Ch;
unsigned int NumMinDif,MinDif;
int PCh,I;
V=&AudV[CurChannel];
V->ByteCount++;
V->D4=V->D3;
V->D3=V->D2;
V->D2=V->LastDelta-V->D1;
V->D1=V->LastDelta;
PCh=8*V->LastChar+V->K1*V->D1+V->K2*V->D2+
V->K3*V->D3+V->K4*V->D4+V->K5*ChannelDelta;
PCh=(PCh>>3) & 0xFF;
Ch=PCh-Delta;
I=((signed char)Delta)<<3;
V->Dif[0]+=abs(I);
V->Dif[1]+=abs(I-V->D1);
V->Dif[2]+=abs(I+V->D1);
V->Dif[3]+=abs(I-V->D2);
V->Dif[4]+=abs(I+V->D2);
V->Dif[5]+=abs(I-V->D3);
V->Dif[6]+=abs(I+V->D3);
V->Dif[7]+=abs(I-V->D4);
V->Dif[8]+=abs(I+V->D4);
V->Dif[9]+=abs(I-ChannelDelta);
V->Dif[10]+=abs(I+ChannelDelta);
ChannelDelta=V->LastDelta=(signed char)(Ch-V->LastChar);
V->LastChar=Ch;
if ((V->ByteCount & 0x1F)==0)
{
MinDif=V->Dif[0];
NumMinDif=0;
V->Dif[0]=0;
for (I=1;(unsigned int)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((UBYTE)Ch);
}
#define NROUNDS 32
#define rol(x,n) (((x)<<(n)) | ((x)>>(8*sizeof(x)-(n))))
#define ror(x,n) (((x)>>(n)) | ((x)<<(8*sizeof(x)-(n))))
#define substLong(t) ( (UDWORD)SubstTable[(int)t&255] | \
((UDWORD)SubstTable[(int)(t>> 8)&255]<< 8) | \
((UDWORD)SubstTable[(int)(t>>16)&255]<<16) | \
((UDWORD)SubstTable[(int)(t>>24)&255]<<24) )
static UDWORD CRCTab[256];
static UBYTE SubstTable[256];
static const UBYTE InitSubstTable[256]={
215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42,
232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137,
255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6,
71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235,
107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36,
158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251,
97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11,
164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51,
207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7,
122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80,
131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129,
224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10,
118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108,
161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225,
0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52,
116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84
};
static UDWORD Key[4];
static void EncryptBlock(UBYTE *Buf)
{
int I;
UDWORD A,B,C,D,T,TA,TB;
#ifdef NON_INTEL_BYTE_ORDER
A=((UDWORD)Buf[0]|((UDWORD)Buf[1]<<8)|((UDWORD)Buf[2]<<16)|
((UDWORD)Buf[3]<<24))^Key[0];
B=((UDWORD)Buf[4]|((UDWORD)Buf[5]<<8)|((UDWORD)Buf[6]<<16)|
((UDWORD)Buf[7]<<24))^Key[1];
C=((UDWORD)Buf[8]|((UDWORD)Buf[9]<<8)|((UDWORD)Buf[10]<<16)|
((UDWORD)Buf[11]<<24))^Key[2];
D=((UDWORD)Buf[12]|((UDWORD)Buf[13]<<8)|((UDWORD)Buf[14]<<16)|
((UDWORD)Buf[15]<<24))^Key[3];
#else
UDWORD *BufPtr;
BufPtr=(UDWORD *)Buf;
A=BufPtr[0]^Key[0];
B=BufPtr[1]^Key[1];
C=BufPtr[2]^Key[2];
D=BufPtr[3]^Key[3];
#endif
for(I=0;I<NROUNDS;I++)
{
T=((C+rol(D,11))^Key[I&3]);
TA=A^substLong(T);
T=((D^rol(C,17))+Key[I&3]);
TB=B^substLong(T);
A=C;
B=D;
C=TA;
D=TB;
}
#ifdef NON_INTEL_BYTE_ORDER
C^=Key[0];
Buf[0]=(UBYTE)C;
Buf[1]=(UBYTE)(C>>8);
Buf[2]=(UBYTE)(C>>16);
Buf[3]=(UBYTE)(C>>24);
D^=Key[1];
Buf[4]=(UBYTE)D;
Buf[5]=(UBYTE)(D>>8);
Buf[6]=(UBYTE)(D>>16);
Buf[7]=(UBYTE)(D>>24);
A^=Key[2];
Buf[8]=(UBYTE)A;
Buf[9]=(UBYTE)(A>>8);
Buf[10]=(UBYTE)(A>>16);
Buf[11]=(UBYTE)(A>>24);
B^=Key[3];
Buf[12]=(UBYTE)B;
Buf[13]=(UBYTE)(B>>8);
Buf[14]=(UBYTE)(B>>16);
Buf[15]=(UBYTE)(B>>24);
#else
BufPtr[0]=C^Key[0];
BufPtr[1]=D^Key[1];
BufPtr[2]=A^Key[2];
BufPtr[3]=B^Key[3];
#endif
UpdKeys(Buf);
}
void DecryptBlock(UBYTE *Buf)
{
int I;
UBYTE InBuf[16];
UDWORD A,B,C,D,T,TA,TB;
#ifdef NON_INTEL_BYTE_ORDER
A=((UDWORD)Buf[0]|((UDWORD)Buf[1]<<8)|((UDWORD)Buf[2]<<16)|
((UDWORD)Buf[3]<<24))^Key[0];
B=((UDWORD)Buf[4]|((UDWORD)Buf[5]<<8)|((UDWORD)Buf[6]<<16)|
((UDWORD)Buf[7]<<24))^Key[1];
C=((UDWORD)Buf[8]|((UDWORD)Buf[9]<<8)|((UDWORD)Buf[10]<<16)|
((UDWORD)Buf[11]<<24))^Key[2];
D=((UDWORD)Buf[12]|((UDWORD)Buf[13]<<8)|((UDWORD)Buf[14]<<16)|
((UDWORD)Buf[15]<<24))^Key[3];
#else
UDWORD *BufPtr;
BufPtr=(UDWORD *)Buf;
A=BufPtr[0]^Key[0];
B=BufPtr[1]^Key[1];
C=BufPtr[2]^Key[2];
D=BufPtr[3]^Key[3];
#endif
memcpy(InBuf,Buf,sizeof(InBuf));
for(I=NROUNDS-1;I>=0;I--)
{
T=((C+rol(D,11))^Key[I&3]);
TA=A^substLong(T);
T=((D^rol(C,17))+Key[I&3]);
TB=B^substLong(T);
A=C;
B=D;
C=TA;
D=TB;
}
#ifdef NON_INTEL_BYTE_ORDER
C^=Key[0];
Buf[0]=(UBYTE)C;
Buf[1]=(UBYTE)(C>>8);
Buf[2]=(UBYTE)(C>>16);
Buf[3]=(UBYTE)(C>>24);
D^=Key[1];
Buf[4]=(UBYTE)D;
Buf[5]=(UBYTE)(D>>8);
Buf[6]=(UBYTE)(D>>16);
Buf[7]=(UBYTE)(D>>24);
A^=Key[2];
Buf[8]=(UBYTE)A;
Buf[9]=(UBYTE)(A>>8);
Buf[10]=(UBYTE)(A>>16);
Buf[11]=(UBYTE)(A>>24);
B^=Key[3];
Buf[12]=(UBYTE)B;
Buf[13]=(UBYTE)(B>>8);
Buf[14]=(UBYTE)(B>>16);
Buf[15]=(UBYTE)(B>>24);
#else
BufPtr[0]=C^Key[0];
BufPtr[1]=D^Key[1];
BufPtr[2]=A^Key[2];
BufPtr[3]=B^Key[3];
#endif
UpdKeys(InBuf);
}
void UpdKeys(UBYTE *Buf)
{
int I;
for (I=0;I<16;I+=4)
{
Key[0]^=CRCTab[Buf[I]];
Key[1]^=CRCTab[Buf[I+1]];
Key[2]^=CRCTab[Buf[I+2]];
Key[3]^=CRCTab[Buf[I+3]];
}
}
static void SetCryptKeys(char *NewPassword)
{
unsigned int I,J,K,PswLength;
unsigned char N1,N2;
unsigned char Psw[256];
#if !defined _USE_ASM
UBYTE Ch;
#endif
SetOldKeys(NewPassword);
Key[0]=0xD3A3B879L;
Key[1]=0x3F6D12F7L;
Key[2]=0x7515A235L;
Key[3]=0xA4E7F123L;
memset(Psw,0,sizeof(Psw));
strcpy((char *)Psw,NewPassword);
PswLength=strlen(NewPassword);
memcpy(SubstTable,InitSubstTable,sizeof(SubstTable));
for (J=0;J<256;J++)
for (I=0;I<PswLength;I+=2)
{
N2=(unsigned char)CRCTab[(Psw[I+1]+J)&0xFF];
for (K=1, N1=(unsigned char)CRCTab[(Psw[I]-J)&0xFF];
(N1!=N2);
N1++, K++)
{
#ifdef _USE_ASM
#ifdef _WIN_32
__asm {
mov ebx, Offset SubstTable
mov edx, ebx
xor ecx, ecx
mov cl, N1
add ebx, ecx
mov al, byte ptr[ebx]
mov cl, N1
add ecx, I
add ecx, K
and ecx, 0xFF
add edx, ecx
mov ah, byte ptr[edx]
mov byte ptr[ebx], ah
mov byte ptr[edx], al
}
#else
__asm__ __volatile__ (
" xorl %%ecx, %%ecx"
" movl %2, %%ecx /* ecx = N1 */"
" mov %%ebx, %%edx"
" addl %%ecx, %%ebx"
""
" addl %0, %%ecx"
" addl %1, %%ecx"
" andl $0x000000FF, %%ecx"
" addl %%ecx, %%edx"
" "
" movb (%%ebx), %%al"
" movb (%%edx), %%ah"
""
" movb %%ah, (%%ebx) /* and write back */"
" movb %%al, (%%edx)"
: : "g" ((long)I),
"g" ((long)K),
"g" ((long)N1),
"ebx"((long)SubstTable)
: "ecx", "edx"
);
#endif
#else
Ch=SubstTable[N1];
SubstTable[N1]=SubstTable[(N1+I+K)&0xFF];
SubstTable[(N1+I+K)&0xFF]=Ch;
#endif
}
}
for (I=0;I<PswLength;I+=16)
EncryptBlock(&Psw[I]);
}
void SetOldKeys(char *NewPassword)
{
UDWORD PswCRC;
UBYTE Ch;
PswCRC=CalcCRC32(0xFFFFFFFFL,(UBYTE*)NewPassword,strlen(NewPassword));
OldKey[0]=(UWORD)PswCRC;
OldKey[1]=(UWORD)(PswCRC>>16);
OldKey[2]=OldKey[3]=0;
PN1=PN2=PN3=0;
while ((Ch=*NewPassword)!=0)
{
PN1+=Ch;
PN2^=Ch;
PN3+=Ch;
PN3=(UBYTE)rol(PN3,1);
OldKey[2]^=((UWORD)(Ch^CRCTab[Ch]));
OldKey[3]+=((UWORD)(Ch+(CRCTab[Ch]>>16)));
NewPassword++;
}
}
static short crcInitialized = 0;
void InitCRC(void)
{
int I, J;
UDWORD C;
if (crcInitialized) return;
cli_dbgmsg("%s:%d:%s Initialize CRC table\n", __FILE__, __LINE__, "InitCRC");
for (I=0;I<256;I++)
{
for (C=I,J=0;J<8;J++)
C=(C & 1) ? (C>>1)^0xEDB88320L : (C>>1);
CRCTab[I]=C;
}
crcInitialized = 1;
}
static UDWORD CalcCRC32(UDWORD StartCRC,UBYTE *Addr,UDWORD Size)
{
unsigned int I;
for (I=0; I<Size; I++)
StartCRC = CRCTab[(UBYTE)StartCRC ^ Addr[I]] ^ (StartCRC >> 8);
return(StartCRC);
}
#ifdef _DEBUG_LOG
char log_file_name[256];
DWORD debug_start_time;
BOOL debug_started = FALSE;
void debug_init_proc(char *file_name)
{
FILE *fp;
char date[] = __DATE__;
char time[] = __TIME__;
debug_start_time = GetTickCount();
strcpy(log_file_name, file_name);
if((fp = fopen(log_file_name, CREATETEXT)) != NULL)
{
debug_started = TRUE;
fprintf(fp, "Debug log of UniquE's RARFileLib\n"\
"~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~\n");
fprintf(fp, "(executable compiled on %s at %s)\n\n", date, time);
fclose(fp);
}
}
void debug_log_proc(char *text, char *sourcefile, int sourceline)
{
FILE *fp;
if(debug_started == FALSE) return;
if((fp = fopen(log_file_name, APPENDTEXT)) != NULL)
{
fprintf(fp, " %8u ms (line %u in %s):\n - %s\n",
(unsigned int)(GetTickCount() - debug_start_time),
sourceline, sourcefile, text);
fclose(fp);
}
}
#endif