size_t Archive::ReadHeader15() { RawRead Raw(this); bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD3; if (Decrypt) { #ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll. return 0; #else RequestArcPassword(); byte Salt[SIZE_SALT30]; if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30) { UnexpEndArcMsg(); return 0; } HeadersCrypt.SetCryptKeys(false,CRYPT_RAR30,&Cmd->Password,Salt,NULL,0,NULL,NULL); Raw.SetCrypt(&HeadersCrypt); #endif } Raw.Read(SIZEOF_SHORTBLOCKHEAD); if (Raw.Size()==0) { UnexpEndArcMsg(); return 0; } ShortBlock.HeadCRC=Raw.Get2(); ShortBlock.Reset(); uint HeaderType=Raw.Get1(); ShortBlock.Flags=Raw.Get2(); ShortBlock.SkipIfUnknown=(ShortBlock.Flags & SKIP_IF_UNKNOWN)!=0; ShortBlock.HeadSize=Raw.Get2(); ShortBlock.HeaderType=(HEADER_TYPE)HeaderType; if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD) { BrokenHeaderMsg(); return 0; } // For simpler further processing we map header types common // for RAR 1.5 and 5.0 formats to RAR 5.0 values. It does not include // header types specific for RAR 1.5 - 4.x only. switch(ShortBlock.HeaderType) { case HEAD3_MAIN: ShortBlock.HeaderType=HEAD_MAIN; break; case HEAD3_FILE: ShortBlock.HeaderType=HEAD_FILE; break; case HEAD3_SERVICE: ShortBlock.HeaderType=HEAD_SERVICE; break; case HEAD3_ENDARC: ShortBlock.HeaderType=HEAD_ENDARC; break; } CurHeaderType=ShortBlock.HeaderType; if (ShortBlock.HeaderType==HEAD3_CMT) { // Old style (up to RAR 2.9) comment header embedded into main // or file header. We must not read the entire ShortBlock.HeadSize here // to not break the comment processing logic later. Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD); } else if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0) { // Old style (up to RAR 2.9) main archive comment embedded into // the main archive header found. While we can read the entire // ShortBlock.HeadSize here and remove this part of "if", it would be // waste of memory, because we'll read and process this comment data // in other function anyway and we do not need them here now. Raw.Read(SIZEOF_MAINHEAD3-SIZEOF_SHORTBLOCKHEAD); } else Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD); NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize); switch(ShortBlock.HeaderType) { case HEAD_MAIN: MainHead.Reset(); *(BaseBlock *)&MainHead=ShortBlock; MainHead.HighPosAV=Raw.Get2(); MainHead.PosAV=Raw.Get4(); Volume=(MainHead.Flags & MHD_VOLUME)!=0; Solid=(MainHead.Flags & MHD_SOLID)!=0; Locked=(MainHead.Flags & MHD_LOCK)!=0; Protected=(MainHead.Flags & MHD_PROTECT)!=0; Encrypted=(MainHead.Flags & MHD_PASSWORD)!=0; Signed=MainHead.PosAV!=0 || MainHead.HighPosAV!=0; MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0; // Only for encrypted 3.0+ archives. 2.x archives did not have this // flag, so for non-encrypted archives, we'll set it later based on // file attributes. FirstVolume=(MainHead.Flags & MHD_FIRSTVOLUME)!=0; NewNumbering=(MainHead.Flags & MHD_NEWNUMBERING)!=0; break; case HEAD_FILE: case HEAD_SERVICE: { bool FileBlock=ShortBlock.HeaderType==HEAD_FILE; FileHeader *hd=FileBlock ? &FileHead:&SubHead; hd->Reset(); *(BaseBlock *)hd=ShortBlock; hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0; hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0; hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0; hd->SaltSet=(hd->Flags & LHD_SALT)!=0; hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0; hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0; hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY; hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5); hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0; hd->Version=(hd->Flags & LHD_VERSION)!=0; hd->DataSize=Raw.Get4(); uint LowUnpSize=Raw.Get4(); hd->HostOS=Raw.Get1(); hd->FileHash.Type=HASH_CRC32; hd->FileHash.CRC32=Raw.Get4(); uint FileTime=Raw.Get4(); hd->UnpVer=Raw.Get1(); hd->Method=Raw.Get1()-0x30; size_t NameSize=Raw.Get2(); hd->FileAttr=Raw.Get4(); hd->CryptMethod=CRYPT_NONE; if (hd->Encrypted) switch(hd->UnpVer) { case 13: hd->CryptMethod=CRYPT_RAR13; break; case 15: hd->CryptMethod=CRYPT_RAR15; break; case 20: case 26: hd->CryptMethod=CRYPT_RAR20; break; default: hd->CryptMethod=CRYPT_RAR30; break; } hd->HSType=HSYS_UNKNOWN; if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS) hd->HSType=HSYS_UNIX; else if (hd->HostOS<HOST_MAX) hd->HSType=HSYS_WINDOWS; hd->RedirType=FSREDIR_NONE; // RAR 4.x Unix symlink. if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000) { hd->RedirType=FSREDIR_UNIXSYMLINK; *hd->RedirName=0; } hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0; hd->LargeFile=(hd->Flags & LHD_LARGE)!=0; uint HighPackSize,HighUnpSize; if (hd->LargeFile) { HighPackSize=Raw.Get4(); HighUnpSize=Raw.Get4(); hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff); } else { HighPackSize=HighUnpSize=0; // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates // that we do not know the unpacked file size and must unpack it // until we find the end of file marker in compressed data. hd->UnknownUnpSize=(LowUnpSize==0xffffffff); } hd->PackSize=INT32TO64(HighPackSize,hd->DataSize); hd->UnpSize=INT32TO64(HighUnpSize,LowUnpSize); if (hd->UnknownUnpSize) hd->UnpSize=INT64NDF; char FileName[NM*4]; size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1); Raw.GetB((byte *)FileName,ReadNameSize); FileName[ReadNameSize]=0; if (FileBlock) { if ((hd->Flags & LHD_UNICODE)!=0) { EncodeFileName NameCoder; size_t Length=strlen(FileName); Length++; NameCoder.Decode(FileName,(byte *)FileName+Length, NameSize-Length,hd->FileName, ASIZE(hd->FileName)); } else *hd->FileName=0; char AnsiName[NM]; IntToExt(FileName,AnsiName,ASIZE(AnsiName)); GetWideName(AnsiName,hd->FileName,hd->FileName,ASIZE(hd->FileName)); #ifndef SFX_MODULE ConvertNameCase(hd->FileName); #endif ConvertFileHeader(hd); } else { CharToWide(FileName,hd->FileName,ASIZE(hd->FileName)); // Calculate the size of optional data. int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3); if ((hd->Flags & LHD_SALT)!=0) DataSize-=SIZE_SALT30; if (DataSize>0) { // Here we read optional additional fields for subheaders. // They are stored after the file name and before salt. hd->SubData.Alloc(DataSize); Raw.GetB(&hd->SubData[0],DataSize); if (hd->CmpName(SUBHEAD_TYPE_RR)) { byte *D=&hd->SubData[8]; RecoverySize=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24); RecoverySize*=512; // Sectors to size. int64 CurPos=Tell(); RecoveryPercent=ToPercent(RecoverySize,CurPos); // Round fractional percent exceeding .5 to upper value. if (ToPercent(RecoverySize+CurPos/200,CurPos)>RecoveryPercent) RecoveryPercent++; } } if (hd->CmpName(SUBHEAD_TYPE_CMT)) MainComment=true; } if ((hd->Flags & LHD_SALT)!=0) Raw.GetB(hd->Salt,SIZE_SALT30); hd->mtime.SetDos(FileTime); if ((hd->Flags & LHD_EXTTIME)!=0) { ushort Flags=Raw.Get2(); RarTime *tbl[4]; tbl[0]=&FileHead.mtime; tbl[1]=&FileHead.ctime; tbl[2]=&FileHead.atime; tbl[3]=NULL; // Archive time is not used now. for (int I=0;I<4;I++) { RarTime *CurTime=tbl[I]; uint rmode=Flags>>(3-I)*4; if ((rmode & 8)==0 || CurTime==NULL) continue; if (I!=0) { uint DosTime=Raw.Get4(); CurTime->SetDos(DosTime); } RarLocalTime rlt; CurTime->GetLocal(&rlt); if (rmode & 4) rlt.Second++; rlt.Reminder=0; int count=rmode&3; for (int J=0;J<count;J++) { byte CurByte=Raw.Get1(); rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8)); } CurTime->SetLocal(&rlt); } } NextBlockPos+=hd->PackSize; bool CRCProcessedOnly=hd->CommentInHeader; ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly); if (hd->HeadCRC!=HeaderCRC) { BrokenHeader=true; ErrHandler.SetErrorCode(RARX_WARNING); // If we have a broken encrypted header, we do not need to display // the error message here, because it will be displayed for such // headers later in this function. Also such headers are unlikely // to have anything sensible in file name field, so it is useless // to display the file name. if (!Decrypt) uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName); } } break; case HEAD_ENDARC: *(BaseBlock *)&EndArcHead=ShortBlock; EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0; EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0; EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0; EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0; if (EndArcHead.DataCRC) EndArcHead.ArcDataCRC=Raw.Get4(); if (EndArcHead.StoreVolNumber) VolNumber=EndArcHead.VolNumber=Raw.Get2(); break; #ifndef SFX_MODULE case HEAD3_CMT: *(BaseBlock *)&CommHead=ShortBlock; CommHead.UnpSize=Raw.Get2(); CommHead.UnpVer=Raw.Get1(); CommHead.Method=Raw.Get1(); CommHead.CommCRC=Raw.Get2(); break; case HEAD3_SIGN: *(BaseBlock *)&SignHead=ShortBlock; SignHead.CreationTime=Raw.Get4(); SignHead.ArcNameSize=Raw.Get2(); SignHead.UserNameSize=Raw.Get2(); break; case HEAD3_AV: *(BaseBlock *)&AVHead=ShortBlock; AVHead.UnpVer=Raw.Get1(); AVHead.Method=Raw.Get1(); AVHead.AVVer=Raw.Get1(); AVHead.AVInfoCRC=Raw.Get4(); break; case HEAD3_PROTECT: *(BaseBlock *)&ProtectHead=ShortBlock; ProtectHead.DataSize=Raw.Get4(); ProtectHead.Version=Raw.Get1(); ProtectHead.RecSectors=Raw.Get2(); ProtectHead.TotalBlocks=Raw.Get4(); Raw.GetB(ProtectHead.Mark,8); NextBlockPos+=ProtectHead.DataSize; RecoverySize=ProtectHead.RecSectors*512; break; case HEAD3_OLDSERVICE: *(BaseBlock *)&SubBlockHead=ShortBlock; SubBlockHead.DataSize=Raw.Get4(); NextBlockPos+=SubBlockHead.DataSize; SubBlockHead.SubType=Raw.Get2(); SubBlockHead.Level=Raw.Get1(); switch(SubBlockHead.SubType) { case UO_HEAD: *(SubBlockHeader *)&UOHead=SubBlockHead; UOHead.OwnerNameSize=Raw.Get2(); UOHead.GroupNameSize=Raw.Get2(); if (UOHead.OwnerNameSize>=ASIZE(UOHead.OwnerName)) UOHead.OwnerNameSize=ASIZE(UOHead.OwnerName)-1; if (UOHead.GroupNameSize>=ASIZE(UOHead.GroupName)) UOHead.GroupNameSize=ASIZE(UOHead.GroupName)-1; Raw.GetB(UOHead.OwnerName,UOHead.OwnerNameSize); Raw.GetB(UOHead.GroupName,UOHead.GroupNameSize); UOHead.OwnerName[UOHead.OwnerNameSize]=0; UOHead.GroupName[UOHead.GroupNameSize]=0; break; case MAC_HEAD: *(SubBlockHeader *)&MACHead=SubBlockHead; MACHead.fileType=Raw.Get4(); MACHead.fileCreator=Raw.Get4(); break; case EA_HEAD: case BEEA_HEAD: case NTACL_HEAD: *(SubBlockHeader *)&EAHead=SubBlockHead; EAHead.UnpSize=Raw.Get4(); EAHead.UnpVer=Raw.Get1(); EAHead.Method=Raw.Get1(); EAHead.EACRC=Raw.Get4(); break; case STREAM_HEAD: *(SubBlockHeader *)&StreamHead=SubBlockHead; StreamHead.UnpSize=Raw.Get4(); StreamHead.UnpVer=Raw.Get1(); StreamHead.Method=Raw.Get1(); StreamHead.StreamCRC=Raw.Get4(); StreamHead.StreamNameSize=Raw.Get2(); if (StreamHead.StreamNameSize>=ASIZE(StreamHead.StreamName)) StreamHead.StreamNameSize=ASIZE(StreamHead.StreamName)-1; Raw.GetB(StreamHead.StreamName,StreamHead.StreamNameSize); StreamHead.StreamName[StreamHead.StreamNameSize]=0; break; } break; #endif default: if (ShortBlock.Flags & LONG_BLOCK) NextBlockPos+=Raw.Get4(); break; }
size_t Archive::ReadHeader() { // Once we failed to decrypt an encrypted block, there is no reason to // attempt to do it further. We'll never be successful and only generate // endless errors. if (FailedHeaderDecryption) return 0; 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(RAR_NOCRYPT) return(0); #else if (Read(HeadersSalt,SALT_SIZE)!=SALT_SIZE) { UnexpEndArcMsg(); return(0); } if (*Cmd->Password==0) { #ifdef RARDLL char PasswordA[MAXPASSWORD]; if (Cmd->Callback==NULL || Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1) { Close(); //ErrHandler.Exit(USER_BREAK); original ErrHandler.Exit(NO_PASSWORD_ERROR); } GetWideName(PasswordA,NULL,Cmd->Password,ASIZE(Cmd->Password)); #else if (!GetPassword(PASSWORD_ARCHIVE,FileName,FileNameW,Cmd->Password,ASIZE(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) { // Old style (up to RAR 2.9) comment header embedded into main // or file header. We must not read the entire ShortBlock.HeadSize here // to not break the comment processing logic later. Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD); } else if (ShortBlock.HeadType==MAIN_HEAD && (ShortBlock.Flags & MHD_COMMENT)!=0) { // Old style (up to RAR 2.9) main archive comment embedded into // the main archive header found. While we can read the entire // ShortBlock.HeadSize here and remove this part of "if", it would be // waste of memory, because we'll read and process this comment data // in other function anyway and we do not need them here now. Raw.Read(SIZEOF_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]; size_t 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) { // Let's calculate the size of optional data. int DataSize=hd->HeadSize-hd->NameSize-SIZEOF_NEWLHD; if (hd->Flags & LHD_SALT) DataSize-=SALT_SIZE; if (DataSize>0) { // Here we read optional additional fields for subheaders. // They are stored after the file name and before salt. hd->SubData.Alloc(DataSize); Raw.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 && strlen(hd->FileName)<ASIZE(hd->FileName)-5) strcat(hd->FileName,"- ???"); BrokenFileHeader=true; ErrHandler.SetErrorCode(WARNING); // If we have a broken encrypted header, we do not need to display // the error message here, because it will be displayed for such // headers later in this function. Also such headers are unlikely // to have anything sensible in file name field, so it is useless // to display the file name. bool EncBroken=Decrypt && ShortBlock.HeadCRC!=(~Raw.GetCRC(false)&0xffff); if (!EncBroken) { #ifndef SHELL_EXT Log(Archive::FileName,St(MLogFileHead),IntNameToExt(hd->FileName)); Alarm(); #endif } } }
int Archive::ReadHeader() { CurBlockPos=Tell(); #ifndef SFX_MODULE if (OldFormat) return(ReadOldHeader()); #endif RawRead Raw(this); bool Decrypt=Encrypted && CurBlockPos>=SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD; if (Decrypt) { #if defined(SHELL_EXT) || defined(NOCRYPT) return(0); #else if (Read(HeadersSalt,SALT_SIZE)!=SALT_SIZE) 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) { Int64 ArcSize=FileLength(); if (CurBlockPos>ArcSize || NextBlockPos>ArcSize) { #ifndef SHELL_EXT Log(FileName,St(MLogUnexpEOF)); #endif ErrHandler.SetErrorCode(WARNING); } 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) { hd->UnpSize=int64to32(INT64MAX); hd->HighUnpSize=int64to32(INT64MAX>>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; int 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 } }
int Archive::ReadHeader() { CurBlockPos=Tell(); #ifndef SFX_MODULE if (OldFormat) return(ReadOldHeader()); #endif RawRead Raw(this); bool Decrypt=Encrypted && CurBlockPos>=SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD; if (Decrypt) { #if defined(SHELL_EXT) || defined(NOCRYPT) return(0); #else if (Read(HeadersSalt,SALT_SIZE)!=SALT_SIZE) return(0); if (*Cmd->Password==0) #ifdef RARDLL if (Cmd->Callback==NULL || Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LONG)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); Raw.SetCrypt(&HeadersCrypt); #endif } Raw.Read(SIZEOF_SHORTBLOCKHEAD); if (Raw.Size()==0) { Int64 ArcSize=FileLength(); if (CurBlockPos>ArcSize || NextBlockPos>ArcSize) { #ifndef SHELL_EXT Log(FileName,St(MLogUnexpEOF)); #endif ErrHandler.SetErrorCode(WARNING); } return(0); } Raw.Get(ShortBlock.HeadCRC); unsigned char 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); break; case ENDARC_HEAD: *(BaseBlock *)&EndArcHead=ShortBlock; if (EndArcHead.Flags & EARC_DATACRC) Raw.Get(EndArcHead.ArcDataCRC); 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; 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((unsigned char *)FileName,NameSize); FileName[NameSize]=0; strncpy(hd->FileName,FileName,sizeof(hd->FileName)); hd->FileName[sizeof(hd->FileName)-1]=0; 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)) { unsigned char *D=&hd->SubData[8]; RecoverySectors=D[0]+((unsigned int)D[1]<<8)+((unsigned int)D[2]<<16)+((unsigned int)D[3]<<24); } } } else if (hd->HeadType==FILE_HEAD) { if (hd->Flags & LHD_UNICODE) { EncodeFileName NameCoder; int Length=strlen(FileName)+1; NameCoder.Decode(FileName,(unsigned char *)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) { unsigned short 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]; unsigned int rmode=Flags>>(3-I)*4; if ((rmode & 8)==0) continue; if (I!=0) { unsigned int 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++) { unsigned char CurByte; Raw.Get(CurByte); rlt.Reminder|=(((unsigned int)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); Raw.Get((unsigned char *)UOHead.OwnerName,UOHead.OwnerNameSize); Raw.Get((unsigned char *)UOHead.GroupName,UOHead.GroupNameSize); if (UOHead.OwnerNameSize>NM-1) UOHead.OwnerNameSize=NM-1; if (UOHead.GroupNameSize>NM-1) UOHead.GroupNameSize=NM-1; 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((unsigned char *)StreamHead.StreamName,StreamHead.StreamNameSize); StreamHead.StreamName[StreamHead.StreamNameSize]=0; break; } break; #endif default: if (ShortBlock.Flags & LONG_BLOCK) { unsigned int DataSize; Raw.Get(DataSize); NextBlockPos+=DataSize; } break; }