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