1 static bool IsAnsiEscComment(const wchar *Data,size_t Size);
2 
GetComment(Array<wchar> * CmtData)3 bool Archive::GetComment(Array<wchar> *CmtData)
4 {
5   if (!MainComment)
6     return false;
7   int64 SavePos=Tell();
8   bool Success=DoGetComment(CmtData);
9   Seek(SavePos,SEEK_SET);
10   return Success;
11 }
12 
13 
DoGetComment(Array<wchar> * CmtData)14 bool Archive::DoGetComment(Array<wchar> *CmtData)
15 {
16 #ifndef SFX_MODULE
17   uint CmtLength;
18   if (Format==RARFMT14)
19   {
20     Seek(SFXSize+SIZEOF_MAINHEAD14,SEEK_SET);
21     CmtLength=GetByte();
22     CmtLength+=(GetByte()<<8);
23   }
24   else
25 #endif
26   {
27     if (MainHead.CommentInHeader)
28     {
29       // Old style (RAR 2.9) archive comment embedded into the main
30       // archive header.
31       Seek(SFXSize+SIZEOF_MARKHEAD3+SIZEOF_MAINHEAD3,SEEK_SET);
32       if (!ReadHeader() || GetHeaderType()!=HEAD3_CMT)
33         return false;
34     }
35     else
36     {
37       // Current (RAR 3.0+) version of archive comment.
38       Seek(GetStartPos(),SEEK_SET);
39       return SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData);
40     }
41 #ifndef SFX_MODULE
42     // Old style (RAR 2.9) comment header embedded into the main
43     // archive header.
44     if (BrokenHeader || CommHead.HeadSize<SIZEOF_COMMHEAD)
45     {
46       uiMsg(UIERROR_CMTBROKEN,FileName);
47       return false;
48     }
49     CmtLength=CommHead.HeadSize-SIZEOF_COMMHEAD;
50 #endif
51   }
52 #ifndef SFX_MODULE
53   if (Format==RARFMT14 && MainHead.PackComment || Format!=RARFMT14 && CommHead.Method!=0x30)
54   {
55     if (Format!=RARFMT14 && (CommHead.UnpVer < 15 || CommHead.UnpVer > VER_UNPACK || CommHead.Method > 0x35))
56       return false;
57     ComprDataIO DataIO;
58     DataIO.SetTestMode(true);
59     uint UnpCmtLength;
60     if (Format==RARFMT14)
61     {
62 #ifdef RAR_NOCRYPT
63       return false;
64 #else
65       UnpCmtLength=GetByte();
66       UnpCmtLength+=(GetByte()<<8);
67       if (CmtLength<2)
68         return false;
69       CmtLength-=2;
70       DataIO.SetCmt13Encryption();
71       CommHead.UnpVer=15;
72 #endif
73     }
74     else
75       UnpCmtLength=CommHead.UnpSize;
76     DataIO.SetFiles(this,NULL);
77     DataIO.EnableShowProgress(false);
78     DataIO.SetPackedSizeToRead(CmtLength);
79     DataIO.UnpHash.Init(HASH_CRC32,1);
80     DataIO.SetNoFileHeader(true); // this->FileHead is not filled yet.
81 
82     Unpack CmtUnpack(&DataIO);
83     CmtUnpack.Init(0x10000,false);
84     CmtUnpack.SetDestSize(UnpCmtLength);
85     CmtUnpack.DoUnpack(CommHead.UnpVer,false);
86 
87     if (Format!=RARFMT14 && (DataIO.UnpHash.GetCRC32()&0xffff)!=CommHead.CommCRC)
88     {
89       uiMsg(UIERROR_CMTBROKEN,FileName);
90       return false;
91     }
92     else
93     {
94       byte *UnpData;
95       size_t UnpDataSize;
96       DataIO.GetUnpackedData(&UnpData,&UnpDataSize);
97       if (UnpDataSize>0)
98       {
99 #ifdef _WIN_ALL
100         // If we ever decide to extend it to Android, we'll need to alloc
101         // 4x memory for OEM to UTF-8 output here.
102         OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize);
103 #endif
104         CmtData->Alloc(UnpDataSize+1);
105         memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar));
106         CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size());
107         CmtData->Alloc(wcslen(CmtData->Addr(0)));
108       }
109     }
110   }
111   else
112   {
113     if (CmtLength==0)
114       return false;
115     Array<byte> CmtRaw(CmtLength);
116     int ReadSize=Read(&CmtRaw[0],CmtLength);
117     if (ReadSize>=0 && (uint)ReadSize<CmtLength) // Comment is shorter than declared.
118     {
119       CmtLength=ReadSize;
120       CmtRaw.Alloc(CmtLength);
121     }
122 
123     if (Format!=RARFMT14 && CommHead.CommCRC!=(~CRC32(0xffffffff,&CmtRaw[0],CmtLength)&0xffff))
124     {
125       uiMsg(UIERROR_CMTBROKEN,FileName);
126       return false;
127     }
128     CmtData->Alloc(CmtLength+1);
129     CmtRaw.Push(0);
130 #ifdef _WIN_ALL
131     // If we ever decide to extend it to Android, we'll need to alloc
132     // 4x memory for OEM to UTF-8 output here.
133     OemToCharA((char *)&CmtRaw[0],(char *)&CmtRaw[0]);
134 #endif
135     CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
136     CmtData->Alloc(wcslen(CmtData->Addr(0)));
137   }
138 #endif
139   return CmtData->Size() > 0;
140 }
141 
142 
ReadCommentData(Array<wchar> * CmtData)143 bool Archive::ReadCommentData(Array<wchar> *CmtData)
144 {
145   Array<byte> CmtRaw;
146   if (!ReadSubData(&CmtRaw,NULL,false))
147     return false;
148   size_t CmtSize=CmtRaw.Size();
149   CmtRaw.Push(0);
150   CmtData->Alloc(CmtSize+1);
151   if (Format==RARFMT50)
152     UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
153   else
154     if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0)
155     {
156       RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2);
157       (*CmtData)[CmtSize/2]=0;
158 
159     }
160     else
161     {
162       CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
163     }
164   CmtData->Alloc(wcslen(CmtData->Addr(0))); // Set buffer size to actual comment length.
165   return true;
166 }
167 
168 
ViewComment()169 void Archive::ViewComment()
170 {
171   if (Cmd->DisableComment)
172     return;
173   Array<wchar> CmtBuf;
174   if (GetComment(&CmtBuf)) // In GUI too, so "Test" command detects broken comments.
175   {
176     size_t CmtSize=CmtBuf.Size();
177     wchar *ChPtr=wcschr(&CmtBuf[0],0x1A);
178     if (ChPtr!=NULL)
179       CmtSize=ChPtr-&CmtBuf[0];
180     mprintf(L"\n");
181     OutComment(&CmtBuf[0],CmtSize);
182   }
183 }
184 
185 
186