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