Files
LisherSong--ps5-web-file-ma…/third_party/unrar7/arccmt.cpp
T
Songlx516 c68c0def35 vendor(unrar): add unrar 7.20.1 (RARLab source, opello mirror)
New RAR engine for v1.9, replacing dmc_unrar 1.7.0. dmc_unrar only
dispatches RAR5 compression version 5 (switch(file->version) case
0x5000); WinRAR 6.x/7.x writes version 6 -> DMC_UNRAR_FILE_UNSUPPORTED_VERSION
-> user-facing "corrupt archive" on real v6 archives (diagnosed 2026-09-05
from a v6:8M:m0:m3 test file). unrar 7.20.1 natively supports v6,
encrypted and multi-volume RAR.

Vendored into third_party/unrar7/ (new dir) so the tree stays buildable
while src/rar_extract.c still references the dmc facade. Contents are a
verbatim copy of opello/unrar @97e1780 (159 files, v7.20.1) plus two
project files:
  - unrar_c_api.h  (C facade shim: platform types + dll.hpp re-export)
  - VENDORED.md    (source pin, build model, license notes)

Build model verified on host (MinGW g++ 16.2, Windows):
  - all 49 UnRARDll.vcxproj sources compile with
    -std=c++17 -DRARDLL -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
  - links + runs: RARGetDllVersion() = 9 (smoke binary in .build/, ignored)
  - Windows link additionally needs -lpowrprof

License: UnRAR freeware license (not GPL) - free to use for handling RAR
archives; cannot be used to build a RAR-compatible archiver. THIRD_PARTY_NOTICES
update lands with the engine swap commit.

Next (v1.9 work items): engine swap in rar_extract.c, Makefile .cpp rules,
fixtures + host tests, frontend password/multi-volume, then ELF build.
2026-09-05 21:57:15 +08:00

188 lines
4.8 KiB
C++

static bool IsAnsiEscComment(const wchar *Data,size_t Size);
bool Archive::GetComment(std::wstring &CmtData)
{
if (!MainComment)
return false;
int64 SavePos=Tell();
bool Success=DoGetComment(CmtData);
Seek(SavePos,SEEK_SET);
return Success;
}
bool Archive::DoGetComment(std::wstring &CmtData)
{
#ifndef SFX_MODULE
uint CmtLength;
if (Format==RARFMT14)
{
Seek(SFXSize+SIZEOF_MAINHEAD14,SEEK_SET);
CmtLength=GetByte();
CmtLength+=(GetByte()<<8);
}
else
#endif
{
if (MainHead.CommentInHeader)
{
// Old style (RAR 2.9) archive comment embedded into the main
// archive header.
Seek(SFXSize+SIZEOF_MARKHEAD3+SIZEOF_MAINHEAD3,SEEK_SET);
if (!ReadHeader() || GetHeaderType()!=HEAD3_CMT)
return false;
}
else
{
// Current (RAR 3.0+) version of archive comment.
Seek(GetStartPos(),SEEK_SET);
if (SearchSubBlock(SUBHEAD_TYPE_CMT)!=0)
if (ReadCommentData(CmtData))
return true;
else
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
}
#ifndef SFX_MODULE
// Old style (RAR 2.9) comment header embedded into the main
// archive header.
if (BrokenHeader || CommHead.HeadSize<SIZEOF_COMMHEAD)
{
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
}
CmtLength=CommHead.HeadSize-SIZEOF_COMMHEAD;
#endif
}
#ifndef SFX_MODULE
if (Format==RARFMT14 && MainHead.PackComment || Format!=RARFMT14 && CommHead.Method!=0x30)
{
if (Format!=RARFMT14 && (CommHead.UnpVer < 15 || CommHead.UnpVer > VER_UNPACK || CommHead.Method > 0x35))
return false;
ComprDataIO DataIO;
DataIO.SetTestMode(true);
uint UnpCmtLength;
if (Format==RARFMT14)
{
#ifdef RAR_NOCRYPT
return false;
#else
UnpCmtLength=GetByte();
UnpCmtLength+=(GetByte()<<8);
if (CmtLength<2)
return false;
CmtLength-=2;
DataIO.SetCmt13Encryption();
CommHead.UnpVer=15;
#endif
}
else
UnpCmtLength=CommHead.UnpSize;
DataIO.SetFiles(this,NULL);
DataIO.EnableShowProgress(false);
DataIO.SetPackedSizeToRead(CmtLength);
DataIO.UnpHash.Init(HASH_CRC32,1);
DataIO.SetNoFileHeader(true); // this->FileHead is not filled yet.
Unpack CmtUnpack(&DataIO);
CmtUnpack.Init(0x10000,false);
CmtUnpack.SetDestSize(UnpCmtLength);
CmtUnpack.DoUnpack(CommHead.UnpVer,false);
if (Format!=RARFMT14 && (DataIO.UnpHash.GetCRC32()&0xffff)!=CommHead.CommCRC)
{
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
}
else
{
byte *UnpData;
size_t UnpDataSize;
DataIO.GetUnpackedData(&UnpData,&UnpDataSize);
if (UnpDataSize>0)
{
#ifdef _WIN_ALL
// If we ever decide to extend it to Android, we'll need to alloc
// 4x memory for OEM to UTF-8 output here.
OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize);
#endif
std::string UnpStr((char*)UnpData,UnpDataSize);
CharToWide(UnpStr,CmtData);
}
}
}
else
{
if (CmtLength==0)
return false;
std::vector<byte> CmtRaw(CmtLength);
int ReadSize=Read(CmtRaw.data(),CmtLength);
if (ReadSize>=0 && (uint)ReadSize<CmtLength) // Comment is shorter than declared.
{
CmtLength=ReadSize;
CmtRaw.resize(CmtLength);
}
if (Format!=RARFMT14 && CommHead.CommCRC!=(~CRC32(0xffffffff,&CmtRaw[0],CmtLength)&0xffff))
{
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
}
// CmtData.resize(CmtLength+1);
CmtRaw.push_back(0);
#ifdef _WIN_ALL
// If we ever decide to extend it to Android, we'll need to alloc
// 4x memory for OEM to UTF-8 output here.
OemToCharA((char *)CmtRaw.data(),(char *)CmtRaw.data());
#endif
CharToWide((const char *)CmtRaw.data(),CmtData);
// CmtData->resize(wcslen(CmtData->data()));
}
#endif
return CmtData.size() > 0;
}
bool Archive::ReadCommentData(std::wstring &CmtData)
{
std::vector<byte> CmtRaw;
if (!ReadSubData(&CmtRaw,NULL,false))
return false;
size_t CmtSize=CmtRaw.size();
CmtRaw.push_back(0);
// CmtData->resize(CmtSize+1);
if (Format==RARFMT50)
UtfToWide((char *)CmtRaw.data(),CmtData);
else
if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0)
{
CmtData=RawToWide(CmtRaw);
}
else
{
CharToWide((const char *)CmtRaw.data(),CmtData);
}
// CmtData->resize(wcslen(CmtData->data())); // Set buffer size to actual comment length.
return true;
}
void Archive::ViewComment()
{
if (Cmd->DisableComment)
return;
std::wstring CmtBuf;
if (GetComment(CmtBuf)) // In GUI too, so "Test" command detects broken comments.
{
size_t CmtSize=CmtBuf.size();
auto EndPos=CmtBuf.find(0x1A);
if (EndPos!=std::wstring::npos)
CmtSize=EndPos;
mprintf(St(MArcComment));
mprintf(L":\n");
OutComment(CmtBuf);
}
}