rlm@1
|
1 // Archive/RarIn.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 #include "Common/StringConvert.h"
|
rlm@1
|
6 #include "Common/UTFConvert.h"
|
rlm@1
|
7
|
rlm@1
|
8 #include "RarIn.h"
|
rlm@1
|
9 #include "../../Common/LimitedStreams.h"
|
rlm@1
|
10 #include "../../Common/StreamUtils.h"
|
rlm@1
|
11
|
rlm@1
|
12 #include "../Common/FindSignature.h"
|
rlm@1
|
13
|
rlm@1
|
14 extern "C"
|
rlm@1
|
15 {
|
rlm@1
|
16 #include "../../../../C/7zCrc.h"
|
rlm@1
|
17 }
|
rlm@1
|
18
|
rlm@1
|
19 namespace NArchive {
|
rlm@1
|
20 namespace NRar {
|
rlm@1
|
21
|
rlm@1
|
22 void CInArchive::ThrowExceptionWithCode(
|
rlm@1
|
23 CInArchiveException::CCauseType cause)
|
rlm@1
|
24 {
|
rlm@1
|
25 throw CInArchiveException(cause);
|
rlm@1
|
26 }
|
rlm@1
|
27
|
rlm@1
|
28 HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit)
|
rlm@1
|
29 {
|
rlm@1
|
30 try
|
rlm@1
|
31 {
|
rlm@1
|
32 Close();
|
rlm@1
|
33 HRESULT res = Open2(inStream, searchHeaderSizeLimit);
|
rlm@1
|
34 if (res == S_OK)
|
rlm@1
|
35 return res;
|
rlm@1
|
36 Close();
|
rlm@1
|
37 return res;
|
rlm@1
|
38 }
|
rlm@1
|
39 catch(...) { Close(); throw; }
|
rlm@1
|
40 }
|
rlm@1
|
41
|
rlm@1
|
42 void CInArchive::Close()
|
rlm@1
|
43 {
|
rlm@1
|
44 m_Stream.Release();
|
rlm@1
|
45 }
|
rlm@1
|
46
|
rlm@1
|
47
|
rlm@1
|
48 static inline bool TestMarkerCandidate(const void *aTestBytes)
|
rlm@1
|
49 {
|
rlm@1
|
50 for (UInt32 i = 0; i < NHeader::kMarkerSize; i++)
|
rlm@1
|
51 if (((const Byte *)aTestBytes)[i] != NHeader::kMarker[i])
|
rlm@1
|
52 return false;
|
rlm@1
|
53 return true;
|
rlm@1
|
54 }
|
rlm@1
|
55
|
rlm@1
|
56 HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
|
rlm@1
|
57 {
|
rlm@1
|
58 RINOK(FindSignatureInStream(stream,
|
rlm@1
|
59 NHeader::kMarker, NHeader::kMarkerSize,
|
rlm@1
|
60 searchHeaderSizeLimit, m_ArchiveStartPosition));
|
rlm@1
|
61 m_Stream = stream;
|
rlm@1
|
62 m_Position = m_ArchiveStartPosition + NHeader::kMarkerSize;
|
rlm@1
|
63 return m_Stream->Seek(m_Position, STREAM_SEEK_SET, NULL);
|
rlm@1
|
64 }
|
rlm@1
|
65
|
rlm@1
|
66 void CInArchive::ThrowUnexpectedEndOfArchiveException()
|
rlm@1
|
67 {
|
rlm@1
|
68 ThrowExceptionWithCode(CInArchiveException::kUnexpectedEndOfArchive);
|
rlm@1
|
69 }
|
rlm@1
|
70
|
rlm@1
|
71 bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size)
|
rlm@1
|
72 {
|
rlm@1
|
73 if (m_CryptoMode)
|
rlm@1
|
74 {
|
rlm@1
|
75 const Byte *bufData = (const Byte *)m_DecryptedData;
|
rlm@1
|
76 UInt32 bufSize = m_DecryptedDataSize;
|
rlm@1
|
77 UInt32 i;
|
rlm@1
|
78 for (i = 0; i < size && m_CryptoPos < bufSize; i++)
|
rlm@1
|
79 ((Byte *)data)[i] = bufData[m_CryptoPos++];
|
rlm@1
|
80 return (i == size);
|
rlm@1
|
81 }
|
rlm@1
|
82 return (ReadStream_FALSE(m_Stream, data, size) == S_OK);
|
rlm@1
|
83 }
|
rlm@1
|
84
|
rlm@1
|
85 void CInArchive::ReadBytesAndTestResult(void *data, UInt32 size)
|
rlm@1
|
86 {
|
rlm@1
|
87 if(!ReadBytesAndTestSize(data,size))
|
rlm@1
|
88 ThrowUnexpectedEndOfArchiveException();
|
rlm@1
|
89 }
|
rlm@1
|
90
|
rlm@1
|
91 HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize)
|
rlm@1
|
92 {
|
rlm@1
|
93 size_t realProcessedSize = size;
|
rlm@1
|
94 HRESULT result = ReadStream(m_Stream, data, &realProcessedSize);
|
rlm@1
|
95 if (processedSize != NULL)
|
rlm@1
|
96 *processedSize = (UInt32)realProcessedSize;
|
rlm@1
|
97 AddToSeekValue(realProcessedSize);
|
rlm@1
|
98 return result;
|
rlm@1
|
99 }
|
rlm@1
|
100
|
rlm@1
|
101 static UInt32 CrcUpdateUInt16(UInt32 crc, UInt16 v)
|
rlm@1
|
102 {
|
rlm@1
|
103 crc = CRC_UPDATE_BYTE(crc, (Byte)(v & 0xFF));
|
rlm@1
|
104 crc = CRC_UPDATE_BYTE(crc, (Byte)((v >> 8) & 0xFF));
|
rlm@1
|
105 return crc;
|
rlm@1
|
106 }
|
rlm@1
|
107
|
rlm@1
|
108 static UInt32 CrcUpdateUInt32(UInt32 crc, UInt32 v)
|
rlm@1
|
109 {
|
rlm@1
|
110 crc = CRC_UPDATE_BYTE(crc, (Byte)(v & 0xFF));
|
rlm@1
|
111 crc = CRC_UPDATE_BYTE(crc, (Byte)((v >> 8) & 0xFF));
|
rlm@1
|
112 crc = CRC_UPDATE_BYTE(crc, (Byte)((v >> 16) & 0xFF));
|
rlm@1
|
113 crc = CRC_UPDATE_BYTE(crc, (Byte)((v >> 24) & 0xFF));
|
rlm@1
|
114 return crc;
|
rlm@1
|
115 }
|
rlm@1
|
116
|
rlm@1
|
117
|
rlm@1
|
118 HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
|
rlm@1
|
119 {
|
rlm@1
|
120 m_CryptoMode = false;
|
rlm@1
|
121 RINOK(stream->Seek(0, STREAM_SEEK_SET, &m_StreamStartPosition));
|
rlm@1
|
122 m_Position = m_StreamStartPosition;
|
rlm@1
|
123
|
rlm@1
|
124 RINOK(FindAndReadMarker(stream, searchHeaderSizeLimit));
|
rlm@1
|
125
|
rlm@1
|
126 Byte buf[NHeader::NArchive::kArchiveHeaderSize];
|
rlm@1
|
127 UInt32 processedSize;
|
rlm@1
|
128 ReadBytes(buf, sizeof(buf), &processedSize);
|
rlm@1
|
129 if (processedSize != sizeof(buf))
|
rlm@1
|
130 return S_FALSE;
|
rlm@1
|
131 m_CurData = buf;
|
rlm@1
|
132 m_CurPos = 0;
|
rlm@1
|
133 m_PosLimit = sizeof(buf);
|
rlm@1
|
134
|
rlm@1
|
135 m_ArchiveHeader.CRC = ReadUInt16();
|
rlm@1
|
136 m_ArchiveHeader.Type = ReadByte();
|
rlm@1
|
137 m_ArchiveHeader.Flags = ReadUInt16();
|
rlm@1
|
138 m_ArchiveHeader.Size = ReadUInt16();
|
rlm@1
|
139 m_ArchiveHeader.Reserved1 = ReadUInt16();
|
rlm@1
|
140 m_ArchiveHeader.Reserved2 = ReadUInt32();
|
rlm@1
|
141 m_ArchiveHeader.EncryptVersion = 0;
|
rlm@1
|
142
|
rlm@1
|
143 UInt32 crc = CRC_INIT_VAL;
|
rlm@1
|
144 crc = CRC_UPDATE_BYTE(crc, m_ArchiveHeader.Type);
|
rlm@1
|
145 crc = CrcUpdateUInt16(crc, m_ArchiveHeader.Flags);
|
rlm@1
|
146 crc = CrcUpdateUInt16(crc, m_ArchiveHeader.Size);
|
rlm@1
|
147 crc = CrcUpdateUInt16(crc, m_ArchiveHeader.Reserved1);
|
rlm@1
|
148 crc = CrcUpdateUInt32(crc, m_ArchiveHeader.Reserved2);
|
rlm@1
|
149
|
rlm@1
|
150 if (m_ArchiveHeader.IsThereEncryptVer() && m_ArchiveHeader.Size > NHeader::NArchive::kArchiveHeaderSize)
|
rlm@1
|
151 {
|
rlm@1
|
152 ReadBytes(&m_ArchiveHeader.EncryptVersion, 1, &processedSize);
|
rlm@1
|
153 if (processedSize != 1)
|
rlm@1
|
154 return S_FALSE;
|
rlm@1
|
155 crc = CRC_UPDATE_BYTE(crc, m_ArchiveHeader.EncryptVersion);
|
rlm@1
|
156 }
|
rlm@1
|
157
|
rlm@1
|
158 if(m_ArchiveHeader.CRC != (CRC_GET_DIGEST(crc) & 0xFFFF))
|
rlm@1
|
159 ThrowExceptionWithCode(CInArchiveException::kArchiveHeaderCRCError);
|
rlm@1
|
160 if (m_ArchiveHeader.Type != NHeader::NBlockType::kArchiveHeader)
|
rlm@1
|
161 return S_FALSE;
|
rlm@1
|
162 m_ArchiveCommentPosition = m_Position;
|
rlm@1
|
163 m_SeekOnArchiveComment = true;
|
rlm@1
|
164 return S_OK;
|
rlm@1
|
165 }
|
rlm@1
|
166
|
rlm@1
|
167 void CInArchive::SkipArchiveComment()
|
rlm@1
|
168 {
|
rlm@1
|
169 if (!m_SeekOnArchiveComment)
|
rlm@1
|
170 return;
|
rlm@1
|
171 AddToSeekValue(m_ArchiveHeader.Size - m_ArchiveHeader.GetBaseSize());
|
rlm@1
|
172 m_SeekOnArchiveComment = false;
|
rlm@1
|
173 }
|
rlm@1
|
174
|
rlm@1
|
175 void CInArchive::GetArchiveInfo(CInArchiveInfo &archiveInfo) const
|
rlm@1
|
176 {
|
rlm@1
|
177 archiveInfo.StartPosition = m_ArchiveStartPosition;
|
rlm@1
|
178 archiveInfo.Flags = m_ArchiveHeader.Flags;
|
rlm@1
|
179 archiveInfo.CommentPosition = m_ArchiveCommentPosition;
|
rlm@1
|
180 archiveInfo.CommentSize = (UInt16)(m_ArchiveHeader.Size - NHeader::NArchive::kArchiveHeaderSize);
|
rlm@1
|
181 }
|
rlm@1
|
182
|
rlm@1
|
183 static void DecodeUnicodeFileName(const char *name, const Byte *encName,
|
rlm@1
|
184 int encSize, wchar_t *unicodeName, int maxDecSize)
|
rlm@1
|
185 {
|
rlm@1
|
186 int encPos = 0;
|
rlm@1
|
187 int decPos = 0;
|
rlm@1
|
188 int flagBits = 0;
|
rlm@1
|
189 Byte flags = 0;
|
rlm@1
|
190 Byte highByte = encName[encPos++];
|
rlm@1
|
191 while (encPos < encSize && decPos < maxDecSize)
|
rlm@1
|
192 {
|
rlm@1
|
193 if (flagBits == 0)
|
rlm@1
|
194 {
|
rlm@1
|
195 flags = encName[encPos++];
|
rlm@1
|
196 flagBits = 8;
|
rlm@1
|
197 }
|
rlm@1
|
198 switch(flags >> 6)
|
rlm@1
|
199 {
|
rlm@1
|
200 case 0:
|
rlm@1
|
201 unicodeName[decPos++] = encName[encPos++];
|
rlm@1
|
202 break;
|
rlm@1
|
203 case 1:
|
rlm@1
|
204 unicodeName[decPos++] = (wchar_t)(encName[encPos++] + (highByte << 8));
|
rlm@1
|
205 break;
|
rlm@1
|
206 case 2:
|
rlm@1
|
207 unicodeName[decPos++] = (wchar_t)(encName[encPos] + (encName[encPos + 1] << 8));
|
rlm@1
|
208 encPos += 2;
|
rlm@1
|
209 break;
|
rlm@1
|
210 case 3:
|
rlm@1
|
211 {
|
rlm@1
|
212 int length = encName[encPos++];
|
rlm@1
|
213 if (length & 0x80)
|
rlm@1
|
214 {
|
rlm@1
|
215 Byte correction = encName[encPos++];
|
rlm@1
|
216 for (length = (length & 0x7f) + 2;
|
rlm@1
|
217 length > 0 && decPos < maxDecSize; length--, decPos++)
|
rlm@1
|
218 unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + (highByte << 8));
|
rlm@1
|
219 }
|
rlm@1
|
220 else
|
rlm@1
|
221 for (length += 2; length > 0 && decPos < maxDecSize; length--, decPos++)
|
rlm@1
|
222 unicodeName[decPos] = name[decPos];
|
rlm@1
|
223 }
|
rlm@1
|
224 break;
|
rlm@1
|
225 }
|
rlm@1
|
226 flags <<= 2;
|
rlm@1
|
227 flagBits -= 2;
|
rlm@1
|
228 }
|
rlm@1
|
229 unicodeName[decPos < maxDecSize ? decPos : maxDecSize - 1] = 0;
|
rlm@1
|
230 }
|
rlm@1
|
231
|
rlm@1
|
232 void CInArchive::ReadName(CItemEx &item, int nameSize)
|
rlm@1
|
233 {
|
rlm@1
|
234 item.UnicodeName.Empty();
|
rlm@1
|
235 if (nameSize > 0)
|
rlm@1
|
236 {
|
rlm@1
|
237 m_NameBuffer.EnsureCapacity(nameSize + 1);
|
rlm@1
|
238 char *buffer = (char *)m_NameBuffer;
|
rlm@1
|
239
|
rlm@1
|
240 for (int i = 0; i < nameSize; i++)
|
rlm@1
|
241 buffer[i] = ReadByte();
|
rlm@1
|
242
|
rlm@1
|
243 int mainLen;
|
rlm@1
|
244 for (mainLen = 0; mainLen < nameSize; mainLen++)
|
rlm@1
|
245 if (buffer[mainLen] == '\0')
|
rlm@1
|
246 break;
|
rlm@1
|
247 buffer[mainLen] = '\0';
|
rlm@1
|
248 item.Name = buffer;
|
rlm@1
|
249
|
rlm@1
|
250 if(item.HasUnicodeName())
|
rlm@1
|
251 {
|
rlm@1
|
252 if(mainLen < nameSize)
|
rlm@1
|
253 {
|
rlm@1
|
254 int unicodeNameSizeMax = MyMin(nameSize, (0x400));
|
rlm@1
|
255 _unicodeNameBuffer.EnsureCapacity(unicodeNameSizeMax + 1);
|
rlm@1
|
256 DecodeUnicodeFileName(buffer, (const Byte *)buffer + mainLen + 1,
|
rlm@1
|
257 nameSize - (mainLen + 1), _unicodeNameBuffer, unicodeNameSizeMax);
|
rlm@1
|
258 item.UnicodeName = _unicodeNameBuffer;
|
rlm@1
|
259 }
|
rlm@1
|
260 else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName))
|
rlm@1
|
261 item.UnicodeName.Empty();
|
rlm@1
|
262 }
|
rlm@1
|
263 }
|
rlm@1
|
264 else
|
rlm@1
|
265 item.Name.Empty();
|
rlm@1
|
266 }
|
rlm@1
|
267
|
rlm@1
|
268 Byte CInArchive::ReadByte()
|
rlm@1
|
269 {
|
rlm@1
|
270 if (m_CurPos >= m_PosLimit)
|
rlm@1
|
271 throw CInArchiveException(CInArchiveException::kIncorrectArchive);
|
rlm@1
|
272 return m_CurData[m_CurPos++];
|
rlm@1
|
273 }
|
rlm@1
|
274
|
rlm@1
|
275 UInt16 CInArchive::ReadUInt16()
|
rlm@1
|
276 {
|
rlm@1
|
277 UInt16 value = 0;
|
rlm@1
|
278 for (int i = 0; i < 2; i++)
|
rlm@1
|
279 {
|
rlm@1
|
280 Byte b = ReadByte();
|
rlm@1
|
281 value |= (UInt16(b) << (8 * i));
|
rlm@1
|
282 }
|
rlm@1
|
283 return value;
|
rlm@1
|
284 }
|
rlm@1
|
285
|
rlm@1
|
286 UInt32 CInArchive::ReadUInt32()
|
rlm@1
|
287 {
|
rlm@1
|
288 UInt32 value = 0;
|
rlm@1
|
289 for (int i = 0; i < 4; i++)
|
rlm@1
|
290 {
|
rlm@1
|
291 Byte b = ReadByte();
|
rlm@1
|
292 value |= (UInt32(b) << (8 * i));
|
rlm@1
|
293 }
|
rlm@1
|
294 return value;
|
rlm@1
|
295 }
|
rlm@1
|
296
|
rlm@1
|
297 void CInArchive::ReadTime(Byte mask, CRarTime &rarTime)
|
rlm@1
|
298 {
|
rlm@1
|
299 rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0);
|
rlm@1
|
300 int numDigits = (mask & 3);
|
rlm@1
|
301 rarTime.SubTime[0] = rarTime.SubTime[1] = rarTime.SubTime[2] = 0;
|
rlm@1
|
302 for (int i = 0; i < numDigits; i++)
|
rlm@1
|
303 rarTime.SubTime[3 - numDigits + i] = ReadByte();
|
rlm@1
|
304 }
|
rlm@1
|
305
|
rlm@1
|
306 void CInArchive::ReadHeaderReal(CItemEx &item)
|
rlm@1
|
307 {
|
rlm@1
|
308 item.Flags = m_BlockHeader.Flags;
|
rlm@1
|
309 item.PackSize = ReadUInt32();
|
rlm@1
|
310 item.Size = ReadUInt32();
|
rlm@1
|
311 item.HostOS = ReadByte();
|
rlm@1
|
312 item.FileCRC = ReadUInt32();
|
rlm@1
|
313 item.MTime.DosTime = ReadUInt32();
|
rlm@1
|
314 item.UnPackVersion = ReadByte();
|
rlm@1
|
315 item.Method = ReadByte();
|
rlm@1
|
316 int nameSize = ReadUInt16();
|
rlm@1
|
317 item.Attrib = ReadUInt32();
|
rlm@1
|
318
|
rlm@1
|
319 item.MTime.LowSecond = 0;
|
rlm@1
|
320 item.MTime.SubTime[0] =
|
rlm@1
|
321 item.MTime.SubTime[1] =
|
rlm@1
|
322 item.MTime.SubTime[2] = 0;
|
rlm@1
|
323
|
rlm@1
|
324 if((item.Flags & NHeader::NFile::kSize64Bits) != 0)
|
rlm@1
|
325 {
|
rlm@1
|
326 item.PackSize |= ((UInt64)ReadUInt32() << 32);
|
rlm@1
|
327 item.Size |= ((UInt64)ReadUInt32() << 32);
|
rlm@1
|
328 }
|
rlm@1
|
329
|
rlm@1
|
330 ReadName(item, nameSize);
|
rlm@1
|
331
|
rlm@1
|
332 if (item.HasSalt())
|
rlm@1
|
333 for (int i = 0; i < sizeof(item.Salt); i++)
|
rlm@1
|
334 item.Salt[i] = ReadByte();
|
rlm@1
|
335
|
rlm@1
|
336 // some rar archives have HasExtTime flag without field.
|
rlm@1
|
337 if (m_CurPos < m_PosLimit && item.HasExtTime())
|
rlm@1
|
338 {
|
rlm@1
|
339 Byte accessMask = (Byte)(ReadByte() >> 4);
|
rlm@1
|
340 Byte b = ReadByte();
|
rlm@1
|
341 Byte modifMask = (Byte)(b >> 4);
|
rlm@1
|
342 Byte createMask = (Byte)(b & 0xF);
|
rlm@1
|
343 if ((modifMask & 8) != 0)
|
rlm@1
|
344 ReadTime(modifMask, item.MTime);
|
rlm@1
|
345 item.CTimeDefined = ((createMask & 8) != 0);
|
rlm@1
|
346 if (item.CTimeDefined)
|
rlm@1
|
347 {
|
rlm@1
|
348 item.CTime.DosTime = ReadUInt32();
|
rlm@1
|
349 ReadTime(createMask, item.CTime);
|
rlm@1
|
350 }
|
rlm@1
|
351 item.ATimeDefined = ((accessMask & 8) != 0);
|
rlm@1
|
352 if (item.ATimeDefined)
|
rlm@1
|
353 {
|
rlm@1
|
354 item.ATime.DosTime = ReadUInt32();
|
rlm@1
|
355 ReadTime(accessMask, item.ATime);
|
rlm@1
|
356 }
|
rlm@1
|
357 }
|
rlm@1
|
358
|
rlm@1
|
359 UInt16 fileHeaderWithNameSize = (UInt16)m_CurPos;
|
rlm@1
|
360
|
rlm@1
|
361 item.Position = m_Position;
|
rlm@1
|
362 item.MainPartSize = fileHeaderWithNameSize;
|
rlm@1
|
363 item.CommentSize = (UInt16)(m_BlockHeader.HeadSize - fileHeaderWithNameSize);
|
rlm@1
|
364
|
rlm@1
|
365 if (m_CryptoMode)
|
rlm@1
|
366 item.AlignSize = (UInt16)((16 - ((m_BlockHeader.HeadSize) & 0xF)) & 0xF);
|
rlm@1
|
367 else
|
rlm@1
|
368 item.AlignSize = 0;
|
rlm@1
|
369 AddToSeekValue(m_BlockHeader.HeadSize);
|
rlm@1
|
370 }
|
rlm@1
|
371
|
rlm@1
|
372 void CInArchive::AddToSeekValue(UInt64 addValue)
|
rlm@1
|
373 {
|
rlm@1
|
374 m_Position += addValue;
|
rlm@1
|
375 }
|
rlm@1
|
376
|
rlm@1
|
377 HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword)
|
rlm@1
|
378 {
|
rlm@1
|
379 if (m_SeekOnArchiveComment)
|
rlm@1
|
380 SkipArchiveComment();
|
rlm@1
|
381 for (;;)
|
rlm@1
|
382 {
|
rlm@1
|
383 if(!SeekInArchive(m_Position))
|
rlm@1
|
384 return S_FALSE;
|
rlm@1
|
385 if (!m_CryptoMode && (m_ArchiveHeader.Flags &
|
rlm@1
|
386 NHeader::NArchive::kBlockHeadersAreEncrypted) != 0)
|
rlm@1
|
387 {
|
rlm@1
|
388 m_CryptoMode = false;
|
rlm@1
|
389 if (getTextPassword == 0)
|
rlm@1
|
390 return S_FALSE;
|
rlm@1
|
391 if(!SeekInArchive(m_Position))
|
rlm@1
|
392 return S_FALSE;
|
rlm@1
|
393 if (!m_RarAES)
|
rlm@1
|
394 {
|
rlm@1
|
395 m_RarAESSpec = new NCrypto::NRar29::CDecoder;
|
rlm@1
|
396 m_RarAES = m_RarAESSpec;
|
rlm@1
|
397 }
|
rlm@1
|
398 m_RarAESSpec->SetRar350Mode(m_ArchiveHeader.IsEncryptOld());
|
rlm@1
|
399
|
rlm@1
|
400 // Salt
|
rlm@1
|
401 const UInt32 kSaltSize = 8;
|
rlm@1
|
402 Byte salt[kSaltSize];
|
rlm@1
|
403 if(!ReadBytesAndTestSize(salt, kSaltSize))
|
rlm@1
|
404 return S_FALSE;
|
rlm@1
|
405 m_Position += kSaltSize;
|
rlm@1
|
406 RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize))
|
rlm@1
|
407 // Password
|
rlm@1
|
408 CMyComBSTR password;
|
rlm@1
|
409 RINOK(getTextPassword->CryptoGetTextPassword(&password))
|
rlm@1
|
410 UString unicodePassword(password);
|
rlm@1
|
411
|
rlm@1
|
412 CByteBuffer buffer;
|
rlm@1
|
413 const UInt32 sizeInBytes = unicodePassword.Length() * 2;
|
rlm@1
|
414 buffer.SetCapacity(sizeInBytes);
|
rlm@1
|
415 for (int i = 0; i < unicodePassword.Length(); i++)
|
rlm@1
|
416 {
|
rlm@1
|
417 wchar_t c = unicodePassword[i];
|
rlm@1
|
418 ((Byte *)buffer)[i * 2] = (Byte)c;
|
rlm@1
|
419 ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
|
rlm@1
|
420 }
|
rlm@1
|
421
|
rlm@1
|
422 RINOK(m_RarAESSpec->CryptoSetPassword((const Byte *)buffer, sizeInBytes));
|
rlm@1
|
423
|
rlm@1
|
424 const UInt32 kDecryptedBufferSize = (1 << 12);
|
rlm@1
|
425 if (m_DecryptedData.GetCapacity() == 0)
|
rlm@1
|
426 {
|
rlm@1
|
427 m_DecryptedData.SetCapacity(kDecryptedBufferSize);
|
rlm@1
|
428 }
|
rlm@1
|
429 RINOK(m_RarAES->Init());
|
rlm@1
|
430 size_t decryptedDataSizeT = kDecryptedBufferSize;
|
rlm@1
|
431 RINOK(ReadStream(m_Stream, (Byte *)m_DecryptedData, &decryptedDataSizeT));
|
rlm@1
|
432 m_DecryptedDataSize = (UInt32)decryptedDataSizeT;
|
rlm@1
|
433 m_DecryptedDataSize = m_RarAES->Filter((Byte *)m_DecryptedData, m_DecryptedDataSize);
|
rlm@1
|
434
|
rlm@1
|
435 m_CryptoMode = true;
|
rlm@1
|
436 m_CryptoPos = 0;
|
rlm@1
|
437 }
|
rlm@1
|
438
|
rlm@1
|
439 m_FileHeaderData.EnsureCapacity(7);
|
rlm@1
|
440 if(!ReadBytesAndTestSize((Byte *)m_FileHeaderData, 7))
|
rlm@1
|
441 return S_FALSE;
|
rlm@1
|
442
|
rlm@1
|
443 m_CurData = (Byte *)m_FileHeaderData;
|
rlm@1
|
444 m_CurPos = 0;
|
rlm@1
|
445 m_PosLimit = 7;
|
rlm@1
|
446 m_BlockHeader.CRC = ReadUInt16();
|
rlm@1
|
447 m_BlockHeader.Type = ReadByte();
|
rlm@1
|
448 m_BlockHeader.Flags = ReadUInt16();
|
rlm@1
|
449 m_BlockHeader.HeadSize = ReadUInt16();
|
rlm@1
|
450
|
rlm@1
|
451 if (m_BlockHeader.HeadSize < 7)
|
rlm@1
|
452 ThrowExceptionWithCode(CInArchiveException::kIncorrectArchive);
|
rlm@1
|
453
|
rlm@1
|
454 if (m_BlockHeader.Type == NHeader::NBlockType::kEndOfArchive)
|
rlm@1
|
455 return S_FALSE;
|
rlm@1
|
456
|
rlm@1
|
457 if (m_BlockHeader.Type == NHeader::NBlockType::kFileHeader)
|
rlm@1
|
458 {
|
rlm@1
|
459 m_FileHeaderData.EnsureCapacity(m_BlockHeader.HeadSize);
|
rlm@1
|
460 m_CurData = (Byte *)m_FileHeaderData;
|
rlm@1
|
461 m_PosLimit = m_BlockHeader.HeadSize;
|
rlm@1
|
462 ReadBytesAndTestResult(m_CurData + m_CurPos, m_BlockHeader.HeadSize - 7);
|
rlm@1
|
463 ReadHeaderReal(item);
|
rlm@1
|
464 if ((CrcCalc(m_CurData + 2,
|
rlm@1
|
465 m_BlockHeader.HeadSize - item.CommentSize - 2) & 0xFFFF) != m_BlockHeader.CRC)
|
rlm@1
|
466 ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError);
|
rlm@1
|
467
|
rlm@1
|
468 FinishCryptoBlock();
|
rlm@1
|
469 m_CryptoMode = false;
|
rlm@1
|
470 SeekInArchive(m_Position); // Move Position to compressed Data;
|
rlm@1
|
471 AddToSeekValue(item.PackSize); // m_Position points to next header;
|
rlm@1
|
472 return S_OK;
|
rlm@1
|
473 }
|
rlm@1
|
474 if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 12))
|
rlm@1
|
475 return E_FAIL; // it's for bad passwords
|
rlm@1
|
476 if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0)
|
rlm@1
|
477 {
|
rlm@1
|
478 m_FileHeaderData.EnsureCapacity(7 + 4);
|
rlm@1
|
479 m_CurData = (Byte *)m_FileHeaderData;
|
rlm@1
|
480 ReadBytesAndTestResult(m_CurData + m_CurPos, 4); // test it
|
rlm@1
|
481 m_PosLimit = 7 + 4;
|
rlm@1
|
482 UInt32 dataSize = ReadUInt32();
|
rlm@1
|
483 AddToSeekValue(dataSize);
|
rlm@1
|
484 if (m_CryptoMode && dataSize > (1 << 27))
|
rlm@1
|
485 return E_FAIL; // it's for bad passwords
|
rlm@1
|
486 m_CryptoPos = m_BlockHeader.HeadSize;
|
rlm@1
|
487 }
|
rlm@1
|
488 else
|
rlm@1
|
489 m_CryptoPos = 0;
|
rlm@1
|
490 AddToSeekValue(m_BlockHeader.HeadSize);
|
rlm@1
|
491 FinishCryptoBlock();
|
rlm@1
|
492 m_CryptoMode = false;
|
rlm@1
|
493 }
|
rlm@1
|
494 }
|
rlm@1
|
495
|
rlm@1
|
496 bool CInArchive::SeekInArchive(UInt64 position)
|
rlm@1
|
497 {
|
rlm@1
|
498 UInt64 newPosition;
|
rlm@1
|
499 m_Stream->Seek(position, STREAM_SEEK_SET, &newPosition);
|
rlm@1
|
500 return newPosition == position;
|
rlm@1
|
501 }
|
rlm@1
|
502
|
rlm@1
|
503 ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size)
|
rlm@1
|
504 {
|
rlm@1
|
505 CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
rlm@1
|
506 CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
rlm@1
|
507 SeekInArchive(position);
|
rlm@1
|
508 streamSpec->SetStream(m_Stream);
|
rlm@1
|
509 streamSpec->Init(size);
|
rlm@1
|
510 return inStream.Detach();
|
rlm@1
|
511 }
|
rlm@1
|
512
|
rlm@1
|
513 }}
|