5 #include "Common/Defs.h"
6 #include "Common/StringConvert.h"
7 #include "Common/ComTry.h"
9 #include "Windows/Time.h"
10 #include "Windows/PropVariant.h"
12 #include "LzhHandler.h"
13 #include "LzhOutStreamWithCRC.h"
15 #include "../../ICoder.h"
17 #include "../../Common/ProgressUtils.h"
18 #include "../../Common/LimitedStreams.h"
20 #include "../../Compress/Copy/CopyCoder.h"
21 #include "../../Compress/Lzh/LzhDecoder.h"
23 #include "../Common/ItemNameUtils.h"
25 using namespace NWindows;
26 using namespace NTime;
52 { 'w', L"Windows95" },
53 { 'W', L"WindowsNT" },
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)
64 for (int i = 0; i < kNumHostOSes; i++)
65 if (g_OsPairs[i].Id == osId)
66 return g_OsPairs[i].Name;
70 STATPROPSTG kProps[] =
72 { NULL, kpidPath, VT_BSTR},
73 { NULL, kpidIsFolder, VT_BOOL},
74 { NULL, kpidSize, VT_UI8},
75 { NULL, kpidPackedSize, VT_UI8},
76 { NULL, kpidLastWriteTime, VT_FILETIME},
77 { NULL, kpidAttributes, VT_UI4},
79 // { NULL, kpidCommented, VT_BOOL},
81 { NULL, kpidCRC, VT_UI4},
83 { NULL, kpidMethod, VT_UI1},
84 { NULL, kpidHostOS, VT_BSTR}
89 IMP_IInArchive_ArcProps_NO
91 CHandler::CHandler() {}
93 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
95 *numItems = _items.Size();
99 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
102 NWindows::NCOM::CPropVariant prop;
103 const CItemEx &item = _items[index];
108 UString s = NItemName::WinNameToOSName(MultiByteToUnicodeString(item.GetName(), CP_OEMCP));
111 if (s[s.Length() - 1] == WCHAR_PATH_SEPARATOR)
112 s.Delete(s.Length() - 1);
118 prop = item.IsDirectory();
124 prop = item.PackSize;
126 case kpidLastWriteTime:
128 FILETIME utcFileTime;
130 if (item.GetUnixTime(unixTime))
132 NTime::UnixTimeToFileTime(unixTime, utcFileTime);
136 FILETIME localFileTime;
137 if (DosTimeToFileTime(item.ModifiedTime, localFileTime))
139 if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
140 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
143 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
150 prop = (UInt32)item.Attributes;
153 prop = item.IsCommented();
157 prop = (UInt32)item.CRC;
161 wchar_t method2[kMethodIdSize + 1];
162 method2[kMethodIdSize] = 0;
163 for (int i = 0; i < kMethodIdSize; i++)
164 method2[i] = item.Method[i];
169 prop = GetOS(item.OsId);
178 class CPropgressImp: public CProgressVirt
181 CMyComPtr<IArchiveOpenCallback> Callback;
182 STDMETHOD(SetCompleted)(const UInt64 *numFiles);
185 STDMETHODIMP CPropgressImp::SetCompleted(const UInt64 *numFiles)
188 return Callback->SetCompleted(numFiles, NULL);
193 STDMETHODIMP CHandler::Open(IInStream *inStream,
194 const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)
201 RINOK(archive.Open(inStream));
202 if (callback != NULL)
204 RINOK(callback->SetTotal(NULL, NULL));
205 UInt64 numFiles = _items.Size();
206 RINOK(callback->SetCompleted(&numFiles, NULL));
212 HRESULT result = archive.GetNextItem(filled, item);
213 if (result == S_FALSE)
220 archive.Skeep(item.PackSize);
221 if (callback != NULL)
223 UInt64 numFiles = _items.Size();
224 RINOK(callback->SetCompleted(&numFiles, NULL));
227 if (_items.IsEmpty())
240 STDMETHODIMP CHandler::Close()
249 //////////////////////////////////////
250 // CHandler::DecompressItems
252 STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
253 Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
256 bool testMode = (testModeSpec != 0);
257 UInt64 totalUnPacked = 0, totalPacked = 0;
258 bool allFilesMode = (numItems == UInt32(-1));
260 numItems = _items.Size();
264 for(i = 0; i < numItems; i++)
266 const CItemEx &item = _items[allFilesMode ? i : indices[i]];
267 totalUnPacked += item.Size;
268 totalPacked += item.PackSize;
270 extractCallback->SetTotal(totalUnPacked);
272 UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
273 UInt64 currentItemUnPacked, currentItemPacked;
275 NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = 0;
276 CMyComPtr<ICompressCoder> lzhDecoder;
277 CMyComPtr<ICompressCoder> lzh1Decoder;
278 CMyComPtr<ICompressCoder> arj2Decoder;
280 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
281 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
283 CLocalProgress *lps = new CLocalProgress;
284 CMyComPtr<ICompressProgressInfo> progress = lps;
285 lps->Init(extractCallback, false);
287 CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
288 CMyComPtr<ISequentialInStream> inStream(streamSpec);
289 streamSpec->SetStream(_stream);
291 for(i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,
292 currentTotalPacked += currentItemPacked)
294 currentItemUnPacked = 0;
295 currentItemPacked = 0;
297 lps->InSize = currentTotalPacked;
298 lps->OutSize = currentTotalUnPacked;
299 RINOK(lps->SetCur());
301 CMyComPtr<ISequentialOutStream> realOutStream;
303 askMode = testMode ? NExtract::NAskMode::kTest :
304 NExtract::NAskMode::kExtract;
305 Int32 index = allFilesMode ? i : indices[i];
306 const CItemEx &item = _items[index];
307 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
309 if(item.IsDirectory())
313 RINOK(extractCallback->PrepareOperation(askMode));
314 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
319 if (!testMode && (!realOutStream))
322 RINOK(extractCallback->PrepareOperation(askMode));
323 currentItemUnPacked = item.Size;
324 currentItemPacked = item.PackSize;
327 COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
328 CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
329 outStreamSpec->Init(realOutStream);
330 realOutStream.Release();
333 _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos);
335 streamSpec->Init(item.PackSize);
337 HRESULT result = S_OK;
338 Int32 opRes = NExtract::NOperationResult::kOK;
340 if (item.IsCopyMethod())
342 result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
343 if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)
346 else if (item.IsLh4GroupMethod())
350 lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
351 lzhDecoder = lzhDecoderSpec;
353 lzhDecoderSpec->SetDictionary(item.GetNumDictBits());
354 result = lzhDecoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress);
357 else if (item.IsLh1GroupMethod())
361 lzh1DecoderSpec = new NCompress::NLzh1::NDecoder::CCoder;
362 lzh1Decoder = lzh1DecoderSpec;
364 lzh1DecoderSpec->SetDictionary(item.GetNumDictBits());
365 result = lzh1Decoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress);
369 opRes = NExtract::NOperationResult::kUnSupportedMethod;
371 if (opRes == NExtract::NOperationResult::kOK)
373 if (result == S_FALSE)
374 opRes = NExtract::NOperationResult::kDataError;
378 if (outStreamSpec->GetCRC() != item.CRC)
379 opRes = NExtract::NOperationResult::kCRCError;
383 RINOK(extractCallback->SetOperationResult(opRes));