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