annotate 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
rev   line source
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 }}