Mercurial > vba-linux
view src/win32/7zip/7z/CPP/7zip/Archive/Lzh/LzhHandler.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 // LzhHandler.cpp3 #include "StdAfx.h"5 #include "Common/ComTry.h"6 #include "Common/Defs.h"7 #include "Common/StringConvert.h"9 #include "Windows/PropVariant.h"10 #include "Windows/Time.h"12 #include "LzhHandler.h"13 #include "LzhOutStreamWithCRC.h"15 #include "../../ICoder.h"17 #include "../../Common/LimitedStreams.h"18 #include "../../Common/ProgressUtils.h"20 #include "../../Compress/CopyCoder.h"21 #include "../../Compress/LzhDecoder.h"23 #include "../Common/ItemNameUtils.h"25 using namespace NWindows;26 using namespace NTime;28 namespace NArchive {29 namespace NLzh{31 struct COsPair32 {33 Byte Id;34 const wchar_t *Name;35 };37 COsPair g_OsPairs[] =38 {39 { 'M', L"MS-DOS" },40 { '2', L"OS/2" },41 { '9', L"OS9" },42 { 'K', L"OS/68K" },43 { '3', L"OS/386" },44 { 'H', L"HUMAN" },45 { 'U', L"UNIX" },46 { 'C', L"CP/M" },47 { 'F', L"FLEX" },48 { 'm', L"Mac" },49 { 'R', L"Runser" },50 { 'T', L"TownsOS" },51 { 'X', L"XOSK" },52 { 'w', L"Windows95" },53 { 'W', L"WindowsNT" },54 { 0, L"MS-DOS" },55 { 'J', L"Java VM" }56 };58 const wchar_t *kUnknownOS = L"Unknown";60 const int kNumHostOSes = sizeof(g_OsPairs) / sizeof(g_OsPairs[0]);62 static const wchar_t *GetOS(Byte osId)63 {64 for (int i = 0; i < kNumHostOSes; i++)65 if (g_OsPairs[i].Id == osId)66 return g_OsPairs[i].Name;67 return kUnknownOS;68 };70 STATPROPSTG kProps[] =71 {72 { NULL, kpidPath, VT_BSTR},73 { NULL, kpidIsDir, VT_BOOL},74 { NULL, kpidSize, VT_UI8},75 { NULL, kpidPackSize, VT_UI8},76 { NULL, kpidMTime, VT_FILETIME},77 { NULL, kpidAttrib, VT_UI4},79 // { NULL, kpidCommented, VT_BOOL},81 { NULL, kpidCRC, VT_UI4},83 { NULL, kpidMethod, VT_UI1},84 { NULL, kpidHostOS, VT_BSTR}86 };88 IMP_IInArchive_Props89 IMP_IInArchive_ArcProps_NO91 CHandler::CHandler() {}93 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)94 {95 *numItems = _items.Size();96 return S_OK;97 }99 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)100 {101 COM_TRY_BEGIN102 NWindows::NCOM::CPropVariant prop;103 const CItemEx &item = _items[index];104 switch(propID)105 {106 case kpidPath:107 {108 UString s = NItemName::WinNameToOSName(MultiByteToUnicodeString(item.GetName(), CP_OEMCP));109 if (!s.IsEmpty())110 {111 if (s[s.Length() - 1] == WCHAR_PATH_SEPARATOR)112 s.Delete(s.Length() - 1);113 prop = s;114 }115 break;116 }117 case kpidIsDir: prop = item.IsDir(); break;118 case kpidSize: prop = item.Size; break;119 case kpidPackSize: prop = item.PackSize; break;120 case kpidCRC: prop = (UInt32)item.CRC; break;121 case kpidHostOS: prop = GetOS(item.OsId); break;122 case kpidMTime:123 {124 FILETIME utcFileTime;125 UInt32 unixTime;126 if (item.GetUnixTime(unixTime))127 NTime::UnixTimeToFileTime(unixTime, utcFileTime);128 else129 {130 FILETIME localFileTime;131 if (DosTimeToFileTime(item.ModifiedTime, localFileTime))132 {133 if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))134 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;135 }136 else137 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;138 }139 prop = utcFileTime;140 break;141 }142 /*143 case kpidAttrib: prop = (UInt32)item.Attributes; break;144 case kpidCommented: prop = item.IsCommented(); break;145 */146 case kpidMethod:147 {148 wchar_t method2[kMethodIdSize + 1];149 method2[kMethodIdSize] = 0;150 for (int i = 0; i < kMethodIdSize; i++)151 method2[i] = item.Method[i];152 prop = method2;153 break;154 }155 }156 prop.Detach(value);157 return S_OK;158 COM_TRY_END159 }161 /*162 class CProgressImp: public CProgressVirt163 {164 public:165 CMyComPtr<IArchiveOpenCallback> Callback;166 STDMETHOD(SetCompleted)(const UInt64 *numFiles);167 };169 STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles)170 {171 if (Callback)172 return Callback->SetCompleted(numFiles, NULL);173 return S_OK;174 }175 */177 STDMETHODIMP CHandler::Open(IInStream *stream,178 const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)179 {180 COM_TRY_BEGIN181 try182 {183 _items.Clear();184 CInArchive archive;186 UInt64 endPos = 0;187 bool needSetTotal = true;189 if (callback != NULL)190 {191 RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));192 RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));193 }195 RINOK(archive.Open(stream));196 for (;;)197 {198 CItemEx item;199 bool filled;200 HRESULT result = archive.GetNextItem(filled, item);201 if (result == S_FALSE)202 return S_FALSE;203 if (result != S_OK)204 return S_FALSE;205 if (!filled)206 break;207 _items.Add(item);208 archive.Skeep(item.PackSize);209 if (callback != NULL)210 {211 if (needSetTotal)212 {213 RINOK(callback->SetTotal(NULL, &endPos));214 needSetTotal = false;215 }216 if (_items.Size() % 100 == 0)217 {218 UInt64 numFiles = _items.Size();219 UInt64 numBytes = item.DataPosition;220 RINOK(callback->SetCompleted(&numFiles, &numBytes));221 }222 }223 }224 if (_items.IsEmpty())225 return S_FALSE;227 _stream = stream;228 }229 catch(...)230 {231 return S_FALSE;232 }233 COM_TRY_END234 return S_OK;235 }237 STDMETHODIMP CHandler::Close()238 {239 _items.Clear();240 _stream.Release();241 return S_OK;242 }246 //////////////////////////////////////247 // CHandler::DecompressItems249 STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,250 Int32 testModeSpec, IArchiveExtractCallback *extractCallback)251 {252 COM_TRY_BEGIN253 bool testMode = (testModeSpec != 0);254 UInt64 totalUnPacked = 0, totalPacked = 0;255 bool allFilesMode = (numItems == UInt32(-1));256 if (allFilesMode)257 numItems = _items.Size();258 if(numItems == 0)259 return S_OK;260 UInt32 i;261 for(i = 0; i < numItems; i++)262 {263 const CItemEx &item = _items[allFilesMode ? i : indices[i]];264 totalUnPacked += item.Size;265 totalPacked += item.PackSize;266 }267 extractCallback->SetTotal(totalUnPacked);269 UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;270 UInt64 currentItemUnPacked, currentItemPacked;272 NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = 0;273 CMyComPtr<ICompressCoder> lzhDecoder;274 CMyComPtr<ICompressCoder> lzh1Decoder;275 CMyComPtr<ICompressCoder> arj2Decoder;277 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();278 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;280 CLocalProgress *lps = new CLocalProgress;281 CMyComPtr<ICompressProgressInfo> progress = lps;282 lps->Init(extractCallback, false);284 CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;285 CMyComPtr<ISequentialInStream> inStream(streamSpec);286 streamSpec->SetStream(_stream);288 for(i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,289 currentTotalPacked += currentItemPacked)290 {291 currentItemUnPacked = 0;292 currentItemPacked = 0;294 lps->InSize = currentTotalPacked;295 lps->OutSize = currentTotalUnPacked;296 RINOK(lps->SetCur());298 CMyComPtr<ISequentialOutStream> realOutStream;299 Int32 askMode;300 askMode = testMode ? NExtract::NAskMode::kTest :301 NExtract::NAskMode::kExtract;302 Int32 index = allFilesMode ? i : indices[i];303 const CItemEx &item = _items[index];304 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));306 if (item.IsDir())307 {308 // if (!testMode)309 {310 RINOK(extractCallback->PrepareOperation(askMode));311 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));312 }313 continue;314 }316 if (!testMode && (!realOutStream))317 continue;319 RINOK(extractCallback->PrepareOperation(askMode));320 currentItemUnPacked = item.Size;321 currentItemPacked = item.PackSize;323 {324 COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;325 CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);326 outStreamSpec->Init(realOutStream);327 realOutStream.Release();329 UInt64 pos;330 _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos);332 streamSpec->Init(item.PackSize);334 HRESULT result = S_OK;335 Int32 opRes = NExtract::NOperationResult::kOK;337 if (item.IsCopyMethod())338 {339 result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);340 if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)341 result = S_FALSE;342 }343 else if (item.IsLh4GroupMethod())344 {345 if (!lzhDecoder)346 {347 lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;348 lzhDecoder = lzhDecoderSpec;349 }350 lzhDecoderSpec->SetDictionary(item.GetNumDictBits());351 result = lzhDecoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress);352 }353 /*354 else if (item.IsLh1GroupMethod())355 {356 if (!lzh1Decoder)357 {358 lzh1DecoderSpec = new NCompress::NLzh1::NDecoder::CCoder;359 lzh1Decoder = lzh1DecoderSpec;360 }361 lzh1DecoderSpec->SetDictionary(item.GetNumDictBits());362 result = lzh1Decoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress);363 }364 */365 else366 opRes = NExtract::NOperationResult::kUnSupportedMethod;368 if (opRes == NExtract::NOperationResult::kOK)369 {370 if (result == S_FALSE)371 opRes = NExtract::NOperationResult::kDataError;372 else373 {374 RINOK(result);375 if (outStreamSpec->GetCRC() != item.CRC)376 opRes = NExtract::NOperationResult::kCRCError;377 }378 }379 outStream.Release();380 RINOK(extractCallback->SetOperationResult(opRes));381 }382 }383 return S_OK;384 COM_TRY_END385 }387 }}