/****** ***** ****** ** ** ** ** ** ** unRAR utility version 1.01 ****** ******* ****** ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ** ** ** ** ** ** FREE portable version ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~ Main code YOU CAN CHANGE FOLLOWING CODE IN ORDER TO ACHIEVE COMPATIBILITY WITH YOUR OPERATING MEDIA. PLEASE SEND ALL NOTES, PATCHES TO andrey@vybor.chel.su OR TO Andrey Spasibozhko, 2:5010/23@fidonet. VOICE PHONE: +7-3512-130-231 */ #include "unrar.h" /* definitions */ #include "unpack.c" /* unpacking procedures */ void SplitCommandLine(); /* parses command string */ int CmpName(); /* checks name for mask */ char* PointToName(); /* returns pathname */ void NextVolumeName(); /* gets next volume name */ void SplitName(); /* splits pathname */ void ExecuteCommand(); /* executes extr. command */ void ListArchive(); /* lists archive contents */ int ExtrFile(); /* extracts single file */ void Help(); /* prints usage help */ void ShutDown(); /* stops working */ void ErrExit(); /* exits with error code */ void CreatePath(); /* creates path */ int tread(); /* reads with checking */ void tclose(); /* closes with checking */ void MergeArc(); /* to next volume */ void UnstoreFile(); /* unpacks non-compressed file */ int IsArchive(); /* checks for RAR archive signature */ void CheckArc(); /* similar but with exit */ int strnicomp(); /* compares strings */ char* strtolwr(); /* convert string to lowercase int ToPercent(); /* calculates percentage */ int ReadBlock(); /* reads archive block */ int IsProcessFile(); /* should file be processed */ int UnpRead(); /* reading while unpacking */ int UnpWrite(); /* writing while unpacking */ void InitCRC(); /* initializes CRC table */ UDWORD CRC(); /* calculates CRC */ struct MarkHeader MarkHead; struct ArchiveHeader Mhd; struct FileHeader Lhd; UDWORD CRC32_Table[256],UnpFileCRC; HPBYTE TmpMemory; int ArgCount=0; char ArgNames[16][80],MainCommand; char CurExtrFile[80]={0},ArcName[80],ArcFileName[80],ExtrPath[80]; int SolidType,UnpVolume,TestMode,ExitCode=0; FILE *ArcFPtr=NULL,*FileFPtr=NULL,*RdUnpFPtr,*WrUnpFPtr; long NextBlockPos,UnpPackedSize; main(Argc,Argv) int Argc; char *Argv[]; { printf("\n UNRAR 1.01 freeware portable version (C) 1994-95 Eugene Roshal\n"); if ((TmpMemory=(HPBYTE)MEMALLOC(UNP_MEMORY))==NULL) ErrExit(EMEMORY,MEMORY_ERROR); MakeTbl(); SplitCommandLine(Argc,Argv); ExecuteCommand(); ShutDown(SD_MEMORY); exit(ExitCode); } int CmpName(Mask,Name) char *Mask; char *Name; { while (1) { if (*Mask=='*') { while (*Mask!='.' && *Mask!=0) Mask++; while (*Name!='.' && *Name!=0) Name++; } if (*Mask==0) return(*Name==0); if (*Name==0 && *Mask=='.') { Mask++; continue; } if (toupper(*Mask)==toupper(*Name) || *Mask=='?' && *Name!=0) { Mask++; Name++; } else return(0); } } void ErrExit(ErrCode,Code) int ErrCode; int Code; { char ErrMsg[80]; switch(ErrCode) { case EEMPTY: strcpy(ErrMsg,""); break; case EWRITE: strcpy(ErrMsg,"Write error. Disk full ?"); break; case EREAD: strcpy(ErrMsg,"Read error"); break; case EOPEN: strcpy(ErrMsg,"File open error"); break; case ECLOSE: strcpy(ErrMsg,"File close error"); break; case EMEMORY: strcpy(ErrMsg,"Not enough memory"); break; case EARCH: strcpy(ErrMsg,"Broken archive"); break; } if (ErrCode!=EEMPTY) printf("\n Program aborted\n %s",ErrMsg); ShutDown(SD_FILES | SD_MEMORY); exit(Code); } void CreatePath(fpath) char *fpath; { char *ChPtr; ChPtr=fpath; while(*ChPtr!=0 && (ChPtr=strchr(ChPtr,PATHDIV))!=NULL) { *ChPtr=0; if (MAKEDIR(fpath)==0) printf("\n Creating %-55s",fpath); *ChPtr=PATHDIV; ChPtr++; } } void NextVolumeName() { char *ChPtr; ChPtr=strrchr(ArcName,'.'); if (!isdigit(*(ChPtr+2)) || !isdigit(*(ChPtr+3))) strcpy(ChPtr+2,"00"); else { ChPtr+=3; while ((++(*ChPtr))=='9'+1) { if (*(ChPtr-1)=='.') { *ChPtr='A'; break; } else { *ChPtr='0'; ChPtr--; } } } } void MergeArc(ShowFileName) int ShowFileName; { int Ch; tclose(ArcFPtr); NextVolumeName(); while ((ArcFPtr=fopen(ArcName,FOPENREADMODE))==NULL) { printf("\n Disk with %s required. Continue ? ",ArcName); Ch=getchar(); if (toupper(Ch)=='N') ErrExit(EEMPTY,USER_BREAK); } if (MainCommand=='T') printf("\n\n Testing archive %s",ArcName); else if (MainCommand!='P') printf("\n\n Extracting from %s",ArcName); CheckArc(); ReadBlock(FILE_HEAD); if (ShowFileName) printf("\n ... %-55s",ArcFileName); UnpVolume=(Lhd.Flags & LHD_SPLIT_AFTER); fseek(ArcFPtr,NextBlockPos-Lhd.PackSize,SEEK_SET); UnpPackedSize=Lhd.PackSize; RdUnpFPtr=ArcFPtr; } void UnstoreFile() { int Code; while ( 1 ) { if ((Code=UnpRead((UBYTE *)TmpMemory,0x7f00))==-1) ErrExit(EWRITE,WRITE_ERROR); if (Code==0) break; if (UnpWrite((UBYTE *)TmpMemory,(UWORD)Code)==-1) ErrExit(EWRITE,WRITE_ERROR); } } int IsArchive() { UBYTE Mark[7],Header[13]; SolidType=0; if (tread(ArcFPtr,Mark,7)!=7) return(0); if (Mark[0]!=0x52 || Mark[1]!=0x61 || Mark[2]!=0x72 || Mark[3]!=0x21 || Mark[4]!=0x1a || Mark[5]!=0x07 || Mark[6]!=0x00) return(0); if (tread(ArcFPtr,Header,13) != 13) return(0); Mhd.HeadCRC = Header[0]+(UWORD)Header[1]*0x100; Mhd.HeadType = Header[2]; Mhd.Flags = Header[3]+(UWORD)Header[4]*0x100; Mhd.HeadSize = Header[5]+(UWORD)Header[6]*0x100; if (!(Mhd.HeadCRC==(UWORD)~CRC(0xFFFFFFFFL,&Header[2],11))) printf("\n Archive header broken"); SolidType=(Mhd.Flags & MHD_SOLID); fseek(ArcFPtr,Mhd.HeadSize-13,SEEK_CUR); return(1); } void CheckArc() { if (!IsArchive()) { printf("\nBad archive %s",ArcName); ErrExit(EEMPTY,FATAL_ERROR); } } int tread(FPtr,buf,len) FILE *FPtr; void *buf; unsigned len; { int Code; Code=fread(buf,1,len,FPtr); if (Code==-1) ErrExit(EREAD,FATAL_ERROR); return(Code); } void tclose(FPtr) FILE *FPtr; { if (fclose(FPtr)==EOF) ErrExit(ECLOSE,FATAL_ERROR); } char* PointToName(Path) char *Path; { char *ChPtr; if ((ChPtr=strrchr(Path,PATHDIV))!=NULL) return(ChPtr+1); else if ((ChPtr=strrchr(Path,':'))!=NULL) return(ChPtr+1); else return(Path); } int strnicomp(Str1,Str2,MaxLen) char *Str1; char *Str2; int MaxLen; { if (MaxLen==0) return(0); while (MaxLen-- > 0) { if (toupper(*Str1)!=toupper(*Str2)) return(1); if (*Str1==0) return(0); Str1++; Str2++; } return(0); } char* strtolwr(Str) char *Str; { char *ChPtr; for (ChPtr=Str;*ChPtr!=0;ChPtr++) *ChPtr=tolower(*ChPtr); return(Str); } void SplitName(Path,Dir,Name) char *Path; char *Dir; char *Name; { char *ChPtr,*ChPtr1; if ((ChPtr=strrchr(Path,':'))!=NULL) ChPtr++; else ChPtr=Path; if ((ChPtr1=strrchr(ChPtr,PATHDIV))!=NULL) { *ChPtr1=0; strcpy(Dir,ChPtr); *ChPtr1=PATHDIV; ChPtr=ChPtr1+1; } else *Dir=0; strcpy(Name,ChPtr); } int ToPercent(N1,N2) long N1; long N2; { if (N1 > 10000) { N1/=100; N2/=100; } if (N2==0) return(0); if (N20 && (Argv[I][Len-1]==':' || (Argv[I][Len-1]=='\\' || Argv[I][Len-1]=='/'))) { strcpy(ExtrPath,Argv[I]); ExtrPath[Len-1]=PATHDIV; } else strncpy(ArgNames[(ArgCount++) & 0x0f],Argv[I],80); } } } if (ArgCount==0 && *ArcName!=0) strcpy(ArgNames[(ArgCount++) & 0x0f],"*.*"); if (strrchr(PointToName(ArcName),'.')==NULL) strcat(ArcName,isupper(*ArcName) ? ".RAR":".rar"); ArgCount &= 0xF; } void ExecuteCommand() { switch(MainCommand) { case 'E': case 'X': case 'T': ExtrFile(); break; case 'V': case 'L': ListArchive(); break; case 0: Help(); exit(0); default: Help(); exit(USER_ERROR); } } void ShutDown(Mode) int Mode; { if (Mode & SD_FILES) { if (ArcFPtr!=NULL) fclose(ArcFPtr); if (FileFPtr!=NULL) fclose(FileFPtr); } if (Mode & SD_MEMORY) { if (TmpMemory!=NULL) MEMFREE(TmpMemory); printf("\n"); } } void Help() { printf("\n Usage: UNRAR \n"); printf("\n \n"); printf("\n x Extract files with full path"); printf("\n e Extract files to current directory"); printf("\n t Test archive files"); printf("\n v Verbosely list contents of archive"); printf("\n l List contents of archive"); printf("\n"); } int ExtrFile() { char DestFileName[80]; long FileCount=0,TotalFileCount=0,DirCount=0,ErrCount=0; int ExtrFile=0,Size,SkipSolid=0,UnpSolid; if ((ArcFPtr=fopen(ArcName,FOPENREADMODE))==NULL) ErrExit(EOPEN,FATAL_ERROR); CheckArc(); CreateEncTbl(TmpMemory); UnpVolume=UnpSolid=0; if (MainCommand=='T') printf("\n Testing archive %s\n",ArcName); else printf("\n Extracting from %s\n",ArcName); while (1) { Size=ReadBlock(FILE_HEAD); if (Size<=0 && UnpVolume==0) break; if ((Lhd.Flags & LHD_SPLIT_BEFORE) && SolidType) { printf("\nSolid archive: first volume required"); ErrExit(EEMPTY,FATAL_ERROR); } if (UnpVolume && Size==0) MergeArc(0); UnpVolume=(Lhd.Flags & LHD_SPLIT_AFTER); fseek(ArcFPtr,NextBlockPos-Lhd.PackSize,SEEK_SET); TestMode=0; ExtrFile=0; SkipSolid=0; if (IsProcessFile(COMPARE_PATH) && (Lhd.Flags & LHD_SPLIT_BEFORE)==0 || (SkipSolid=SolidType)!=0) { strcpy(DestFileName,ExtrPath); strcat(DestFileName,(MainCommand!='E') ? ArcFileName : PointToName(ArcFileName)); ExtrFile=!SkipSolid; if (Lhd.UnpVer<15 || Lhd.UnpVer>UNP_VER) { printf("\n %s: unknown method",ArcFileName); ExtrFile=0; ErrCount++; ExitCode=WARNING; } if (Lhd.Flags & LHD_PASSWORD) { printf("\n %s: cannot process encrypted file",ArcFileName); if (SolidType) ErrExit(EEMPTY,FATAL_ERROR); ExtrFile=0; ErrCount++; ExitCode=WARNING; } if (Lhd.HostOS==MS_DOS && (Lhd.FileAttr & DOSFA_DIREC)) { if (MainCommand=='E') continue; if (SkipSolid) { printf("\n Skipping %-55s Ok",ArcFileName); continue; } if (MainCommand=='T') { printf("\n Testing %-55s Ok",ArcFileName); continue; } CreatePath(DestFileName); if (MAKEDIR(DestFileName)==0) printf("\n Creating %-55s",ArcFileName); continue; } else { if (MainCommand=='T' && ExtrFile) TestMode=1; if ((MainCommand=='E' || MainCommand=='X') && ExtrFile) { CreatePath(DestFileName); if ((FileFPtr=fopen(DestFileName,FOPENWRITEMODE))==NULL) { printf("\n Cannot create %s",DestFileName); ExitCode=WARNING; ExtrFile=0; } } } if (!ExtrFile && SolidType) SkipSolid=TestMode=ExtrFile=1; if (ExtrFile) { TotalFileCount++; if (SkipSolid) printf("\n Skipping %-55s",ArcFileName); else { FileCount++; switch(MainCommand) { case 'T': printf("\n Testing %-55s",ArcFileName); break; case 'X': case 'E': printf("\n Extracting %-55s",DestFileName); break; } } strcpy(CurExtrFile,DestFileName); UnpFileCRC=0xFFFFFFFFL; UnpPackedSize=Lhd.PackSize; DestUnpSize=Lhd.UnpSize; RdUnpFPtr=ArcFPtr; WrUnpFPtr=FileFPtr; if (Lhd.Method==0x30) UnstoreFile(); else if (unpack(TmpMemory,UnpRead,UnpWrite,UnpSolid)==-1) ErrExit(EWRITE,WRITE_ERROR); if (TotalFileCount>0 && SolidType) UnpSolid=1; if (UnpFileCRC==~Lhd.FileCRC) { if (MainCommand!='P') printf(" Ok"); } else { fseek(ArcFPtr,NextBlockPos,SEEK_SET); printf("\n %-15s : CRC failed",ArcFileName); ExitCode=CRC_ERROR; ErrCount++; } if (!TestMode) { SETFILETIME(FileFPtr,(void *)&Lhd.FileTime); tclose(FileFPtr); } TestMode=0; *CurExtrFile=0; } } if (!ExtrFile && !SolidType) fseek(ArcFPtr,NextBlockPos,SEEK_SET); } tclose(ArcFPtr); if ((FileCount+DirCount)==0) { printf("\n No files"); ExitCode=WARNING; } else if (ErrCount==0) printf("\n All OK"); else printf("\n Total errors: %ld",ErrCount); return(0); } void ListArchive() { unsigned long TotalPackSize,TotalUnpSize,FileCount; int I; TotalPackSize=TotalUnpSize=FileCount=0; if ((ArcFPtr=fopen(ArcName,FOPENREADMODE))==NULL) ErrExit(EOPEN,FATAL_ERROR); CheckArc(); printf("\n "); if (SolidType) printf("Solid "); if (Mhd.Flags & MHD_MULT_VOL) printf("%colume ",(SolidType) ? 'v':'V'); else printf("%crchive ",(SolidType) ? 'a':'A'); printf("%s\n",ArcName); if (MainCommand=='V') printf("\n Pathname/Comment\n%12.12s",""); else printf("\n Name "); printf(" Size Packed Ratio Date Time Attr CRC-32 Meth Ver\n"); for (I=0;I<77;I++) printf("-"); while(ReadBlock(FILE_HEAD) > 0) { if (IsProcessFile(NOT_COMPARE_PATH)) { printf("\n%c",(Lhd.Flags & LHD_PASSWORD) ? '*' : ' '); if (MainCommand=='V') { printf("%-s",ArcFileName); printf("\n%12s ",""); } else printf("%-12s",PointToName(ArcFileName)); printf(" %8ld %8ld ",Lhd.UnpSize,Lhd.PackSize); if (Lhd.Flags & (LHD_SPLIT_AFTER | LHD_SPLIT_BEFORE)) printf(" Split"); else printf(" %3d%% ",ToPercent(Lhd.PackSize,Lhd.UnpSize)); printf(" %02d-%02d-%02d %02d:%02d ",(int)(Lhd.FileTime>>16) & 0x1f, (int)(Lhd.FileTime>>21) & 0xf,(int)((Lhd.FileTime>>25)+1980)%100, (int)(Lhd.FileTime>>11) & 0x1f,(int)(Lhd.FileTime>>5) & 0x3f); if (Lhd.HostOS==MS_DOS) printf("%c%c%c%c%c", (Lhd.FileAttr & DOSFA_DIREC ) ? 'D' : '.', (Lhd.FileAttr & DOSFA_RDONLY) ? 'R' : '.', (Lhd.FileAttr & DOSFA_HIDDEN) ? 'H' : '.', (Lhd.FileAttr & DOSFA_SYSTEM) ? 'S' : '.', (Lhd.FileAttr & DOSFA_ARCH ) ? 'A' : '.'); else printf(" "); printf(" %8.8lX m%d %d.%d",Lhd.FileCRC,Lhd.Method-0x30,Lhd.UnpVer/10,Lhd.UnpVer%10); if (!(Lhd.Flags & LHD_SPLIT_BEFORE)) { TotalUnpSize+=Lhd.UnpSize; FileCount++; } TotalPackSize+=Lhd.PackSize; } fseek(ArcFPtr,NextBlockPos,SEEK_SET); } printf("\n"); for (I=0;I<77;I++) printf("-"); printf("\n%5ld %16ld %8ld %4d%%\n",FileCount,TotalUnpSize,TotalPackSize,ToPercent(TotalPackSize,TotalUnpSize)); tclose(ArcFPtr); } int IsProcessFile(ComparePath) int ComparePath; { int NumName,WildCards; char ArgName[80],dir1[80],name1[15],dir2[80],name2[15]; for (NumName=0;NumName0 && BlockType==FILE_HEAD) { tread(ArcFPtr,ArcFileName,Lhd.NameSize); ArcFileName[Lhd.NameSize]=0; Size+=Lhd.NameSize; HeadCRC=CRC(0xFFFFFFFFL,&Header[2],30); if (!(Lhd.HeadCRC==(UWORD)~CRC(HeadCRC,&ArcFileName[0],Lhd.NameSize))) printf("\n %s: file header broken\n",ArcFileName); for (I=0;ArcFileName[I];I++) if (ArcFileName[I]=='\\' || ArcFileName[I]=='/') ArcFileName[I]=PATHDIV; if (Lhd.HostOS==MS_DOS) strtolwr(ArcFileName); } return(Size); } int UnpRead(Addr,Count) UBYTE *Addr; UWORD Count; { int RetCode; unsigned int ReadSize,TotalRead=0; UBYTE *ReadAddr; ReadAddr=Addr; while (Count > 0) { ReadSize=(unsigned int)((Count>UnpPackedSize) ? UnpPackedSize : Count); if ((RetCode=fread(ReadAddr,1,ReadSize,RdUnpFPtr))!=ReadSize) break; TotalRead+=RetCode; ReadAddr+=RetCode; Count-=RetCode; UnpPackedSize-=RetCode; if (UnpPackedSize == 0 && UnpVolume) MergeArc(1); else break; } if (RetCode!=-1) RetCode=(int)TotalRead; return(RetCode); } int UnpWrite(Addr,Count) UBYTE *Addr; UWORD Count; { int RetCode; if (TestMode) RetCode=(int)Count; else if ((RetCode=fwrite(Addr,1,Count,WrUnpFPtr))!=Count) RetCode = -1; if (RetCode!=-1) UnpFileCRC=CRC(UnpFileCRC,Addr,(UWORD)RetCode); return(RetCode); } UDWORD CRC(StartCRC,Addr,Size) UDWORD StartCRC; UBYTE *Addr; UWORD Size; { UWORD I; if (!CRC32_Table[1]) InitCRC(); for (I=0;I> 8); return(StartCRC); } void InitCRC() { int I, J; UDWORD C; for (I=0;I<256;I++) { for (C=I,J=0;J<8;J++) C=(C & 1) ? (C>>1)^0xEDB88320L : (C>>1); CRC32_Table[I]=C; } }