Mercurial > vba-linux
comparison 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 |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
1 // LzhHandler.cpp | |
2 | |
3 #include "StdAfx.h" | |
4 | |
5 #include "Common/ComTry.h" | |
6 #include "Common/Defs.h" | |
7 #include "Common/StringConvert.h" | |
8 | |
9 #include "Windows/PropVariant.h" | |
10 #include "Windows/Time.h" | |
11 | |
12 #include "LzhHandler.h" | |
13 #include "LzhOutStreamWithCRC.h" | |
14 | |
15 #include "../../ICoder.h" | |
16 | |
17 #include "../../Common/LimitedStreams.h" | |
18 #include "../../Common/ProgressUtils.h" | |
19 | |
20 #include "../../Compress/CopyCoder.h" | |
21 #include "../../Compress/LzhDecoder.h" | |
22 | |
23 #include "../Common/ItemNameUtils.h" | |
24 | |
25 using namespace NWindows; | |
26 using namespace NTime; | |
27 | |
28 namespace NArchive { | |
29 namespace NLzh{ | |
30 | |
31 struct COsPair | |
32 { | |
33 Byte Id; | |
34 const wchar_t *Name; | |
35 }; | |
36 | |
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 }; | |
57 | |
58 const wchar_t *kUnknownOS = L"Unknown"; | |
59 | |
60 const int kNumHostOSes = sizeof(g_OsPairs) / sizeof(g_OsPairs[0]); | |
61 | |
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 }; | |
69 | |
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}, | |
78 | |
79 // { NULL, kpidCommented, VT_BOOL}, | |
80 | |
81 { NULL, kpidCRC, VT_UI4}, | |
82 | |
83 { NULL, kpidMethod, VT_UI1}, | |
84 { NULL, kpidHostOS, VT_BSTR} | |
85 | |
86 }; | |
87 | |
88 IMP_IInArchive_Props | |
89 IMP_IInArchive_ArcProps_NO | |
90 | |
91 CHandler::CHandler() {} | |
92 | |
93 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) | |
94 { | |
95 *numItems = _items.Size(); | |
96 return S_OK; | |
97 } | |
98 | |
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 } | |
160 | |
161 /* | |
162 class CProgressImp: public CProgressVirt | |
163 { | |
164 public: | |
165 CMyComPtr<IArchiveOpenCallback> Callback; | |
166 STDMETHOD(SetCompleted)(const UInt64 *numFiles); | |
167 }; | |
168 | |
169 STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles) | |
170 { | |
171 if (Callback) | |
172 return Callback->SetCompleted(numFiles, NULL); | |
173 return S_OK; | |
174 } | |
175 */ | |
176 | |
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; | |
185 | |
186 UInt64 endPos = 0; | |
187 bool needSetTotal = true; | |
188 | |
189 if (callback != NULL) | |
190 { | |
191 RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); | |
192 RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); | |
193 } | |
194 | |
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; | |
226 | |
227 _stream = stream; | |
228 } | |
229 catch(...) | |
230 { | |
231 return S_FALSE; | |
232 } | |
233 COM_TRY_END | |
234 return S_OK; | |
235 } | |
236 | |
237 STDMETHODIMP CHandler::Close() | |
238 { | |
239 _items.Clear(); | |
240 _stream.Release(); | |
241 return S_OK; | |
242 } | |
243 | |
244 | |
245 | |
246 ////////////////////////////////////// | |
247 // CHandler::DecompressItems | |
248 | |
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); | |
268 | |
269 UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0; | |
270 UInt64 currentItemUnPacked, currentItemPacked; | |
271 | |
272 NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = 0; | |
273 CMyComPtr<ICompressCoder> lzhDecoder; | |
274 CMyComPtr<ICompressCoder> lzh1Decoder; | |
275 CMyComPtr<ICompressCoder> arj2Decoder; | |
276 | |
277 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); | |
278 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; | |
279 | |
280 CLocalProgress *lps = new CLocalProgress; | |
281 CMyComPtr<ICompressProgressInfo> progress = lps; | |
282 lps->Init(extractCallback, false); | |
283 | |
284 CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; | |
285 CMyComPtr<ISequentialInStream> inStream(streamSpec); | |
286 streamSpec->SetStream(_stream); | |
287 | |
288 for(i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked, | |
289 currentTotalPacked += currentItemPacked) | |
290 { | |
291 currentItemUnPacked = 0; | |
292 currentItemPacked = 0; | |
293 | |
294 lps->InSize = currentTotalPacked; | |
295 lps->OutSize = currentTotalUnPacked; | |
296 RINOK(lps->SetCur()); | |
297 | |
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)); | |
305 | |
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 } | |
315 | |
316 if (!testMode && (!realOutStream)) | |
317 continue; | |
318 | |
319 RINOK(extractCallback->PrepareOperation(askMode)); | |
320 currentItemUnPacked = item.Size; | |
321 currentItemPacked = item.PackSize; | |
322 | |
323 { | |
324 COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; | |
325 CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); | |
326 outStreamSpec->Init(realOutStream); | |
327 realOutStream.Release(); | |
328 | |
329 UInt64 pos; | |
330 _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos); | |
331 | |
332 streamSpec->Init(item.PackSize); | |
333 | |
334 HRESULT result = S_OK; | |
335 Int32 opRes = NExtract::NOperationResult::kOK; | |
336 | |
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 else | |
366 opRes = NExtract::NOperationResult::kUnSupportedMethod; | |
367 | |
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 } | |
386 | |
387 }} |