rlm@1
|
1 // TarHandler.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 #include "Common/ComTry.h"
|
rlm@1
|
6 #include "Common/Defs.h"
|
rlm@1
|
7 #include "Common/NewHandler.h"
|
rlm@1
|
8 #include "Common/StringConvert.h"
|
rlm@1
|
9
|
rlm@1
|
10 #include "Windows/PropVariant.h"
|
rlm@1
|
11 #include "Windows/Time.h"
|
rlm@1
|
12
|
rlm@1
|
13 #include "../../Common/LimitedStreams.h"
|
rlm@1
|
14 #include "../../Common/ProgressUtils.h"
|
rlm@1
|
15
|
rlm@1
|
16 #include "../../Compress/CopyCoder.h"
|
rlm@1
|
17
|
rlm@1
|
18 #include "../Common/DummyOutStream.h"
|
rlm@1
|
19 #include "../Common/ItemNameUtils.h"
|
rlm@1
|
20
|
rlm@1
|
21 #include "TarHandler.h"
|
rlm@1
|
22 #include "TarIn.h"
|
rlm@1
|
23
|
rlm@1
|
24 using namespace NWindows;
|
rlm@1
|
25
|
rlm@1
|
26 namespace NArchive {
|
rlm@1
|
27 namespace NTar {
|
rlm@1
|
28
|
rlm@1
|
29 STATPROPSTG kProps[] =
|
rlm@1
|
30 {
|
rlm@1
|
31 { NULL, kpidPath, VT_BSTR},
|
rlm@1
|
32 { NULL, kpidIsDir, VT_BOOL},
|
rlm@1
|
33 { NULL, kpidSize, VT_UI8},
|
rlm@1
|
34 { NULL, kpidPackSize, VT_UI8},
|
rlm@1
|
35 { NULL, kpidMTime, VT_FILETIME},
|
rlm@1
|
36 { NULL, kpidUser, VT_BSTR},
|
rlm@1
|
37 { NULL, kpidGroup, VT_BSTR}
|
rlm@1
|
38 };
|
rlm@1
|
39
|
rlm@1
|
40 IMP_IInArchive_Props
|
rlm@1
|
41 IMP_IInArchive_ArcProps_NO
|
rlm@1
|
42
|
rlm@1
|
43 HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
rlm@1
|
44 {
|
rlm@1
|
45 UInt64 endPos = 0;
|
rlm@1
|
46 if (callback != NULL)
|
rlm@1
|
47 {
|
rlm@1
|
48 RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
|
rlm@1
|
49 RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
|
rlm@1
|
50 }
|
rlm@1
|
51
|
rlm@1
|
52 UInt64 pos = 0;
|
rlm@1
|
53 for (;;)
|
rlm@1
|
54 {
|
rlm@1
|
55 CItemEx item;
|
rlm@1
|
56 bool filled;
|
rlm@1
|
57 item.HeaderPosition = pos;
|
rlm@1
|
58 RINOK(ReadItem(stream, filled, item));
|
rlm@1
|
59 if (!filled)
|
rlm@1
|
60 break;
|
rlm@1
|
61 _items.Add(item);
|
rlm@1
|
62
|
rlm@1
|
63 RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &pos));
|
rlm@1
|
64 if (pos >= endPos)
|
rlm@1
|
65 return S_FALSE;
|
rlm@1
|
66 if (callback != NULL)
|
rlm@1
|
67 {
|
rlm@1
|
68 if (_items.Size() == 1)
|
rlm@1
|
69 {
|
rlm@1
|
70 RINOK(callback->SetTotal(NULL, &endPos));
|
rlm@1
|
71 }
|
rlm@1
|
72 if (_items.Size() % 100 == 0)
|
rlm@1
|
73 {
|
rlm@1
|
74 UInt64 numFiles = _items.Size();
|
rlm@1
|
75 RINOK(callback->SetCompleted(&numFiles, &pos));
|
rlm@1
|
76 }
|
rlm@1
|
77 }
|
rlm@1
|
78 }
|
rlm@1
|
79
|
rlm@1
|
80 if (_items.Size() == 0)
|
rlm@1
|
81 {
|
rlm@1
|
82 CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
|
rlm@1
|
83 if (!callback)
|
rlm@1
|
84 return S_FALSE;
|
rlm@1
|
85 callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
|
rlm@1
|
86 if (!openVolumeCallback)
|
rlm@1
|
87 return S_FALSE;
|
rlm@1
|
88 NCOM::CPropVariant prop;
|
rlm@1
|
89 if (openVolumeCallback->GetProperty(kpidName, &prop) != S_OK)
|
rlm@1
|
90 return S_FALSE;
|
rlm@1
|
91 if (prop.vt != VT_BSTR)
|
rlm@1
|
92 return S_FALSE;
|
rlm@1
|
93 UString baseName = prop.bstrVal;
|
rlm@1
|
94 baseName = baseName.Right(4);
|
rlm@1
|
95 if (baseName.CompareNoCase(L".tar") != 0)
|
rlm@1
|
96 return S_FALSE;
|
rlm@1
|
97 }
|
rlm@1
|
98 return S_OK;
|
rlm@1
|
99 }
|
rlm@1
|
100
|
rlm@1
|
101 STDMETHODIMP CHandler::Open(IInStream *stream,
|
rlm@1
|
102 const UInt64 * /* maxCheckStartPosition */,
|
rlm@1
|
103 IArchiveOpenCallback *openArchiveCallback)
|
rlm@1
|
104 {
|
rlm@1
|
105 COM_TRY_BEGIN
|
rlm@1
|
106 {
|
rlm@1
|
107 Close();
|
rlm@1
|
108 RINOK(Open2(stream, openArchiveCallback));
|
rlm@1
|
109 _inStream = stream;
|
rlm@1
|
110 }
|
rlm@1
|
111 return S_OK;
|
rlm@1
|
112 COM_TRY_END
|
rlm@1
|
113 }
|
rlm@1
|
114
|
rlm@1
|
115 STDMETHODIMP CHandler::Close()
|
rlm@1
|
116 {
|
rlm@1
|
117 _items.Clear();
|
rlm@1
|
118 _inStream.Release();
|
rlm@1
|
119 return S_OK;
|
rlm@1
|
120 }
|
rlm@1
|
121
|
rlm@1
|
122 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
rlm@1
|
123 {
|
rlm@1
|
124 *numItems = _items.Size();
|
rlm@1
|
125 return S_OK;
|
rlm@1
|
126 }
|
rlm@1
|
127
|
rlm@1
|
128 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
rlm@1
|
129 {
|
rlm@1
|
130 COM_TRY_BEGIN
|
rlm@1
|
131 NWindows::NCOM::CPropVariant prop;
|
rlm@1
|
132 const CItemEx &item = _items[index];
|
rlm@1
|
133
|
rlm@1
|
134 switch(propID)
|
rlm@1
|
135 {
|
rlm@1
|
136 case kpidPath: prop = NItemName::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
|
rlm@1
|
137 case kpidIsDir: prop = item.IsDir(); break;
|
rlm@1
|
138 case kpidSize: prop = item.Size; break;
|
rlm@1
|
139 case kpidPackSize: prop = item.GetPackSize(); break;
|
rlm@1
|
140 case kpidMTime:
|
rlm@1
|
141 if (item.MTime != 0)
|
rlm@1
|
142 {
|
rlm@1
|
143 FILETIME ft;
|
rlm@1
|
144 NTime::UnixTimeToFileTime(item.MTime, ft);
|
rlm@1
|
145 prop = ft;
|
rlm@1
|
146 }
|
rlm@1
|
147 break;
|
rlm@1
|
148 case kpidUser: prop = MultiByteToUnicodeString(item.UserName, CP_OEMCP); break;
|
rlm@1
|
149 case kpidGroup: prop = MultiByteToUnicodeString(item.GroupName, CP_OEMCP); break;
|
rlm@1
|
150 }
|
rlm@1
|
151 prop.Detach(value);
|
rlm@1
|
152 return S_OK;
|
rlm@1
|
153 COM_TRY_END
|
rlm@1
|
154 }
|
rlm@1
|
155
|
rlm@1
|
156 STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
rlm@1
|
157 Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
|
rlm@1
|
158 {
|
rlm@1
|
159 COM_TRY_BEGIN
|
rlm@1
|
160 bool testMode = (_aTestMode != 0);
|
rlm@1
|
161 bool allFilesMode = (numItems == UInt32(-1));
|
rlm@1
|
162 if (allFilesMode)
|
rlm@1
|
163 numItems = _items.Size();
|
rlm@1
|
164 if (numItems == 0)
|
rlm@1
|
165 return S_OK;
|
rlm@1
|
166 UInt64 totalSize = 0;
|
rlm@1
|
167 UInt32 i;
|
rlm@1
|
168 for (i = 0; i < numItems; i++)
|
rlm@1
|
169 totalSize += _items[allFilesMode ? i : indices[i]].Size;
|
rlm@1
|
170 extractCallback->SetTotal(totalSize);
|
rlm@1
|
171
|
rlm@1
|
172 UInt64 totalPackSize, curPackSize, curSize;
|
rlm@1
|
173 totalSize = totalPackSize = 0;
|
rlm@1
|
174
|
rlm@1
|
175 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
rlm@1
|
176 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
rlm@1
|
177
|
rlm@1
|
178 CLocalProgress *lps = new CLocalProgress;
|
rlm@1
|
179 CMyComPtr<ICompressProgressInfo> progress = lps;
|
rlm@1
|
180 lps->Init(extractCallback, false);
|
rlm@1
|
181
|
rlm@1
|
182 CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
rlm@1
|
183 CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
rlm@1
|
184 streamSpec->SetStream(_inStream);
|
rlm@1
|
185
|
rlm@1
|
186 CDummyOutStream *outStreamSpec = new CDummyOutStream;
|
rlm@1
|
187 CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
rlm@1
|
188
|
rlm@1
|
189 for (i = 0; i < numItems; i++, totalSize += curSize, totalPackSize += curPackSize)
|
rlm@1
|
190 {
|
rlm@1
|
191 lps->InSize = totalPackSize;
|
rlm@1
|
192 lps->OutSize = totalSize;
|
rlm@1
|
193 RINOK(lps->SetCur());
|
rlm@1
|
194 CMyComPtr<ISequentialOutStream> realOutStream;
|
rlm@1
|
195 Int32 askMode = testMode ?
|
rlm@1
|
196 NArchive::NExtract::NAskMode::kTest :
|
rlm@1
|
197 NArchive::NExtract::NAskMode::kExtract;
|
rlm@1
|
198 Int32 index = allFilesMode ? i : indices[i];
|
rlm@1
|
199 const CItemEx &item = _items[index];
|
rlm@1
|
200 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
rlm@1
|
201 curSize = item.Size;
|
rlm@1
|
202 curPackSize = item.GetPackSize();
|
rlm@1
|
203 if (item.IsDir())
|
rlm@1
|
204 {
|
rlm@1
|
205 RINOK(extractCallback->PrepareOperation(askMode));
|
rlm@1
|
206 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
rlm@1
|
207 continue;
|
rlm@1
|
208 }
|
rlm@1
|
209 if (!testMode && (!realOutStream))
|
rlm@1
|
210 continue;
|
rlm@1
|
211 RINOK(extractCallback->PrepareOperation(askMode));
|
rlm@1
|
212
|
rlm@1
|
213 outStreamSpec->SetStream(realOutStream);
|
rlm@1
|
214 realOutStream.Release();
|
rlm@1
|
215 outStreamSpec->Init();
|
rlm@1
|
216
|
rlm@1
|
217 RINOK(_inStream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
|
rlm@1
|
218 streamSpec->Init(item.Size);
|
rlm@1
|
219 RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
rlm@1
|
220 outStreamSpec->ReleaseStream();
|
rlm@1
|
221 RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == item.Size ?
|
rlm@1
|
222 NArchive::NExtract::NOperationResult::kOK:
|
rlm@1
|
223 NArchive::NExtract::NOperationResult::kDataError));
|
rlm@1
|
224 }
|
rlm@1
|
225 return S_OK;
|
rlm@1
|
226 COM_TRY_END
|
rlm@1
|
227 }
|
rlm@1
|
228
|
rlm@1
|
229 }}
|