From 1637590528c8dc789fbab5456951f9d3b5627e1e Mon Sep 17 00:00:00 2001 From: kmkaplan Date: Fri, 20 Sep 2002 01:26:39 +0000 Subject: Automatic unrar of vobsub. Does not work with rar v3 git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@7447 b3059339-0415-0410-9bf9-f77b7e298cf2 --- Makefile | 4 + configure | 16 + unrarlib.c | 2716 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ unrarlib.h | 200 +++++ vobsub.c | 243 +++++- 5 files changed, 3138 insertions(+), 41 deletions(-) create mode 100644 unrarlib.c create mode 100644 unrarlib.h diff --git a/Makefile b/Makefile index a0d3fad226..5475b51c9a 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,10 @@ ifeq ($(GUI),yes) PARTS += Gui endif +ifeq ($(UNRARLIB),yes) +SRCS_COMMON += unrarlib.c +endif + ifneq ($(W32_LIB),) PARTS += loader loader/dshow endif diff --git a/configure b/configure index 8905593f09..17ff00ce91 100755 --- a/configure +++ b/configure @@ -149,6 +149,7 @@ Optional features: --disable-css Disable old-style libcss DVD support [autodetect] --disable-cdparanoia Disable cdparanoia support [autodetect] --enable-freetype Enable freetype2 font rendering support [disabled] + --disable-unrarlib Disable Unique RAR File Library [enabled] Codecs: --enable-gif enable gif89a output support [autodetect] @@ -965,6 +966,7 @@ _sgiaudio=auto _sunaudio=auto _alsa=auto _fastmemcpy=yes +_unrarlib=yes _win32=auto _dshow=yes _select=yes @@ -1159,6 +1161,8 @@ for ac_option do --disable-big-endian) _big_endian=no ;; --enable-freetype) _freetype=yes ;; --disable-freetype) _freetype=no ;; + --enable-unralib) _unrarlib=yes ;; + --disable-unrarlib) _unrarlib=no ;; --enable-dga) _dga=auto ;; # as we don't know if it's 1 or 2 --enable-dga=*) _dga=`echo $ac_option | cut -d '=' -f 2` ;; @@ -3960,6 +3964,13 @@ else fi echores "$_fastmemcpy" +echocheck "UniquE RAR File Library" +if test "$_unrarlib" = yes ; then + _def_unrarlib='#define USE_UNRARLIB 1' +else + _def_unrarlib='#undef USE_UNRARLIB' +fi +echores "$_unrarlib" echocheck "TV interface" if test "$_tv" = yes ; then @@ -4343,6 +4354,8 @@ VIDIX = $_vidix OPENDIVX = $_opendivx +UNRARLIB = $_unrarlib + PNG = $_mkf_png JPEG = $_mkf_jpg GIF = $_mkf_gif @@ -4659,6 +4672,9 @@ $_def_live /* Use 3dnow/mmxext/sse/mmx optimized fast memcpy() [maybe buggy... signal 4]*/ $_def_fastmemcpy +/* Use unrarlib for Vobsubs */ +$_def_unrarlib + /* gui support, please do not edit this option */ $_def_gui diff --git a/unrarlib.c b/unrarlib.c new file mode 100644 index 0000000000..48bece58e0 --- /dev/null +++ b/unrarlib.c @@ -0,0 +1,2716 @@ +/* *************************************************************************** + ** + ** This file is part of the UniquE RAR File Library. + ** + ** Copyright (C) 2000-2002 by Christian Scheurer (www.ChristianScheurer.ch) + ** UNIX port copyright (c) 2000-2002 by Johannes Winkelmann (jw@tks6.net) + ** + ** The contents of this file are subject to the UniquE RAR File Library + ** License (the "unrarlib-license.txt"). You may not use this file except + ** in compliance with the License. You may obtain a copy of the License + ** at http://www.unrarlib.org/license.html. + ** Software distributed under the License is distributed on an "AS IS" + ** basis, WITHOUT WARRANTY OF ANY KIND, either express or implied warranty. + ** + ** Alternatively, the contents of this file may be used under the terms + ** of the GNU General Public License Version 2 or later (the "GPL"), in + ** which case the provisions of the GPL are applicable instead of those + ** above. If you wish to allow use of your version of this file only + ** under the terms of the GPL and not to allow others to use your version + ** of this file under the terms of the UniquE RAR File Library License, + ** indicate your decision by deleting the provisions above and replace + ** them with the notice and other provisions required by the GPL. If you + ** do not delete the provisions above, a recipient may use your version + ** of this file under the terms of the GPL or the UniquE RAR File Library + ** License. + ** + ************************************************************************** */ + +/* *************************************************************************** + ** + ** UniquE RAR File Library + ** The free file lib for the demoscene + ** multi-OS version (Win32, Linux and SunOS) + ** + ***************************************************************************** + ** + ** ==> Please configure the program in "unrarlib.h". <== + ** + ** RAR decompression code: + ** (C) Eugene Roshal + ** Modifications to a FileLib: + ** (C) 2000-2002 Christian Scheurer aka. UniquE/Vantage (cs@unrarlib.org) + ** Linux port: + ** (C) 2000-2002 Johannes Winkelmann (jw@tks6.net) + ** + ** The UniquE RAR File Library gives you the ability to access RAR archives + ** (any compression method supported in RAR v2.0 including Multimedia + ** Compression and encryption) directly from your program with ease an by + ** adding only 12kB (6kB UPX-compressed) additional code to your program. + ** Both solid and normal (recommended for fast random access to the files!) + ** archives are supported. This FileLib is made for the Demo scene, so it's + ** designed for easy use within your demos and intros. + ** Please read "licence.txt" to learn more about how you may use URARFileLib + ** in your productions. + ** + ***************************************************************************** + ** + ** ==> see the "CHANGES" file to see what's new + ** + ************************************************************************** */ + +/* -- include files ------------------------------------------------------- */ +#include "unrarlib.h" /* include global configuration */ +/* ------------------------------------------------------------------------ */ + + + +/* -- global stuff -------------------------------------------------------- */ +#ifdef _WIN_32 + +#include /* WIN32 definitions */ +#include +#include + + +#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 /* LINUX/UNIX definitions */ +#include +#include +#include + +#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" + + +/* emulation of the windows API and data types */ +/* 20-08-2000 Johannes Winkelmann, jw@tks6.net */ + +typedef long DWORD; +typedef short BOOL; +#define TRUE 1 +#define FALSE 0 + + +#ifdef _DEBUG_LOG /* define macros for debugging */ +#include +#include + +DWORD GetTickCount() +{ + struct timeval tv; + gettimeofday( &tv, 0 ); + return (tv.tv_usec / 1000); +} +#endif + +#endif + + + + + +#ifdef _DEBUG_LOG /* define macros for debugging */ + +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); /* no debug this time */ +#define debug_init(a); /* no debug this time */ +#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 /* version of decompression code*/ +#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]; +}; + + +struct MarkHeader MarkHead; +struct NewMainArchiveHeader NewMhd; +struct NewFileHeader NewLhd; +struct BlockHeader BlockHead; + +UBYTE *TempMemory; /* temporary unpack-buffer */ +char *CommMemory; + + +UBYTE *UnpMemory; +char ArgName[NM]; /* current file in rar archive */ +char ArcFileName[NM]; /* file to decompress */ + +#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION /* mem-to-mem decompression */ + MemoryFile *MemRARFile; /* pointer to RAR file in memory*/ +#else + char ArcName[255]; /* RAR archive name */ + FILE *ArcPtr; /* input RAR file handler */ +#endif +char Password[255]; /* password to decrypt files */ + +unsigned char *temp_output_buffer; /* extract files to this pointer*/ +unsigned long *temp_output_buffer_offset; /* size of temp. extract buffer */ + +BOOL FileFound; /* TRUE=use current extracted */ + /* data FALSE=throw data away, */ + /* wrong file */ +int MainHeadSize; +long CurBlockPos,NextBlockPos; + +unsigned long CurUnpRead, CurUnpWrite; +long UnpPackedSize; +long DestUnpSize; + +UDWORD HeaderCRC; +int Encryption; + +unsigned int UnpWrSize; +unsigned char *UnpWrAddr; +unsigned int UnpPtr,WrPtr; + +unsigned char PN1,PN2,PN3; +unsigned short OldKey[4]; + + + +/* function header definitions */ +int ReadHeader(int BlockType); +BOOL ExtrFile(void); +BOOL ListFile(void); +int tread(void *stream,void *buf,unsigned len); +int tseek(void *stream,long offset,int fromwhere); +BOOL UnstoreFile(void); +int IsArchive(void); +int ReadBlock(int BlockType); +unsigned int UnpRead(unsigned char *Addr,unsigned int Count); +void UnpInitData(void); +void Unpack(unsigned char *UnpAddr); +UBYTE DecodeAudio(int Delta); +static void DecodeNumber(struct Decode *Dec); +void UpdKeys(UBYTE *Buf); +void SetCryptKeys(char *Password); +void SetOldKeys(char *Password); +void DecryptBlock(unsigned char *Buf); +void InitCRC(void); +UDWORD CalcCRC32(UDWORD StartCRC,UBYTE *Addr,UDWORD Size); +void UnpReadBuf(int FirstBuf); +void ReadTables(void); +static void ReadLastTables(void); +static void MakeDecodeTables(unsigned char *LenTab, + struct Decode *Dec, + int Size); +int stricomp(char *Str1,char *Str2); +/* ------------------------------------------------------------------------ */ + + +/* -- global functions ---------------------------------------------------- */ + +int urarlib_get(void *output, + unsigned long *size, + char *filename, + void *rarfile, + char *libpassword) +/* Get a file from a RAR file to the "output" buffer. The UniquE RAR FileLib + * does everything from allocating memory, decrypting and unpacking the file + * from the archive. TRUE is returned if the file could be successfully + * extracted, else a FALSE indicates a failure. + */ +{ + BOOL retcode = FALSE; + +#ifdef _DEBUG_LOG + int str_offs; /* used for debug-strings */ + char DebugMsg[500]; /* used to compose debug msg */ + + if(debug_log_first_start) + { + debug_log_first_start=FALSE; /* only create a new log file */ + debug_init(_DEBUG_LOG_FILE); /* on startup */ + } + +#endif + + InitCRC(); /* init some vars */ + + strcpy(ArgName, filename); /* set file(s) to extract */ +#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION + MemRARFile = rarfile; /* set pointer to mem-RAR file */ +#else + strcpy(ArcName, rarfile); /* set RAR file name */ +#endif + if(libpassword != NULL) + strcpy(Password, libpassword); /* init password */ + + temp_output_buffer = NULL; + temp_output_buffer_offset=size; /* set size of the temp buffer */ + +#ifdef _DEBUG_LOG + sprintf(DebugMsg, "Extracting >%s< from >%s< (password is >%s<)...", + filename, (char*)rarfile, libpassword); + debug_log(DebugMsg); +#endif + + retcode = ExtrFile(); /* unpack file now! */ + + memset(Password,0,sizeof(Password)); /* clear password */ + +#ifndef _USE_MEMORY_TO_MEMORY_DECOMPRESSION + if (ArcPtr!=NULL){ + fclose(ArcPtr); + ArcPtr = NULL; + } +#endif + + free(UnpMemory); /* free memory */ + free(TempMemory); + free(CommMemory); + UnpMemory=NULL; + TempMemory=NULL; + CommMemory=NULL; + + + if(retcode == FALSE) + { + free(temp_output_buffer); /* free memory and return NULL */ + temp_output_buffer=NULL; + *(DWORD*)output=0; /* pointer on errors */ + *size=0; +#ifdef _DEBUG_LOG + + + /* sorry for this ugly code, but older SunOS gcc compilers don't support */ + /* white spaces within strings */ + 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 pointer for unpacked*/ + /* data */ + + return retcode; +} + + +int urarlib_list(void *rarfile, ArchiveList_struct *list) +{ + ArchiveList_struct *tmp_List = NULL; + int NoOfFilesInArchive = 0; /* number of files in archive */ + +#ifdef _DEBUG_LOG + if(debug_log_first_start) + { + debug_log_first_start=FALSE; /* only create a new log file */ + debug_init(_DEBUG_LOG_FILE); /* on startup */ + } +#endif + + InitCRC(); /* init some vars */ + +#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION + MemRARFile = rarfile; /* assign pointer to RAR file */ + MemRARFile->offset = 0; + if (!IsArchive()) + { + debug_log("Not a RAR file"); + return NoOfFilesInArchive; /* error => exit! */ + } +#else + /* open and identify archive */ + if ((ArcPtr=fopen(rarfile,READBINARY))!=NULL) + { + if (!IsArchive()) + { + debug_log("Not a RAR file"); + fclose(ArcPtr); + ArcPtr = NULL; + return NoOfFilesInArchive; /* error => exit! */ + } + } + else { + debug_log("Error opening file."); + return NoOfFilesInArchive; + } +#endif + + if ((UnpMemory=malloc(UNP_MEMORY))==NULL) + { + debug_log("Can't allocate memory for decompression!"); + 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; /* init file list */ + /* do while file is not extracted and there's no error */ + while (TRUE) + { + if (ReadBlock(FILE_HEAD | READSUBBLOCK) <= 0) /* read name of the next */ + { /* file within the RAR archive */ + debug_log("Couldn't read next filename from archive (I/O error)."); + break; /* error, file not found in */ + } /* archive or I/O error */ + if (BlockHead.HeadType==SUB_HEAD) + { + debug_log("Sorry, sub-headers not supported."); + break; /* error => exit */ + } + + if((void*)(*(DWORD*)list) == NULL) /* first entry */ + { + tmp_List = malloc(sizeof(ArchiveList_struct)); + tmp_List->next = NULL; + + (*(DWORD*)list) = (DWORD)tmp_List; + + } else /* add entry */ + { + 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; + + NoOfFilesInArchive++; /* count files */ + +#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION + MemRARFile->offset = NextBlockPos; +#else + if (ArcPtr!=NULL) tseek(ArcPtr,NextBlockPos,SEEK_SET); +#endif + + }; + + /* free memory, clear password and close archive */ + memset(Password,0,sizeof(Password)); /* clear password */ +#ifndef _USE_MEMORY_TO_MEMORY_DECOMPRESSION + if (ArcPtr!=NULL){ + fclose(ArcPtr); + ArcPtr = NULL; + } +#endif + + free(UnpMemory); /* free memory */ + free(TempMemory); + free(CommMemory); + UnpMemory=NULL; + TempMemory=NULL; + CommMemory=NULL; + + return NoOfFilesInArchive; +} + + + +/* urarlib_freelist: + * (after the suggestion and code of Duy Nguyen, Sean O'Blarney + * and Johannes Winkelmann who independently wrote a patch) + * free the memory of a ArchiveList_struct created by urarlib_list. + * + * input: *list pointer to an ArchiveList_struct + * output: - + */ + +void urarlib_freelist(ArchiveList_struct *list) +{ + ArchiveList_struct* tmp = list; + + while ( list ) { + tmp = list->next; + free( list->item.Name ); + free( list ); + list = tmp; + } +} + + +/* ------------------------------------------------------------------------ */ + + + + + + + + + + + + + + + + + +/**************************************************************************** + **************************************************************************** + **************************************************************************** + **************************************************************************** + ******* ******* + ******* ******* + ******* ******* + ******* B L O C K I / O ******* + ******* ******* + ******* ******* + ******* ******* + **************************************************************************** + **************************************************************************** + **************************************************************************** + ****************************************************************************/ + + + +#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; /* get offset of mem-file */ +#else + CurBlockPos=ftell(ArcPtr); +#endif + Size=ReadHeader(FILE_HEAD); + if (Size!=0) + { + if (NewLhd.HeadSize 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]; + 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: /* log errors in case of debug */ + 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: /* else do nothing */ + break; +#endif + } + return(Size); +} + +/* ************************************************************************** + **************************************************************************** + **************************************************************************** + ************************************************************************** */ + + + + + + + + + + + + + + + + + +/* ************************************************************************** + **************************************************************************** + **************************************************************************** + **************************************************************************** + ******* ******* + ******* ******* + ******* ******* + ******* E X T R A C T L O O P ******* + ******* ******* + ******* ******* + ******* ******* + **************************************************************************** + **************************************************************************** + **************************************************************************** + ************************************************************************** */ + + +int IsArchive(void) +{ +#ifdef _DEBUG_LOG + int str_offs; /* used for debug-strings */ + char DebugMsg[500]; /* used to compose debug msg */ +#endif + +#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION + if (tread(MemRARFile, MarkHead.Mark, SIZEOF_MARKHEAD) != SIZEOF_MARKHEAD) + return(FALSE); +#else + if (tread(ArcPtr,MarkHead.Mark,SIZEOF_MARKHEAD)!=SIZEOF_MARKHEAD) + return(FALSE); +#endif + /* Old archive => error */ + 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 handel archive!"); + } + else + /* original RAR v2.0 */ + if ((MarkHead.Mark[0]==0x52 && MarkHead.Mark[1]==0x61 && /* original */ + MarkHead.Mark[2]==0x72 && MarkHead.Mark[3]==0x21 && /* RAR header*/ + MarkHead.Mark[4]==0x1a && MarkHead.Mark[5]==0x07 && + MarkHead.Mark[6]==0x00) || + /* "UniquE!" - header */ + (MarkHead.Mark[0]=='U' && MarkHead.Mark[1]=='n' && /* "UniquE!" */ + MarkHead.Mark[2]=='i' && MarkHead.Mark[3]=='q' && /* header */ + MarkHead.Mark[4]=='u' && MarkHead.Mark[5]=='E' && + MarkHead.Mark[6]=='!')) + + { + if (ReadHeader(MAIN_HEAD)!=SIZEOF_NEWMHD) + return(FALSE); + } else + { + +#ifdef _DEBUG_LOG + /* sorry for this ugly code, but older SunOS gcc compilers don't */ + /* support white spaces within strings */ + 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(void) +{ + BOOL ReturnCode=TRUE; + FileFound=FALSE; /* no file found by default */ + +#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION + MemRARFile->offset = 0; /* start reading from offset 0 */ + if (!IsArchive()) + { + debug_log("Not a RAR file"); + return FALSE; /* error => exit! */ + } + +#else + /* open and identify archive */ + if ((ArcPtr=fopen(ArcName,READBINARY))!=NULL) + { + if (!IsArchive()) + { + debug_log("Not a RAR file"); + fclose(ArcPtr); + ArcPtr = NULL; + return FALSE; /* error => exit! */ + } + } else + { + debug_log("Error opening file."); + return FALSE; + } +#endif + + + if ((UnpMemory=malloc(UNP_MEMORY))==NULL) + { + debug_log("Can't allocate memory for decompression!"); + return FALSE; + } + +#ifdef _USE_MEMORY_TO_MEMORY_DECOMPRESSION + MemRARFile->offset+=NewMhd.HeadSize-MainHeadSize; +#else + tseek(ArcPtr,NewMhd.HeadSize-MainHeadSize,SEEK_CUR); +#endif + + /* do while file is not extracted and there's no error */ + do + { + + if (ReadBlock(FILE_HEAD | READSUBBLOCK) <= 0) /* read name of the next */ + { /* file within the RAR archive */ +/* + * + * 21.11.2000 UnQ There's a problem with some linux distros when a file + * can not be found in an archive. + * + * debug_log("Couldn't read next filename from archive (I/O error)."); + * +*/ + ReturnCode=FALSE; + break; /* error, file not found in */ + } /* archive or I/O error */ + if (BlockHead.HeadType==SUB_HEAD) + { + debug_log("Sorry, sub-headers not supported."); + ReturnCode=FALSE; + break; /* error => exit */ + } + + + if(TRUE == (FileFound=(stricomp(ArgName, ArcFileName) == 0))) + /* *** file found! *** */ + { + { + temp_output_buffer=malloc(NewLhd.UnpSize);/* allocate memory for the*/ + } + *temp_output_buffer_offset=0; /* file. The default offset */ + /* within the buffer is 0 */ + + if(temp_output_buffer == NULL) + { + debug_log("can't allocate memory for the file decompression"); + ReturnCode=FALSE; + break; /* error, can't extract file! */ + } + + + } + + /* in case of a solid archive, we need to decompress any single file till + * we have found the one we are looking for. In case of normal archives + * (recommended!!), we skip the files until we are sure that it is the + * one we want. + */ + if((NewMhd.Flags & 0x08) || FileFound) + { + if (NewLhd.UnpVer<13 || NewLhd.UnpVer>UNP_VER) + { + debug_log("unknown compression method"); + ReturnCode=FALSE; + break; /* error, can't extract file! */ + } + + 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) + { + UnstoreFile(); + } else + { + Unpack(UnpMemory); + } + + + +#ifdef _DO_CRC32_CHECK /* calculate CRC32 */ + 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; /* error, can't extract file! */ + } + } +#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);/* exit if file is extracted */ + + /* free memory, clear password and close archive */ + free(UnpMemory); + UnpMemory=NULL; +#ifndef _USE_MEMORY_TO_MEMORY_DECOMPRESSION + if (ArcPtr!=NULL){ + fclose(ArcPtr); + ArcPtr = NULL; + } +#endif + + return ReturnCode; /* file extracted successful! */ +} + +/* ************************************************************************** + **************************************************************************** + **************************************************************************** + ************************************************************************** */ + + + + + + + + + + + + + + + + + + +/* ************************************************************************** + **************************************************************************** + **************************************************************************** + **************************************************************************** + ******* ******* + ******* ******* + ******* ******* + ******* G L O B A L F U N C T I O N S ******* + ******* ******* + ******* ******* + ******* ******* + **************************************************************************** + **************************************************************************** + **************************************************************************** + ************************************************************************** */ + + +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; /* update read pointer */ + 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 + + +char* strupper(char *Str) +{ + char *ChPtr; + for (ChPtr=Str;*ChPtr;ChPtr++) + *ChPtr=(char)toupper(*ChPtr); + return(Str); +} + + +int stricomp(char *Str1,char *Str2) +/* compare strings without regard of '\' and '/' */ +{ + char S1[512],S2[512]; + char *chptr; + + strncpy(S1,Str1,sizeof(S1)); + strncpy(S2,Str2,sizeof(S2)); + + while((chptr = strchr(S1, '\\')) != NULL) /* ignore backslash */ + { + *chptr = '_'; + } + + while((chptr = strchr(S2, '\\')) != NULL) /* ignore backslash */ + { + *chptr = '_'; + } + + while((chptr = strchr(S1, '/')) != NULL) /* ignore slash */ + { + *chptr = '_'; + } + + while((chptr = strchr(S2, '/')) != NULL) /* ignore slash */ + { + *chptr = '_'; + } + + return(strcmp(strupper(S1),strupper(S2))); +} + + +/* ************************************************************************** + **************************************************************************** + **************************************************************************** + ************************************************************************** */ + + + + + + + + + + + + + + + + + + +/* ************************************************************************** + **************************************************************************** + **************************************************************************** + **************************************************************************** + ******* ******* + ******* ******* + ******* ******* + ******* U N P A C K C O D E ******* + ******* ******* + ******* ******* + ******* ******* + **************************************************************************** + **************************************************************************** + **************************************************************************** + ************************************************************************** */ + + +/* ***************************** + * ** unpack stored RAR files ** + * *****************************/ + +BOOL UnstoreFile(void) +{ + if ((long)(*temp_output_buffer_offset=UnpRead(temp_output_buffer, + NewLhd.UnpSize))==-1) + { + debug_log("Read error of stored file!"); + return FALSE; + } + return TRUE; +} + + + + +/* **************************************** + * ** RAR decompression code starts here ** + * ****************************************/ + +#define NC 298 /* alphabet = {0,1,2, .,NC - 1} */ +#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 /* alphabet = {0, 1, 2, ..., NC - 1} */ +#define DC 48 +#define RC 28 +#define BC 19 +#define MC 257 + + +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; + +unsigned char InBuf[8192]; /* input read buffer */ + +unsigned char UnpOldTable[MC*4]; + +unsigned int InAddr,InBit,ReadTop; + +unsigned int LastDist,LastLength; +static unsigned int Length,Distance; + +unsigned int OldDist[4],OldDistPtr; + + +struct LitDecode +{ + unsigned int MaxNum; + unsigned int DecodeLen[16]; + unsigned int DecodePos[16]; + unsigned int DecodeNum[NC]; +} LD; + +struct DistDecode +{ + unsigned int MaxNum; + unsigned int DecodeLen[16]; + unsigned int DecodePos[16]; + unsigned int DecodeNum[DC]; +} DD; + +struct RepDecode +{ + unsigned int MaxNum; + unsigned int DecodeLen[16]; + unsigned int DecodePos[16]; + unsigned int DecodeNum[RC]; +} RD; + +struct MultDecode +{ + unsigned int MaxNum; + unsigned int DecodeLen[16]; + unsigned int DecodePos[16]; + unsigned int DecodeNum[MC]; +} MD[4]; + +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]}; + +int UnpAudioBlock,UnpChannels,CurChannel,ChannelDelta; + + +void Unpack(unsigned char *UnpAddr) +/* *** 38.3% of all CPU time is spent within this function!!! */ +{ + 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; /* UnpAddr is a pointer to the */ + UnpInitData(); /* unpack buffer */ + 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 NewLhd.UnpSize) + { + debug_log("Fatal! Buffer overrun during decompression!"); + DestUnpSize=-1; + + } else + { + /* copy extracted data to output buffer */ + memcpy(temp_output_buffer + *temp_output_buffer_offset, + &UnpBuf[WrPtr], (0-WrPtr) & MAXWINMASK); + /* update offset within buffer */ + *temp_output_buffer_offset+= (0-WrPtr) & MAXWINMASK; + /* copy extracted data to output buffer */ + memcpy(temp_output_buffer + *temp_output_buffer_offset, UnpBuf, + UnpPtr); + /* update offset within buffer */ + *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 + { + /* copy extracted data to output buffer */ + memcpy(temp_output_buffer + *temp_output_buffer_offset, + &UnpBuf[WrPtr], UnpPtr-WrPtr); + *temp_output_buffer_offset+=UnpPtr-WrPtr; /* update offset within buffer */ + } + + } + } + + 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) /* flush buffer */ + { + + if (UnpPtr NewLhd.UnpSize) + { + debug_log("Fatal! Buffer overrun during decompression!"); + DestUnpSize=-1; + } else + { + /* copy extracted data to output buffer */ + memcpy(temp_output_buffer + *temp_output_buffer_offset, &UnpBuf[WrPtr], + (0-WrPtr) & MAXWINMASK); + /* update offset within buffer */ + *temp_output_buffer_offset+= (0-WrPtr) & MAXWINMASK; + /* copy extracted data to output buffer */ + memcpy(temp_output_buffer + *temp_output_buffer_offset, UnpBuf, UnpPtr); + /* update offset within buffer */ + *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 + { + /* copy extracted data to output buffer */ + memcpy(temp_output_buffer + *temp_output_buffer_offset, &UnpBuf[WrPtr], + UnpPtr-WrPtr); + /* update offset within buffer */ + *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 + 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; + } + if (RetCode!= -1) + { + RetCode=TotalRead; + if (Encryption) + { + if (Encryption<20) + { + debug_log("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> 12); + AddBits(4); + } + MakeDecodeTables(BitLength,(struct Decode *)&BD,BC); + I=0; + while (Isizeof(InBuf)-5) + UnpReadBuf(0); + DecodeNumber((struct Decode *)&BD); + if (Number<16) + Table[I++]=(Number+UnpOldTable[I]) & 0xf; + else + if (Number==16) + { + GetBits(); + N=(BitField >> 14)+3; + AddBits(2); + while (N-- > 0 && I> 13)+3; + AddBits(3); + } + else + { + GetBits(); + N=(BitField >> 9)+11; + AddBits(7); + } + while (N-- > 0 && I=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;IDecodePos[0]=Dec->DecodeLen[0]=0,N=0,I=1;I<16;I++) + { + N=2*(N+LenCount[I]); + M=N<<(15-I); + if (M>0xFFFF) + M=0xFFFF; + Dec->DecodeLen[I]=(unsigned int)M; + TmpPos[I]=Dec->DecodePos[I]=Dec->DecodePos[I-1]+LenCount[I-1]; + } + + for (I=0;IDecodeNum[TmpPos[LenTab[I] & 0xF]++]=I; + Dec->MaxNum=Size; +} + + +static void DecodeNumber(struct Decode *Deco) +/* *** 52.6% of all CPU time is spent within this function!!! */ +{ + unsigned int I; + register unsigned int N; + GetBits(); + +#ifdef _USE_ASM + +#ifdef _WIN_32 + __asm { + + xor eax, eax + mov eax, BitField // N=BitField & 0xFFFE; + and eax, 0xFFFFFFFE + mov [N], eax + mov edx, [Deco] // EAX=N, EDX=Deco + + cmp eax, dword ptr[edx + 8*4 + 4]// if (NDecodeLen[8]) + jae else_G + + cmp eax, dword ptr[edx + 4*4 + 4]// if (NDecodeLen[4]) + jae else_F + + + cmp eax, dword ptr[edx + 2*4 + 4]// if (NDecodeLen[2]) + jae else_C + + cmp eax, dword ptr[edx + 1*4 + 4]// if (NDecodeLen[1]) + jae else_1 + mov I, 1 // I=1; + jmp next_1 + else_1: // else + mov I, 2 // I=2; + next_1: + + jmp next_C + else_C: // else + + cmp eax, dword ptr[edx + 3*4 + 4]// if (NDecodeLen[3]) + jae else_2 + mov I, 3 // I=3; + jmp next_2 + else_2: // else + mov I, 4 // I=4; + next_2: + + next_C: // else + + jmp next_F + else_F: + + + cmp eax, dword ptr[edx + 6*4 + 4]// if (NDecodeLen[6]) + jae else_E + + cmp eax, dword ptr[edx + 5*4 + 4]// if (NDecodeLen[5]) + jae else_3 + mov I, 5 // I=5; + jmp next_3 + else_3: // else + mov I, 6 // I=6; + next_3: + + jmp next_E + else_E: // else + + cmp eax, dword ptr[edx + 7*4 + 4]// if (NDecodeLen[7]) + jae else_4 + mov I, 7 // I=7; + jmp next_4 + else_4: // else + mov I, 8 // I=8; + next_4: + + next_E: + + next_F: + + jmp next_G + else_G: + + cmp eax, dword ptr[edx + 12*4 + 4] // if (NDecodeLen[12]) + jae else_D + + cmp eax, dword ptr[edx + 10*4 + 4]// if (NDecodeLen[10]) + jae else_B + + cmp eax, dword ptr[edx + 9*4 + 4]// if (NDecodeLen[9]) + jae else_5 + mov I, 9 // I=9; + jmp next_5 + else_5: // else + mov I, 10 // I=10; + next_5: + + jmp next_B + else_B: // else + + cmp eax, dword ptr[edx + 11*4 + 4]// if (NDecodeLen[11]) + jae else_6 + mov I, 11 // I=11; + jmp next_6 + else_6: // else + mov I, 12 // I=12; + next_6: + + next_B: + + + jmp next_D + else_D: // else + + cmp eax, dword ptr[edx + 14*4 + 4]// if (NDecodeLen[14]) + jae else_A + + cmp eax, dword ptr[edx + 13*4 + 4]// if (NDecodeLen[13]) + jae else_7 + mov I, 13 // I=13; + jmp next_7 + else_7: // else + mov I, 14 // I=14; + next_7: + + jmp next_A + else_A: // else + mov I, 15 // 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 /* #ifdef _WIN_32 ... #elif defined _X86_ASM_ */ + +#else + N=BitField & 0xFFFE; + if (NDecodeLen[8]) { + if (NDecodeLen[4]) { + if (NDecodeLen[2]) { + if (NDecodeLen[1]) + I=1; + else + I=2; + } else { + if (NDecodeLen[3]) + I=3; + else + I=4; + } + } else { + if (NDecodeLen[6]) { + if (NDecodeLen[5]) + I=5; + else + I=6; + } else { + if (NDecodeLen[7]) + I=7; + else + I=8; + } + } + } else { + if (NDecodeLen[12]) { + if (NDecodeLen[10]) { + if (NDecodeLen[9]) + I=9; + else + I=10; + } else { + if (NDecodeLen[11]) + I=11; + else + I=12; + } + } else { + if (NDecodeLen[14]) { + if (NDecodeLen[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 /* Win32 with VisualC */ + + __asm { + push edi + push eax + push ecx + + cld /* increment EDI and ESI */ + mov al, 0x00 + mov ecx, SIZE AudV + mov edi, Offset AudV + rep stosb /* clear memory */ + + mov ecx, SIZE OldDist + mov edi, Offset OldDist + rep stosb /* clear m