| #include "rar.hpp" |
| |
| namespace third_party_unrar { |
| |
| #ifdef RARDLL |
| static bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize); |
| static bool DllVolNotify(RAROptions *Cmd,wchar *NextName); |
| #endif |
| |
| |
| |
| bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Command) |
| { |
| RAROptions *Cmd=Arc.GetRAROptions(); |
| |
| HEADER_TYPE HeaderType=Arc.GetHeaderType(); |
| FileHeader *hd=HeaderType==HEAD_SERVICE ? &Arc.SubHead:&Arc.FileHead; |
| bool SplitHeader=(HeaderType==HEAD_FILE || HeaderType==HEAD_SERVICE) && |
| hd->SplitAfter; |
| |
| if (DataIO!=NULL && SplitHeader) |
| { |
| bool PackedHashPresent=Arc.Format==RARFMT50 || |
| (hd->UnpVer>=20 && hd->FileHash.CRC32!=0xffffffff); |
| if (PackedHashPresent && |
| !DataIO->PackedDataHash.Cmp(&hd->FileHash,hd->UseHashKey ? hd->HashKey:NULL)) |
| uiMsg(UIERROR_CHECKSUMPACKED, Arc.FileName, hd->FileName); |
| } |
| |
| int64 PosBeforeClose=Arc.Tell(); |
| |
| if (DataIO!=NULL) |
| DataIO->ProcessedArcSize+=Arc.FileLength(); |
| |
| |
| Arc.Close(); |
| |
| wchar NextName[NM]; |
| wcscpy(NextName,Arc.FileName); |
| NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering); |
| |
| #if !defined(SFX_MODULE) && !defined(RARDLL) |
| bool RecoveryDone=false; |
| #endif |
| bool FailedOpen=false,OldSchemeTested=false; |
| |
| #if !defined(SILENT) |
| // In -vp mode we force the pause before next volume even if it is present |
| // and even if we are on the hard disk. It is important when user does not |
| // want to process partially downloaded volumes preliminary. |
| if (Cmd->VolumePause && !uiAskNextVolume(NextName,ASIZE(NextName))) |
| FailedOpen=true; |
| #endif |
| |
| uint OpenMode = Cmd->OpenShared ? FMF_OPENSHARED : 0; |
| |
| if (!FailedOpen) |
| while (!Arc.Open(NextName,OpenMode)) |
| { |
| // We need to open a new volume which size was not calculated |
| // in total size before, so we cannot calculate the total progress |
| // anymore. Let's reset the total size to zero and stop |
| // the total progress. |
| if (DataIO!=NULL) |
| DataIO->TotalArcSize=0; |
| |
| if (!OldSchemeTested) |
| { |
| // Checking for new style volumes renamed by user to old style |
| // name format. Some users did it for unknown reason. |
| wchar AltNextName[NM]; |
| wcscpy(AltNextName,Arc.FileName); |
| NextVolumeName(AltNextName,ASIZE(AltNextName),true); |
| OldSchemeTested=true; |
| if (Arc.Open(AltNextName,OpenMode)) |
| { |
| wcscpy(NextName,AltNextName); |
| break; |
| } |
| } |
| #ifdef RARDLL |
| if (!DllVolChange(Cmd,NextName,ASIZE(NextName))) |
| { |
| FailedOpen=true; |
| break; |
| } |
| #else // !RARDLL |
| |
| #ifndef SFX_MODULE |
| if (!RecoveryDone) |
| { |
| RecVolumesRestore(Cmd,Arc.FileName,true); |
| RecoveryDone=true; |
| continue; |
| } |
| #endif |
| |
| if (!Cmd->VolumePause && !IsRemovable(NextName)) |
| { |
| FailedOpen=true; |
| break; |
| } |
| #ifndef SILENT |
| if (Cmd->AllYes || !uiAskNextVolume(NextName,ASIZE(NextName))) |
| #endif |
| { |
| FailedOpen=true; |
| break; |
| } |
| |
| #endif // RARDLL |
| } |
| |
| if (FailedOpen) |
| { |
| uiMsg(UIERROR_MISSINGVOL,NextName); |
| Arc.Open(Arc.FileName,OpenMode); |
| Arc.Seek(PosBeforeClose,SEEK_SET); |
| return false; |
| } |
| |
| if (Command=='T' || Command=='X' || Command=='E') |
| mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName); |
| |
| |
| Arc.CheckArc(true); |
| #ifdef RARDLL |
| if (!DllVolNotify(Cmd,NextName)) |
| return false; |
| #endif |
| |
| if (SplitHeader) |
| Arc.SearchBlock(HeaderType); |
| else |
| Arc.ReadHeader(); |
| if (Arc.GetHeaderType()==HEAD_FILE) |
| { |
| Arc.ConvertAttributes(); |
| Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET); |
| } |
| if (ShowFileName) |
| { |
| mprintf(St(MExtrPoints),Arc.FileHead.FileName); |
| if (!Cmd->DisablePercentage) |
| mprintf(L" "); |
| } |
| if (DataIO!=NULL) |
| { |
| if (HeaderType==HEAD_ENDARC) |
| DataIO->UnpVolume=false; |
| else |
| { |
| DataIO->UnpVolume=hd->SplitAfter; |
| DataIO->SetPackedSizeToRead(hd->PackSize); |
| } |
| #ifdef SFX_MODULE |
| DataIO->UnpArcSize=Arc.FileLength(); |
| #endif |
| |
| // Reset the size of packed data read from current volume. It is used |
| // to display the total progress and preceding volumes are already |
| // compensated with ProcessedArcSize, so we need to reset this variable. |
| DataIO->CurUnpRead=0; |
| |
| DataIO->PackedDataHash.Init(hd->FileHash.Type,Cmd->Threads); |
| } |
| return true; |
| } |
| |
| |
| |
| |
| |
| |
| #ifdef RARDLL |
| #if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64) |
| // Disable the run time stack check for unrar.dll, so we can manipulate |
| // with ChangeVolProc call type below. Run time check would intercept |
| // a wrong ESP before we restore it. |
| #pragma runtime_checks( "s", off ) |
| #endif |
| |
| bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize) |
| { |
| bool DllVolChanged=false,DllVolAborted=false; |
| |
| if (Cmd->Callback!=NULL) |
| { |
| wchar OrgNextName[NM]; |
| wcscpy(OrgNextName,NextName); |
| if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)==-1) |
| DllVolAborted=true; |
| else |
| if (wcscmp(OrgNextName,NextName)!=0) |
| DllVolChanged=true; |
| else |
| { |
| char NextNameA[NM],OrgNextNameA[NM]; |
| WideToChar(NextName,NextNameA,ASIZE(NextNameA)); |
| strcpy(OrgNextNameA,NextNameA); |
| if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_ASK)==-1) |
| DllVolAborted=true; |
| else |
| if (strcmp(OrgNextNameA,NextNameA)!=0) |
| { |
| // We can damage some Unicode characters by U->A->U conversion, |
| // so set Unicode name only if we see that ANSI name is changed. |
| CharToWide(NextNameA,NextName,NameSize); |
| DllVolChanged=true; |
| } |
| } |
| } |
| if (!DllVolChanged && Cmd->ChangeVolProc!=NULL) |
| { |
| char NextNameA[NM]; |
| WideToChar(NextName,NextNameA,ASIZE(NextNameA)); |
| // Here we preserve ESP value. It is necessary for those developers, |
| // who still define ChangeVolProc callback as "C" type function, |
| // even though in year 2001 we announced in unrar.dll whatsnew.txt |
| // that it will be PASCAL type (for compatibility with Visual Basic). |
| #if defined(_MSC_VER) |
| #ifndef _WIN_64 |
| __asm mov ebx,esp |
| #endif |
| #elif defined(_WIN_ALL) && defined(__BORLANDC__) |
| _EBX=_ESP; |
| #endif |
| int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_ASK); |
| |
| // Restore ESP after ChangeVolProc with wrongly defined calling |
| // convention broken it. |
| #if defined(_MSC_VER) |
| #ifndef _WIN_64 |
| __asm mov esp,ebx |
| #endif |
| #elif defined(_WIN_ALL) && defined(__BORLANDC__) |
| _ESP=_EBX; |
| #endif |
| if (RetCode==0) |
| DllVolAborted=true; |
| else |
| CharToWide(NextNameA,NextName,NameSize); |
| } |
| |
| // We quit only on 'abort' condition, but not on 'name not changed'. |
| // It is legitimate for program to return the same name when waiting |
| // for currently non-existent volume. |
| // Also we quit to prevent an infinite loop if no callback is defined. |
| if (DllVolAborted || Cmd->Callback==NULL && Cmd->ChangeVolProc==NULL) |
| { |
| Cmd->DllError=ERAR_EOPEN; |
| return false; |
| } |
| return true; |
| } |
| #endif |
| |
| |
| #ifdef RARDLL |
| bool DllVolNotify(RAROptions *Cmd,wchar *NextName) |
| { |
| char NextNameA[NM]; |
| WideToChar(NextName,NextNameA,ASIZE(NextNameA)); |
| if (Cmd->Callback!=NULL) |
| { |
| if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_NOTIFY)==-1) |
| return false; |
| if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_NOTIFY)==-1) |
| return false; |
| } |
| if (Cmd->ChangeVolProc!=NULL) |
| { |
| #if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__) |
| _EBX=_ESP; |
| #endif |
| int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_NOTIFY); |
| #if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__) |
| _ESP=_EBX; |
| #endif |
| if (RetCode==0) |
| return false; |
| } |
| return true; |
| } |
| |
| #if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64) |
| // Restore the run time stack check for unrar.dll. |
| #pragma runtime_checks( "s", restore ) |
| #endif |
| #endif |
| |
| } // namespace third_party_unrar |