5 #include "Common/ComTry.h"
\r
7 #include "Windows/PropVariant.h"
\r
9 #include "../../Common/LimitedStreams.h"
\r
10 #include "../../Common/ProgressUtils.h"
\r
11 #include "../../Common/StreamUtils.h"
\r
13 #include "../../Compress/CopyCoder.h"
\r
15 #include "ComHandler.h"
\r
17 namespace NArchive {
\r
20 STATPROPSTG kProps[] =
\r
22 { NULL, kpidPath, VT_BSTR},
\r
23 { NULL, kpidIsDir, VT_BOOL},
\r
24 { NULL, kpidSize, VT_UI8},
\r
25 { NULL, kpidPackSize, VT_UI8},
\r
26 { NULL, kpidCTime, VT_FILETIME},
\r
27 { NULL, kpidMTime, VT_FILETIME}
\r
30 STATPROPSTG kArcProps[] =
\r
32 { NULL, kpidClusterSize, VT_UI4},
\r
33 { NULL, kpidSectorSize, VT_UI4}
\r
36 IMP_IInArchive_Props
\r
37 IMP_IInArchive_ArcProps
\r
39 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
\r
42 NWindows::NCOM::CPropVariant prop;
\r
45 case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break;
\r
46 case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break;
\r
47 case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break;
\r
54 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
\r
57 NWindows::NCOM::CPropVariant prop;
\r
58 const CRef &ref = _db.Refs[index];
\r
59 const CItem &item = _db.Items[ref.Did];
\r
63 case kpidPath: prop = _db.GetItemPath(index); break;
\r
64 case kpidIsDir: prop = item.IsDir(); break;
\r
65 case kpidCTime: prop = item.CTime; break;
\r
66 case kpidMTime: prop = item.MTime; break;
\r
67 case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break;
\r
68 case kpidSize: if (!item.IsDir()) prop = item.Size; break;
\r
75 STDMETHODIMP CHandler::Open(IInStream *inStream,
\r
76 const UInt64 * /* maxCheckStartPosition */,
\r
77 IArchiveOpenCallback * /* openArchiveCallback */)
\r
83 if (_db.Open(inStream) != S_OK)
\r
87 catch(...) { return S_FALSE; }
\r
92 STDMETHODIMP CHandler::Close()
\r
99 STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
\r
100 Int32 testMode, IArchiveExtractCallback *extractCallback)
\r
103 bool allFilesMode = (numItems == (UInt32)-1);
\r
105 numItems = _db.Refs.Size();
\r
109 UInt64 totalSize = 0;
\r
110 for(i = 0; i < numItems; i++)
\r
112 const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did];
\r
114 totalSize += item.Size;
\r
116 RINOK(extractCallback->SetTotal(totalSize));
\r
118 UInt64 totalPackSize;
\r
119 totalSize = totalPackSize = 0;
\r
121 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
\r
122 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
\r
124 CLocalProgress *lps = new CLocalProgress;
\r
125 CMyComPtr<ICompressProgressInfo> progress = lps;
\r
126 lps->Init(extractCallback, false);
\r
128 for (i = 0; i < numItems; i++)
\r
130 lps->InSize = totalPackSize;
\r
131 lps->OutSize = totalSize;
\r
132 RINOK(lps->SetCur());
\r
133 Int32 index = allFilesMode ? i : indices[i];
\r
134 const CItem &item = _db.Items[_db.Refs[index].Did];
\r
136 CMyComPtr<ISequentialOutStream> outStream;
\r
137 Int32 askMode = testMode ?
\r
138 NExtract::NAskMode::kTest :
\r
139 NExtract::NAskMode::kExtract;
\r
140 RINOK(extractCallback->GetStream(index, &outStream, askMode));
\r
144 RINOK(extractCallback->PrepareOperation(askMode));
\r
145 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
\r
149 totalPackSize += _db.GetItemPackSize(item.Size);
\r
150 totalSize += item.Size;
\r
152 if (!testMode && !outStream)
\r
154 RINOK(extractCallback->PrepareOperation(askMode));
\r
155 Int32 res = NExtract::NOperationResult::kDataError;
\r
156 CMyComPtr<ISequentialInStream> inStream;
\r
157 HRESULT hres = GetStream(index, &inStream);
\r
158 if (hres == S_FALSE)
\r
159 res = NExtract::NOperationResult::kDataError;
\r
160 else if (hres == E_NOTIMPL)
\r
161 res = NExtract::NOperationResult::kUnSupportedMethod;
\r
167 RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
\r
168 if (copyCoderSpec->TotalSize == item.Size)
\r
169 res = NExtract::NOperationResult::kOK;
\r
172 outStream.Release();
\r
173 RINOK(extractCallback->SetOperationResult(res));
\r
179 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
\r
181 *numItems = _db.Refs.Size();
\r
185 STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
\r
189 const CItem &item = _db.Items[_db.Refs[index].Did];
\r
190 CClusterInStream *streamSpec = new CClusterInStream;
\r
191 CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
\r
192 streamSpec->Stream = _stream;
\r
193 streamSpec->StartOffset = 0;
\r
195 bool isLargeStream = _db.IsLargeStream(item.Size);
\r
196 int bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits;
\r
197 streamSpec->BlockSizeLog = bsLog;
\r
198 streamSpec->Size = item.Size;
\r
200 UInt32 clusterSize = (UInt32)1 << bsLog;
\r
201 UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
\r
202 if (numClusters64 >= ((UInt32)1 << 31))
\r
204 streamSpec->Vector.Reserve((int)numClusters64);
\r
205 UInt32 sid = item.Sid;
\r
206 UInt64 size = item.Size;
\r
210 for (;; size -= clusterSize)
\r
214 if (sid >= _db.FatSize)
\r
216 streamSpec->Vector.Add(sid + 1);
\r
217 sid = _db.Fat[sid];
\r
222 if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32)
\r
224 streamSpec->Vector.Add((UInt32)val);
\r
225 sid = _db.Mat[sid];
\r
227 if (size <= clusterSize)
\r
231 if (sid != NFatID::kEndOfChain)
\r
233 RINOK(streamSpec->InitAndSeek());
\r
234 *stream = streamTemp.Detach();
\r