#include "rar.hpp" #include "unrar.h" #include "unicode.hpp" #include "encname.hpp" // arcread.cpp unrar_err_t Archive::ReadHeader() { CurBlockPos=Tell(); #ifndef SFX_MODULE if (OldFormat) { ReadOldHeader(); if ( Raw.Size() == 0 ) return unrar_err_arc_eof; // right at end of file if ( Raw.PaddedSize() > 0 ) // added check return unrar_err_corrupt; // missing data return unrar_ok; } #endif Raw.Reset(); // (removed decryption) Raw.Read(SIZEOF_SHORTBLOCKHEAD); if (Raw.Size()==0) { return unrar_err_arc_eof; // right at end of file } 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 0 ) // fewer than requested bytes read above? return unrar_err_corrupt; // missing data NextBlockPos=CurBlockPos+ShortBlock.HeadSize; switch(ShortBlock.HeadType) { case MAIN_HEAD: *(BaseBlock *)&NewMhd=ShortBlock; Raw.Get(NewMhd.HighPosAV); Raw.Get(NewMhd.PosAV); check( Raw.ReadPos == Raw.DataSize ); // we should have read all fields 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) { // TODO: what the heck is this for anyway? hd->UnpSize=0; hd->HighUnpSize=0x7fffffff; } } hd->FullPackSize=int32to64(hd->HighPackSize,hd->PackSize); hd->FullUnpSize=int32to64(hd->HighUnpSize,hd->UnpSize); if ( int32to64( 1, 0 ) == 0 && (hd->HighPackSize || hd->HighUnpSize) ) return unrar_err_huge; char (&FileName) [sizeof hd->FileName] = hd->FileName; // eliminated local buffer int NameSize=Min(hd->NameSize,sizeof(FileName)-1); Raw.Get((byte *)FileName,NameSize); FileName[NameSize]=0; if (hd->HeadType==NEWSUB_HEAD) { // have to adjust this, even through we're ignoring this block NextBlockPos+=hd->FullPackSize; break; } 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; ConvertUnknownHeader(); } if (hd->Flags & LHD_SALT) Raw.Get(hd->Salt,SALT_SIZE); hd->mtime.SetDos(hd->FileTime); if (hd->Flags & LHD_EXTTIME) { ushort Flags; Raw.Get(Flags); // Ignore additional time information for (int I=0;I<4;I++) { uint rmode=Flags>>(3-I)*4; if ((rmode & 8)==0) continue; if (I!=0) { uint DosTime; Raw.Get(DosTime); } // skip time info int count=rmode&3; for (int J=0;JFullPackSize; bool CRCProcessedOnly=(hd->Flags & LHD_COMMENT)!=0; HeaderCRC=~Raw.GetCRC(CRCProcessedOnly)&0xffff; if (hd->HeadCRC!=HeaderCRC) return unrar_err_corrupt; check( CRCProcessedOnly == false ); // I need to test on archives where this doesn't hold check( Raw.ReadPos == Raw.DataSize ); // we should have read all fields } break; #ifndef SFX_MODULE // Handle these block types just so we can adjust NextBlockPos properly case PROTECT_HEAD: Raw.Get(ProtectHead.DataSize); NextBlockPos+=ProtectHead.DataSize; break; case SUB_HEAD: Raw.Get(SubBlockHead.DataSize); NextBlockPos+=SubBlockHead.DataSize; break; #endif default: if (ShortBlock.Flags & LONG_BLOCK) { uint DataSize; Raw.Get(DataSize); NextBlockPos+=DataSize; } break; } HeaderCRC=~Raw.GetCRC(false)&0xffff; CurHeaderType=ShortBlock.HeadType; // (removed decryption) if (NextBlockPosCurBlockPos ? Raw.Size():0); } #endif // (removed name case and attribute conversion) bool Archive::IsArcDir() { return((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY); } bool Archive::IsArcLabel() { return(NewLhd.HostOS<=HOST_WIN32 && (NewLhd.FileAttr & 8)); } // TODO: use '\\' on Windows? char const CPATHDIVIDER = '/'; #define charnext(s) ((s)+1) 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; } } // (removed Apple Unicode handling) for (wchar *s=NewLhd.FileNameW;*s!=0;s++) { if (*s=='/' || *s=='\\') *s=CPATHDIVIDER; } }