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.cpp
3 #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 COsPair
32 {
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_Props
89 IMP_IInArchive_ArcProps_NO
91 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_BEGIN
102 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 else
129 {
130 FILETIME localFileTime;
131 if (DosTimeToFileTime(item.ModifiedTime, localFileTime))
132 {
133 if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
134 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
135 }
136 else
137 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_END
159 }
161 /*
162 class CProgressImp: public CProgressVirt
163 {
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_BEGIN
181 try
182 {
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_END
234 return S_OK;
235 }
237 STDMETHODIMP CHandler::Close()
238 {
239 _items.Clear();
240 _stream.Release();
241 return S_OK;
242 }
246 //////////////////////////////////////
247 // CHandler::DecompressItems
249 STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
250 Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
251 {
252 COM_TRY_BEGIN
253 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, &currentItemUnPacked, 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, &currentItemUnPacked, progress);
363 }
364 */
365 else
366 opRes = NExtract::NOperationResult::kUnSupportedMethod;
368 if (opRes == NExtract::NOperationResult::kOK)
369 {
370 if (result == S_FALSE)
371 opRes = NExtract::NOperationResult::kDataError;
372 else
373 {
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_END
385 }
387 }}