view src/win32/7zip/7z/CPP/7zip/Archive/Tar/TarHandler.cpp @ 1:f9f4f1b99eed

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