static bool IsAnsiEscComment(const wchar *Data,size_t Size); bool Archive::GetComment(Array *CmtData) { if (!MainComment) return false; SaveFilePos SavePos(*this); #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); return SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData); } #ifndef SFX_MODULE // Old style (RAR 2.9) comment header embedded into the main // archive header. if (BrokenHeader) { 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); 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); #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 CmtData->Alloc(UnpDataSize+1); memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar)); CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size()); CmtData->Alloc(wcslen(CmtData->Addr(0))); } } else { if (CmtLength==0) return false; Array CmtRaw(CmtLength); int ReadSize=Read(&CmtRaw[0],CmtLength); if (ReadSize>=0 && (uint)ReadSizeAlloc(CmtLength+1); CmtRaw.Push(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[0],(char *)&CmtRaw[0]); #endif CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size()); CmtData->Alloc(wcslen(CmtData->Addr(0))); } #endif return CmtData->Size() > 0; } bool Archive::ReadCommentData(Array *CmtData) { Array CmtRaw; if (!ReadSubData(&CmtRaw,NULL)) return false; size_t CmtSize=CmtRaw.Size(); CmtRaw.Push(0); CmtData->Alloc(CmtSize+1); if (Format==RARFMT50) UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size()); else if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0) { RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2); (*CmtData)[CmtSize/2]=0; } else { CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size()); } CmtData->Alloc(wcslen(CmtData->Addr(0))); // Set buffer size to actual comment length. return true; } void Archive::ViewComment() { if (Cmd->DisableComment) return; Array CmtBuf; if (GetComment(&CmtBuf)) // In GUI too, so "Test" command detects broken comments. { size_t CmtSize=CmtBuf.Size(); wchar *ChPtr=wcschr(&CmtBuf[0],0x1A); if (ChPtr!=NULL) CmtSize=ChPtr-&CmtBuf[0]; mprintf(L"\n"); OutComment(&CmtBuf[0],CmtSize); } }