5 #include "../../../../C/Alloc.h"
\r
7 #include "Common/Buffer.h"
\r
8 #include "Common/ComTry.h"
\r
9 #include "Common/Defs.h"
\r
10 #include "Common/IntToString.h"
\r
11 #include "Common/StringConvert.h"
\r
12 #include "Common/UTFConvert.h"
\r
14 #include "Windows/PropVariant.h"
\r
15 #include "Windows/Time.h"
\r
17 #include "../../Common/ProgressUtils.h"
\r
18 #include "../../Common/StreamUtils.h"
\r
20 #include "../../Compress/CopyCoder.h"
\r
21 #include "../../Compress/DeflateDecoder.h"
\r
22 #include "../../Compress/LzxDecoder.h"
\r
23 #include "../../Compress/QuantumDecoder.h"
\r
25 #include "../Common/ItemNameUtils.h"
\r
27 #include "CabBlockInStream.h"
\r
28 #include "CabHandler.h"
\r
30 using namespace NWindows;
\r
32 namespace NArchive {
\r
35 // #define _CAB_DETAILS
\r
40 kpidBlockReal = kpidUserDefined
\r
44 static STATPROPSTG kProps[] =
\r
46 { NULL, kpidPath, VT_BSTR},
\r
47 { NULL, kpidSize, VT_UI8},
\r
48 { NULL, kpidMTime, VT_FILETIME},
\r
49 { NULL, kpidAttrib, VT_UI4},
\r
50 { NULL, kpidMethod, VT_BSTR},
\r
51 { NULL, kpidBlock, VT_I4}
\r
54 { L"BlockReal", kpidBlockReal, VT_UI4},
\r
55 { NULL, kpidOffset, VT_UI4},
\r
56 { NULL, kpidVolume, VT_UI4}
\r
60 static const char *kMethods[] =
\r
68 static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]);
\r
69 static const char *kUnknownMethod = "Unknown";
\r
71 static STATPROPSTG kArcProps[] =
\r
73 { NULL, kpidMethod, VT_BSTR},
\r
74 // { NULL, kpidSolid, VT_BOOL},
\r
75 { NULL, kpidNumBlocks, VT_UI4},
\r
76 { NULL, kpidNumVolumes, VT_UI4}
\r
79 IMP_IInArchive_Props
\r
80 IMP_IInArchive_ArcProps
\r
82 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
\r
85 NWindows::NCOM::CPropVariant prop;
\r
91 CRecordVector<Byte> ids;
\r
93 for (int v = 0; v < m_Database.Volumes.Size(); v++)
\r
95 const CDatabaseEx &de = m_Database.Volumes[v];
\r
96 for (i = 0; i < de.Folders.Size(); i++)
\r
97 ids.AddToUniqueSorted(de.Folders[i].GetCompressionMethod());
\r
99 for (i = 0; i < ids.Size(); i++)
\r
102 AString method = (id < kNumMethods) ? kMethods[id] : kUnknownMethod;
\r
103 if (!resString.IsEmpty())
\r
105 resString += method;
\r
110 // case kpidSolid: prop = _database.IsSolid(); break;
\r
111 case kpidNumBlocks:
\r
113 UInt32 numFolders = 0;
\r
114 for (int v = 0; v < m_Database.Volumes.Size(); v++)
\r
115 numFolders += m_Database.Volumes[v].Folders.Size();
\r
119 case kpidNumVolumes:
\r
121 prop = (UInt32)m_Database.Volumes.Size();
\r
125 prop.Detach(value);
\r
130 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
\r
133 NWindows::NCOM::CPropVariant prop;
\r
135 const CMvItem &mvItem = m_Database.Items[index];
\r
136 const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
\r
137 int itemIndex = mvItem.ItemIndex;
\r
138 const CItem &item = db.Items[itemIndex];
\r
143 UString unicodeName;
\r
144 if (item.IsNameUTF())
\r
145 ConvertUTF8ToUnicode(item.Name, unicodeName);
\r
147 unicodeName = MultiByteToUnicodeString(item.Name, CP_ACP);
\r
148 prop = (const wchar_t *)NItemName::WinNameToOSName(unicodeName);
\r
151 case kpidIsDir: prop = item.IsDir(); break;
\r
152 case kpidSize: prop = item.Size; break;
\r
153 case kpidAttrib: prop = item.GetWinAttributes(); break;
\r
157 FILETIME localFileTime, utcFileTime;
\r
158 if (NTime::DosTimeToFileTime(item.Time, localFileTime))
\r
160 if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
\r
161 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
\r
164 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
\r
165 prop = utcFileTime;
\r
171 UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size());
\r
172 const CFolder &folder = db.Folders[realFolderIndex];
\r
173 int methodIndex = folder.GetCompressionMethod();
\r
174 AString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod;
\r
175 if (methodIndex == NHeader::NCompressionMethodMajor::kLZX ||
\r
176 methodIndex == NHeader::NCompressionMethodMajor::kQuantum)
\r
180 ConvertUInt64ToString(folder.CompressionTypeMinor, temp);
\r
186 case kpidBlock: prop = (Int32)m_Database.GetFolderIndex(&mvItem); break;
\r
188 #ifdef _CAB_DETAILS
\r
190 case kpidBlockReal: prop = (UInt32)item.FolderIndex; break;
\r
191 case kpidOffset: prop = (UInt32)item.Offset; break;
\r
192 case kpidVolume: prop = (UInt32)mvItem.VolumeIndex; break;
\r
196 prop.Detach(value);
\r
202 class CProgressImp: public CProgressVirt
\r
204 CMyComPtr<IArchiveOpenCallback> m_OpenArchiveCallback;
\r
206 STDMETHOD(SetTotal)(const UInt64 *numFiles);
\r
207 STDMETHOD(SetCompleted)(const UInt64 *numFiles);
\r
208 void Init(IArchiveOpenCallback *openArchiveCallback)
\r
209 { m_OpenArchiveCallback = openArchiveCallback; }
\r
212 STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles)
\r
214 if (m_OpenArchiveCallback)
\r
215 return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
\r
219 STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles)
\r
221 if (m_OpenArchiveCallback)
\r
222 return m_OpenArchiveCallback->SetCompleted(numFiles, NULL);
\r
227 STDMETHODIMP CHandler::Open(IInStream *inStream,
\r
228 const UInt64 *maxCheckStartPosition,
\r
229 IArchiveOpenCallback *callback)
\r
233 HRESULT res = S_FALSE;
\r
234 CInArchive archive;
\r
235 CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
\r
236 callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
\r
238 CMyComPtr<IInStream> nextStream = inStream;
\r
239 bool prevChecked = false;
\r
240 UInt64 numItems = 0;
\r
243 while (nextStream != 0)
\r
246 db.Stream = nextStream;
\r
247 res = archive.Open(maxCheckStartPosition, db);
\r
250 if (!m_Database.Volumes.IsEmpty())
\r
252 const CDatabaseEx &dbPrev = m_Database.Volumes[prevChecked ? m_Database.Volumes.Size() - 1 : 0];
\r
253 if (dbPrev.ArchiveInfo.SetID != db.ArchiveInfo.SetID ||
\r
254 dbPrev.ArchiveInfo.CabinetNumber + (prevChecked ? 1: - 1) !=
\r
255 db.ArchiveInfo.CabinetNumber)
\r
260 m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : 0, db);
\r
261 else if (res != S_FALSE)
\r
265 if (m_Database.Volumes.IsEmpty())
\r
269 prevChecked = true;
\r
272 numItems += db.Items.Size();
\r
273 RINOK(callback->SetCompleted(&numItems, NULL));
\r
278 const COtherArchive *otherArchive = 0;
\r
281 const CInArchiveInfo &ai = m_Database.Volumes.Front().ArchiveInfo;
\r
282 if (ai.IsTherePrev())
\r
283 otherArchive = &ai.PrevArc;
\r
285 prevChecked = true;
\r
287 if (otherArchive == 0)
\r
289 const CInArchiveInfo &ai = m_Database.Volumes.Back().ArchiveInfo;
\r
290 if (ai.IsThereNext())
\r
291 otherArchive = &ai.NextArc;
\r
295 const UString fullName = MultiByteToUnicodeString(otherArchive->FileName, CP_ACP);
\r
296 if (!openVolumeCallback)
\r
299 HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream);
\r
300 if (result == S_OK)
\r
302 if (result != S_FALSE)
\r
306 prevChecked = true;
\r
311 m_Database.FillSortAndShrink();
\r
312 if (!m_Database.Check())
\r
329 STDMETHODIMP CHandler::Close()
\r
331 m_Database.Clear();
\r
335 class CFolderOutStream:
\r
336 public ISequentialOutStream,
\r
337 public CMyUnknownImp
\r
342 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
\r
344 const CMvDatabaseEx *m_Database;
\r
345 const CRecordVector<bool> *m_ExtractStatuses;
\r
348 UInt32 TempBufSize;
\r
349 int NumIdenticalFiles;
\r
351 UInt32 m_BufStartFolderOffset;
\r
354 int m_CurrentIndex;
\r
355 CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;
\r
358 CMyComPtr<ISequentialOutStream> m_RealOutStream;
\r
362 UInt32 m_RemainFileSize;
\r
363 UInt64 m_FolderSize;
\r
364 UInt64 m_PosInFolder;
\r
372 HRESULT OpenFile();
\r
373 HRESULT CloseFileWithResOp(Int32 resOp);
\r
374 HRESULT CloseFile();
\r
375 HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK);
\r
377 HRESULT WriteEmptyFiles();
\r
379 CFolderOutStream(): TempBuf(NULL) {}
\r
380 ~CFolderOutStream() { FreeTempBuf(); }
\r
382 const CMvDatabaseEx *database,
\r
383 const CRecordVector<bool> *extractStatuses,
\r
386 IArchiveExtractCallback *extractCallback,
\r
388 HRESULT FlushCorrupted();
\r
389 HRESULT Unsupported();
\r
391 UInt64 GetRemain() const { return m_FolderSize - m_PosInFolder; }
\r
392 UInt64 GetPosInFolder() const { return m_PosInFolder; }
\r
395 void CFolderOutStream::Init(
\r
396 const CMvDatabaseEx *database,
\r
397 const CRecordVector<bool> *extractStatuses,
\r
400 IArchiveExtractCallback *extractCallback,
\r
403 m_Database = database;
\r
404 m_ExtractStatuses = extractStatuses;
\r
405 m_StartIndex = startIndex;
\r
406 m_FolderSize = folderSize;
\r
408 m_ExtractCallback = extractCallback;
\r
409 m_TestMode = testMode;
\r
411 m_CurrentIndex = 0;
\r
413 m_FileIsOpen = false;
\r
415 TempBufMode = false;
\r
416 NumIdenticalFiles = 0;
\r
419 HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp)
\r
421 m_RealOutStream.Release();
\r
422 m_FileIsOpen = false;
\r
423 NumIdenticalFiles--;
\r
424 return m_ExtractCallback->SetOperationResult(resOp);
\r
427 HRESULT CFolderOutStream::CloseFile()
\r
429 return CloseFileWithResOp(m_IsOk ?
\r
430 NExtract::NOperationResult::kOK:
\r
431 NExtract::NOperationResult::kDataError);
\r
434 HRESULT CFolderOutStream::OpenFile()
\r
436 if (NumIdenticalFiles == 0)
\r
438 const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
\r
439 const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
\r
440 int numExtractItems = 0;
\r
442 for (curIndex = m_CurrentIndex; curIndex < m_ExtractStatuses->Size(); curIndex++)
\r
444 const CMvItem &mvItem2 = m_Database->Items[m_StartIndex + curIndex];
\r
445 const CItem &item2 = m_Database->Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex];
\r
446 if (item.Offset != item2.Offset ||
\r
447 item.Size != item2.Size ||
\r
450 if (!m_TestMode && (*m_ExtractStatuses)[curIndex])
\r
453 NumIdenticalFiles = (curIndex - m_CurrentIndex);
\r
454 if (NumIdenticalFiles == 0)
\r
455 NumIdenticalFiles = 1;
\r
456 TempBufMode = false;
\r
457 if (numExtractItems > 1)
\r
459 if (!TempBuf || item.Size > TempBufSize)
\r
462 TempBuf = (Byte *)MyAlloc(item.Size);
\r
463 TempBufSize = item.Size;
\r
464 if (TempBuf == NULL)
\r
465 return E_OUTOFMEMORY;
\r
467 TempBufMode = true;
\r
468 m_BufStartFolderOffset = item.Offset;
\r
470 else if (numExtractItems == 1)
\r
472 while (NumIdenticalFiles && !(*m_ExtractStatuses)[m_CurrentIndex])
\r
474 CMyComPtr<ISequentialOutStream> stream;
\r
475 RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &stream, NExtract::NAskMode::kSkip));
\r
478 RINOK(m_ExtractCallback->PrepareOperation(NExtract::NAskMode::kSkip));
\r
480 m_FileIsOpen = true;
\r
486 Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ?
\r
487 NExtract::NAskMode::kTest :
\r
488 NExtract::NAskMode::kExtract) :
\r
489 NExtract::NAskMode::kSkip;
\r
490 RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode));
\r
491 if (!m_RealOutStream && !m_TestMode)
\r
492 askMode = NExtract::NAskMode::kSkip;
\r
493 return m_ExtractCallback->PrepareOperation(askMode);
\r
496 HRESULT CFolderOutStream::WriteEmptyFiles()
\r
500 for (; m_CurrentIndex < m_ExtractStatuses->Size(); m_CurrentIndex++)
\r
502 const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
\r
503 const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
\r
504 UInt64 fileSize = item.Size;
\r
507 HRESULT result = OpenFile();
\r
508 m_RealOutStream.Release();
\r
510 RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
\r
515 // This is Write function
\r
516 HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK)
\r
519 UInt32 realProcessed = 0;
\r
520 if (processedSize != NULL)
\r
521 *processedSize = 0;
\r
526 UInt32 numBytesToWrite = MyMin(m_RemainFileSize, size);
\r
527 HRESULT res = S_OK;
\r
528 if (numBytesToWrite > 0)
\r
532 if (m_RealOutStream)
\r
534 UInt32 processedSizeLocal = 0;
\r
535 res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal);
\r
536 numBytesToWrite = processedSizeLocal;
\r
538 if (TempBufMode && TempBuf)
\r
539 memcpy(TempBuf + (m_PosInFolder - m_BufStartFolderOffset), data, numBytesToWrite);
\r
541 realProcessed += numBytesToWrite;
\r
542 if (processedSize != NULL)
\r
543 *processedSize = realProcessed;
\r
544 data = (const void *)((const Byte *)data + numBytesToWrite);
\r
545 size -= numBytesToWrite;
\r
546 m_RemainFileSize -= numBytesToWrite;
\r
547 m_PosInFolder += numBytesToWrite;
\r
550 if (m_RemainFileSize == 0)
\r
552 RINOK(CloseFile());
\r
554 while (NumIdenticalFiles)
\r
556 HRESULT result = OpenFile();
\r
557 m_FileIsOpen = true;
\r
559 if (result == S_OK && m_RealOutStream && TempBuf)
\r
560 result = WriteStream(m_RealOutStream, TempBuf, (size_t)(m_PosInFolder - m_BufStartFolderOffset));
\r
562 if (!TempBuf && TempBufMode && m_RealOutStream)
\r
564 RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnSupportedMethod));
\r
568 RINOK(CloseFile());
\r
572 TempBufMode = false;
\r
574 if (realProcessed > 0)
\r
575 break; // with this break this function works as Write-Part
\r
579 if (m_CurrentIndex >= m_ExtractStatuses->Size())
\r
582 const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex];
\r
583 const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
\r
585 m_RemainFileSize = item.Size;
\r
587 UInt32 fileOffset = item.Offset;
\r
588 if (fileOffset < m_PosInFolder)
\r
590 if (fileOffset > m_PosInFolder)
\r
592 UInt32 numBytesToWrite = MyMin(fileOffset - (UInt32)m_PosInFolder, size);
\r
593 realProcessed += numBytesToWrite;
\r
594 if (processedSize != NULL)
\r
595 *processedSize = realProcessed;
\r
596 data = (const void *)((const Byte *)data + numBytesToWrite);
\r
597 size -= numBytesToWrite;
\r
598 m_PosInFolder += numBytesToWrite;
\r
600 if (fileOffset == m_PosInFolder)
\r
603 m_FileIsOpen = true;
\r
609 return WriteEmptyFiles();
\r
613 STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
\r
615 return Write2(data, size, processedSize, true);
\r
618 HRESULT CFolderOutStream::FlushCorrupted()
\r
620 const UInt32 kBufferSize = (1 << 10);
\r
621 Byte buffer[kBufferSize];
\r
622 for (int i = 0; i < kBufferSize; i++)
\r
626 UInt64 remain = GetRemain();
\r
629 UInt32 size = (UInt32)MyMin(remain, (UInt64)kBufferSize);
\r
630 UInt32 processedSizeLocal = 0;
\r
631 RINOK(Write2(buffer, size, &processedSizeLocal, false));
\r
635 HRESULT CFolderOutStream::Unsupported()
\r
637 while(m_CurrentIndex < m_ExtractStatuses->Size())
\r
639 HRESULT result = OpenFile();
\r
640 if (result != S_FALSE && result != S_OK)
\r
642 m_RealOutStream.Release();
\r
643 RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
\r
650 STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
\r
651 Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
\r
654 bool allFilesMode = (numItems == (UInt32)-1);
\r
656 numItems = m_Database.Items.Size();
\r
659 bool testMode = (testModeSpec != 0);
\r
660 UInt64 totalUnPacked = 0;
\r
663 int lastFolder = -2;
\r
664 UInt64 lastFolderSize = 0;
\r
665 for(i = 0; i < numItems; i++)
\r
667 int index = allFilesMode ? i : indices[i];
\r
668 const CMvItem &mvItem = m_Database.Items[index];
\r
669 const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
\r
672 int folderIndex = m_Database.GetFolderIndex(&mvItem);
\r
673 if (folderIndex != lastFolder)
\r
674 totalUnPacked += lastFolderSize;
\r
675 lastFolder = folderIndex;
\r
676 lastFolderSize = item.GetEndOffset();
\r
678 totalUnPacked += lastFolderSize;
\r
680 extractCallback->SetTotal(totalUnPacked);
\r
684 UInt64 totalPacked = 0;
\r
686 CLocalProgress *lps = new CLocalProgress;
\r
687 CMyComPtr<ICompressProgressInfo> progress = lps;
\r
688 lps->Init(extractCallback, false);
\r
690 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
\r
691 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
\r
693 NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL;
\r
694 CMyComPtr<ICompressCoder> deflateDecoder;
\r
696 NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL;
\r
697 CMyComPtr<ICompressCoder> lzxDecoder;
\r
699 NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL;
\r
700 CMyComPtr<ICompressCoder> quantumDecoder;
\r
702 CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream();
\r
703 CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec;
\r
704 if (!cabBlockInStreamSpec->Create())
\r
705 return E_OUTOFMEMORY;
\r
707 CRecordVector<bool> extractStatuses;
\r
708 for(i = 0; i < numItems;)
\r
710 int index = allFilesMode ? i : indices[i];
\r
712 const CMvItem &mvItem = m_Database.Items[index];
\r
713 const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
\r
714 int itemIndex = mvItem.ItemIndex;
\r
715 const CItem &item = db.Items[itemIndex];
\r
720 Int32 askMode = testMode ?
\r
721 NExtract::NAskMode::kTest :
\r
722 NExtract::NAskMode::kExtract;
\r
723 CMyComPtr<ISequentialOutStream> realOutStream;
\r
724 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
\r
725 RINOK(extractCallback->PrepareOperation(askMode));
\r
726 realOutStream.Release();
\r
727 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
\r
730 int folderIndex = m_Database.GetFolderIndex(&mvItem);
\r
731 if (folderIndex < 0)
\r
733 // If we need previous archive
\r
734 Int32 askMode= testMode ?
\r
735 NExtract::NAskMode::kTest :
\r
736 NExtract::NAskMode::kExtract;
\r
737 CMyComPtr<ISequentialOutStream> realOutStream;
\r
738 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
\r
739 RINOK(extractCallback->PrepareOperation(askMode));
\r
740 realOutStream.Release();
\r
741 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError));
\r
744 int startIndex2 = m_Database.FolderStartFileIndex[folderIndex];
\r
745 int startIndex = startIndex2;
\r
746 extractStatuses.Clear();
\r
747 for (; startIndex < index; startIndex++)
\r
748 extractStatuses.Add(false);
\r
749 extractStatuses.Add(true);
\r
751 UInt64 curUnpack = item.GetEndOffset();
\r
752 for(;i < numItems; i++)
\r
754 int indexNext = allFilesMode ? i : indices[i];
\r
755 const CMvItem &mvItem = m_Database.Items[indexNext];
\r
756 const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex];
\r
759 int newFolderIndex = m_Database.GetFolderIndex(&mvItem);
\r
761 if (newFolderIndex != folderIndex)
\r
763 for (; startIndex < indexNext; startIndex++)
\r
764 extractStatuses.Add(false);
\r
765 extractStatuses.Add(true);
\r
767 curUnpack = item.GetEndOffset();
\r
770 lps->OutSize = totalUnPacked;
\r
771 lps->InSize = totalPacked;
\r
772 RINOK(lps->SetCur());
\r
774 CFolderOutStream *cabFolderOutStream = new CFolderOutStream;
\r
775 CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream);
\r
777 const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())];
\r
779 cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2,
\r
780 curUnpack, extractCallback, testMode);
\r
782 cabBlockInStreamSpec->MsZip = false;
\r
783 switch(folder.GetCompressionMethod())
\r
785 case NHeader::NCompressionMethodMajor::kNone:
\r
787 case NHeader::NCompressionMethodMajor::kMSZip:
\r
788 if(deflateDecoderSpec == NULL)
\r
790 deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
\r
791 deflateDecoder = deflateDecoderSpec;
\r
793 cabBlockInStreamSpec->MsZip = true;
\r
795 case NHeader::NCompressionMethodMajor::kLZX:
\r
796 if(lzxDecoderSpec == NULL)
\r
798 lzxDecoderSpec = new NCompress::NLzx::CDecoder;
\r
799 lzxDecoder = lzxDecoderSpec;
\r
801 RINOK(lzxDecoderSpec->SetParams(folder.CompressionTypeMinor));
\r
803 case NHeader::NCompressionMethodMajor::kQuantum:
\r
804 if(quantumDecoderSpec == NULL)
\r
806 quantumDecoderSpec = new NCompress::NQuantum::CDecoder;
\r
807 quantumDecoder = quantumDecoderSpec;
\r
809 quantumDecoderSpec->SetParams(folder.CompressionTypeMinor);
\r
813 RINOK(cabFolderOutStream->Unsupported());
\r
814 totalUnPacked += curUnpack;
\r
819 cabBlockInStreamSpec->InitForNewFolder();
\r
821 HRESULT res = S_OK;
\r
824 int volIndex = mvItem.VolumeIndex;
\r
825 int locFolderIndex = item.GetFolderIndex(db.Folders.Size());
\r
826 bool keepHistory = false;
\r
827 bool keepInputBuffer = false;
\r
828 for (UInt32 f = 0; cabFolderOutStream->GetRemain() != 0;)
\r
830 if (volIndex >= m_Database.Volumes.Size())
\r
836 const CDatabaseEx &db = m_Database.Volumes[volIndex];
\r
837 const CFolder &folder = db.Folders[locFolderIndex];
\r
840 cabBlockInStreamSpec->SetStream(db.Stream);
\r
841 cabBlockInStreamSpec->ReservedSize = db.ArchiveInfo.GetDataBlockReserveSize();
\r
842 RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL));
\r
844 if (f == folder.NumDataBlocks)
\r
847 locFolderIndex = 0;
\r
853 cabBlockInStreamSpec->DataError = false;
\r
855 if (!keepInputBuffer)
\r
856 cabBlockInStreamSpec->InitForNewBlock();
\r
858 UInt32 packSize, unpackSize;
\r
859 res = cabBlockInStreamSpec->PreRead(packSize, unpackSize);
\r
860 if (res == S_FALSE)
\r
863 keepInputBuffer = (unpackSize == 0);
\r
864 if (keepInputBuffer)
\r
867 UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder();
\r
868 totalPacked += packSize;
\r
870 lps->OutSize = totalUnPacked2;
\r
871 lps->InSize = totalPacked;
\r
872 RINOK(lps->SetCur());
\r
874 UInt64 unpackRemain = cabFolderOutStream->GetRemain();
\r
876 const UInt32 kBlockSizeMax = (1 << 15);
\r
877 if (unpackRemain > kBlockSizeMax)
\r
878 unpackRemain = kBlockSizeMax;
\r
879 if (unpackRemain > unpackSize)
\r
880 unpackRemain = unpackSize;
\r
882 switch(folder.GetCompressionMethod())
\r
884 case NHeader::NCompressionMethodMajor::kNone:
\r
885 res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
\r
887 case NHeader::NCompressionMethodMajor::kMSZip:
\r
888 deflateDecoderSpec->SetKeepHistory(keepHistory);
\r
889 res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
\r
891 case NHeader::NCompressionMethodMajor::kLZX:
\r
892 lzxDecoderSpec->SetKeepHistory(keepHistory);
\r
893 res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
\r
895 case NHeader::NCompressionMethodMajor::kQuantum:
\r
896 quantumDecoderSpec->SetKeepHistory(keepHistory);
\r
897 res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL);
\r
902 if (res != S_FALSE)
\r
906 keepHistory = true;
\r
910 RINOK(cabFolderOutStream->WriteEmptyFiles());
\r
913 if (res != S_OK || cabFolderOutStream->GetRemain() != 0)
\r
915 RINOK(cabFolderOutStream->FlushCorrupted());
\r
917 totalUnPacked += curUnpack;
\r
923 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
\r
925 *numItems = m_Database.Items.Size();
\r