713 lines
19 KiB
C++
713 lines
19 KiB
C++
|
#include "rar.hpp"
|
||
|
|
||
|
size_t Archive::SearchBlock(int BlockType)
|
||
|
{
|
||
|
size_t Size,Count=0;
|
||
|
while ((Size=ReadHeader())!=0 &&
|
||
|
(BlockType==ENDARC_HEAD || GetHeaderType()!=ENDARC_HEAD))
|
||
|
{
|
||
|
if ((++Count & 127)==0)
|
||
|
Wait();
|
||
|
if (GetHeaderType()==BlockType)
|
||
|
return(Size);
|
||
|
SeekToNext();
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t Archive::SearchSubBlock(const char *Type)
|
||
|
{
|
||
|
size_t Size;
|
||
|
while ((Size=ReadHeader())!=0 && GetHeaderType()!=ENDARC_HEAD)
|
||
|
{
|
||
|
if (GetHeaderType()==NEWSUB_HEAD && SubHead.CmpName(Type))
|
||
|
return(Size);
|
||
|
SeekToNext();
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Archive::UnexpEndArcMsg()
|
||
|
{
|
||
|
int64 ArcSize=FileLength();
|
||
|
if (CurBlockPos>ArcSize || NextBlockPos>ArcSize)
|
||
|
{
|
||
|
#ifndef SHELL_EXT
|
||
|
Log(FileName,St(MLogUnexpEOF));
|
||
|
#endif
|
||
|
ErrHandler.SetErrorCode(WARNING);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t Archive::ReadHeader()
|
||
|
{
|
||
|
CurBlockPos=Tell();
|
||
|
|
||
|
#ifndef SFX_MODULE
|
||
|
if (OldFormat)
|
||
|
return(ReadOldHeader());
|
||
|
#endif
|
||
|
|
||
|
RawRead Raw(this);
|
||
|
|
||
|
bool Decrypt=Encrypted && CurBlockPos>=(int64)SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD;
|
||
|
|
||
|
if (Decrypt)
|
||
|
{
|
||
|
#if defined(SHELL_EXT) || defined(NOCRYPT)
|
||
|
return(0);
|
||
|
#else
|
||
|
if (Read(HeadersSalt,SALT_SIZE)!=SALT_SIZE)
|
||
|
{
|
||
|
UnexpEndArcMsg();
|
||
|
return(0);
|
||
|
}
|
||
|
if (*Cmd->Password==0)
|
||
|
#ifdef RARDLL
|
||
|
if (Cmd->Callback==NULL ||
|
||
|
Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)Cmd->Password,sizeof(Cmd->Password))==-1)
|
||
|
{
|
||
|
Close();
|
||
|
ErrHandler.Exit(USER_BREAK);
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
if (!GetPassword(PASSWORD_ARCHIVE,FileName,Cmd->Password,sizeof(Cmd->Password)))
|
||
|
{
|
||
|
Close();
|
||
|
ErrHandler.Exit(USER_BREAK);
|
||
|
}
|
||
|
#endif
|
||
|
HeadersCrypt.SetCryptKeys(Cmd->Password,HeadersSalt,false,false,NewMhd.EncryptVer>=36);
|
||
|
Raw.SetCrypt(&HeadersCrypt);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
Raw.Read(SIZEOF_SHORTBLOCKHEAD);
|
||
|
if (Raw.Size()==0)
|
||
|
{
|
||
|
UnexpEndArcMsg();
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
Raw.Get(ShortBlock.HeadCRC);
|
||
|
byte HeadType;
|
||
|
Raw.Get(HeadType);
|
||
|
ShortBlock.HeadType=(HEADER_TYPE)HeadType;
|
||
|
Raw.Get(ShortBlock.Flags);
|
||
|
Raw.Get(ShortBlock.HeadSize);
|
||
|
if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
|
||
|
{
|
||
|
#ifndef SHELL_EXT
|
||
|
Log(FileName,St(MLogFileHead),"???");
|
||
|
#endif
|
||
|
BrokenFileHeader=true;
|
||
|
ErrHandler.SetErrorCode(CRC_ERROR);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
if (ShortBlock.HeadType==COMM_HEAD)
|
||
|
Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
|
||
|
else
|
||
|
if (ShortBlock.HeadType==MAIN_HEAD && (ShortBlock.Flags & MHD_COMMENT)!=0)
|
||
|
Raw.Read(SIZEOF_NEWMHD-SIZEOF_SHORTBLOCKHEAD);
|
||
|
else
|
||
|
Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);
|
||
|
|
||
|
NextBlockPos=CurBlockPos+ShortBlock.HeadSize;
|
||
|
|
||
|
switch(ShortBlock.HeadType)
|
||
|
{
|
||
|
case MAIN_HEAD:
|
||
|
*(BaseBlock *)&NewMhd=ShortBlock;
|
||
|
Raw.Get(NewMhd.HighPosAV);
|
||
|
Raw.Get(NewMhd.PosAV);
|
||
|
if (NewMhd.Flags & MHD_ENCRYPTVER)
|
||
|
Raw.Get(NewMhd.EncryptVer);
|
||
|
break;
|
||
|
case ENDARC_HEAD:
|
||
|
*(BaseBlock *)&EndArcHead=ShortBlock;
|
||
|
if (EndArcHead.Flags & EARC_DATACRC)
|
||
|
Raw.Get(EndArcHead.ArcDataCRC);
|
||
|
if (EndArcHead.Flags & EARC_VOLNUMBER)
|
||
|
Raw.Get(EndArcHead.VolNumber);
|
||
|
break;
|
||
|
case FILE_HEAD:
|
||
|
case NEWSUB_HEAD:
|
||
|
{
|
||
|
FileHeader *hd=ShortBlock.HeadType==FILE_HEAD ? &NewLhd:&SubHead;
|
||
|
*(BaseBlock *)hd=ShortBlock;
|
||
|
Raw.Get(hd->PackSize);
|
||
|
Raw.Get(hd->UnpSize);
|
||
|
Raw.Get(hd->HostOS);
|
||
|
Raw.Get(hd->FileCRC);
|
||
|
Raw.Get(hd->FileTime);
|
||
|
Raw.Get(hd->UnpVer);
|
||
|
Raw.Get(hd->Method);
|
||
|
Raw.Get(hd->NameSize);
|
||
|
Raw.Get(hd->FileAttr);
|
||
|
if (hd->Flags & LHD_LARGE)
|
||
|
{
|
||
|
Raw.Get(hd->HighPackSize);
|
||
|
Raw.Get(hd->HighUnpSize);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hd->HighPackSize=hd->HighUnpSize=0;
|
||
|
if (hd->UnpSize==0xffffffff)
|
||
|
{
|
||
|
// UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
|
||
|
// that we do not know the unpacked file size and must unpack it
|
||
|
// until we find the end of file marker in compressed data.
|
||
|
hd->UnpSize=(uint)(INT64NDF);
|
||
|
hd->HighUnpSize=(uint)(INT64NDF>>32);
|
||
|
}
|
||
|
}
|
||
|
hd->FullPackSize=INT32TO64(hd->HighPackSize,hd->PackSize);
|
||
|
hd->FullUnpSize=INT32TO64(hd->HighUnpSize,hd->UnpSize);
|
||
|
|
||
|
char FileName[NM*4];
|
||
|
int NameSize=Min(hd->NameSize,sizeof(FileName)-1);
|
||
|
Raw.Get((byte *)FileName,NameSize);
|
||
|
FileName[NameSize]=0;
|
||
|
|
||
|
strncpyz(hd->FileName,FileName,ASIZE(hd->FileName));
|
||
|
|
||
|
if (hd->HeadType==NEWSUB_HEAD)
|
||
|
{
|
||
|
int DataSize=hd->HeadSize-hd->NameSize-SIZEOF_NEWLHD;
|
||
|
if (hd->Flags & LHD_SALT)
|
||
|
DataSize-=SALT_SIZE;
|
||
|
if (DataSize>0)
|
||
|
{
|
||
|
hd->SubData.Alloc(DataSize);
|
||
|
Raw.Get(&hd->SubData[0],DataSize);
|
||
|
if (hd->CmpName(SUBHEAD_TYPE_RR))
|
||
|
{
|
||
|
byte *D=&hd->SubData[8];
|
||
|
RecoverySectors=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (hd->HeadType==FILE_HEAD)
|
||
|
{
|
||
|
if (hd->Flags & LHD_UNICODE)
|
||
|
{
|
||
|
EncodeFileName NameCoder;
|
||
|
size_t Length=strlen(FileName);
|
||
|
if (Length==hd->NameSize)
|
||
|
{
|
||
|
UtfToWide(FileName,hd->FileNameW,sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0])-1);
|
||
|
WideToChar(hd->FileNameW,hd->FileName,sizeof(hd->FileName)/sizeof(hd->FileName[0])-1);
|
||
|
ExtToInt(hd->FileName,hd->FileName);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Length++;
|
||
|
NameCoder.Decode(FileName,(byte *)FileName+Length,
|
||
|
hd->NameSize-Length,hd->FileNameW,
|
||
|
sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0]));
|
||
|
}
|
||
|
if (*hd->FileNameW==0)
|
||
|
hd->Flags &= ~LHD_UNICODE;
|
||
|
}
|
||
|
else
|
||
|
*hd->FileNameW=0;
|
||
|
#ifndef SFX_MODULE
|
||
|
ConvertNameCase(hd->FileName);
|
||
|
ConvertNameCase(hd->FileNameW);
|
||
|
#endif
|
||
|
ConvertUnknownHeader();
|
||
|
}
|
||
|
if (hd->Flags & LHD_SALT)
|
||
|
Raw.Get(hd->Salt,SALT_SIZE);
|
||
|
hd->mtime.SetDos(hd->FileTime);
|
||
|
hd->ctime.Reset();
|
||
|
hd->atime.Reset();
|
||
|
hd->arctime.Reset();
|
||
|
if (hd->Flags & LHD_EXTTIME)
|
||
|
{
|
||
|
ushort Flags;
|
||
|
Raw.Get(Flags);
|
||
|
RarTime *tbl[4];
|
||
|
tbl[0]=&NewLhd.mtime;
|
||
|
tbl[1]=&NewLhd.ctime;
|
||
|
tbl[2]=&NewLhd.atime;
|
||
|
tbl[3]=&NewLhd.arctime;
|
||
|
for (int I=0;I<4;I++)
|
||
|
{
|
||
|
RarTime *CurTime=tbl[I];
|
||
|
uint rmode=Flags>>(3-I)*4;
|
||
|
if ((rmode & 8)==0)
|
||
|
continue;
|
||
|
if (I!=0)
|
||
|
{
|
||
|
uint DosTime;
|
||
|
Raw.Get(DosTime);
|
||
|
CurTime->SetDos(DosTime);
|
||
|
}
|
||
|
RarLocalTime rlt;
|
||
|
CurTime->GetLocal(&rlt);
|
||
|
if (rmode & 4)
|
||
|
rlt.Second++;
|
||
|
rlt.Reminder=0;
|
||
|
int count=rmode&3;
|
||
|
for (int J=0;J<count;J++)
|
||
|
{
|
||
|
byte CurByte;
|
||
|
Raw.Get(CurByte);
|
||
|
rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
|
||
|
}
|
||
|
CurTime->SetLocal(&rlt);
|
||
|
}
|
||
|
}
|
||
|
NextBlockPos+=hd->FullPackSize;
|
||
|
bool CRCProcessedOnly=(hd->Flags & LHD_COMMENT)!=0;
|
||
|
HeaderCRC=~Raw.GetCRC(CRCProcessedOnly)&0xffff;
|
||
|
if (hd->HeadCRC!=HeaderCRC)
|
||
|
{
|
||
|
if (hd->HeadType==NEWSUB_HEAD)
|
||
|
strcat(hd->FileName,"- ???");
|
||
|
BrokenFileHeader=true;
|
||
|
ErrHandler.SetErrorCode(WARNING);
|
||
|
#ifndef SHELL_EXT
|
||
|
Log(Archive::FileName,St(MLogFileHead),IntNameToExt(hd->FileName));
|
||
|
Alarm();
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
#ifndef SFX_MODULE
|
||
|
case COMM_HEAD:
|
||
|
*(BaseBlock *)&CommHead=ShortBlock;
|
||
|
Raw.Get(CommHead.UnpSize);
|
||
|
Raw.Get(CommHead.UnpVer);
|
||
|
Raw.Get(CommHead.Method);
|
||
|
Raw.Get(CommHead.CommCRC);
|
||
|
break;
|
||
|
case SIGN_HEAD:
|
||
|
*(BaseBlock *)&SignHead=ShortBlock;
|
||
|
Raw.Get(SignHead.CreationTime);
|
||
|
Raw.Get(SignHead.ArcNameSize);
|
||
|
Raw.Get(SignHead.UserNameSize);
|
||
|
break;
|
||
|
case AV_HEAD:
|
||
|
*(BaseBlock *)&AVHead=ShortBlock;
|
||
|
Raw.Get(AVHead.UnpVer);
|
||
|
Raw.Get(AVHead.Method);
|
||
|
Raw.Get(AVHead.AVVer);
|
||
|
Raw.Get(AVHead.AVInfoCRC);
|
||
|
break;
|
||
|
case PROTECT_HEAD:
|
||
|
*(BaseBlock *)&ProtectHead=ShortBlock;
|
||
|
Raw.Get(ProtectHead.DataSize);
|
||
|
Raw.Get(ProtectHead.Version);
|
||
|
Raw.Get(ProtectHead.RecSectors);
|
||
|
Raw.Get(ProtectHead.TotalBlocks);
|
||
|
Raw.Get(ProtectHead.Mark,8);
|
||
|
NextBlockPos+=ProtectHead.DataSize;
|
||
|
RecoverySectors=ProtectHead.RecSectors;
|
||
|
break;
|
||
|
case SUB_HEAD:
|
||
|
*(BaseBlock *)&SubBlockHead=ShortBlock;
|
||
|
Raw.Get(SubBlockHead.DataSize);
|
||
|
NextBlockPos+=SubBlockHead.DataSize;
|
||
|
Raw.Get(SubBlockHead.SubType);
|
||
|
Raw.Get(SubBlockHead.Level);
|
||
|
switch(SubBlockHead.SubType)
|
||
|
{
|
||
|
case UO_HEAD:
|
||
|
*(SubBlockHeader *)&UOHead=SubBlockHead;
|
||
|
Raw.Get(UOHead.OwnerNameSize);
|
||
|
Raw.Get(UOHead.GroupNameSize);
|
||
|
if (UOHead.OwnerNameSize>NM-1)
|
||
|
UOHead.OwnerNameSize=NM-1;
|
||
|
if (UOHead.GroupNameSize>NM-1)
|
||
|
UOHead.GroupNameSize=NM-1;
|
||
|
Raw.Get((byte *)UOHead.OwnerName,UOHead.OwnerNameSize);
|
||
|
Raw.Get((byte *)UOHead.GroupName,UOHead.GroupNameSize);
|
||
|
UOHead.OwnerName[UOHead.OwnerNameSize]=0;
|
||
|
UOHead.GroupName[UOHead.GroupNameSize]=0;
|
||
|
break;
|
||
|
case MAC_HEAD:
|
||
|
*(SubBlockHeader *)&MACHead=SubBlockHead;
|
||
|
Raw.Get(MACHead.fileType);
|
||
|
Raw.Get(MACHead.fileCreator);
|
||
|
break;
|
||
|
case EA_HEAD:
|
||
|
case BEEA_HEAD:
|
||
|
case NTACL_HEAD:
|
||
|
*(SubBlockHeader *)&EAHead=SubBlockHead;
|
||
|
Raw.Get(EAHead.UnpSize);
|
||
|
Raw.Get(EAHead.UnpVer);
|
||
|
Raw.Get(EAHead.Method);
|
||
|
Raw.Get(EAHead.EACRC);
|
||
|
break;
|
||
|
case STREAM_HEAD:
|
||
|
*(SubBlockHeader *)&StreamHead=SubBlockHead;
|
||
|
Raw.Get(StreamHead.UnpSize);
|
||
|
Raw.Get(StreamHead.UnpVer);
|
||
|
Raw.Get(StreamHead.Method);
|
||
|
Raw.Get(StreamHead.StreamCRC);
|
||
|
Raw.Get(StreamHead.StreamNameSize);
|
||
|
if (StreamHead.StreamNameSize>NM-1)
|
||
|
StreamHead.StreamNameSize=NM-1;
|
||
|
Raw.Get((byte *)StreamHead.StreamName,StreamHead.StreamNameSize);
|
||
|
StreamHead.StreamName[StreamHead.StreamNameSize]=0;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
#endif
|
||
|
default:
|
||
|
if (ShortBlock.Flags & LONG_BLOCK)
|
||
|
{
|
||
|
uint DataSize;
|
||
|
Raw.Get(DataSize);
|
||
|
NextBlockPos+=DataSize;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
HeaderCRC=~Raw.GetCRC(false)&0xffff;
|
||
|
CurHeaderType=ShortBlock.HeadType;
|
||
|
if (Decrypt)
|
||
|
{
|
||
|
NextBlockPos+=Raw.PaddedSize()+SALT_SIZE;
|
||
|
|
||
|
if (ShortBlock.HeadCRC!=HeaderCRC)
|
||
|
{
|
||
|
bool Recovered=false;
|
||
|
if (ShortBlock.HeadType==ENDARC_HEAD && (EndArcHead.Flags & EARC_REVSPACE)!=0)
|
||
|
{
|
||
|
// Last 7 bytes of recovered volume can contain zeroes, because
|
||
|
// REV files store its own information (volume number, etc.) here.
|
||
|
SaveFilePos SavePos(*this);
|
||
|
int64 Length=Tell();
|
||
|
Seek(Length-7,SEEK_SET);
|
||
|
Recovered=true;
|
||
|
for (int J=0;J<7;J++)
|
||
|
if (GetByte()!=0)
|
||
|
Recovered=false;
|
||
|
}
|
||
|
if (!Recovered)
|
||
|
{
|
||
|
#ifndef SILENT
|
||
|
Log(FileName,St(MEncrBadCRC),FileName);
|
||
|
#endif
|
||
|
Close();
|
||
|
|
||
|
BrokenFileHeader=true;
|
||
|
ErrHandler.SetErrorCode(CRC_ERROR);
|
||
|
return(0);
|
||
|
// ErrHandler.Exit(CRC_ERROR);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NextBlockPos<=CurBlockPos)
|
||
|
{
|
||
|
#ifndef SHELL_EXT
|
||
|
Log(FileName,St(MLogFileHead),"???");
|
||
|
#endif
|
||
|
BrokenFileHeader=true;
|
||
|
ErrHandler.SetErrorCode(CRC_ERROR);
|
||
|
return(0);
|
||
|
}
|
||
|
return(Raw.Size());
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef SFX_MODULE
|
||
|
size_t Archive::ReadOldHeader()
|
||
|
{
|
||
|
RawRead Raw(this);
|
||
|
if (CurBlockPos<=(int64)SFXSize)
|
||
|
{
|
||
|
Raw.Read(SIZEOF_OLDMHD);
|
||
|
Raw.Get(OldMhd.Mark,4);
|
||
|
Raw.Get(OldMhd.HeadSize);
|
||
|
Raw.Get(OldMhd.Flags);
|
||
|
NextBlockPos=CurBlockPos+OldMhd.HeadSize;
|
||
|
CurHeaderType=MAIN_HEAD;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
OldFileHeader OldLhd;
|
||
|
Raw.Read(SIZEOF_OLDLHD);
|
||
|
NewLhd.HeadType=FILE_HEAD;
|
||
|
Raw.Get(NewLhd.PackSize);
|
||
|
Raw.Get(NewLhd.UnpSize);
|
||
|
Raw.Get(OldLhd.FileCRC);
|
||
|
Raw.Get(NewLhd.HeadSize);
|
||
|
Raw.Get(NewLhd.FileTime);
|
||
|
Raw.Get(OldLhd.FileAttr);
|
||
|
Raw.Get(OldLhd.Flags);
|
||
|
Raw.Get(OldLhd.UnpVer);
|
||
|
Raw.Get(OldLhd.NameSize);
|
||
|
Raw.Get(OldLhd.Method);
|
||
|
|
||
|
NewLhd.Flags=OldLhd.Flags|LONG_BLOCK;
|
||
|
NewLhd.UnpVer=(OldLhd.UnpVer==2) ? 13 : 10;
|
||
|
NewLhd.Method=OldLhd.Method+0x30;
|
||
|
NewLhd.NameSize=OldLhd.NameSize;
|
||
|
NewLhd.FileAttr=OldLhd.FileAttr;
|
||
|
NewLhd.FileCRC=OldLhd.FileCRC;
|
||
|
NewLhd.FullPackSize=NewLhd.PackSize;
|
||
|
NewLhd.FullUnpSize=NewLhd.UnpSize;
|
||
|
|
||
|
NewLhd.mtime.SetDos(NewLhd.FileTime);
|
||
|
NewLhd.ctime.Reset();
|
||
|
NewLhd.atime.Reset();
|
||
|
NewLhd.arctime.Reset();
|
||
|
|
||
|
Raw.Read(OldLhd.NameSize);
|
||
|
Raw.Get((byte *)NewLhd.FileName,OldLhd.NameSize);
|
||
|
NewLhd.FileName[OldLhd.NameSize]=0;
|
||
|
ConvertNameCase(NewLhd.FileName);
|
||
|
*NewLhd.FileNameW=0;
|
||
|
|
||
|
if (Raw.Size()!=0)
|
||
|
NextBlockPos=CurBlockPos+NewLhd.HeadSize+NewLhd.PackSize;
|
||
|
CurHeaderType=FILE_HEAD;
|
||
|
}
|
||
|
return(NextBlockPos>CurBlockPos ? Raw.Size():0);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
void Archive::ConvertNameCase(char *Name)
|
||
|
{
|
||
|
if (Cmd->ConvertNames==NAMES_UPPERCASE)
|
||
|
{
|
||
|
IntToExt(Name,Name);
|
||
|
strupper(Name);
|
||
|
ExtToInt(Name,Name);
|
||
|
}
|
||
|
if (Cmd->ConvertNames==NAMES_LOWERCASE)
|
||
|
{
|
||
|
IntToExt(Name,Name);
|
||
|
strlower(Name);
|
||
|
ExtToInt(Name,Name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef SFX_MODULE
|
||
|
void Archive::ConvertNameCase(wchar *Name)
|
||
|
{
|
||
|
if (Cmd->ConvertNames==NAMES_UPPERCASE)
|
||
|
strupperw(Name);
|
||
|
if (Cmd->ConvertNames==NAMES_LOWERCASE)
|
||
|
strlowerw(Name);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
bool Archive::IsArcDir()
|
||
|
{
|
||
|
return((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY);
|
||
|
}
|
||
|
|
||
|
|
||
|
bool Archive::IsArcLabel()
|
||
|
{
|
||
|
return(NewLhd.HostOS<=HOST_WIN32 && (NewLhd.FileAttr & 8));
|
||
|
}
|
||
|
|
||
|
|
||
|
void Archive::ConvertAttributes()
|
||
|
{
|
||
|
#if defined(_WIN_32) || defined(_EMX)
|
||
|
switch(NewLhd.HostOS)
|
||
|
{
|
||
|
case HOST_MSDOS:
|
||
|
case HOST_OS2:
|
||
|
case HOST_WIN32:
|
||
|
break;
|
||
|
case HOST_UNIX:
|
||
|
case HOST_BEOS:
|
||
|
if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
|
||
|
NewLhd.FileAttr=0x10;
|
||
|
else
|
||
|
NewLhd.FileAttr=0x20;
|
||
|
break;
|
||
|
default:
|
||
|
if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
|
||
|
NewLhd.FileAttr=0x10;
|
||
|
else
|
||
|
NewLhd.FileAttr=0x20;
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
#ifdef _UNIX
|
||
|
// umask defines which permission bits must not be set by default
|
||
|
// when creating a file or directory.
|
||
|
static mode_t mask = (mode_t) -1;
|
||
|
|
||
|
if (mask == (mode_t) -1)
|
||
|
{
|
||
|
// umask call returns the current umask value. Argument (022) is not
|
||
|
// important here.
|
||
|
mask = umask(022);
|
||
|
|
||
|
// Restore the original umask value, which was changed to 022 above.
|
||
|
umask(mask);
|
||
|
}
|
||
|
|
||
|
switch(NewLhd.HostOS)
|
||
|
{
|
||
|
case HOST_MSDOS:
|
||
|
case HOST_OS2:
|
||
|
case HOST_WIN32:
|
||
|
{
|
||
|
// Mapping MSDOS, OS/2 and Windows file attributes to Unix.
|
||
|
|
||
|
if (NewLhd.FileAttr & 0x10) // FILE_ATTRIBUTE_DIRECTORY
|
||
|
{
|
||
|
// For directories we use 0777 mask.
|
||
|
NewLhd.FileAttr=0777 & ~mask;
|
||
|
}
|
||
|
else
|
||
|
if (NewLhd.FileAttr & 1) // FILE_ATTRIBUTE_READONLY
|
||
|
{
|
||
|
// For read only files we use 0444 mask with 'w' bits turned off.
|
||
|
NewLhd.FileAttr=0444 & ~mask;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// umask does not set +x for regular files, so we use 0666
|
||
|
// instead of 0777 as for directories.
|
||
|
NewLhd.FileAttr=0666 & ~mask;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case HOST_UNIX:
|
||
|
case HOST_BEOS:
|
||
|
break;
|
||
|
default:
|
||
|
if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
|
||
|
NewLhd.FileAttr=0x41ff & ~mask;
|
||
|
else
|
||
|
NewLhd.FileAttr=0x81b6 & ~mask;
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void Archive::ConvertUnknownHeader()
|
||
|
{
|
||
|
if (NewLhd.UnpVer<20 && (NewLhd.FileAttr & 0x10))
|
||
|
NewLhd.Flags|=LHD_DIRECTORY;
|
||
|
if (NewLhd.HostOS>=HOST_MAX)
|
||
|
{
|
||
|
if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
|
||
|
NewLhd.FileAttr=0x10;
|
||
|
else
|
||
|
NewLhd.FileAttr=0x20;
|
||
|
}
|
||
|
for (char *s=NewLhd.FileName;*s!=0;s=charnext(s))
|
||
|
{
|
||
|
if (*s=='/' || *s=='\\')
|
||
|
*s=CPATHDIVIDER;
|
||
|
#if defined(_APPLE) && !defined(UNICODE_SUPPORTED)
|
||
|
if ((byte)*s<32 || (byte)*s>127)
|
||
|
*s='_';
|
||
|
#endif
|
||
|
|
||
|
#if defined(_WIN_32) || defined(_EMX)
|
||
|
// ':' in file names is allowed in Unix, but not in Windows.
|
||
|
// Even worse, file data will be written to NTFS stream on NTFS,
|
||
|
// so automatic name correction on file create error in extraction
|
||
|
// routine does not work. In Windows and DOS versions we better
|
||
|
// replace ':' now.
|
||
|
if (*s==':')
|
||
|
*s='_';
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
for (wchar *s=NewLhd.FileNameW;*s!=0;s++)
|
||
|
{
|
||
|
if (*s=='/' || *s=='\\')
|
||
|
*s=CPATHDIVIDER;
|
||
|
|
||
|
#if defined(_WIN_32) || defined(_EMX)
|
||
|
// ':' in file names is allowed in Unix, but not in Windows.
|
||
|
// Even worse, file data will be written to NTFS stream on NTFS,
|
||
|
// so automatic name correction on file create error in extraction
|
||
|
// routine does not work. In Windows and DOS versions we better
|
||
|
// replace ':' now.
|
||
|
if (*s==':')
|
||
|
*s='_';
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef SHELL_EXT
|
||
|
bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
|
||
|
{
|
||
|
if (HeaderCRC!=SubHead.HeadCRC)
|
||
|
{
|
||
|
#ifndef SHELL_EXT
|
||
|
Log(FileName,St(MSubHeadCorrupt));
|
||
|
#endif
|
||
|
ErrHandler.SetErrorCode(CRC_ERROR);
|
||
|
return(false);
|
||
|
}
|
||
|
if (SubHead.Method<0x30 || SubHead.Method>0x35 || SubHead.UnpVer>/*PACK_VER*/36)
|
||
|
{
|
||
|
#ifndef SHELL_EXT
|
||
|
Log(FileName,St(MSubHeadUnknown));
|
||
|
#endif
|
||
|
return(false);
|
||
|
}
|
||
|
|
||
|
if (SubHead.PackSize==0 && (SubHead.Flags & LHD_SPLIT_AFTER)==0)
|
||
|
return(true);
|
||
|
|
||
|
SubDataIO.Init();
|
||
|
Unpack Unpack(&SubDataIO);
|
||
|
Unpack.Init();
|
||
|
|
||
|
if (DestFile==NULL)
|
||
|
{
|
||
|
UnpData->Alloc(SubHead.UnpSize);
|
||
|
SubDataIO.SetUnpackToMemory(&(*UnpData)[0],SubHead.UnpSize);
|
||
|
}
|
||
|
if (SubHead.Flags & LHD_PASSWORD)
|
||
|
if (*Cmd->Password)
|
||
|
SubDataIO.SetEncryption(SubHead.UnpVer,Cmd->Password,
|
||
|
(SubHead.Flags & LHD_SALT) ? SubHead.Salt:NULL,false,
|
||
|
SubHead.UnpVer>=36);
|
||
|
else
|
||
|
return(false);
|
||
|
SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
|
||
|
SubDataIO.EnableShowProgress(false);
|
||
|
SubDataIO.SetFiles(this,DestFile);
|
||
|
SubDataIO.UnpVolume=(SubHead.Flags & LHD_SPLIT_AFTER)!=0;
|
||
|
SubDataIO.SetSubHeader(&SubHead,NULL);
|
||
|
Unpack.SetDestSize(SubHead.UnpSize);
|
||
|
if (SubHead.Method==0x30)
|
||
|
CmdExtract::UnstoreFile(SubDataIO,SubHead.UnpSize);
|
||
|
else
|
||
|
Unpack.DoUnpack(SubHead.UnpVer,false);
|
||
|
|
||
|
if (SubHead.FileCRC!=~SubDataIO.UnpFileCRC)
|
||
|
{
|
||
|
#ifndef SHELL_EXT
|
||
|
Log(FileName,St(MSubHeadDataCRC),SubHead.FileName);
|
||
|
#endif
|
||
|
ErrHandler.SetErrorCode(CRC_ERROR);
|
||
|
if (UnpData!=NULL)
|
||
|
UnpData->Reset();
|
||
|
return(false);
|
||
|
}
|
||
|
return(true);
|
||
|
}
|
||
|
#endif
|