diff options
author | XhmikosR <xhmikosr@users.sourceforge.net> | 2013-05-05 11:39:47 +0400 |
---|---|---|
committer | XhmikosR <xhmikosr@users.sourceforge.net> | 2013-05-06 02:56:22 +0400 |
commit | 00f8520475b119d50d40b8a4b2298f04afa821b9 (patch) | |
tree | e389319284c45b5305bb5156e1d8f8310849902a /src/thirdparty/unrar/archive.cpp | |
parent | b18faab4208d8368d28c7b51afe5a73bbc90b05e (diff) |
update unrar to v5.0.2
Diffstat (limited to 'src/thirdparty/unrar/archive.cpp')
-rw-r--r-- | src/thirdparty/unrar/archive.cpp | 234 |
1 files changed, 143 insertions, 91 deletions
diff --git a/src/thirdparty/unrar/archive.cpp b/src/thirdparty/unrar/archive.cpp index b061e540a..b05eef462 100644 --- a/src/thirdparty/unrar/archive.cpp +++ b/src/thirdparty/unrar/archive.cpp @@ -7,48 +7,48 @@ Archive::Archive(RAROptions *InitCmd) { - Cmd=InitCmd==NULL ? &DummyCmd:InitCmd; + Cmd=NULL; // Just in case we'll have an exception in 'new' below. + + DummyCmd=(InitCmd==NULL); + Cmd=DummyCmd ? (new RAROptions):InitCmd; + OpenShared=Cmd->OpenShared; - OldFormat=false; + Format=RARFMT15; Solid=false; Volume=false; MainComment=false; Locked=false; Signed=false; - NotFirstVolume=false; + FirstVolume=false; + NewNumbering=false; SFXSize=0; LatestTime.Reset(); Protected=false; Encrypted=false; FailedHeaderDecryption=false; - BrokenFileHeader=false; + BrokenHeader=false; LastReadBlock=0; CurBlockPos=0; NextBlockPos=0; - RecoveryPos=SIZEOF_MARKHEAD; - RecoverySectors=-1; + RecoverySize=-1; + RecoveryPercent=-1; - memset(&NewMhd,0,sizeof(NewMhd)); - NewMhd.HeadType=MAIN_HEAD; - NewMhd.HeadSize=SIZEOF_NEWMHD; - HeaderCRC=0; + memset(&MainHead,0,sizeof(MainHead)); + memset(&CryptHead,0,sizeof(CryptHead)); + memset(&EndArcHead,0,sizeof(EndArcHead)); + + VolNumber=0; VolWrite=0; AddingFilesSize=0; AddingHeadersSize=0; -#if !defined(SHELL_EXT) && !defined(RAR_NOCRYPT) - *HeadersSalt=0; - *SubDataSalt=0; -#endif *FirstVolumeName=0; - *FirstVolumeNameW=0; Splitting=false; NewArchive=false; SilentOpen=false; - } @@ -66,37 +66,37 @@ void Archive::CheckArc(bool EnableBroken) #if !defined(SHELL_EXT) && !defined(SFX_MODULE) -void Archive::CheckOpen(const char *Name,const wchar *NameW) +void Archive::CheckOpen(const wchar *Name) { - TOpen(Name,NameW); + TOpen(Name); CheckArc(false); } #endif -bool Archive::WCheckOpen(const char *Name,const wchar *NameW) +bool Archive::WCheckOpen(const wchar *Name) { - if (!WOpen(Name,NameW)) - return(false); + if (!WOpen(Name)) + return false; if (!IsArchive(false)) { #ifndef SHELL_EXT Log(FileName,St(MNotRAR),FileName); #endif Close(); - return(false); + return false; } - return(true); + return true; } -ARCSIGN_TYPE Archive::IsSignature(const byte *D,size_t Size) +RARFORMAT Archive::IsSignature(const byte *D,size_t Size) { - ARCSIGN_TYPE Type=ARCSIGN_NONE; + RARFORMAT Type=RARFMT_NONE; if (Size>=1 && D[0]==0x52) #ifndef SFX_MODULE if (Size>=4 && D[1]==0x45 && D[2]==0x7e && D[3]==0x5e) - Type=ARCSIGN_OLD; + Type=RARFMT14; else #endif if (Size>=7 && D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07) @@ -104,7 +104,14 @@ ARCSIGN_TYPE Archive::IsSignature(const byte *D,size_t Size) // We check for non-zero last signature byte, so we can return // a sensible warning in case we'll want to change the archive // format sometimes in the future. - Type=D[6]==0 ? ARCSIGN_CURRENT:ARCSIGN_FUTURE; + if (D[6]==0) + Type=RARFMT15; + else + if (D[6]==1) + Type=RARFMT50; + else + if (D[6]==2) + Type=RARFMT_FUTURE; } return Type; } @@ -113,24 +120,32 @@ ARCSIGN_TYPE Archive::IsSignature(const byte *D,size_t Size) bool Archive::IsArchive(bool EnableBroken) { Encrypted=false; +#ifdef USE_QOPEN + QOpen.Unload(); +#endif + + // Important if we reuse Archive object and it has virtual QOpen + // file position not matching real. For example, for 'l -v volname'. + Seek(0,SEEK_SET); + #ifndef SFX_MODULE if (IsDevice()) { #ifndef SHELL_EXT Log(FileName,St(MInvalidName),FileName); #endif - return(false); + return false; } #endif - if (Read(MarkHead.Mark,SIZEOF_MARKHEAD)!=SIZEOF_MARKHEAD) + if (Read(MarkHead.Mark,SIZEOF_MARKHEAD3)!=SIZEOF_MARKHEAD3) return(false); SFXSize=0; - ARCSIGN_TYPE Type; - if ((Type=IsSignature(MarkHead.Mark,sizeof(MarkHead.Mark)))!=ARCSIGN_NONE) + RARFORMAT Type; + if ((Type=IsSignature(MarkHead.Mark,SIZEOF_MARKHEAD3))!=RARFMT_NONE) { - OldFormat=(Type==ARCSIGN_OLD); - if (OldFormat) + Format=Type; + if (Format==RARFMT14) Seek(0,SEEK_SET); } else @@ -139,10 +154,10 @@ bool Archive::IsArchive(bool EnableBroken) long CurPos=(long)Tell(); int ReadSize=Read(&Buffer[0],Buffer.Size()-16); for (int I=0;I<ReadSize;I++) - if (Buffer[I]==0x52 && (Type=IsSignature((byte *)&Buffer[I],ReadSize-I))!=ARCSIGN_NONE) + if (Buffer[I]==0x52 && (Type=IsSignature((byte *)&Buffer[I],ReadSize-I))!=RARFMT_NONE) { - OldFormat=(Type==ARCSIGN_OLD); - if (OldFormat && I>0 && CurPos<28 && ReadSize>31) + Format=Type; + if (Format==RARFMT14 && I>0 && CurPos<28 && ReadSize>31) { char *D=&Buffer[28-CurPos]; if (D[0]!=0x52 || D[1]!=0x53 || D[2]!=0x46 || D[3]!=0x58) @@ -150,50 +165,52 @@ bool Archive::IsArchive(bool EnableBroken) } SFXSize=CurPos+I; Seek(SFXSize,SEEK_SET); - if (!OldFormat) - Read(MarkHead.Mark,SIZEOF_MARKHEAD); + if (Format==RARFMT15 || Format==RARFMT50) + Read(MarkHead.Mark,SIZEOF_MARKHEAD3); break; } if (SFXSize==0) return false; } - if (Type==ARCSIGN_FUTURE) + if (Format==RARFMT_FUTURE) { #if !defined(SHELL_EXT) && !defined(SFX_MODULE) Log(FileName,St(MNewRarFormat)); #endif return false; } - ReadHeader(); - SeekToNext(); -#ifndef SFX_MODULE - if (OldFormat) + if (Format==RARFMT50) // RAR 5.0 signature is by one byte longer. { - NewMhd.Flags=OldMhd.Flags & 0x3f; - NewMhd.HeadSize=OldMhd.HeadSize; + Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1); + if (MarkHead.Mark[SIZEOF_MARKHEAD3]!=0) + return false; + MarkHead.HeadSize=SIZEOF_MARKHEAD5; } else -#endif + MarkHead.HeadSize=SIZEOF_MARKHEAD3; + + // Skip the archive encryption header if any and read the main header. + while (ReadHeader()!=0 && GetHeaderType()!=HEAD_MAIN) + SeekToNext(); + + // This check allows to make RS based recovery even if password is incorrect. + // But we should not do it for EnableBroken or we'll get 'not RAR archive' + // messages when extracting encrypted archives with wrong password. + if (FailedHeaderDecryption && !EnableBroken) + return false; + + SeekToNext(); + if (BrokenHeader) { - if (HeaderCRC!=NewMhd.HeadCRC) - { #ifndef SHELL_EXT - Log(FileName,St(MLogMainHead)); + Log(FileName,St(MMainHeaderBroken)); #endif - Alarm(); - if (!EnableBroken) - return(false); - } + if (!EnableBroken) + return false; } - Volume=(NewMhd.Flags & MHD_VOLUME); - Solid=(NewMhd.Flags & MHD_SOLID)!=0; - MainComment=(NewMhd.Flags & MHD_COMMENT)!=0; - Locked=(NewMhd.Flags & MHD_LOCK)!=0; - Signed=(NewMhd.PosAV!=0); - Protected=(NewMhd.Flags & MHD_PROTECT)!=0; - Encrypted=(NewMhd.Flags & MHD_PASSWORD)!=0; - - if (NewMhd.EncryptVer>UNP_VER) + +/* + if (MainHead.EncryptVer>VER_UNPACK) { #ifdef RARDLL Cmd->DllError=ERAR_UNKNOWN_FORMAT; @@ -201,11 +218,13 @@ bool Archive::IsArchive(bool EnableBroken) ErrHandler.SetErrorCode(RARX_WARNING); #if !defined(SILENT) && !defined(SFX_MODULE) Log(FileName,St(MUnknownMeth),FileName); - Log(FileName,St(MVerRequired),NewMhd.EncryptVer/10,NewMhd.EncryptVer%10); + Log(FileName,St(MVerRequired),MainHead.EncryptVer/10,MainHead.EncryptVer%10); #endif #endif return(false); } +*/ + #ifdef RARDLL // If callback function is not set, we cannot get the password, // so we skip the initial header processing for encrypted header archive. @@ -215,31 +234,37 @@ bool Archive::IsArchive(bool EnableBroken) SilentOpen=true; #endif - // If not encrypted, we'll check it below. - NotFirstVolume=Encrypted && (NewMhd.Flags & MHD_FIRSTVOLUME)==0; + MainComment=MainHead.CommentInHeader; +#ifdef USE_QOPEN + if (MainHead.Locator && MainHead.QOpenOffset>0 && Cmd->QOpenMode!=QOPEN_NONE) + { + QOpen.Init(this,false); + QOpen.Load(MainHead.QOpenOffset); + } +#endif + + // If we process non-encrypted archive or can request a password, + // we set 'first volume' flag based on file attributes below. + // It is necessary for RAR 2.x archives, which did not have 'first volume' + // flag in main header. if (!SilentOpen || !Encrypted) { SaveFilePos SavePos(*this); int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos; - NotFirstVolume=false; while (ReadHeader()!=0) { - int HeaderType=GetHeaderType(); - if (HeaderType==NEWSUB_HEAD) + HEADER_TYPE HeaderType=GetHeaderType(); + if (HeaderType==HEAD_SERVICE) { if (SubHead.CmpName(SUBHEAD_TYPE_CMT)) MainComment=true; - if ((SubHead.Flags & LHD_SPLIT_BEFORE) || - Volume && (NewMhd.Flags & MHD_FIRSTVOLUME)==0) - NotFirstVolume=true; + FirstVolume=!SubHead.SplitBefore; } else { - if (HeaderType==FILE_HEAD && ((NewLhd.Flags & LHD_SPLIT_BEFORE)!=0 || - Volume && NewLhd.UnpVer>=29 && (NewMhd.Flags & MHD_FIRSTVOLUME)==0)) - NotFirstVolume=true; + FirstVolume=HeaderType==HEAD_FILE && !FileHead.SplitBefore; break; } SeekToNext(); @@ -247,13 +272,10 @@ bool Archive::IsArchive(bool EnableBroken) CurBlockPos=SaveCurBlockPos; NextBlockPos=SaveNextBlockPos; } - if (!Volume || !NotFirstVolume) - { - strcpy(FirstVolumeName,FileName); - wcscpy(FirstVolumeNameW,FileNameW); - } + if (!Volume || FirstVolume) + wcscpy(FirstVolumeName,FileName); - return(true); + return true; } @@ -265,20 +287,50 @@ void Archive::SeekToNext() } -#ifndef SFX_MODULE -int Archive::GetRecoverySize(bool Required) + + + + +// Calculate the block size including encryption fields and padding if any. +uint Archive::FullHeaderSize(size_t Size) { - if (!Protected) - return(0); - if (RecoverySectors!=-1 || !Required) - return(RecoverySectors); - SaveFilePos SavePos(*this); - Seek(SFXSize,SEEK_SET); - SearchSubBlock(SUBHEAD_TYPE_RR); - return(RecoverySectors); + if (Encrypted) + { + Size = ALIGN_VALUE(Size, CRYPT_BLOCK_SIZE); // Align to encryption block size. + if (Format == RARFMT50) + Size += SIZE_INITV; + else + Size += SIZE_SALT30; + } + return uint(Size); } -#endif +#ifdef USE_QOPEN +int Archive::Read(void *Data,size_t Size) +{ + size_t Result; + if (QOpen.Read(Data,Size,Result)) + return (int)Result; + return File::Read(Data,Size); +} + + +void Archive::Seek(int64 Offset,int Method) +{ + if (!QOpen.Seek(Offset,Method)) + File::Seek(Offset,Method); +} + + +int64 Archive::Tell() +{ + int64 QPos; + if (QOpen.Tell(&QPos)) + return QPos; + return File::Tell(); +} +#endif + |