|
1 // 7zHandler.cpp |
|
2 |
|
3 #include "StdAfx.h" |
|
4 |
|
5 #include "7zHandler.h" |
|
6 #include "7zProperties.h" |
|
7 |
|
8 #include "../../../Common/IntToString.h" |
|
9 #include "../../../Common/ComTry.h" |
|
10 #include "../../../Windows/Defs.h" |
|
11 |
|
12 #include "../Common/ItemNameUtils.h" |
|
13 #ifdef _7Z_VOL |
|
14 #include "../Common/MultiStream.h" |
|
15 #endif |
|
16 |
|
17 #ifdef __7Z_SET_PROPERTIES |
|
18 #ifdef EXTRACT_ONLY |
|
19 #include "../Common/ParseProperties.h" |
|
20 #endif |
|
21 #endif |
|
22 |
|
23 using namespace NWindows; |
|
24 |
|
25 namespace NArchive { |
|
26 namespace N7z { |
|
27 |
|
28 CHandler::CHandler() |
|
29 { |
|
30 #ifdef COMPRESS_MT |
|
31 _numThreads = NWindows::NSystem::GetNumberOfProcessors(); |
|
32 #endif |
|
33 #ifndef EXTRACT_ONLY |
|
34 Init(); |
|
35 #endif |
|
36 #ifndef EXCLUDE_COM |
|
37 LoadMethodMap(); |
|
38 #endif |
|
39 } |
|
40 |
|
41 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) |
|
42 { |
|
43 COM_TRY_BEGIN |
|
44 *numItems = |
|
45 #ifdef _7Z_VOL |
|
46 _refs.Size(); |
|
47 #else |
|
48 *numItems = _database.Files.Size(); |
|
49 #endif |
|
50 return S_OK; |
|
51 COM_TRY_END |
|
52 } |
|
53 |
|
54 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) |
|
55 { |
|
56 value->vt = VT_EMPTY; |
|
57 return S_OK; |
|
58 } |
|
59 |
|
60 #ifdef _SFX |
|
61 |
|
62 STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) |
|
63 { |
|
64 return E_NOTIMPL; |
|
65 } |
|
66 |
|
67 STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, |
|
68 BSTR *name, PROPID *propID, VARTYPE *varType) |
|
69 { |
|
70 return E_NOTIMPL; |
|
71 } |
|
72 |
|
73 #endif |
|
74 |
|
75 |
|
76 STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) |
|
77 { |
|
78 *numProperties = 0; |
|
79 return S_OK; |
|
80 } |
|
81 |
|
82 STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32 index, |
|
83 BSTR *name, PROPID *propID, VARTYPE *varType) |
|
84 { |
|
85 return E_NOTIMPL; |
|
86 } |
|
87 |
|
88 |
|
89 static void MySetFileTime(bool timeDefined, FILETIME unixTime, |
|
90 NWindows::NCOM::CPropVariant &propVariant) |
|
91 { |
|
92 if (timeDefined) |
|
93 propVariant = unixTime; |
|
94 } |
|
95 |
|
96 /* |
|
97 inline static wchar_t GetHex(Byte value) |
|
98 { |
|
99 return (value < 10) ? ('0' + value) : ('A' + (value - 10)); |
|
100 } |
|
101 |
|
102 static UString ConvertBytesToHexString(const Byte *data, UInt32 size) |
|
103 { |
|
104 UString result; |
|
105 for (UInt32 i = 0; i < size; i++) |
|
106 { |
|
107 Byte b = data[i]; |
|
108 result += GetHex(b >> 4); |
|
109 result += GetHex(b & 0xF); |
|
110 } |
|
111 return result; |
|
112 } |
|
113 */ |
|
114 |
|
115 |
|
116 #ifndef _SFX |
|
117 |
|
118 static UString ConvertUInt32ToString(UInt32 value) |
|
119 { |
|
120 wchar_t buffer[32]; |
|
121 ConvertUInt64ToString(value, buffer); |
|
122 return buffer; |
|
123 } |
|
124 |
|
125 static UString GetStringForSizeValue(UInt32 value) |
|
126 { |
|
127 for (int i = 31; i >= 0; i--) |
|
128 if ((UInt32(1) << i) == value) |
|
129 return ConvertUInt32ToString(i); |
|
130 UString result; |
|
131 if (value % (1 << 20) == 0) |
|
132 { |
|
133 result += ConvertUInt32ToString(value >> 20); |
|
134 result += L"m"; |
|
135 } |
|
136 else if (value % (1 << 10) == 0) |
|
137 { |
|
138 result += ConvertUInt32ToString(value >> 10); |
|
139 result += L"k"; |
|
140 } |
|
141 else |
|
142 { |
|
143 result += ConvertUInt32ToString(value); |
|
144 result += L"b"; |
|
145 } |
|
146 return result; |
|
147 } |
|
148 |
|
149 static CMethodID k_Copy = { { 0x0 }, 1 }; |
|
150 static CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 }; |
|
151 static CMethodID k_BCJ = { { 0x3, 0x3, 0x1, 0x3 }, 4 }; |
|
152 static CMethodID k_BCJ2 = { { 0x3, 0x3, 0x1, 0x1B }, 4 }; |
|
153 static CMethodID k_PPMD = { { 0x3, 0x4, 0x1 }, 3 }; |
|
154 static CMethodID k_Deflate = { { 0x4, 0x1, 0x8 }, 3 }; |
|
155 static CMethodID k_BZip2 = { { 0x4, 0x2, 0x2 }, 3 }; |
|
156 |
|
157 static inline char GetHex(Byte value) |
|
158 { |
|
159 return (value < 10) ? ('0' + value) : ('A' + (value - 10)); |
|
160 } |
|
161 static inline UString GetHex2(Byte value) |
|
162 { |
|
163 UString result; |
|
164 result += GetHex(value >> 4); |
|
165 result += GetHex(value & 0xF); |
|
166 return result; |
|
167 } |
|
168 |
|
169 #endif |
|
170 |
|
171 static inline UInt32 GetUInt32FromMemLE(const Byte *p) |
|
172 { |
|
173 return p[0] | (((UInt32)p[1]) << 8) | (((UInt32)p[2]) << 16) | (((UInt32)p[3]) << 24); |
|
174 } |
|
175 |
|
176 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) |
|
177 { |
|
178 COM_TRY_BEGIN |
|
179 NWindows::NCOM::CPropVariant propVariant; |
|
180 |
|
181 /* |
|
182 const CRef2 &ref2 = _refs[index]; |
|
183 if (ref2.Refs.IsEmpty()) |
|
184 return E_FAIL; |
|
185 const CRef &ref = ref2.Refs.Front(); |
|
186 */ |
|
187 |
|
188 #ifdef _7Z_VOL |
|
189 const CRef &ref = _refs[index]; |
|
190 const CVolume &volume = _volumes[ref.VolumeIndex]; |
|
191 const CArchiveDatabaseEx &_database = volume.Database; |
|
192 UInt32 index2 = ref.ItemIndex; |
|
193 const CFileItem &item = _database.Files[index2]; |
|
194 #else |
|
195 const CFileItem &item = _database.Files[index]; |
|
196 UInt32 index2 = index; |
|
197 #endif |
|
198 |
|
199 switch(propID) |
|
200 { |
|
201 case kpidPath: |
|
202 { |
|
203 if (!item.Name.IsEmpty()) |
|
204 propVariant = NItemName::GetOSName(item.Name); |
|
205 break; |
|
206 } |
|
207 case kpidIsFolder: |
|
208 propVariant = item.IsDirectory; |
|
209 break; |
|
210 case kpidSize: |
|
211 { |
|
212 propVariant = item.UnPackSize; |
|
213 // propVariant = ref2.UnPackSize; |
|
214 break; |
|
215 } |
|
216 case kpidPosition: |
|
217 { |
|
218 /* |
|
219 if (ref2.Refs.Size() > 1) |
|
220 propVariant = ref2.StartPos; |
|
221 else |
|
222 */ |
|
223 if (item.IsStartPosDefined) |
|
224 propVariant = item.StartPos; |
|
225 break; |
|
226 } |
|
227 case kpidPackedSize: |
|
228 { |
|
229 // propVariant = ref2.PackSize; |
|
230 { |
|
231 CNum folderIndex = _database.FileIndexToFolderIndexMap[index2]; |
|
232 if (folderIndex != kNumNoIndex) |
|
233 { |
|
234 if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2) |
|
235 propVariant = _database.GetFolderFullPackSize(folderIndex); |
|
236 /* |
|
237 else |
|
238 propVariant = UInt64(0); |
|
239 */ |
|
240 } |
|
241 else |
|
242 propVariant = UInt64(0); |
|
243 } |
|
244 break; |
|
245 } |
|
246 case kpidLastAccessTime: |
|
247 MySetFileTime(item.IsLastAccessTimeDefined, item.LastAccessTime, propVariant); |
|
248 break; |
|
249 case kpidCreationTime: |
|
250 MySetFileTime(item.IsCreationTimeDefined, item.CreationTime, propVariant); |
|
251 break; |
|
252 case kpidLastWriteTime: |
|
253 MySetFileTime(item.IsLastWriteTimeDefined, item.LastWriteTime, propVariant); |
|
254 break; |
|
255 case kpidAttributes: |
|
256 if (item.AreAttributesDefined) |
|
257 propVariant = item.Attributes; |
|
258 break; |
|
259 case kpidCRC: |
|
260 if (item.IsFileCRCDefined) |
|
261 propVariant = item.FileCRC; |
|
262 break; |
|
263 #ifndef _SFX |
|
264 case kpidMethod: |
|
265 { |
|
266 CNum folderIndex = _database.FileIndexToFolderIndexMap[index2]; |
|
267 if (folderIndex != kNumNoIndex) |
|
268 { |
|
269 const CFolder &folderInfo = _database.Folders[folderIndex]; |
|
270 UString methodsString; |
|
271 for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--) |
|
272 { |
|
273 const CCoderInfo &coderInfo = folderInfo.Coders[i]; |
|
274 if (!methodsString.IsEmpty()) |
|
275 methodsString += L' '; |
|
276 CMethodInfo methodInfo; |
|
277 |
|
278 bool methodIsKnown; |
|
279 |
|
280 for (int j = 0; j < coderInfo.AltCoders.Size(); j++) |
|
281 { |
|
282 if (j > 0) |
|
283 methodsString += L"|"; |
|
284 const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders[j]; |
|
285 |
|
286 UString methodName; |
|
287 #ifdef NO_REGISTRY |
|
288 |
|
289 methodIsKnown = true; |
|
290 if (altCoderInfo.MethodID == k_Copy) |
|
291 methodName = L"Copy"; |
|
292 else if (altCoderInfo.MethodID == k_LZMA) |
|
293 methodName = L"LZMA"; |
|
294 else if (altCoderInfo.MethodID == k_BCJ) |
|
295 methodName = L"BCJ"; |
|
296 else if (altCoderInfo.MethodID == k_BCJ2) |
|
297 methodName = L"BCJ2"; |
|
298 else if (altCoderInfo.MethodID == k_PPMD) |
|
299 methodName = L"PPMD"; |
|
300 else if (altCoderInfo.MethodID == k_Deflate) |
|
301 methodName = L"Deflate"; |
|
302 else if (altCoderInfo.MethodID == k_BZip2) |
|
303 methodName = L"BZip2"; |
|
304 else |
|
305 methodIsKnown = false; |
|
306 |
|
307 #else |
|
308 |
|
309 methodIsKnown = GetMethodInfo( |
|
310 altCoderInfo.MethodID, methodInfo); |
|
311 methodName = methodInfo.Name; |
|
312 |
|
313 #endif |
|
314 |
|
315 if (methodIsKnown) |
|
316 { |
|
317 methodsString += methodName; |
|
318 if (altCoderInfo.MethodID == k_LZMA) |
|
319 { |
|
320 if (altCoderInfo.Properties.GetCapacity() >= 5) |
|
321 { |
|
322 methodsString += L":"; |
|
323 UInt32 dicSize = GetUInt32FromMemLE( |
|
324 ((const Byte *)altCoderInfo.Properties + 1)); |
|
325 methodsString += GetStringForSizeValue(dicSize); |
|
326 } |
|
327 } |
|
328 else if (altCoderInfo.MethodID == k_PPMD) |
|
329 { |
|
330 if (altCoderInfo.Properties.GetCapacity() >= 5) |
|
331 { |
|
332 Byte order = *(const Byte *)altCoderInfo.Properties; |
|
333 methodsString += L":o"; |
|
334 methodsString += ConvertUInt32ToString(order); |
|
335 methodsString += L":mem"; |
|
336 UInt32 dicSize = GetUInt32FromMemLE( |
|
337 ((const Byte *)altCoderInfo.Properties + 1)); |
|
338 methodsString += GetStringForSizeValue(dicSize); |
|
339 } |
|
340 } |
|
341 else |
|
342 { |
|
343 if (altCoderInfo.Properties.GetCapacity() > 0) |
|
344 { |
|
345 methodsString += L":["; |
|
346 for (size_t bi = 0; bi < altCoderInfo.Properties.GetCapacity(); bi++) |
|
347 { |
|
348 if (bi > 2 && bi + 1 < altCoderInfo.Properties.GetCapacity()) |
|
349 { |
|
350 methodsString += L".."; |
|
351 break; |
|
352 } |
|
353 else |
|
354 methodsString += GetHex2(altCoderInfo.Properties[bi]); |
|
355 } |
|
356 methodsString += L"]"; |
|
357 } |
|
358 } |
|
359 } |
|
360 else |
|
361 { |
|
362 methodsString += altCoderInfo.MethodID.ConvertToString(); |
|
363 } |
|
364 } |
|
365 } |
|
366 propVariant = methodsString; |
|
367 } |
|
368 } |
|
369 break; |
|
370 case kpidBlock: |
|
371 { |
|
372 CNum folderIndex = _database.FileIndexToFolderIndexMap[index2]; |
|
373 if (folderIndex != kNumNoIndex) |
|
374 propVariant = (UInt32)folderIndex; |
|
375 } |
|
376 break; |
|
377 case kpidPackedSize0: |
|
378 case kpidPackedSize1: |
|
379 case kpidPackedSize2: |
|
380 case kpidPackedSize3: |
|
381 case kpidPackedSize4: |
|
382 { |
|
383 CNum folderIndex = _database.FileIndexToFolderIndexMap[index2]; |
|
384 if (folderIndex != kNumNoIndex) |
|
385 { |
|
386 const CFolder &folderInfo = _database.Folders[folderIndex]; |
|
387 if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2 && |
|
388 folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0)) |
|
389 { |
|
390 propVariant = _database.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0); |
|
391 } |
|
392 else |
|
393 propVariant = UInt64(0); |
|
394 } |
|
395 else |
|
396 propVariant = UInt64(0); |
|
397 } |
|
398 break; |
|
399 #endif |
|
400 case kpidIsAnti: |
|
401 propVariant = item.IsAnti; |
|
402 break; |
|
403 } |
|
404 propVariant.Detach(value); |
|
405 return S_OK; |
|
406 COM_TRY_END |
|
407 } |
|
408 |
|
409 static const wchar_t *kExt = L"7z"; |
|
410 static const wchar_t *kAfterPart = L".7z"; |
|
411 |
|
412 #ifdef _7Z_VOL |
|
413 |
|
414 class CVolumeName |
|
415 { |
|
416 bool _first; |
|
417 UString _unchangedPart; |
|
418 UString _changedPart; |
|
419 UString _afterPart; |
|
420 public: |
|
421 bool InitName(const UString &name) |
|
422 { |
|
423 _first = true; |
|
424 int dotPos = name.ReverseFind('.'); |
|
425 UString basePart = name; |
|
426 if (dotPos >= 0) |
|
427 { |
|
428 UString ext = name.Mid(dotPos + 1); |
|
429 if (ext.CompareNoCase(kExt)==0 || |
|
430 ext.CompareNoCase(L"EXE") == 0) |
|
431 { |
|
432 _afterPart = kAfterPart; |
|
433 basePart = name.Left(dotPos); |
|
434 } |
|
435 } |
|
436 |
|
437 int numLetters = 1; |
|
438 bool splitStyle = false; |
|
439 if (basePart.Right(numLetters) == L"1") |
|
440 { |
|
441 while (numLetters < basePart.Length()) |
|
442 { |
|
443 if (basePart[basePart.Length() - numLetters - 1] != '0') |
|
444 break; |
|
445 numLetters++; |
|
446 } |
|
447 } |
|
448 else |
|
449 return false; |
|
450 _unchangedPart = basePart.Left(basePart.Length() - numLetters); |
|
451 _changedPart = basePart.Right(numLetters); |
|
452 return true; |
|
453 } |
|
454 |
|
455 UString GetNextName() |
|
456 { |
|
457 UString newName; |
|
458 // if (_newStyle || !_first) |
|
459 { |
|
460 int i; |
|
461 int numLetters = _changedPart.Length(); |
|
462 for (i = numLetters - 1; i >= 0; i--) |
|
463 { |
|
464 wchar_t c = _changedPart[i]; |
|
465 if (c == L'9') |
|
466 { |
|
467 c = L'0'; |
|
468 newName = c + newName; |
|
469 if (i == 0) |
|
470 newName = UString(L'1') + newName; |
|
471 continue; |
|
472 } |
|
473 c++; |
|
474 newName = UString(c) + newName; |
|
475 i--; |
|
476 for (; i >= 0; i--) |
|
477 newName = _changedPart[i] + newName; |
|
478 break; |
|
479 } |
|
480 _changedPart = newName; |
|
481 } |
|
482 _first = false; |
|
483 return _unchangedPart + _changedPart + _afterPart; |
|
484 } |
|
485 }; |
|
486 |
|
487 #endif |
|
488 |
|
489 STDMETHODIMP CHandler::Open(IInStream *stream, |
|
490 const UInt64 *maxCheckStartPosition, |
|
491 IArchiveOpenCallback *openArchiveCallback) |
|
492 { |
|
493 COM_TRY_BEGIN |
|
494 Close(); |
|
495 #ifndef _SFX |
|
496 _fileInfoPopIDs.Clear(); |
|
497 #endif |
|
498 try |
|
499 { |
|
500 CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback; |
|
501 #ifdef _7Z_VOL |
|
502 CVolumeName seqName; |
|
503 |
|
504 CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; |
|
505 #endif |
|
506 |
|
507 #ifndef _NO_CRYPTO |
|
508 CMyComPtr<ICryptoGetTextPassword> getTextPassword; |
|
509 if (openArchiveCallback) |
|
510 { |
|
511 openArchiveCallbackTemp.QueryInterface( |
|
512 IID_ICryptoGetTextPassword, &getTextPassword); |
|
513 } |
|
514 #endif |
|
515 #ifdef _7Z_VOL |
|
516 if (openArchiveCallback) |
|
517 { |
|
518 openArchiveCallbackTemp.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback); |
|
519 } |
|
520 while(true) |
|
521 { |
|
522 CMyComPtr<IInStream> inStream; |
|
523 if (!_volumes.IsEmpty()) |
|
524 { |
|
525 if (!openVolumeCallback) |
|
526 break; |
|
527 if(_volumes.Size() == 1) |
|
528 { |
|
529 UString baseName; |
|
530 { |
|
531 NCOM::CPropVariant propVariant; |
|
532 RINOK(openVolumeCallback->GetProperty(kpidName, &propVariant)); |
|
533 if (propVariant.vt != VT_BSTR) |
|
534 break; |
|
535 baseName = propVariant.bstrVal; |
|
536 } |
|
537 seqName.InitName(baseName); |
|
538 } |
|
539 |
|
540 UString fullName = seqName.GetNextName(); |
|
541 HRESULT result = openVolumeCallback->GetStream(fullName, &inStream); |
|
542 if (result == S_FALSE) |
|
543 break; |
|
544 if (result != S_OK) |
|
545 return result; |
|
546 if (!stream) |
|
547 break; |
|
548 } |
|
549 else |
|
550 inStream = stream; |
|
551 |
|
552 CInArchive archive; |
|
553 RINOK(archive.Open(inStream, maxCheckStartPosition)); |
|
554 |
|
555 _volumes.Add(CVolume()); |
|
556 CVolume &volume = _volumes.Back(); |
|
557 CArchiveDatabaseEx &database = volume.Database; |
|
558 volume.Stream = inStream; |
|
559 volume.StartRef2Index = _refs.Size(); |
|
560 |
|
561 HRESULT result = archive.ReadDatabase(database |
|
562 #ifndef _NO_CRYPTO |
|
563 , getTextPassword |
|
564 #endif |
|
565 ); |
|
566 if (result != S_OK) |
|
567 { |
|
568 _volumes.Clear(); |
|
569 return result; |
|
570 } |
|
571 database.Fill(); |
|
572 for(int i = 0; i < database.Files.Size(); i++) |
|
573 { |
|
574 CRef refNew; |
|
575 refNew.VolumeIndex = _volumes.Size() - 1; |
|
576 refNew.ItemIndex = i; |
|
577 _refs.Add(refNew); |
|
578 /* |
|
579 const CFileItem &file = database.Files[i]; |
|
580 int j; |
|
581 */ |
|
582 /* |
|
583 for (j = _refs.Size() - 1; j >= 0; j--) |
|
584 { |
|
585 CRef2 &ref2 = _refs[j]; |
|
586 const CRef &ref = ref2.Refs.Back(); |
|
587 const CVolume &volume2 = _volumes[ref.VolumeIndex]; |
|
588 const CArchiveDatabaseEx &database2 = volume2.Database; |
|
589 const CFileItem &file2 = database2.Files[ref.ItemIndex]; |
|
590 if (file2.Name.CompareNoCase(file.Name) == 0) |
|
591 { |
|
592 if (!file.IsStartPosDefined) |
|
593 continue; |
|
594 if (file.StartPos != ref2.StartPos + ref2.UnPackSize) |
|
595 continue; |
|
596 ref2.Refs.Add(refNew); |
|
597 break; |
|
598 } |
|
599 } |
|
600 */ |
|
601 /* |
|
602 j = -1; |
|
603 if (j < 0) |
|
604 { |
|
605 CRef2 ref2New; |
|
606 ref2New.Refs.Add(refNew); |
|
607 j = _refs.Add(ref2New); |
|
608 } |
|
609 CRef2 &ref2 = _refs[j]; |
|
610 ref2.UnPackSize += file.UnPackSize; |
|
611 ref2.PackSize += database.GetFilePackSize(i); |
|
612 if (ref2.Refs.Size() == 1 && file.IsStartPosDefined) |
|
613 ref2.StartPos = file.StartPos; |
|
614 */ |
|
615 } |
|
616 if (database.Files.Size() != 1) |
|
617 break; |
|
618 const CFileItem &file = database.Files.Front(); |
|
619 if (!file.IsStartPosDefined) |
|
620 break; |
|
621 } |
|
622 #else |
|
623 CInArchive archive; |
|
624 RINOK(archive.Open(stream, maxCheckStartPosition)); |
|
625 HRESULT result = archive.ReadDatabase(_database |
|
626 #ifndef _NO_CRYPTO |
|
627 , getTextPassword |
|
628 #endif |
|
629 ); |
|
630 RINOK(result); |
|
631 _database.Fill(); |
|
632 _inStream = stream; |
|
633 #endif |
|
634 } |
|
635 catch(...) |
|
636 { |
|
637 Close(); |
|
638 return S_FALSE; |
|
639 } |
|
640 // _inStream = stream; |
|
641 #ifndef _SFX |
|
642 FillPopIDs(); |
|
643 #endif |
|
644 return S_OK; |
|
645 COM_TRY_END |
|
646 } |
|
647 |
|
648 STDMETHODIMP CHandler::Close() |
|
649 { |
|
650 COM_TRY_BEGIN |
|
651 #ifdef _7Z_VOL |
|
652 _volumes.Clear(); |
|
653 _refs.Clear(); |
|
654 #else |
|
655 _inStream.Release(); |
|
656 _database.Clear(); |
|
657 #endif |
|
658 return S_OK; |
|
659 COM_TRY_END |
|
660 } |
|
661 |
|
662 #ifdef _7Z_VOL |
|
663 STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) |
|
664 { |
|
665 if (index != 0) |
|
666 return E_INVALIDARG; |
|
667 *stream = 0; |
|
668 CMultiStream *streamSpec = new CMultiStream; |
|
669 CMyComPtr<ISequentialInStream> streamTemp = streamSpec; |
|
670 |
|
671 UInt64 pos = 0; |
|
672 const UString *fileName; |
|
673 for (int i = 0; i < _refs.Size(); i++) |
|
674 { |
|
675 const CRef &ref = _refs[i]; |
|
676 const CVolume &volume = _volumes[ref.VolumeIndex]; |
|
677 const CArchiveDatabaseEx &database = volume.Database; |
|
678 const CFileItem &file = database.Files[ref.ItemIndex]; |
|
679 if (i == 0) |
|
680 fileName = &file.Name; |
|
681 else |
|
682 if (fileName->Compare(file.Name) != 0) |
|
683 return S_FALSE; |
|
684 if (!file.IsStartPosDefined) |
|
685 return S_FALSE; |
|
686 if (file.StartPos != pos) |
|
687 return S_FALSE; |
|
688 CNum folderIndex = database.FileIndexToFolderIndexMap[ref.ItemIndex]; |
|
689 if (folderIndex == kNumNoIndex) |
|
690 { |
|
691 if (file.UnPackSize != 0) |
|
692 return E_FAIL; |
|
693 continue; |
|
694 } |
|
695 if (database.NumUnPackStreamsVector[folderIndex] != 1) |
|
696 return S_FALSE; |
|
697 const CFolder &folder = database.Folders[folderIndex]; |
|
698 if (folder.Coders.Size() != 1) |
|
699 return S_FALSE; |
|
700 const CCoderInfo &coder = folder.Coders.Front(); |
|
701 if (coder.NumInStreams != 1 || coder.NumOutStreams != 1) |
|
702 return S_FALSE; |
|
703 const CAltCoderInfo &altCoder = coder.AltCoders.Front(); |
|
704 if (altCoder.MethodID.IDSize != 1 || altCoder.MethodID.ID[0] != 0) |
|
705 return S_FALSE; |
|
706 |
|
707 pos += file.UnPackSize; |
|
708 CMultiStream::CSubStreamInfo subStreamInfo; |
|
709 subStreamInfo.Stream = volume.Stream; |
|
710 subStreamInfo.Pos = database.GetFolderStreamPos(folderIndex, 0); |
|
711 subStreamInfo.Size = file.UnPackSize; |
|
712 streamSpec->Streams.Add(subStreamInfo); |
|
713 } |
|
714 streamSpec->Init(); |
|
715 *stream = streamTemp.Detach(); |
|
716 return S_OK; |
|
717 } |
|
718 #endif |
|
719 |
|
720 |
|
721 #ifdef __7Z_SET_PROPERTIES |
|
722 #ifdef EXTRACT_ONLY |
|
723 |
|
724 STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) |
|
725 { |
|
726 COM_TRY_BEGIN |
|
727 const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); |
|
728 _numThreads = numProcessors; |
|
729 |
|
730 for (int i = 0; i < numProperties; i++) |
|
731 { |
|
732 UString name = names[i]; |
|
733 name.MakeUpper(); |
|
734 if (name.IsEmpty()) |
|
735 return E_INVALIDARG; |
|
736 const PROPVARIANT &value = values[i]; |
|
737 UInt32 number; |
|
738 int index = ParseStringToUInt32(name, number); |
|
739 if (index == 0) |
|
740 { |
|
741 if(name.Left(2).CompareNoCase(L"MT") == 0) |
|
742 { |
|
743 RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads)); |
|
744 continue; |
|
745 } |
|
746 else |
|
747 return E_INVALIDARG; |
|
748 } |
|
749 } |
|
750 return S_OK; |
|
751 COM_TRY_END |
|
752 } |
|
753 |
|
754 #endif |
|
755 #endif |
|
756 |
|
757 }} |