annotate src/win32/7zip/7z/CPP/7zip/Archive/7z/7zHandler.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 // 7zHandler.cpp
rlm@1 2
rlm@1 3 #include "StdAfx.h"
rlm@1 4
rlm@1 5 extern "C"
rlm@1 6 {
rlm@1 7 #include "../../../../C/CpuArch.h"
rlm@1 8 }
rlm@1 9
rlm@1 10 #include "../../../Common/ComTry.h"
rlm@1 11 #include "../../../Common/IntToString.h"
rlm@1 12
rlm@1 13 #ifdef COMPRESS_MT
rlm@1 14 #include "../../../Windows/System.h"
rlm@1 15 #endif
rlm@1 16
rlm@1 17 #include "../Common/ItemNameUtils.h"
rlm@1 18
rlm@1 19 #include "7zHandler.h"
rlm@1 20 #include "7zProperties.h"
rlm@1 21
rlm@1 22 #ifdef __7Z_SET_PROPERTIES
rlm@1 23 #ifdef EXTRACT_ONLY
rlm@1 24 #include "../Common/ParseProperties.h"
rlm@1 25 #endif
rlm@1 26 #endif
rlm@1 27
rlm@1 28 using namespace NWindows;
rlm@1 29
rlm@1 30 extern UString ConvertMethodIdToString(UInt64 id);
rlm@1 31
rlm@1 32 namespace NArchive {
rlm@1 33 namespace N7z {
rlm@1 34
rlm@1 35 CHandler::CHandler()
rlm@1 36 {
rlm@1 37 _crcSize = 4;
rlm@1 38
rlm@1 39 #ifndef _NO_CRYPTO
rlm@1 40 _passwordIsDefined = false;
rlm@1 41 #endif
rlm@1 42
rlm@1 43 #ifdef EXTRACT_ONLY
rlm@1 44 #ifdef COMPRESS_MT
rlm@1 45 _numThreads = NSystem::GetNumberOfProcessors();
rlm@1 46 #endif
rlm@1 47 #else
rlm@1 48 Init();
rlm@1 49 #endif
rlm@1 50 }
rlm@1 51
rlm@1 52 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
rlm@1 53 {
rlm@1 54 *numItems = _db.Files.Size();
rlm@1 55 return S_OK;
rlm@1 56 }
rlm@1 57
rlm@1 58 #ifdef _SFX
rlm@1 59
rlm@1 60 IMP_IInArchive_ArcProps_NO
rlm@1 61
rlm@1 62 STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */)
rlm@1 63 {
rlm@1 64 return E_NOTIMPL;
rlm@1 65 }
rlm@1 66
rlm@1 67 STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
rlm@1 68 BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
rlm@1 69 {
rlm@1 70 return E_NOTIMPL;
rlm@1 71 }
rlm@1 72
rlm@1 73
rlm@1 74 #else
rlm@1 75
rlm@1 76 STATPROPSTG kArcProps[] =
rlm@1 77 {
rlm@1 78 { NULL, kpidMethod, VT_BSTR},
rlm@1 79 { NULL, kpidSolid, VT_BOOL},
rlm@1 80 { NULL, kpidNumBlocks, VT_UI4},
rlm@1 81 { NULL, kpidPhySize, VT_UI8},
rlm@1 82 { NULL, kpidHeadersSize, VT_UI8},
rlm@1 83 { NULL, kpidOffset, VT_UI8}
rlm@1 84 };
rlm@1 85
rlm@1 86 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
rlm@1 87 {
rlm@1 88 COM_TRY_BEGIN
rlm@1 89 NCOM::CPropVariant prop;
rlm@1 90 switch(propID)
rlm@1 91 {
rlm@1 92 case kpidMethod:
rlm@1 93 {
rlm@1 94 UString resString;
rlm@1 95 CRecordVector<UInt64> ids;
rlm@1 96 int i;
rlm@1 97 for (i = 0; i < _db.Folders.Size(); i++)
rlm@1 98 {
rlm@1 99 const CFolder &f = _db.Folders[i];
rlm@1 100 for (int j = f.Coders.Size() - 1; j >= 0; j--)
rlm@1 101 ids.AddToUniqueSorted(f.Coders[j].MethodID);
rlm@1 102 }
rlm@1 103
rlm@1 104 for (i = 0; i < ids.Size(); i++)
rlm@1 105 {
rlm@1 106 UInt64 id = ids[i];
rlm@1 107 UString methodName;
rlm@1 108 /* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
rlm@1 109 if (methodName.IsEmpty())
rlm@1 110 methodName = ConvertMethodIdToString(id);
rlm@1 111 if (!resString.IsEmpty())
rlm@1 112 resString += L' ';
rlm@1 113 resString += methodName;
rlm@1 114 }
rlm@1 115 prop = resString;
rlm@1 116 break;
rlm@1 117 }
rlm@1 118 case kpidSolid: prop = _db.IsSolid(); break;
rlm@1 119 case kpidNumBlocks: prop = (UInt32)_db.Folders.Size(); break;
rlm@1 120 case kpidHeadersSize: prop = _db.HeadersSize; break;
rlm@1 121 case kpidPhySize: prop = _db.PhySize; break;
rlm@1 122 case kpidOffset: if (_db.ArchiveInfo.StartPosition != 0) prop = _db.ArchiveInfo.StartPosition; break;
rlm@1 123 }
rlm@1 124 prop.Detach(value);
rlm@1 125 return S_OK;
rlm@1 126 COM_TRY_END
rlm@1 127 }
rlm@1 128
rlm@1 129 IMP_IInArchive_ArcProps
rlm@1 130
rlm@1 131 #endif
rlm@1 132
rlm@1 133 static void SetPropFromUInt64Def(CUInt64DefVector &v, int index, NCOM::CPropVariant &prop)
rlm@1 134 {
rlm@1 135 UInt64 value;
rlm@1 136 if (v.GetItem(index, value))
rlm@1 137 {
rlm@1 138 FILETIME ft;
rlm@1 139 ft.dwLowDateTime = (DWORD)value;
rlm@1 140 ft.dwHighDateTime = (DWORD)(value >> 32);
rlm@1 141 prop = ft;
rlm@1 142 }
rlm@1 143 }
rlm@1 144
rlm@1 145 #ifndef _SFX
rlm@1 146
rlm@1 147 static UString ConvertUInt32ToString(UInt32 value)
rlm@1 148 {
rlm@1 149 wchar_t buffer[32];
rlm@1 150 ConvertUInt64ToString(value, buffer);
rlm@1 151 return buffer;
rlm@1 152 }
rlm@1 153
rlm@1 154 static UString GetStringForSizeValue(UInt32 value)
rlm@1 155 {
rlm@1 156 for (int i = 31; i >= 0; i--)
rlm@1 157 if ((UInt32(1) << i) == value)
rlm@1 158 return ConvertUInt32ToString(i);
rlm@1 159 UString result;
rlm@1 160 if (value % (1 << 20) == 0)
rlm@1 161 {
rlm@1 162 result += ConvertUInt32ToString(value >> 20);
rlm@1 163 result += L"m";
rlm@1 164 }
rlm@1 165 else if (value % (1 << 10) == 0)
rlm@1 166 {
rlm@1 167 result += ConvertUInt32ToString(value >> 10);
rlm@1 168 result += L"k";
rlm@1 169 }
rlm@1 170 else
rlm@1 171 {
rlm@1 172 result += ConvertUInt32ToString(value);
rlm@1 173 result += L"b";
rlm@1 174 }
rlm@1 175 return result;
rlm@1 176 }
rlm@1 177
rlm@1 178 static const UInt64 k_Copy = 0x0;
rlm@1 179 static const UInt64 k_LZMA = 0x030101;
rlm@1 180 static const UInt64 k_PPMD = 0x030401;
rlm@1 181
rlm@1 182 static wchar_t GetHex(Byte value)
rlm@1 183 {
rlm@1 184 return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10)));
rlm@1 185 }
rlm@1 186 static inline UString GetHex2(Byte value)
rlm@1 187 {
rlm@1 188 UString result;
rlm@1 189 result += GetHex((Byte)(value >> 4));
rlm@1 190 result += GetHex((Byte)(value & 0xF));
rlm@1 191 return result;
rlm@1 192 }
rlm@1 193
rlm@1 194 #endif
rlm@1 195
rlm@1 196 static const UInt64 k_AES = 0x06F10701;
rlm@1 197
rlm@1 198 bool CHandler::IsEncrypted(UInt32 index2) const
rlm@1 199 {
rlm@1 200 CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
rlm@1 201 if (folderIndex != kNumNoIndex)
rlm@1 202 {
rlm@1 203 const CFolder &folderInfo = _db.Folders[folderIndex];
rlm@1 204 for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
rlm@1 205 if (folderInfo.Coders[i].MethodID == k_AES)
rlm@1 206 return true;
rlm@1 207 }
rlm@1 208 return false;
rlm@1 209 }
rlm@1 210
rlm@1 211 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
rlm@1 212 {
rlm@1 213 COM_TRY_BEGIN
rlm@1 214 NCOM::CPropVariant prop;
rlm@1 215
rlm@1 216 /*
rlm@1 217 const CRef2 &ref2 = _refs[index];
rlm@1 218 if (ref2.Refs.IsEmpty())
rlm@1 219 return E_FAIL;
rlm@1 220 const CRef &ref = ref2.Refs.Front();
rlm@1 221 */
rlm@1 222
rlm@1 223 const CFileItem &item = _db.Files[index];
rlm@1 224 UInt32 index2 = index;
rlm@1 225
rlm@1 226 switch(propID)
rlm@1 227 {
rlm@1 228 case kpidPath:
rlm@1 229 if (!item.Name.IsEmpty())
rlm@1 230 prop = NItemName::GetOSName(item.Name);
rlm@1 231 break;
rlm@1 232 case kpidIsDir: prop = item.IsDir; break;
rlm@1 233 case kpidSize:
rlm@1 234 {
rlm@1 235 prop = item.Size;
rlm@1 236 // prop = ref2.Size;
rlm@1 237 break;
rlm@1 238 }
rlm@1 239 case kpidPackSize:
rlm@1 240 {
rlm@1 241 // prop = ref2.PackSize;
rlm@1 242 {
rlm@1 243 CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
rlm@1 244 if (folderIndex != kNumNoIndex)
rlm@1 245 {
rlm@1 246 if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2)
rlm@1 247 prop = _db.GetFolderFullPackSize(folderIndex);
rlm@1 248 /*
rlm@1 249 else
rlm@1 250 prop = (UInt64)0;
rlm@1 251 */
rlm@1 252 }
rlm@1 253 else
rlm@1 254 prop = (UInt64)0;
rlm@1 255 }
rlm@1 256 break;
rlm@1 257 }
rlm@1 258 case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) prop = v; break; }
rlm@1 259 case kpidCTime: SetPropFromUInt64Def(_db.CTime, index2, prop); break;
rlm@1 260 case kpidATime: SetPropFromUInt64Def(_db.ATime, index2, prop); break;
rlm@1 261 case kpidMTime: SetPropFromUInt64Def(_db.MTime, index2, prop); break;
rlm@1 262 case kpidAttrib: if (item.AttribDefined) prop = item.Attrib; break;
rlm@1 263 case kpidCRC: if (item.CrcDefined) prop = item.Crc; break;
rlm@1 264 case kpidEncrypted: prop = IsEncrypted(index2); break;
rlm@1 265 case kpidIsAnti: prop = _db.IsItemAnti(index2); break;
rlm@1 266 #ifndef _SFX
rlm@1 267 case kpidMethod:
rlm@1 268 {
rlm@1 269 CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
rlm@1 270 if (folderIndex != kNumNoIndex)
rlm@1 271 {
rlm@1 272 const CFolder &folderInfo = _db.Folders[folderIndex];
rlm@1 273 UString methodsString;
rlm@1 274 for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
rlm@1 275 {
rlm@1 276 const CCoderInfo &coderInfo = folderInfo.Coders[i];
rlm@1 277 if (!methodsString.IsEmpty())
rlm@1 278 methodsString += L' ';
rlm@1 279
rlm@1 280 {
rlm@1 281 UString methodName;
rlm@1 282 bool methodIsKnown = FindMethod(
rlm@1 283 EXTERNAL_CODECS_VARS
rlm@1 284 coderInfo.MethodID, methodName);
rlm@1 285
rlm@1 286 if (methodIsKnown)
rlm@1 287 {
rlm@1 288 methodsString += methodName;
rlm@1 289 if (coderInfo.MethodID == k_LZMA)
rlm@1 290 {
rlm@1 291 if (coderInfo.Props.GetCapacity() >= 5)
rlm@1 292 {
rlm@1 293 methodsString += L":";
rlm@1 294 UInt32 dicSize = GetUi32((const Byte *)coderInfo.Props + 1);
rlm@1 295 methodsString += GetStringForSizeValue(dicSize);
rlm@1 296 }
rlm@1 297 }
rlm@1 298 else if (coderInfo.MethodID == k_PPMD)
rlm@1 299 {
rlm@1 300 if (coderInfo.Props.GetCapacity() >= 5)
rlm@1 301 {
rlm@1 302 Byte order = *(const Byte *)coderInfo.Props;
rlm@1 303 methodsString += L":o";
rlm@1 304 methodsString += ConvertUInt32ToString(order);
rlm@1 305 methodsString += L":mem";
rlm@1 306 UInt32 dicSize = GetUi32((const Byte *)coderInfo.Props + 1);
rlm@1 307 methodsString += GetStringForSizeValue(dicSize);
rlm@1 308 }
rlm@1 309 }
rlm@1 310 else if (coderInfo.MethodID == k_AES)
rlm@1 311 {
rlm@1 312 if (coderInfo.Props.GetCapacity() >= 1)
rlm@1 313 {
rlm@1 314 methodsString += L":";
rlm@1 315 const Byte *data = (const Byte *)coderInfo.Props;
rlm@1 316 Byte firstByte = *data++;
rlm@1 317 UInt32 numCyclesPower = firstByte & 0x3F;
rlm@1 318 methodsString += ConvertUInt32ToString(numCyclesPower);
rlm@1 319 /*
rlm@1 320 if ((firstByte & 0xC0) != 0)
rlm@1 321 {
rlm@1 322 methodsString += L":";
rlm@1 323 return S_OK;
rlm@1 324 UInt32 saltSize = (firstByte >> 7) & 1;
rlm@1 325 UInt32 ivSize = (firstByte >> 6) & 1;
rlm@1 326 if (coderInfo.Props.GetCapacity() >= 2)
rlm@1 327 {
rlm@1 328 Byte secondByte = *data++;
rlm@1 329 saltSize += (secondByte >> 4);
rlm@1 330 ivSize += (secondByte & 0x0F);
rlm@1 331 }
rlm@1 332 }
rlm@1 333 */
rlm@1 334 }
rlm@1 335 }
rlm@1 336 else
rlm@1 337 {
rlm@1 338 if (coderInfo.Props.GetCapacity() > 0)
rlm@1 339 {
rlm@1 340 methodsString += L":[";
rlm@1 341 for (size_t bi = 0; bi < coderInfo.Props.GetCapacity(); bi++)
rlm@1 342 {
rlm@1 343 if (bi > 5 && bi + 1 < coderInfo.Props.GetCapacity())
rlm@1 344 {
rlm@1 345 methodsString += L"..";
rlm@1 346 break;
rlm@1 347 }
rlm@1 348 else
rlm@1 349 methodsString += GetHex2(coderInfo.Props[bi]);
rlm@1 350 }
rlm@1 351 methodsString += L"]";
rlm@1 352 }
rlm@1 353 }
rlm@1 354 }
rlm@1 355 else
rlm@1 356 {
rlm@1 357 methodsString += ConvertMethodIdToString(coderInfo.MethodID);
rlm@1 358 }
rlm@1 359 }
rlm@1 360 }
rlm@1 361 prop = methodsString;
rlm@1 362 }
rlm@1 363 }
rlm@1 364 break;
rlm@1 365 case kpidBlock:
rlm@1 366 {
rlm@1 367 CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
rlm@1 368 if (folderIndex != kNumNoIndex)
rlm@1 369 prop = (UInt32)folderIndex;
rlm@1 370 }
rlm@1 371 break;
rlm@1 372 case kpidPackedSize0:
rlm@1 373 case kpidPackedSize1:
rlm@1 374 case kpidPackedSize2:
rlm@1 375 case kpidPackedSize3:
rlm@1 376 case kpidPackedSize4:
rlm@1 377 {
rlm@1 378 CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
rlm@1 379 if (folderIndex != kNumNoIndex)
rlm@1 380 {
rlm@1 381 const CFolder &folderInfo = _db.Folders[folderIndex];
rlm@1 382 if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
rlm@1 383 folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
rlm@1 384 {
rlm@1 385 prop = _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
rlm@1 386 }
rlm@1 387 else
rlm@1 388 prop = (UInt64)0;
rlm@1 389 }
rlm@1 390 else
rlm@1 391 prop = (UInt64)0;
rlm@1 392 }
rlm@1 393 break;
rlm@1 394 #endif
rlm@1 395 }
rlm@1 396 prop.Detach(value);
rlm@1 397 return S_OK;
rlm@1 398 COM_TRY_END
rlm@1 399 }
rlm@1 400
rlm@1 401 STDMETHODIMP CHandler::Open(IInStream *stream,
rlm@1 402 const UInt64 *maxCheckStartPosition,
rlm@1 403 IArchiveOpenCallback *openArchiveCallback)
rlm@1 404 {
rlm@1 405 COM_TRY_BEGIN
rlm@1 406 Close();
rlm@1 407 #ifndef _SFX
rlm@1 408 _fileInfoPopIDs.Clear();
rlm@1 409 #endif
rlm@1 410 try
rlm@1 411 {
rlm@1 412 CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
rlm@1 413
rlm@1 414 #ifndef _NO_CRYPTO
rlm@1 415 CMyComPtr<ICryptoGetTextPassword> getTextPassword;
rlm@1 416 if (openArchiveCallback)
rlm@1 417 {
rlm@1 418 openArchiveCallbackTemp.QueryInterface(
rlm@1 419 IID_ICryptoGetTextPassword, &getTextPassword);
rlm@1 420 }
rlm@1 421 #endif
rlm@1 422 CInArchive archive;
rlm@1 423 RINOK(archive.Open(stream, maxCheckStartPosition));
rlm@1 424 #ifndef _NO_CRYPTO
rlm@1 425 _passwordIsDefined = false;
rlm@1 426 UString password;
rlm@1 427 #endif
rlm@1 428 HRESULT result = archive.ReadDatabase(
rlm@1 429 EXTERNAL_CODECS_VARS
rlm@1 430 _db
rlm@1 431 #ifndef _NO_CRYPTO
rlm@1 432 , getTextPassword, _passwordIsDefined
rlm@1 433 #endif
rlm@1 434 );
rlm@1 435 RINOK(result);
rlm@1 436 _db.Fill();
rlm@1 437 _inStream = stream;
rlm@1 438 }
rlm@1 439 catch(...)
rlm@1 440 {
rlm@1 441 Close();
rlm@1 442 return S_FALSE;
rlm@1 443 }
rlm@1 444 // _inStream = stream;
rlm@1 445 #ifndef _SFX
rlm@1 446 FillPopIDs();
rlm@1 447 #endif
rlm@1 448 return S_OK;
rlm@1 449 COM_TRY_END
rlm@1 450 }
rlm@1 451
rlm@1 452 STDMETHODIMP CHandler::Close()
rlm@1 453 {
rlm@1 454 COM_TRY_BEGIN
rlm@1 455 _inStream.Release();
rlm@1 456 _db.Clear();
rlm@1 457 return S_OK;
rlm@1 458 COM_TRY_END
rlm@1 459 }
rlm@1 460
rlm@1 461 #ifdef __7Z_SET_PROPERTIES
rlm@1 462 #ifdef EXTRACT_ONLY
rlm@1 463
rlm@1 464 STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
rlm@1 465 {
rlm@1 466 COM_TRY_BEGIN
rlm@1 467 #ifdef COMPRESS_MT
rlm@1 468 const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
rlm@1 469 _numThreads = numProcessors;
rlm@1 470 #endif
rlm@1 471
rlm@1 472 for (int i = 0; i < numProperties; i++)
rlm@1 473 {
rlm@1 474 UString name = names[i];
rlm@1 475 name.MakeUpper();
rlm@1 476 if (name.IsEmpty())
rlm@1 477 return E_INVALIDARG;
rlm@1 478 const PROPVARIANT &value = values[i];
rlm@1 479 UInt32 number;
rlm@1 480 int index = ParseStringToUInt32(name, number);
rlm@1 481 if (index == 0)
rlm@1 482 {
rlm@1 483 if(name.Left(2).CompareNoCase(L"MT") == 0)
rlm@1 484 {
rlm@1 485 #ifdef COMPRESS_MT
rlm@1 486 RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
rlm@1 487 #endif
rlm@1 488 continue;
rlm@1 489 }
rlm@1 490 else
rlm@1 491 return E_INVALIDARG;
rlm@1 492 }
rlm@1 493 }
rlm@1 494 return S_OK;
rlm@1 495 COM_TRY_END
rlm@1 496 }
rlm@1 497
rlm@1 498 #endif
rlm@1 499 #endif
rlm@1 500
rlm@1 501 IMPL_ISetCompressCodecsInfo
rlm@1 502
rlm@1 503 }}