929 lines
24 KiB
C++
929 lines
24 KiB
C++
#include "rar.hpp"
|
|
|
|
CmdExtract::CmdExtract()
|
|
{
|
|
TotalFileCount=0;
|
|
*Password=0;
|
|
Unp=new Unpack(&DataIO);
|
|
Unp->Init(NULL);
|
|
}
|
|
|
|
|
|
CmdExtract::~CmdExtract()
|
|
{
|
|
delete Unp;
|
|
memset(Password,0,sizeof(Password));
|
|
}
|
|
|
|
|
|
void CmdExtract::DoExtract(CommandData *Cmd)
|
|
{
|
|
PasswordCancelled=false;
|
|
DataIO.SetCurrentCommand(*Cmd->Command);
|
|
|
|
struct FindData FD;
|
|
while (Cmd->GetArcName(ArcName,ArcNameW,sizeof(ArcName)))
|
|
if (FindFile::FastFind(ArcName,ArcNameW,&FD))
|
|
DataIO.TotalArcSize+=FD.Size;
|
|
|
|
Cmd->ArcNames->Rewind();
|
|
while (Cmd->GetArcName(ArcName,ArcNameW,sizeof(ArcName)))
|
|
{
|
|
while (true)
|
|
{
|
|
char PrevCmdPassword[MAXPASSWORD];
|
|
strcpy(PrevCmdPassword,Cmd->Password);
|
|
|
|
EXTRACT_ARC_CODE Code=ExtractArchive(Cmd);
|
|
|
|
// Restore Cmd->Password, which could be changed in IsArchive() call
|
|
// for next header encrypted archive.
|
|
strcpy(Cmd->Password,PrevCmdPassword);
|
|
|
|
if (Code!=EXTRACT_ARC_REPEAT)
|
|
break;
|
|
}
|
|
if (FindFile::FastFind(ArcName,ArcNameW,&FD))
|
|
DataIO.ProcessedArcSize+=FD.Size;
|
|
}
|
|
|
|
if (TotalFileCount==0 && *Cmd->Command!='I')
|
|
{
|
|
if (!PasswordCancelled)
|
|
{
|
|
mprintf(St(MExtrNoFiles));
|
|
}
|
|
ErrHandler.SetErrorCode(WARNING);
|
|
}
|
|
#ifndef GUI
|
|
else
|
|
if (!Cmd->DisableDone)
|
|
if (*Cmd->Command=='I')
|
|
mprintf(St(MDone));
|
|
else
|
|
if (ErrHandler.GetErrorCount()==0)
|
|
mprintf(St(MExtrAllOk));
|
|
else
|
|
mprintf(St(MExtrTotalErr),ErrHandler.GetErrorCount());
|
|
#endif
|
|
}
|
|
|
|
|
|
void CmdExtract::ExtractArchiveInit(CommandData *Cmd,Archive &Arc)
|
|
{
|
|
DataIO.UnpArcSize=Arc.FileLength();
|
|
|
|
FileCount=0;
|
|
MatchedArgs=0;
|
|
#ifndef SFX_MODULE
|
|
FirstFile=true;
|
|
#endif
|
|
|
|
if (*Cmd->Password!=0)
|
|
strcpy(Password,Cmd->Password);
|
|
PasswordAll=(*Cmd->Password!=0);
|
|
|
|
DataIO.UnpVolume=false;
|
|
|
|
PrevExtracted=false;
|
|
SignatureFound=false;
|
|
AllMatchesExact=true;
|
|
ReconstructDone=false;
|
|
|
|
StartTime.SetCurrentTime();
|
|
}
|
|
|
|
|
|
EXTRACT_ARC_CODE CmdExtract::ExtractArchive(CommandData *Cmd)
|
|
{
|
|
Archive Arc(Cmd);
|
|
if (!Arc.WOpen(ArcName,ArcNameW))
|
|
{
|
|
ErrHandler.SetErrorCode(OPEN_ERROR);
|
|
return(EXTRACT_ARC_NEXT);
|
|
}
|
|
|
|
if (!Arc.IsArchive(true))
|
|
{
|
|
#ifndef GUI
|
|
mprintf(St(MNotRAR),ArcName);
|
|
#endif
|
|
if (CmpExt(ArcName,"rar"))
|
|
ErrHandler.SetErrorCode(WARNING);
|
|
return(EXTRACT_ARC_NEXT);
|
|
}
|
|
|
|
// archive with corrupt encrypted header can be closed in IsArchive() call
|
|
if (!Arc.IsOpened())
|
|
return(EXTRACT_ARC_NEXT);
|
|
|
|
#ifndef SFX_MODULE
|
|
if (Arc.Volume && Arc.NotFirstVolume)
|
|
{
|
|
char FirstVolName[NM];
|
|
VolNameToFirstName(ArcName,FirstVolName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0);
|
|
|
|
// If several volume names from same volume set are specified
|
|
// and current volume is not first in set and first volume is present
|
|
// and specified too, let's skip the current volume.
|
|
if (stricomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) &&
|
|
Cmd->ArcNames->Search(FirstVolName,NULL,false))
|
|
return(EXTRACT_ARC_NEXT);
|
|
}
|
|
#endif
|
|
|
|
int64 VolumeSetSize=0; // Total size of volumes after the current volume.
|
|
|
|
if (Arc.Volume)
|
|
{
|
|
// Calculate the total size of all accessible volumes.
|
|
// This size is necessary to display the correct total progress indicator.
|
|
|
|
char NextName[NM];
|
|
wchar NextNameW[NM];
|
|
|
|
strcpy(NextName,Arc.FileName);
|
|
strcpyw(NextNameW,Arc.FileNameW);
|
|
|
|
while (true)
|
|
{
|
|
// First volume is already added to DataIO.TotalArcSize
|
|
// in initial TotalArcSize calculation in DoExtract.
|
|
// So we skip it and start from second volume.
|
|
NextVolumeName(NextName,NextNameW,ASIZE(NextName),(Arc.NewMhd.Flags & MHD_NEWNUMBERING)==0 || Arc.OldFormat);
|
|
struct FindData FD;
|
|
if (FindFile::FastFind(NextName,NextNameW,&FD))
|
|
VolumeSetSize+=FD.Size;
|
|
else
|
|
break;
|
|
}
|
|
DataIO.TotalArcSize+=VolumeSetSize;
|
|
}
|
|
|
|
ExtractArchiveInit(Cmd,Arc);
|
|
|
|
if (*Cmd->Command=='T' || *Cmd->Command=='I')
|
|
Cmd->Test=true;
|
|
|
|
#ifndef GUI
|
|
if (*Cmd->Command=='I')
|
|
Cmd->DisablePercentage=true;
|
|
else
|
|
if (Cmd->Test)
|
|
mprintf(St(MExtrTest),ArcName);
|
|
else
|
|
mprintf(St(MExtracting),ArcName);
|
|
#endif
|
|
|
|
Arc.ViewComment();
|
|
|
|
// RAR can close a corrupt encrypted archive
|
|
if (!Arc.IsOpened())
|
|
return(EXTRACT_ARC_NEXT);
|
|
|
|
|
|
while (1)
|
|
{
|
|
size_t Size=Arc.ReadHeader();
|
|
bool Repeat=false;
|
|
if (!ExtractCurrentFile(Cmd,Arc,Size,Repeat))
|
|
if (Repeat)
|
|
{
|
|
// If we started extraction from not first volume and need to
|
|
// restart it from first, we must correct DataIO.TotalArcSize
|
|
// for correct total progress display. We subtract the size
|
|
// of current volume and all volumes after it and add the size
|
|
// of new (first) volume.
|
|
struct FindData OldArc,NewArc;
|
|
if (FindFile::FastFind(Arc.FileName,Arc.FileNameW,&OldArc) &&
|
|
FindFile::FastFind(ArcName,ArcNameW,&NewArc))
|
|
DataIO.TotalArcSize-=VolumeSetSize+OldArc.Size-NewArc.Size;
|
|
return(EXTRACT_ARC_REPEAT);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
return(EXTRACT_ARC_NEXT);
|
|
}
|
|
|
|
|
|
bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,size_t HeaderSize,bool &Repeat)
|
|
{
|
|
char Command=*Cmd->Command;
|
|
if (HeaderSize==0)
|
|
if (DataIO.UnpVolume)
|
|
{
|
|
#ifdef NOVOLUME
|
|
return(false);
|
|
#else
|
|
if (!MergeArchive(Arc,&DataIO,false,Command))
|
|
{
|
|
ErrHandler.SetErrorCode(WARNING);
|
|
return(false);
|
|
}
|
|
SignatureFound=false;
|
|
#endif
|
|
}
|
|
else
|
|
return(false);
|
|
int HeadType=Arc.GetHeaderType();
|
|
if (HeadType!=FILE_HEAD)
|
|
{
|
|
if (HeadType==AV_HEAD || HeadType==SIGN_HEAD)
|
|
SignatureFound=true;
|
|
#if !defined(SFX_MODULE) && !defined(_WIN_CE)
|
|
if (HeadType==SUB_HEAD && PrevExtracted)
|
|
SetExtraInfo(Cmd,Arc,DestFileName,*DestFileNameW ? DestFileNameW:NULL);
|
|
#endif
|
|
if (HeadType==NEWSUB_HEAD)
|
|
{
|
|
if (Arc.SubHead.CmpName(SUBHEAD_TYPE_AV))
|
|
SignatureFound=true;
|
|
#if !defined(NOSUBBLOCKS) && !defined(_WIN_CE)
|
|
if (PrevExtracted)
|
|
SetExtraInfoNew(Cmd,Arc,DestFileName,*DestFileNameW ? DestFileNameW:NULL);
|
|
#endif
|
|
}
|
|
if (HeadType==ENDARC_HEAD)
|
|
if (Arc.EndArcHead.Flags & EARC_NEXT_VOLUME)
|
|
{
|
|
#ifndef NOVOLUME
|
|
if (!MergeArchive(Arc,&DataIO,false,Command))
|
|
{
|
|
ErrHandler.SetErrorCode(WARNING);
|
|
return(false);
|
|
}
|
|
SignatureFound=false;
|
|
#endif
|
|
Arc.Seek(Arc.CurBlockPos,SEEK_SET);
|
|
return(true);
|
|
}
|
|
else
|
|
return(false);
|
|
Arc.SeekToNext();
|
|
return(true);
|
|
}
|
|
PrevExtracted=false;
|
|
|
|
if (SignatureFound ||
|
|
!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs->ItemsCount() &&
|
|
AllMatchesExact)
|
|
return(false);
|
|
|
|
char ArcFileName[NM];
|
|
IntToExt(Arc.NewLhd.FileName,Arc.NewLhd.FileName);
|
|
strcpy(ArcFileName,Arc.NewLhd.FileName);
|
|
|
|
wchar ArcFileNameW[NM];
|
|
*ArcFileNameW=0;
|
|
|
|
int MatchType=MATCH_WILDSUBPATH;
|
|
|
|
bool EqualNames=false;
|
|
int MatchNumber=Cmd->IsProcessFile(Arc.NewLhd,&EqualNames,MatchType);
|
|
bool ExactMatch=MatchNumber!=0;
|
|
#if !defined(SFX_MODULE) && !defined(_WIN_CE)
|
|
if (Cmd->ExclPath==EXCL_BASEPATH)
|
|
{
|
|
*Cmd->ArcPath=0;
|
|
if (ExactMatch)
|
|
{
|
|
Cmd->FileArgs->Rewind();
|
|
if (Cmd->FileArgs->GetString(Cmd->ArcPath,NULL,sizeof(Cmd->ArcPath),MatchNumber-1))
|
|
*PointToName(Cmd->ArcPath)=0;
|
|
}
|
|
}
|
|
#endif
|
|
if (ExactMatch && !EqualNames)
|
|
AllMatchesExact=false;
|
|
|
|
#ifdef UNICODE_SUPPORTED
|
|
bool WideName=(Arc.NewLhd.Flags & LHD_UNICODE) && UnicodeEnabled();
|
|
#else
|
|
bool WideName=false;
|
|
#endif
|
|
|
|
#ifdef _APPLE
|
|
if (WideName)
|
|
{
|
|
WideToUtf(Arc.NewLhd.FileNameW,ArcFileName,sizeof(ArcFileName));
|
|
WideName=false;
|
|
}
|
|
#endif
|
|
|
|
wchar *DestNameW=WideName ? DestFileNameW:NULL;
|
|
|
|
#ifdef UNICODE_SUPPORTED
|
|
if (WideName)
|
|
{
|
|
ConvertPath(Arc.NewLhd.FileNameW,ArcFileNameW);
|
|
char Name[NM];
|
|
if (WideToChar(ArcFileNameW,Name) && IsNameUsable(Name))
|
|
strcpy(ArcFileName,Name);
|
|
}
|
|
#endif
|
|
|
|
ConvertPath(ArcFileName,ArcFileName);
|
|
|
|
if (Arc.IsArcLabel())
|
|
return(true);
|
|
|
|
if (Arc.NewLhd.Flags & LHD_VERSION)
|
|
{
|
|
if (Cmd->VersionControl!=1 && !EqualNames)
|
|
{
|
|
if (Cmd->VersionControl==0)
|
|
ExactMatch=false;
|
|
int Version=ParseVersionFileName(ArcFileName,ArcFileNameW,false);
|
|
if (Cmd->VersionControl-1==Version)
|
|
ParseVersionFileName(ArcFileName,ArcFileNameW,true);
|
|
else
|
|
ExactMatch=false;
|
|
}
|
|
}
|
|
else
|
|
if (!Arc.IsArcDir() && Cmd->VersionControl>1)
|
|
ExactMatch=false;
|
|
|
|
Arc.ConvertAttributes();
|
|
|
|
#ifndef SFX_MODULE
|
|
if ((Arc.NewLhd.Flags & (LHD_SPLIT_BEFORE/*|LHD_SOLID*/)) && FirstFile)
|
|
{
|
|
char CurVolName[NM];
|
|
strcpy(CurVolName,ArcName);
|
|
|
|
VolNameToFirstName(ArcName,ArcName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0);
|
|
if (stricomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
|
|
{
|
|
*ArcNameW=0;
|
|
Repeat=true;
|
|
return(false);
|
|
}
|
|
#if !defined(RARDLL) && !defined(_WIN_CE)
|
|
if (!ReconstructDone)
|
|
{
|
|
ReconstructDone=true;
|
|
|
|
RecVolumes RecVol;
|
|
if (RecVol.Restore(Cmd,Arc.FileName,Arc.FileNameW,true))
|
|
{
|
|
Repeat=true;
|
|
return(false);
|
|
}
|
|
}
|
|
#endif
|
|
strcpy(ArcName,CurVolName);
|
|
}
|
|
#endif
|
|
DataIO.UnpVolume=(Arc.NewLhd.Flags & LHD_SPLIT_AFTER)!=0;
|
|
DataIO.NextVolumeMissing=false;
|
|
|
|
Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET);
|
|
|
|
bool TestMode=false;
|
|
bool ExtrFile=false;
|
|
bool SkipSolid=false;
|
|
|
|
#ifndef SFX_MODULE
|
|
if (FirstFile && (ExactMatch || Arc.Solid) && (Arc.NewLhd.Flags & (LHD_SPLIT_BEFORE/*|LHD_SOLID*/))!=0)
|
|
{
|
|
if (ExactMatch)
|
|
{
|
|
Log(Arc.FileName,St(MUnpCannotMerge),ArcFileName);
|
|
#ifdef RARDLL
|
|
Cmd->DllError=ERAR_BAD_DATA;
|
|
#endif
|
|
ErrHandler.SetErrorCode(OPEN_ERROR);
|
|
}
|
|
ExactMatch=false;
|
|
}
|
|
|
|
FirstFile=false;
|
|
#endif
|
|
|
|
if (ExactMatch || (SkipSolid=Arc.Solid)!=0)
|
|
{
|
|
if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0)
|
|
#ifndef RARDLL
|
|
if (*Password==0)
|
|
#endif
|
|
{
|
|
#ifdef RARDLL
|
|
if (*Cmd->Password==0)
|
|
if (Cmd->Callback==NULL ||
|
|
Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)Cmd->Password,sizeof(Cmd->Password))==-1)
|
|
return(false);
|
|
strcpy(Password,Cmd->Password);
|
|
|
|
#else
|
|
if (!GetPassword(PASSWORD_FILE,ArcFileName,Password,sizeof(Password)))
|
|
{
|
|
PasswordCancelled=true;
|
|
return(false);
|
|
}
|
|
#endif
|
|
}
|
|
#if !defined(GUI) && !defined(SILENT)
|
|
else
|
|
if (!PasswordAll && (!Arc.Solid || Arc.NewLhd.UnpVer>=20 && (Arc.NewLhd.Flags & LHD_SOLID)==0))
|
|
{
|
|
eprintf(St(MUseCurPsw),ArcFileName);
|
|
switch(Cmd->AllYes ? 1:Ask(St(MYesNoAll)))
|
|
{
|
|
case -1:
|
|
ErrHandler.Exit(USER_BREAK);
|
|
case 2:
|
|
if (!GetPassword(PASSWORD_FILE,ArcFileName,Password,sizeof(Password)))
|
|
{
|
|
return(false);
|
|
}
|
|
break;
|
|
case 3:
|
|
PasswordAll=true;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef SFX_MODULE
|
|
if (*Cmd->ExtrPath==0 && *Cmd->ExtrPathW!=0)
|
|
WideToChar(Cmd->ExtrPathW,DestFileName);
|
|
else
|
|
#endif
|
|
strcpy(DestFileName,Cmd->ExtrPath);
|
|
|
|
|
|
#ifndef SFX_MODULE
|
|
if (Cmd->AppendArcNameToPath)
|
|
{
|
|
strcat(DestFileName,PointToName(Arc.FirstVolumeName));
|
|
SetExt(DestFileName,NULL);
|
|
AddEndSlash(DestFileName);
|
|
}
|
|
#endif
|
|
|
|
char *ExtrName=ArcFileName;
|
|
|
|
bool EmptyName=false;
|
|
#ifndef SFX_MODULE
|
|
size_t Length=strlen(Cmd->ArcPath);
|
|
if (Length>1 && IsPathDiv(Cmd->ArcPath[Length-1]) &&
|
|
strlen(ArcFileName)==Length-1)
|
|
Length--;
|
|
if (Length>0 && strnicomp(Cmd->ArcPath,ArcFileName,Length)==0)
|
|
{
|
|
ExtrName+=Length;
|
|
while (*ExtrName==CPATHDIVIDER)
|
|
ExtrName++;
|
|
if (*ExtrName==0)
|
|
EmptyName=true;
|
|
}
|
|
#endif
|
|
|
|
bool AbsPaths=Cmd->ExclPath==EXCL_ABSPATH && Command=='X' && IsDriveDiv(':');
|
|
if (AbsPaths)
|
|
*DestFileName=0;
|
|
|
|
if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
|
|
strcat(DestFileName,PointToName(ExtrName));
|
|
else
|
|
strcat(DestFileName,ExtrName);
|
|
|
|
char DiskLetter=etoupper(DestFileName[0]);
|
|
|
|
if (AbsPaths && DestFileName[1]=='_' && IsPathDiv(DestFileName[2]) &&
|
|
DiskLetter>='A' && DiskLetter<='Z')
|
|
DestFileName[1]=':';
|
|
|
|
#ifndef SFX_MODULE
|
|
if (!WideName && *Cmd->ExtrPathW!=0)
|
|
{
|
|
DestNameW=DestFileNameW;
|
|
WideName=true;
|
|
CharToWide(ArcFileName,ArcFileNameW);
|
|
}
|
|
#endif
|
|
|
|
if (WideName)
|
|
{
|
|
if (*Cmd->ExtrPathW!=0)
|
|
strcpyw(DestFileNameW,Cmd->ExtrPathW);
|
|
else
|
|
CharToWide(Cmd->ExtrPath,DestFileNameW);
|
|
|
|
#ifndef SFX_MODULE
|
|
if (Cmd->AppendArcNameToPath)
|
|
{
|
|
wchar FileNameW[NM];
|
|
if (*Arc.FirstVolumeNameW!=0)
|
|
strcpyw(FileNameW,Arc.FirstVolumeNameW);
|
|
else
|
|
CharToWide(Arc.FirstVolumeName,FileNameW);
|
|
strcatw(DestFileNameW,PointToName(FileNameW));
|
|
SetExt(DestFileNameW,NULL);
|
|
AddEndSlash(DestFileNameW);
|
|
}
|
|
#endif
|
|
wchar *ExtrNameW=ArcFileNameW;
|
|
#ifndef SFX_MODULE
|
|
if (Length>0)
|
|
{
|
|
wchar ArcPathW[NM];
|
|
GetWideName(Cmd->ArcPath,Cmd->ArcPathW,ArcPathW);
|
|
Length=strlenw(ArcPathW);
|
|
}
|
|
ExtrNameW+=Length;
|
|
while (*ExtrNameW==CPATHDIVIDER)
|
|
ExtrNameW++;
|
|
#endif
|
|
|
|
if (AbsPaths)
|
|
*DestFileNameW=0;
|
|
|
|
if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
|
|
strcatw(DestFileNameW,PointToName(ExtrNameW));
|
|
else
|
|
strcatw(DestFileNameW,ExtrNameW);
|
|
|
|
if (AbsPaths && DestFileNameW[1]=='_' && IsPathDiv(DestFileNameW[2]))
|
|
DestFileNameW[1]=':';
|
|
}
|
|
else
|
|
*DestFileNameW=0;
|
|
|
|
ExtrFile=!SkipSolid && !EmptyName && (Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0;
|
|
|
|
if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X'))
|
|
{
|
|
struct FindData FD;
|
|
if (FindFile::FastFind(DestFileName,DestNameW,&FD))
|
|
{
|
|
if (FD.mtime >= Arc.NewLhd.mtime)
|
|
{
|
|
// If directory already exists and its modification time is newer
|
|
// than start of extraction, it is likely it was created
|
|
// when creating a path to one of already extracted items.
|
|
// In such case we'll better update its time even if archived
|
|
// directory is older.
|
|
|
|
if (!FD.IsDir || FD.mtime<StartTime)
|
|
ExtrFile=false;
|
|
}
|
|
}
|
|
else
|
|
if (Cmd->FreshFiles)
|
|
ExtrFile=false;
|
|
}
|
|
|
|
// Skip encrypted file if no password is specified.
|
|
if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0 && *Password==0)
|
|
{
|
|
ErrHandler.SetErrorCode(WARNING);
|
|
#ifdef RARDLL
|
|
Cmd->DllError=ERAR_MISSING_PASSWORD;
|
|
#endif
|
|
ExtrFile=false;
|
|
}
|
|
|
|
#ifdef RARDLL
|
|
if (*Cmd->DllDestName)
|
|
{
|
|
strncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName));
|
|
*DestFileNameW=0;
|
|
if (Cmd->DllOpMode!=RAR_EXTRACT)
|
|
ExtrFile=false;
|
|
}
|
|
if (*Cmd->DllDestNameW)
|
|
{
|
|
strncpyzw(DestFileNameW,Cmd->DllDestNameW,ASIZE(DestFileNameW));
|
|
DestNameW=DestFileNameW;
|
|
if (Cmd->DllOpMode!=RAR_EXTRACT)
|
|
ExtrFile=false;
|
|
}
|
|
#endif
|
|
|
|
#ifdef SFX_MODULE
|
|
if ((Arc.NewLhd.UnpVer!=UNP_VER && Arc.NewLhd.UnpVer!=29) &&
|
|
Arc.NewLhd.Method!=0x30)
|
|
#else
|
|
if (Arc.NewLhd.UnpVer<13 || Arc.NewLhd.UnpVer>UNP_VER)
|
|
#endif
|
|
{
|
|
#ifndef SILENT
|
|
Log(Arc.FileName,St(MUnknownMeth),ArcFileName);
|
|
#ifndef SFX_MODULE
|
|
Log(Arc.FileName,St(MVerRequired),Arc.NewLhd.UnpVer/10,Arc.NewLhd.UnpVer%10);
|
|
#endif
|
|
#endif
|
|
ExtrFile=false;
|
|
ErrHandler.SetErrorCode(WARNING);
|
|
#ifdef RARDLL
|
|
Cmd->DllError=ERAR_UNKNOWN_FORMAT;
|
|
#endif
|
|
}
|
|
|
|
File CurFile;
|
|
|
|
if (!IsLink(Arc.NewLhd.FileAttr))
|
|
if (Arc.IsArcDir())
|
|
{
|
|
if (!ExtrFile || Command=='P' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
|
|
return(true);
|
|
if (SkipSolid)
|
|
{
|
|
#ifndef GUI
|
|
mprintf(St(MExtrSkipFile),ArcFileName);
|
|
#endif
|
|
return(true);
|
|
}
|
|
TotalFileCount++;
|
|
if (Cmd->Test)
|
|
{
|
|
#ifndef GUI
|
|
mprintf(St(MExtrTestFile),ArcFileName);
|
|
mprintf(" %s",St(MOk));
|
|
#endif
|
|
return(true);
|
|
}
|
|
MKDIR_CODE MDCode=MakeDir(DestFileName,DestNameW,!Cmd->IgnoreGeneralAttr,Arc.NewLhd.FileAttr);
|
|
bool DirExist=false;
|
|
if (MDCode!=MKDIR_SUCCESS)
|
|
{
|
|
DirExist=FileExist(DestFileName,DestNameW);
|
|
if (DirExist && !IsDir(GetFileAttr(DestFileName,DestNameW)))
|
|
{
|
|
bool UserReject;
|
|
FileCreate(Cmd,NULL,DestFileName,DestNameW,Cmd->Overwrite,&UserReject,Arc.NewLhd.FullUnpSize,Arc.NewLhd.FileTime);
|
|
DirExist=false;
|
|
}
|
|
CreatePath(DestFileName,DestNameW,true);
|
|
MDCode=MakeDir(DestFileName,DestNameW,!Cmd->IgnoreGeneralAttr,Arc.NewLhd.FileAttr);
|
|
}
|
|
if (MDCode==MKDIR_SUCCESS)
|
|
{
|
|
#ifndef GUI
|
|
mprintf(St(MCreatDir),DestFileName);
|
|
mprintf(" %s",St(MOk));
|
|
#endif
|
|
PrevExtracted=true;
|
|
}
|
|
else
|
|
if (DirExist)
|
|
{
|
|
if (!Cmd->IgnoreGeneralAttr)
|
|
SetFileAttr(DestFileName,DestNameW,Arc.NewLhd.FileAttr);
|
|
PrevExtracted=true;
|
|
}
|
|
else
|
|
{
|
|
Log(Arc.FileName,St(MExtrErrMkDir),DestFileName);
|
|
ErrHandler.SysErrMsg();
|
|
#ifdef RARDLL
|
|
Cmd->DllError=ERAR_ECREATE;
|
|
#endif
|
|
ErrHandler.SetErrorCode(CREATE_ERROR);
|
|
}
|
|
if (PrevExtracted)
|
|
{
|
|
#if defined(_WIN_32) && !defined(_WIN_CE) && !defined(SFX_MODULE)
|
|
if (Cmd->SetCompressedAttr &&
|
|
(Arc.NewLhd.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT())
|
|
SetFileCompression(DestFileName,DestNameW,true);
|
|
#endif
|
|
SetDirTime(DestFileName,DestNameW,
|
|
Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
|
|
Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.NewLhd.ctime,
|
|
Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
|
|
}
|
|
return(true);
|
|
}
|
|
else
|
|
{
|
|
if (Cmd->Test && ExtrFile)
|
|
TestMode=true;
|
|
#if !defined(GUI) && !defined(SFX_MODULE)
|
|
if (Command=='P' && ExtrFile)
|
|
CurFile.SetHandleType(FILE_HANDLESTD);
|
|
#endif
|
|
if ((Command=='E' || Command=='X') && ExtrFile && !Cmd->Test)
|
|
{
|
|
bool UserReject;
|
|
if (!FileCreate(Cmd,&CurFile,DestFileName,DestNameW,Cmd->Overwrite,&UserReject,Arc.NewLhd.FullUnpSize,Arc.NewLhd.FileTime))
|
|
{
|
|
ExtrFile=false;
|
|
if (!UserReject)
|
|
{
|
|
ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName);
|
|
ErrHandler.SetErrorCode(CREATE_ERROR);
|
|
#ifdef RARDLL
|
|
Cmd->DllError=ERAR_ECREATE;
|
|
#endif
|
|
if (!IsNameUsable(DestFileName))
|
|
{
|
|
Log(Arc.FileName,St(MCorrectingName));
|
|
char OrigName[sizeof(DestFileName)];
|
|
strncpyz(OrigName,DestFileName,ASIZE(OrigName));
|
|
|
|
MakeNameUsable(DestFileName,true);
|
|
CreatePath(DestFileName,NULL,true);
|
|
if (FileCreate(Cmd,&CurFile,DestFileName,NULL,Cmd->Overwrite,&UserReject,Arc.NewLhd.FullUnpSize,Arc.NewLhd.FileTime))
|
|
{
|
|
#ifndef SFX_MODULE
|
|
Log(Arc.FileName,St(MRenaming),OrigName,DestFileName);
|
|
#endif
|
|
ExtrFile=true;
|
|
}
|
|
else
|
|
ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ExtrFile && Arc.Solid)
|
|
{
|
|
SkipSolid=true;
|
|
TestMode=true;
|
|
ExtrFile=true;
|
|
|
|
}
|
|
if (ExtrFile)
|
|
{
|
|
if (!SkipSolid)
|
|
{
|
|
if (!TestMode && Command!='P' && CurFile.IsDevice())
|
|
{
|
|
Log(Arc.FileName,St(MInvalidName),DestFileName);
|
|
ErrHandler.WriteError(Arc.FileName,DestFileName);
|
|
}
|
|
TotalFileCount++;
|
|
}
|
|
FileCount++;
|
|
#ifndef GUI
|
|
if (Command!='I')
|
|
if (SkipSolid)
|
|
mprintf(St(MExtrSkipFile),ArcFileName);
|
|
else
|
|
switch(Cmd->Test ? 'T':Command)
|
|
{
|
|
case 'T':
|
|
mprintf(St(MExtrTestFile),ArcFileName);
|
|
break;
|
|
#ifndef SFX_MODULE
|
|
case 'P':
|
|
mprintf(St(MExtrPrinting),ArcFileName);
|
|
break;
|
|
#endif
|
|
case 'X':
|
|
case 'E':
|
|
mprintf(St(MExtrFile),DestFileName);
|
|
break;
|
|
}
|
|
if (!Cmd->DisablePercentage)
|
|
mprintf(" ");
|
|
#endif
|
|
DataIO.CurUnpRead=0;
|
|
DataIO.CurUnpWrite=0;
|
|
DataIO.UnpFileCRC=Arc.OldFormat ? 0 : 0xffffffff;
|
|
DataIO.PackedCRC=0xffffffff;
|
|
DataIO.SetEncryption(
|
|
(Arc.NewLhd.Flags & LHD_PASSWORD) ? Arc.NewLhd.UnpVer:0,Password,
|
|
(Arc.NewLhd.Flags & LHD_SALT) ? Arc.NewLhd.Salt:NULL,false,
|
|
Arc.NewLhd.UnpVer>=36);
|
|
DataIO.SetPackedSizeToRead(Arc.NewLhd.FullPackSize);
|
|
DataIO.SetFiles(&Arc,&CurFile);
|
|
DataIO.SetTestMode(TestMode);
|
|
DataIO.SetSkipUnpCRC(SkipSolid);
|
|
#ifndef _WIN_CE
|
|
if (!TestMode && !Arc.BrokenFileHeader &&
|
|
(Arc.NewLhd.FullPackSize<<11)>Arc.NewLhd.FullUnpSize &&
|
|
(Arc.NewLhd.FullUnpSize<100000000 || Arc.FileLength()>Arc.NewLhd.FullPackSize))
|
|
CurFile.Prealloc(Arc.NewLhd.FullUnpSize);
|
|
#endif
|
|
|
|
CurFile.SetAllowDelete(!Cmd->KeepBroken);
|
|
|
|
bool LinkCreateMode=!Cmd->Test && !SkipSolid;
|
|
if (ExtractLink(DataIO,Arc,DestFileName,DataIO.UnpFileCRC,LinkCreateMode))
|
|
PrevExtracted=LinkCreateMode;
|
|
else
|
|
if ((Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0)
|
|
if (Arc.NewLhd.Method==0x30)
|
|
UnstoreFile(DataIO,Arc.NewLhd.FullUnpSize);
|
|
else
|
|
{
|
|
Unp->SetDestSize(Arc.NewLhd.FullUnpSize);
|
|
#ifndef SFX_MODULE
|
|
if (Arc.NewLhd.UnpVer<=15)
|
|
Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
|
|
else
|
|
#endif
|
|
Unp->DoUnpack(Arc.NewLhd.UnpVer,(Arc.NewLhd.Flags & LHD_SOLID)!=0);
|
|
}
|
|
|
|
if (Arc.IsOpened())
|
|
Arc.SeekToNext();
|
|
|
|
bool BrokenFile=false;
|
|
if (!SkipSolid)
|
|
{
|
|
if (Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC) ||
|
|
!Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC^0xffffffff))
|
|
{
|
|
#ifndef GUI
|
|
if (Command!='P' && Command!='I')
|
|
mprintf("%s%s ",Cmd->DisablePercentage ? " ":"\b\b\b\b\b ",St(MOk));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
char *BadArcName=/*(Arc.NewLhd.Flags & LHD_SPLIT_BEFORE) ? NULL:*/Arc.FileName;
|
|
if (Arc.NewLhd.Flags & LHD_PASSWORD)
|
|
{
|
|
Log(BadArcName,St(MEncrBadCRC),ArcFileName);
|
|
}
|
|
else
|
|
{
|
|
Log(BadArcName,St(MCRCFailed),ArcFileName);
|
|
}
|
|
BrokenFile=true;
|
|
ErrHandler.SetErrorCode(CRC_ERROR);
|
|
#ifdef RARDLL
|
|
Cmd->DllError=ERAR_BAD_DATA;
|
|
#endif
|
|
Alarm();
|
|
}
|
|
}
|
|
#ifndef GUI
|
|
else
|
|
mprintf("\b\b\b\b\b ");
|
|
#endif
|
|
|
|
if (!TestMode && (Command=='X' || Command=='E') &&
|
|
!IsLink(Arc.NewLhd.FileAttr))
|
|
{
|
|
#if defined(_WIN_32) || defined(_EMX)
|
|
if (Cmd->ClearArc)
|
|
Arc.NewLhd.FileAttr&=~FA_ARCH;
|
|
/*
|
|
else
|
|
Arc.NewLhd.FileAttr|=FA_ARCH; //set archive bit for unpacked files (file is not backed up)
|
|
*/
|
|
#endif
|
|
if (!BrokenFile || Cmd->KeepBroken)
|
|
{
|
|
if (BrokenFile)
|
|
CurFile.Truncate();
|
|
CurFile.SetOpenFileTime(
|
|
Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
|
|
Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.NewLhd.ctime,
|
|
Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
|
|
CurFile.Close();
|
|
#if defined(_WIN_32) && !defined(_WIN_CE) && !defined(SFX_MODULE)
|
|
if (Cmd->SetCompressedAttr &&
|
|
(Arc.NewLhd.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT())
|
|
SetFileCompression(CurFile.FileName,CurFile.FileNameW,true);
|
|
#endif
|
|
CurFile.SetCloseFileTime(
|
|
Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
|
|
Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
|
|
if (!Cmd->IgnoreGeneralAttr)
|
|
SetFileAttr(CurFile.FileName,CurFile.FileNameW,Arc.NewLhd.FileAttr);
|
|
PrevExtracted=true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (ExactMatch)
|
|
MatchedArgs++;
|
|
if (DataIO.NextVolumeMissing || !Arc.IsOpened())
|
|
return(false);
|
|
if (!ExtrFile)
|
|
if (!Arc.Solid)
|
|
Arc.SeekToNext();
|
|
else
|
|
if (!SkipSolid)
|
|
return(false);
|
|
return(true);
|
|
}
|
|
|
|
|
|
void CmdExtract::UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize)
|
|
{
|
|
Array<byte> Buffer(0x10000);
|
|
while (1)
|
|
{
|
|
uint Code=DataIO.UnpRead(&Buffer[0],Buffer.Size());
|
|
if (Code==0 || (int)Code==-1)
|
|
break;
|
|
Code=Code<DestUnpSize ? Code:(uint)DestUnpSize;
|
|
DataIO.UnpWrite(&Buffer[0],Code);
|
|
if (DestUnpSize>=0)
|
|
DestUnpSize-=Code;
|
|
}
|
|
}
|
|
|