mirror of https://github.com/bsnes-emu/bsnes.git
315 lines
7.5 KiB
C++
Executable File
315 lines
7.5 KiB
C++
Executable File
#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<SIZEOF_SHORTBLOCKHEAD)
|
|
{
|
|
return unrar_err_corrupt; // invalid HeadSize
|
|
}
|
|
|
|
// catches unknown block types and reading something that isn't even a header
|
|
check( MARK_HEAD <= ShortBlock.HeadType && ShortBlock.HeadType <= ENDARC_HEAD );
|
|
|
|
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);
|
|
|
|
if ( Raw.PaddedSize() > 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;J<count;J++)
|
|
{
|
|
byte CurByte;
|
|
Raw.Get(CurByte);
|
|
}
|
|
}
|
|
}
|
|
NextBlockPos+=hd->FullPackSize;
|
|
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 (NextBlockPos<CurBlockPos+Raw.Size())
|
|
return unrar_err_corrupt; // next block isn't past end of current block's header
|
|
|
|
// If pos went negative, then unrar_pos_t is only 32 bits and it overflowed
|
|
if ( NextBlockPos < 0 )
|
|
return unrar_err_huge;
|
|
|
|
return unrar_ok;
|
|
}
|
|
|
|
// Rar.Read()s are checked by caller of ReadOldHeader() (see above)
|
|
#ifndef SFX_MODULE
|
|
int Archive::ReadOldHeader()
|
|
{
|
|
Raw.Reset();
|
|
if (CurBlockPos<=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);
|
|
// (removed other times)
|
|
|
|
Raw.Read(OldLhd.NameSize);
|
|
Raw.Get((byte *)NewLhd.FileName,OldLhd.NameSize);
|
|
NewLhd.FileName[OldLhd.NameSize]=0;
|
|
// (removed name case conversion)
|
|
*NewLhd.FileNameW=0;
|
|
|
|
if (Raw.Size()!=0)
|
|
NextBlockPos=CurBlockPos+NewLhd.HeadSize+NewLhd.PackSize;
|
|
CurHeaderType=FILE_HEAD;
|
|
}
|
|
return(NextBlockPos>CurBlockPos ? 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;
|
|
}
|
|
}
|