// Convert archived names and comments to Unicode. // Allows user to select a code page in GUI. void ArcCharToWide(const char *Src,wchar *Dest,size_t DestSize,ACTW_ENCODING Encoding) { #if defined(_WIN_ALL) // Console Windows RAR. if (Encoding==ACTW_UTF8) UtfToWide(Src,Dest,DestSize); else { Array<char> NameA; if (Encoding==ACTW_OEM) { NameA.Alloc(DestSize+1); IntToExt(Src,&NameA[0],NameA.Size()); Src=&NameA[0]; } CharToWide(Src,Dest,DestSize); } #else // RAR for Unix. if (Encoding==ACTW_UTF8) UtfToWide(Src,Dest,DestSize); else CharToWide(Src,Dest,DestSize); #endif // Ensure that we return a zero terminate string for security reason. // While [Jni]CharToWide might already do it, be protected in case of future // changes in these functions. if (DestSize>0) Dest[DestSize-1]=0; }
bool FindFile::FastFind(const char *FindMask,const wchar *FindMaskW,struct FindData *fd,bool GetSymLink) { fd->Error=false; #ifndef _UNIX if (IsWildcard(FindMask,FindMaskW)) return(false); #endif #ifdef _WIN_32 HANDLE hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,FindMaskW,fd); if (hFind==INVALID_HANDLE_VALUE) return(false); FindClose(hFind); #else struct stat st; if (GetSymLink) { #ifdef SAVE_LINKS if (lstat(FindMask,&st)!=0) #else if (stat(FindMask,&st)!=0) #endif { fd->Error=(errno!=ENOENT); return(false); } } else if (stat(FindMask,&st)!=0) { fd->Error=(errno!=ENOENT); return(false); } #ifdef _DJGPP fd->FileAttr=_chmod(FindMask,0); #elif defined(_EMX) fd->FileAttr=st.st_attr; #else fd->FileAttr=st.st_mode; #endif fd->IsDir=IsDir(st.st_mode); fd->Size=st.st_size; fd->mtime=st.st_mtime; fd->atime=st.st_atime; fd->ctime=st.st_ctime; fd->FileTime=fd->mtime.GetDos(); strcpy(fd->Name,FindMask); *fd->NameW=0; #ifdef _APPLE if (!LowAscii(fd->Name)) UtfToWide(fd->Name,fd->NameW,sizeof(fd->NameW)); #elif defined(UNICODE_SUPPORTED) if (!LowAscii(fd->Name) && UnicodeEnabled()) CharToWide(fd->Name,fd->NameW); #endif #endif fd->Flags=0; fd->IsDir=IsDir(fd->FileAttr); return(true); }
bool CharToWide(const char *Src,wchar *Dest,size_t DestSize) { bool RetCode=true; *Dest=0; // Set 'Dest' to zero just in case the conversion will fail. #ifdef _WIN_ALL if (MultiByteToWideChar(CP_ACP,0,Src,-1,Dest,(int)DestSize)==0) RetCode=false; #elif defined(_APPLE) UtfToWide(Src,Dest,DestSize); #elif defined(MBFUNCTIONS) size_t ResultingSize=mbstowcs(Dest,Src,DestSize); if (ResultingSize==(size_t)-1) RetCode=false; if (ResultingSize==0 && *Src!=0) RetCode=false; if ((!RetCode || *Dest==0 && *Src!=0) && DestSize>NM && strlen(Src)<NM) { /* Workaround for strange Linux Unicode functions bug. Some of wcstombs and mbstowcs implementations in some situations (we are yet to find out what it depends on) can return an empty string and success code if buffer size value is too large. */ return(CharToWide(Src,Dest,NM)); } #else if (UnicodeEnabled()) { #if defined(_EMX) && !defined(_DJGPP) int len=Min(strlen(Src)+1,DestSize-1); if (uni_toucs((char*)Src,len,(UniChar*)Dest,(size_t*)&DestSize)==-1 || DestSize>len) DestSize=0; RetCode=false; #endif } else for (int I=0;I<DestSize;I++) { Dest[I]=(wchar_t)Src[I]; if (Src[I]==0) break; } #endif // We tried to return the zero terminated string if conversion is failed, // but it does not work well. MultiByteToWideChar returns 'failed' code // even if we wanted to convert only a part of string and passed DestSize // smaller than required for fully converted string. Such call is the valid // behavior in RAR code and we do not expect the empty string in this case. return(RetCode); }
bool CharToWide(const char *Src,wchar *Dest,size_t DestSize) { bool RetCode=true; #ifdef _WIN_32 if (MultiByteToWideChar(CP_ACP,0,Src,-1,Dest,(int)DestSize)==0) RetCode=false; #else #ifdef _APPLE UtfToWide(Src,Dest,DestSize); #else #ifdef MBFUNCTIONS size_t ResultingSize=mbstowcs(Dest,Src,DestSize); if (ResultingSize==(size_t)-1) RetCode=false; if (ResultingSize==0 && *Src!=0) RetCode=false; if ((!RetCode || *Dest==0 && *Src!=0) && DestSize>NM && strlen(Src)<NM) { /* Workaround for strange Linux Unicode functions bug. Some of wcstombs and mbstowcs implementations in some situations (we are yet to find out what it depends on) can return an empty string and success code if buffer size value is too large. */ return(CharToWide(Src,Dest,NM)); } #else if (UnicodeEnabled()) { #if defined(_EMX) && !defined(_DJGPP) int len=Min(strlen(Src)+1,DestSize-1); if (uni_toucs((char*)Src,len,(UniChar*)Dest,(size_t*)&DestSize)==-1 || DestSize>len) DestSize=0; RetCode=false; #endif } else for (int I=0;I<DestSize;I++) { Dest[I]=(wchar_t)Src[I]; if (Src[I]==0) break; } #endif #endif #endif return(RetCode); }
bool CharToWide(const char *Src,wchar *Dest,size_t DestSize) { bool RetCode=true; *Dest=0; // Set 'Dest' to zero just in case the conversion will fail. #ifdef _WIN_ALL if (MultiByteToWideChar(CP_ACP,0,Src,-1,Dest,(int)DestSize)==0) RetCode=false; // mbstowcs is broken in Android NDK r9. #elif defined(_APPLE) || defined(_ANDROID) UtfToWide(Src,Dest,DestSize); #elif defined(MBFUNCTIONS) mbstate_t ps; memset (&ps, 0, sizeof(ps)); const char *SrcParam=Src; // mbsrtowcs can change the pointer. size_t ResultingSize=mbsrtowcs(Dest,&SrcParam,DestSize,&ps); if (ResultingSize==(size_t)-1) RetCode=false; if (ResultingSize==0 && *Src!=0) RetCode=false; if (RetCode==false && DestSize>1) CharToWideMap(Src,Dest,DestSize,RetCode); #else for (int I=0;I<DestSize;I++) { Dest[I]=(wchar_t)Src[I]; if (Src[I]==0) break; } #endif if (DestSize>0) Dest[DestSize-1]=0; // We tried to return the empty string if conversion is failed, // but it does not work well. MultiByteToWideChar returns 'failed' code // even if we wanted to convert only a part of string and passed DestSize // smaller than required for fully converted string. Such call is the valid // behavior in RAR code and we do not expect the empty string in this case. return RetCode; }
void GetStreamNameNTFS(Archive &Arc,wchar *StreamName,size_t MaxSize) { byte *Data=&Arc.SubHead.SubData[0]; size_t DataSize=Arc.SubHead.SubData.Size(); if (Arc.Format==RARFMT15) { size_t DestSize=Min(DataSize/2,MaxSize-1); RawToWide(Data,StreamName,DestSize); StreamName[DestSize]=0; } else { char UtfString[NM*4]; size_t DestSize=Min(DataSize,ASIZE(UtfString)-1); memcpy(UtfString,Data,DestSize); UtfString[DestSize]=0; UtfToWide(UtfString,StreamName,MaxSize); } }
bool CharToWide(const char *Src,wchar *Dest,int DestSize) { bool RetCode=true; #ifdef _WIN_32 if (MultiByteToWideChar(CP_ACP,0,Src,-1,Dest,DestSize)==0) RetCode=false; #else #ifdef _APPLE UtfToWide(Src,Dest,DestSize); #else #ifdef MBFUNCTIONS if (mbstowcs(Dest,Src,DestSize)==-1) RetCode=false; #else if (UnicodeEnabled()) { #if defined(_EMX) && !defined(_DJGPP) int len=Min(strlen(Src)+1,DestSize-1); if (uni_toucs((char*)Src,len,(UniChar*)Dest,(size_t*)&DestSize)==-1 || DestSize>len) DestSize=0; RetCode=false; #endif } else for (int I=0;I<DestSize;I++) { Dest[I]=(wchar_t)Src[I]; if (Src[I]==0) break; } #endif #endif #endif return(RetCode); }
bool Archive::ReadCommentData(Array<wchar> *CmtData) { Array<byte> CmtRaw; if (!ReadSubData(&CmtRaw,NULL)) return false; size_t CmtSize=CmtRaw.Size(); CmtRaw.Push(0); CmtData->Alloc(CmtSize+1); if (Format==RARFMT50) UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size()); else if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0) { RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2); (*CmtData)[CmtSize/2]=0; } else { CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size()); } CmtData->Alloc(wcslen(CmtData->Addr(0))); // Set buffer size to actual comment length. return true; }
bool FindFile::Next(struct FindData *fd,bool GetSymLink) { fd->Error=false; if (*FindMask==0) return(false); #ifdef _WIN_32 if (FirstCall) { if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,FindMaskW,fd))==INVALID_HANDLE_VALUE) return(false); } else if (Win32Find(hFind,FindMask,FindMaskW,fd)==INVALID_HANDLE_VALUE) return(false); #else if (FirstCall) { char DirName[NM]; strcpy(DirName,FindMask); RemoveNameFromPath(DirName); if (*DirName==0) strcpy(DirName,"."); /* else { int Length=strlen(DirName); if (Length>1 && DirName[Length-1]==CPATHDIVIDER && (Length!=3 || !IsDriveDiv(DirName[1]))) DirName[Length-1]=0; } */ if ((dirp=opendir(DirName))==NULL) { fd->Error=(errno!=ENOENT); return(false); } } while (1) { struct dirent *ent=readdir(dirp); if (ent==NULL) return(false); if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0) continue; if (CmpName(FindMask,ent->d_name,MATCH_NAMES)) { char FullName[NM]; strcpy(FullName,FindMask); *PointToName(FullName)=0; if (strlen(FullName)+strlen(ent->d_name)>=ASIZE(FullName)-1) { #ifndef SILENT Log(NULL,"\n%s%s",FullName,ent->d_name); Log(NULL,St(MPathTooLong)); #endif return(false); } strcat(FullName,ent->d_name); if (!FastFind(FullName,NULL,fd,GetSymLink)) { ErrHandler.OpenErrorMsg(FullName); continue; } strcpy(fd->Name,FullName); break; } } *fd->NameW=0; #ifdef _APPLE if (!LowAscii(fd->Name)) UtfToWide(fd->Name,fd->NameW,sizeof(fd->NameW)); #elif defined(UNICODE_SUPPORTED) if (!LowAscii(fd->Name) && UnicodeEnabled()) CharToWide(fd->Name,fd->NameW); #endif #endif fd->Flags=0; fd->IsDir=IsDir(fd->FileAttr); FirstCall=false; char *Name=PointToName(fd->Name); if (strcmp(Name,".")==0 || strcmp(Name,"..")==0) return(Next(fd)); return(true); }
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 } }
bool WideToChar(const wchar *Src,char *Dest,int DestSize) { bool RetCode=true; #ifdef _WIN_32 if (WideCharToMultiByte(CP_ACP,0,Src,-1,Dest,DestSize,NULL,NULL)==0) RetCode=false; #else #ifdef _APPLE WideToUtf(Src,Dest,DestSize); #else #ifdef MBFUNCTIONS if (wcstombs(Dest,Src,DestSize)==(uint)-1) RetCode=false; #else if (UnicodeEnabled()) { for (int I=0;I<DestSize;I++) { Dest[I]=(char)Src[I]; if (Src[I]==0) break; } #endif #endif #endif return(RetCode); } bool CharToWide(const char *Src,wchar *Dest,int DestSize) { bool RetCode=true; #ifdef _WIN_32 if (MultiByteToWideChar(CP_ACP,0,Src,-1,Dest,DestSize)==0) RetCode=false; #else #ifdef _APPLE UtfToWide(Src,Dest,DestSize); #else #ifdef MBFUNCTIONS mbstowcs(Dest,Src,DestSize); #else if (UnicodeEnabled()) { for (int I=0;I<DestSize;I++) { Dest[I]=(wchar_t)Src[I]; if (Src[I]==0) break; } #endif #endif #endif return(RetCode); } byte* WideToRaw(const wchar *Src,byte *Dest,int DestSize) { for (int I=0;I<DestSize;I++,Src++) { Dest[I*2]=(byte)*Src; Dest[I*2+1]=(byte)(*Src>>8); if (*Src==0) break; } return(Dest); } wchar* RawToWide(const byte *Src,wchar *Dest,int DestSize) { for (int I=0;I<DestSize;I++) if ((Dest[I]=Src[I*2]+(Src[I*2+1]<<8))==0) break; return(Dest); } #ifdef _APPLE void WideToUtf(const wchar *Src,char *Dest,int DestSize) { DestSize--; while (*Src!=0 && --DestSize>=0) { uint c=*(Src++); if (c<0x80) *(Dest++)=c; else if (c<0x800 && --DestSize>=0) { *(Dest++)=(0xc0|(c>>6)); *(Dest++)=(0x80|(c&0x3f)); } else if (c<0x10000 && (DestSize-=2)>=0)
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 } } }
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; default: 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); if (Length==NameSize) UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName)-1); else { 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) { #ifndef SHELL_EXT Log(Archive::FileName,St(MLogFileHead),hd->FileName); #endif } } } 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; }