1 // Rar5Handler.h 2 3 #ifndef ZIP7_INC_RAR5_HANDLER_H 4 #define ZIP7_INC_RAR5_HANDLER_H 5 6 #include "../../../../C/Blake2.h" 7 8 #include "../../../Common/MyBuffer.h" 9 10 #include "../../../Windows/PropVariant.h" 11 12 #include "../../Common/CreateCoder.h" 13 14 #include "../IArchive.h" 15 16 namespace NArchive { 17 namespace NRar5 { 18 19 namespace NHeaderFlags 20 { 21 const unsigned kExtra = 1 << 0; 22 const unsigned kData = 1 << 1; 23 // const unsigned kUnknown = 1 << 2; 24 const unsigned kPrevVol = 1 << 3; 25 const unsigned kNextVol = 1 << 4; 26 // const unsigned kIsChild = 1 << 5; 27 // const unsigned kPreserveChild = 1 << 6; 28 } 29 30 namespace NHeaderType 31 { 32 enum 33 { 34 kArc = 1, 35 kFile, 36 kService, 37 kArcEncrypt, 38 kEndOfArc 39 }; 40 } 41 42 namespace NArcFlags 43 { 44 const unsigned kVol = 1 << 0; 45 const unsigned kVolNumber = 1 << 1; 46 const unsigned kSolid = 1 << 2; 47 // const unsigned kRecovery = 1 << 3; 48 // const unsigned kLocked = 1 << 4; 49 } 50 51 const unsigned kArcExtraRecordType_Locator = 1; 52 const unsigned kArcExtraRecordType_Metadata = 2; 53 54 namespace NLocatorFlags 55 { 56 const unsigned kQuickOpen = 1 << 0; 57 const unsigned kRecovery = 1 << 1; 58 } 59 60 namespace NMetadataFlags 61 { 62 const unsigned kArcName = 1 << 0; 63 const unsigned kCTime = 1 << 1; 64 const unsigned kUnixTime = 1 << 2; 65 const unsigned kNanoSec = 1 << 3; 66 } 67 68 namespace NFileFlags 69 { 70 const unsigned kIsDir = 1 << 0; 71 const unsigned kUnixTime = 1 << 1; 72 const unsigned kCrc32 = 1 << 2; 73 const unsigned kUnknownSize = 1 << 3; 74 } 75 76 namespace NMethodFlags 77 { 78 // const unsigned kVersionMask = 0x3F; 79 const unsigned kSolid = 1 << 6; 80 const unsigned kRar5_Compat = 1u << 20; 81 } 82 83 namespace NArcEndFlags 84 { 85 const unsigned kMoreVols = 1 << 0; 86 } 87 88 enum EHostOS 89 { 90 kHost_Windows = 0, 91 kHost_Unix 92 }; 93 94 95 96 // ---------- Extra ---------- 97 98 namespace NExtraID 99 { 100 enum 101 { 102 kCrypto = 1, 103 kHash, 104 kTime, 105 kVersion, 106 kLink, 107 kUnixOwner, 108 kSubdata 109 }; 110 } 111 112 const unsigned kCryptoAlgo_AES = 0; 113 114 namespace NCryptoFlags 115 { 116 const unsigned kPswCheck = 1 << 0; 117 const unsigned kUseMAC = 1 << 1; 118 } 119 120 struct CCryptoInfo 121 { 122 UInt64 Algo; 123 UInt64 Flags; 124 Byte Cnt; 125 UseMACCCryptoInfo126 bool UseMAC() const { return (Flags & NCryptoFlags::kUseMAC) != 0; } IsThereCheckCCryptoInfo127 bool IsThereCheck() const { return (Flags & NCryptoFlags::kPswCheck) != 0; } 128 bool Parse(const Byte *p, size_t size); 129 }; 130 131 const unsigned kHashID_Blake2sp = 0; 132 133 namespace NTimeRecord 134 { 135 enum 136 { 137 k_Index_MTime = 0, 138 k_Index_CTime, 139 k_Index_ATime 140 }; 141 142 namespace NFlags 143 { 144 const unsigned kUnixTime = 1 << 0; 145 const unsigned kMTime = 1 << 1; 146 const unsigned kCTime = 1 << 2; 147 const unsigned kATime = 1 << 3; 148 const unsigned kUnixNs = 1 << 4; 149 } 150 } 151 152 namespace NLinkType 153 { 154 enum 155 { 156 kUnixSymLink = 1, 157 kWinSymLink, 158 kWinJunction, 159 kHardLink, 160 kFileCopy 161 }; 162 } 163 164 namespace NLinkFlags 165 { 166 const unsigned kTargetIsDir = 1 << 0; 167 } 168 169 170 struct CLinkInfo 171 { 172 UInt64 Type; 173 UInt64 Flags; 174 unsigned NameOffset; 175 unsigned NameLen; 176 177 bool Parse(const Byte *p, unsigned size); 178 }; 179 180 181 struct CItem 182 { 183 UInt32 CommonFlags; 184 UInt32 Flags; 185 186 Byte RecordType; 187 bool Version_Defined; 188 189 int ACL; 190 191 AString Name; 192 193 unsigned VolIndex; 194 int NextItem; // in _items{} 195 196 UInt32 UnixMTime; 197 UInt32 CRC; 198 UInt32 Attrib; 199 UInt32 Method; 200 201 CByteBuffer Extra; 202 203 UInt64 Size; 204 UInt64 PackSize; 205 UInt64 HostOS; 206 207 UInt64 DataPos; 208 UInt64 Version; 209 CItemCItem210 CItem() { Clear(); } 211 ClearCItem212 void Clear() 213 { 214 // CommonFlags = 0; 215 // Flags = 0; 216 217 // UnixMTime = 0; 218 // CRC = 0; 219 220 VolIndex = 0; 221 NextItem = -1; 222 223 Version_Defined = false; 224 Version = 0; 225 226 Name.Empty(); 227 Extra.Free(); 228 ACL = -1; 229 } 230 IsSplitBeforeCItem231 bool IsSplitBefore() const { return (CommonFlags & NHeaderFlags::kPrevVol) != 0; } IsSplitAfterCItem232 bool IsSplitAfter() const { return (CommonFlags & NHeaderFlags::kNextVol) != 0; } IsSplitCItem233 bool IsSplit() const { return (CommonFlags & (NHeaderFlags::kPrevVol | NHeaderFlags::kNextVol)) != 0; } 234 IsDirCItem235 bool IsDir() const { return (Flags & NFileFlags::kIsDir) != 0; } Has_UnixMTimeCItem236 bool Has_UnixMTime() const { return (Flags & NFileFlags::kUnixTime) != 0; } Has_CRCCItem237 bool Has_CRC() const { return (Flags & NFileFlags::kCrc32) != 0; } Is_UnknownSizeCItem238 bool Is_UnknownSize() const { return (Flags & NFileFlags::kUnknownSize) != 0; } 239 IsNextForItemCItem240 bool IsNextForItem(const CItem &prev) const 241 { 242 return !IsDir() && !prev.IsDir() && IsSplitBefore() && prev.IsSplitAfter() && (Name == prev.Name); 243 // && false; 244 } 245 246 // rar docs: Solid flag can be set only for file headers and is never set for service headers. IsSolidCItem247 bool IsSolid() const { return ((UInt32)Method & NMethodFlags::kSolid) != 0; } Is_Rar5_CompatCItem248 bool Is_Rar5_Compat() const { return ((UInt32)Method & NMethodFlags::kRar5_Compat) != 0; } Get_Rar5_CompatBitCItem249 unsigned Get_Rar5_CompatBit() const { return ((UInt32)Method >> 20) & 1; } 250 Get_AlgoVersion_RawBitsCItem251 unsigned Get_AlgoVersion_RawBits() const { return (unsigned)Method & 0x3F; } Get_AlgoVersion_HuffRevCItem252 unsigned Get_AlgoVersion_HuffRev() const 253 { 254 unsigned w = (unsigned)Method & 0x3F; 255 if (w == 1 && Is_Rar5_Compat()) 256 w = 0; 257 return w; 258 } Get_MethodCItem259 unsigned Get_Method() const { return ((unsigned)Method >> 7) & 0x7; } 260 Get_DictSize_MainCItem261 unsigned Get_DictSize_Main() const 262 { return ((UInt32)Method >> 10) & (Get_AlgoVersion_RawBits() == 0 ? 0xf : 0x1f); } Get_DictSize_FracCItem263 unsigned Get_DictSize_Frac() const 264 { 265 // original-unrar ignores Frac, if (algo==0) (rar5): 266 if (Get_AlgoVersion_RawBits() == 0) 267 return 0; 268 return ((UInt32)Method >> 15) & 0x1f; 269 } Get_DictSize64CItem270 UInt64 Get_DictSize64() const 271 { 272 // ver 6.* check 273 // return (((UInt32)Method >> 10) & 0xF); 274 UInt64 winSize = 0; 275 const unsigned algo = Get_AlgoVersion_RawBits(); 276 if (algo <= 1) 277 { 278 UInt32 w = 32; 279 if (algo == 1) 280 w += Get_DictSize_Frac(); 281 winSize = (UInt64)w << (12 + Get_DictSize_Main()); 282 } 283 return winSize; 284 } 285 286 IsServiceCItem287 bool IsService() const { return RecordType == NHeaderType::kService; } 288 Is_STMCItem289 bool Is_STM() const { return IsService() && Name == "STM"; } Is_CMTCItem290 bool Is_CMT() const { return IsService() && Name == "CMT"; } Is_ACLCItem291 bool Is_ACL() const { return IsService() && Name == "ACL"; } 292 // bool Is_QO() const { return IsService() && Name == "QO"; } 293 294 int FindExtra(unsigned extraID, unsigned &recordDataSize) const; 295 void PrintInfo(AString &s) const; 296 297 IsEncryptedCItem298 bool IsEncrypted() const 299 { 300 unsigned size; 301 return FindExtra(NExtraID::kCrypto, size) >= 0; 302 } 303 FindExtra_BlakeCItem304 int FindExtra_Blake() const 305 { 306 unsigned size = 0; 307 const int offset = FindExtra(NExtraID::kHash, size); 308 if (offset >= 0 309 && size == Z7_BLAKE2S_DIGEST_SIZE + 1 310 && Extra[(unsigned)offset] == kHashID_Blake2sp) 311 return offset + 1; 312 return -1; 313 } 314 315 bool FindExtra_Version(UInt64 &version) const; 316 317 bool FindExtra_Link(CLinkInfo &link) const; 318 void Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const; 319 bool Is_CopyLink() const; 320 bool Is_HardLink() const; 321 bool Is_CopyLink_or_HardLink() const; 322 NeedUse_as_CopyLinkCItem323 bool NeedUse_as_CopyLink() const { return PackSize == 0 && Is_CopyLink(); } NeedUse_as_HardLinkCItem324 bool NeedUse_as_HardLink() const { return PackSize == 0 && Is_HardLink(); } NeedUse_as_CopyLink_or_HardLinkCItem325 bool NeedUse_as_CopyLink_or_HardLink() const { return PackSize == 0 && Is_CopyLink_or_HardLink(); } 326 327 bool GetAltStreamName(AString &name) const; 328 GetWinAttribCItem329 UInt32 GetWinAttrib() const 330 { 331 UInt32 a; 332 switch (HostOS) 333 { 334 case kHost_Windows: 335 a = Attrib; 336 break; 337 case kHost_Unix: 338 a = Attrib << 16; 339 a |= 0x8000; // add posix mode marker 340 break; 341 default: 342 a = 0; 343 } 344 if (IsDir()) a |= FILE_ATTRIBUTE_DIRECTORY; 345 return a; 346 } 347 GetDataPositionCItem348 UInt64 GetDataPosition() const { return DataPos; } 349 }; 350 351 352 struct CInArcInfo 353 { 354 UInt64 Flags; 355 UInt64 VolNumber; 356 UInt64 StartPos; 357 UInt64 EndPos; 358 359 UInt64 EndFlags; 360 bool EndOfArchive_was_Read; 361 362 bool IsEncrypted; 363 bool Locator_Defined; 364 bool Locator_Error; 365 bool Metadata_Defined; 366 bool Metadata_Error; 367 bool UnknownExtraRecord; 368 bool Extra_Error; 369 bool UnsupportedFeature; 370 371 struct CLocator 372 { 373 UInt64 Flags; 374 UInt64 QuickOpen; 375 UInt64 Recovery; 376 Is_QuickOpenCInArcInfo::CLocator377 bool Is_QuickOpen() const { return (Flags & NLocatorFlags::kQuickOpen) != 0; } Is_RecoveryCInArcInfo::CLocator378 bool Is_Recovery() const { return (Flags & NLocatorFlags::kRecovery) != 0; } 379 380 bool Parse(const Byte *p, size_t size); CLocatorCInArcInfo::CLocator381 CLocator(): 382 Flags(0), 383 QuickOpen(0), 384 Recovery(0) 385 {} 386 }; 387 388 struct CMetadata 389 { 390 UInt64 Flags; 391 UInt64 CTime; 392 AString ArcName; 393 394 bool Parse(const Byte *p, size_t size); CMetadataCInArcInfo::CMetadata395 CMetadata(): 396 Flags(0), 397 CTime(0) 398 {} 399 }; 400 401 CLocator Locator; 402 CMetadata Metadata; 403 404 bool ParseExtra(const Byte *p, size_t size); 405 CInArcInfoCInArcInfo406 CInArcInfo(): 407 Flags(0), 408 VolNumber(0), 409 StartPos(0), 410 EndPos(0), 411 EndFlags(0), 412 EndOfArchive_was_Read(false), 413 IsEncrypted(false), 414 Locator_Defined(false), 415 Locator_Error(false), 416 Metadata_Defined(false), 417 Metadata_Error(false), 418 UnknownExtraRecord(false), 419 Extra_Error(false), 420 UnsupportedFeature(false) 421 {} 422 423 /* 424 void Clear() 425 { 426 Flags = 0; 427 VolNumber = 0; 428 StartPos = 0; 429 EndPos = 0; 430 EndFlags = 0; 431 EndOfArchive_was_Read = false; 432 } 433 */ 434 GetPhySizeCInArcInfo435 UInt64 GetPhySize() const { return EndPos - StartPos; } 436 AreMoreVolumesCInArcInfo437 bool AreMoreVolumes() const { return (EndFlags & NArcEndFlags::kMoreVols) != 0; } 438 IsVolumeCInArcInfo439 bool IsVolume() const { return (Flags & NArcFlags::kVol) != 0; } IsSolidCInArcInfo440 bool IsSolid() const { return (Flags & NArcFlags::kSolid) != 0; } Is_VolNumber_DefinedCInArcInfo441 bool Is_VolNumber_Defined() const { return (Flags & NArcFlags::kVolNumber) != 0; } 442 GetVolIndexCInArcInfo443 UInt64 GetVolIndex() const { return Is_VolNumber_Defined() ? VolNumber : 0; } 444 }; 445 446 447 struct CRefItem 448 { 449 unsigned Item; // First item in _items[] 450 unsigned Last; // Last item in _items[] 451 int Parent; // in _refs[], if alternate stream 452 int Link; // in _refs[] 453 }; 454 455 456 struct CArc 457 { 458 CMyComPtr<IInStream> Stream; 459 CInArcInfo Info; 460 }; 461 462 463 class CHandler Z7_final: 464 public IInArchive, 465 public IArchiveGetRawProps, 466 public ISetProperties, 467 Z7_PUBLIC_ISetCompressCodecsInfo_IFEC 468 public CMyUnknownImp 469 { 470 Z7_COM_QI_BEGIN2(IInArchive) 471 Z7_COM_QI_ENTRY(IArchiveGetRawProps) 472 Z7_COM_QI_ENTRY(ISetProperties) 473 Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC 474 Z7_COM_QI_END 475 Z7_COM_ADDREF_RELEASE 476 477 Z7_IFACE_COM7_IMP(IInArchive) 478 Z7_IFACE_COM7_IMP(IArchiveGetRawProps) 479 Z7_IFACE_COM7_IMP(ISetProperties) 480 DECL_ISetCompressCodecsInfo 481 482 void InitDefaults(); 483 484 bool _isArc; 485 bool _needChecksumCheck; 486 bool _memUsage_WasSet; 487 bool _comment_WasUsedInArc; 488 bool _acl_Used; 489 bool _error_in_ACL; 490 bool _split_Error; 491 public: 492 CRecordVector<CRefItem> _refs; 493 CObjectVector<CItem> _items; 494 495 CHandler(); 496 private: 497 CObjectVector<CArc> _arcs; 498 CObjectVector<CByteBuffer> _acls; 499 500 UInt32 _errorFlags; 501 // UInt32 _warningFlags; 502 503 UInt32 _numBlocks; 504 unsigned _rar5comapt_mask; 505 unsigned _methodMasks[2]; 506 UInt64 _algo_Mask; 507 UInt64 _dictMaxSizes[2]; 508 509 CByteBuffer _comment; 510 UString _missingVolName; 511 512 UInt64 _memUsage_Decompress; 513 514 DECL_EXTERNAL_CODECS_VARS 515 516 UInt64 GetPackSize(unsigned refIndex) const; 517 518 void FillLinks(); 519 520 HRESULT Open2(IInStream *stream, 521 const UInt64 *maxCheckStartPosition, 522 IArchiveOpenCallback *openCallback); 523 }; 524 525 }} 526 527 #endif 528