1 // Archive/ZipItem.h 2 3 #ifndef ZIP7_INC_ARCHIVE_ZIP_ITEM_H 4 #define ZIP7_INC_ARCHIVE_ZIP_ITEM_H 5 6 #include "../../../../C/CpuArch.h" 7 8 #include "../../../Common/MyBuffer.h" 9 #include "../../../Common/MyString.h" 10 #include "../../../Common/UTFConvert.h" 11 12 #include "ZipHeader.h" 13 14 namespace NArchive { 15 namespace NZip { 16 17 /* 18 extern const char *k_SpecName_NTFS_STREAM; 19 extern const char *k_SpecName_MAC_RESOURCE_FORK; 20 */ 21 22 struct CVersion 23 { 24 Byte Version; 25 Byte HostOS; 26 }; 27 28 struct CExtraSubBlock 29 { 30 UInt32 ID; 31 CByteBuffer Data; 32 33 bool ExtractNtfsTime(unsigned index, FILETIME &ft) const; 34 bool Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const; 35 bool Extract_Unix01_Time(unsigned index, UInt32 &res) const; 36 // bool Extract_Unix_Time(unsigned index, UInt32 &res) const; 37 38 bool CheckIzUnicode(const AString &s) const; 39 40 void PrintInfo(AString &s) const; 41 }; 42 43 const unsigned k_WzAesExtra_Size = 7; 44 45 struct CWzAesExtra 46 { 47 UInt16 VendorVersion; // 1: AE-1, 2: AE-2, 48 // UInt16 VendorId; // 'A' 'E' 49 Byte Strength; // 1: 128-bit, 2: 192-bit, 3: 256-bit 50 UInt16 Method; 51 CWzAesExtraCWzAesExtra52 CWzAesExtra(): VendorVersion(2), Strength(3), Method(0) {} 53 NeedCrcCWzAesExtra54 bool NeedCrc() const { return (VendorVersion == 1); } 55 ParseFromSubBlockCWzAesExtra56 bool ParseFromSubBlock(const CExtraSubBlock &sb) 57 { 58 if (sb.ID != NFileHeader::NExtraID::kWzAES) 59 return false; 60 if (sb.Data.Size() < k_WzAesExtra_Size) 61 return false; 62 const Byte *p = (const Byte *)sb.Data; 63 VendorVersion = GetUi16(p); 64 if (p[2] != 'A' || p[3] != 'E') 65 return false; 66 Strength = p[4]; 67 // 9.31: The BUG was fixed: 68 Method = GetUi16(p + 5); 69 return true; 70 } 71 SetSubBlockCWzAesExtra72 void SetSubBlock(CExtraSubBlock &sb) const 73 { 74 sb.Data.Alloc(k_WzAesExtra_Size); 75 sb.ID = NFileHeader::NExtraID::kWzAES; 76 Byte *p = (Byte *)sb.Data; 77 p[0] = (Byte)VendorVersion; 78 p[1] = (Byte)(VendorVersion >> 8); 79 p[2] = 'A'; 80 p[3] = 'E'; 81 p[4] = Strength; 82 p[5] = (Byte)Method; 83 p[6] = (Byte)(Method >> 8); 84 } 85 }; 86 87 namespace NStrongCrypto_AlgId 88 { 89 const UInt16 kDES = 0x6601; 90 const UInt16 kRC2old = 0x6602; 91 const UInt16 k3DES168 = 0x6603; 92 const UInt16 k3DES112 = 0x6609; 93 const UInt16 kAES128 = 0x660E; 94 const UInt16 kAES192 = 0x660F; 95 const UInt16 kAES256 = 0x6610; 96 const UInt16 kRC2 = 0x6702; 97 const UInt16 kBlowfish = 0x6720; 98 const UInt16 kTwofish = 0x6721; 99 const UInt16 kRC4 = 0x6801; 100 } 101 102 struct CStrongCryptoExtra 103 { 104 UInt16 Format; 105 UInt16 AlgId; 106 UInt16 BitLen; 107 UInt16 Flags; 108 ParseFromSubBlockCStrongCryptoExtra109 bool ParseFromSubBlock(const CExtraSubBlock &sb) 110 { 111 if (sb.ID != NFileHeader::NExtraID::kStrongEncrypt) 112 return false; 113 const Byte *p = (const Byte *)sb.Data; 114 if (sb.Data.Size() < 8) 115 return false; 116 Format = GetUi16(p + 0); 117 AlgId = GetUi16(p + 2); 118 BitLen = GetUi16(p + 4); 119 Flags = GetUi16(p + 6); 120 return (Format == 2); 121 } 122 CertificateIsUsedCStrongCryptoExtra123 bool CertificateIsUsed() const { return (Flags > 0x0001); } 124 }; 125 126 127 struct CExtraBlock 128 { 129 CObjectVector<CExtraSubBlock> SubBlocks; 130 bool Error; 131 bool MinorError; 132 bool IsZip64; 133 bool IsZip64_Error; 134 CExtraBlockCExtraBlock135 CExtraBlock(): Error(false), MinorError(false), IsZip64(false), IsZip64_Error(false) {} 136 ClearCExtraBlock137 void Clear() 138 { 139 SubBlocks.Clear(); 140 IsZip64 = false; 141 } 142 GetSizeCExtraBlock143 size_t GetSize() const 144 { 145 size_t res = 0; 146 FOR_VECTOR (i, SubBlocks) 147 res += SubBlocks[i].Data.Size() + 2 + 2; 148 return res; 149 } 150 GetWzAesCExtraBlock151 bool GetWzAes(CWzAesExtra &e) const 152 { 153 FOR_VECTOR (i, SubBlocks) 154 if (e.ParseFromSubBlock(SubBlocks[i])) 155 return true; 156 return false; 157 } 158 HasWzAesCExtraBlock159 bool HasWzAes() const 160 { 161 CWzAesExtra e; 162 return GetWzAes(e); 163 } 164 GetStrongCryptoCExtraBlock165 bool GetStrongCrypto(CStrongCryptoExtra &e) const 166 { 167 FOR_VECTOR (i, SubBlocks) 168 if (e.ParseFromSubBlock(SubBlocks[i])) 169 return true; 170 return false; 171 } 172 173 /* 174 bool HasStrongCrypto() const 175 { 176 CStrongCryptoExtra e; 177 return GetStrongCrypto(e); 178 } 179 */ 180 181 bool GetNtfsTime(unsigned index, FILETIME &ft) const; 182 bool GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const; 183 184 void PrintInfo(AString &s) const; 185 RemoveUnknownSubBlocksCExtraBlock186 void RemoveUnknownSubBlocks() 187 { 188 for (unsigned i = SubBlocks.Size(); i != 0;) 189 { 190 i--; 191 switch (SubBlocks[i].ID) 192 { 193 case NFileHeader::NExtraID::kStrongEncrypt: 194 case NFileHeader::NExtraID::kWzAES: 195 break; 196 default: 197 SubBlocks.Delete(i); 198 } 199 } 200 } 201 }; 202 203 204 class CLocalItem 205 { 206 public: 207 UInt16 Flags; 208 UInt16 Method; 209 210 /* 211 Zip specification doesn't mention that ExtractVersion field uses HostOS subfield. 212 18.06: 7-Zip now doesn't use ExtractVersion::HostOS to detect codePage 213 */ 214 215 CVersion ExtractVersion; 216 217 UInt64 Size; 218 UInt64 PackSize; 219 UInt32 Time; 220 UInt32 Crc; 221 222 UInt32 Disk; 223 224 AString Name; 225 226 CExtraBlock LocalExtra; 227 GetDescriptorSize()228 unsigned GetDescriptorSize() const { return LocalExtra.IsZip64 ? kDataDescriptorSize64 : kDataDescriptorSize32; } 229 GetPackSizeWithDescriptor()230 UInt64 GetPackSizeWithDescriptor() const 231 { return PackSize + (HasDescriptor() ? GetDescriptorSize() : 0); } 232 IsUtf8()233 bool IsUtf8() const { return (Flags & NFileHeader::NFlags::kUtf8) != 0; } IsEncrypted()234 bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kEncrypted) != 0; } IsStrongEncrypted()235 bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; } IsAesEncrypted()236 bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || Method == NFileHeader::NCompressionMethod::kWzAES); } IsLzmaEOS()237 bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; } HasDescriptor()238 bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; } 239 // bool IsAltStream() const { return (Flags & NFileHeader::NFlags::kAltStream) != 0; } 240 GetDeflateLevel()241 unsigned GetDeflateLevel() const { return (Flags >> 1) & 3; } 242 243 bool IsDir() const; 244 245 /* 246 void GetUnicodeString(const AString &s, UString &res) const 247 { 248 bool isUtf8 = IsUtf8(); 249 if (isUtf8) 250 if (ConvertUTF8ToUnicode(s, res)) 251 return; 252 MultiByteToUnicodeString2(res, s, GetCodePage()); 253 } 254 */ 255 256 private: 257 SetFlag(unsigned bitMask,bool enable)258 void SetFlag(unsigned bitMask, bool enable) 259 { 260 if (enable) 261 Flags = (UInt16)(Flags | bitMask); 262 else 263 Flags = (UInt16)(Flags & ~bitMask); 264 } 265 266 public: 267 ClearFlags()268 void ClearFlags() { Flags = 0; } SetEncrypted(bool encrypted)269 void SetEncrypted(bool encrypted) { SetFlag(NFileHeader::NFlags::kEncrypted, encrypted); } SetUtf8(bool isUtf8)270 void SetUtf8(bool isUtf8) { SetFlag(NFileHeader::NFlags::kUtf8, isUtf8); } 271 // void SetFlag_AltStream(bool isAltStream) { SetFlag(NFileHeader::NFlags::kAltStream, isAltStream); } SetDescriptorMode(bool useDescriptor)272 void SetDescriptorMode(bool useDescriptor) { SetFlag(NFileHeader::NFlags::kDescriptorUsedMask, useDescriptor); } 273 GetCodePage()274 UINT GetCodePage() const 275 { 276 if (IsUtf8()) 277 return CP_UTF8; 278 return CP_OEMCP; 279 } 280 }; 281 282 283 class CItem: public CLocalItem 284 { 285 public: 286 CVersion MadeByVersion; 287 UInt16 InternalAttrib; 288 UInt32 ExternalAttrib; 289 290 UInt64 LocalHeaderPos; 291 292 CExtraBlock CentralExtra; 293 CByteBuffer Comment; 294 295 bool FromLocal; 296 bool FromCentral; 297 298 // CItem can be used as CLocalItem. So we must clear unused fields CItem()299 CItem(): 300 InternalAttrib(0), 301 ExternalAttrib(0), 302 FromLocal(false), 303 FromCentral(false) 304 { 305 MadeByVersion.Version = 0; 306 MadeByVersion.HostOS = 0; 307 } 308 GetMainExtra()309 const CExtraBlock &GetMainExtra() const { return *(FromCentral ? &CentralExtra : &LocalExtra); } 310 311 bool IsDir() const; 312 UInt32 GetWinAttrib() const; 313 bool GetPosixAttrib(UInt32 &attrib) const; 314 315 // 18.06: 0 instead of ExtractVersion.HostOS for local item GetHostOS()316 Byte GetHostOS() const { return FromCentral ? MadeByVersion.HostOS : (Byte)0; } 317 318 void GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const; 319 IsThereCrc()320 bool IsThereCrc() const 321 { 322 if (Method == NFileHeader::NCompressionMethod::kWzAES) 323 { 324 CWzAesExtra aesField; 325 if (GetMainExtra().GetWzAes(aesField)) 326 return aesField.NeedCrc(); 327 } 328 return (Crc != 0 || !IsDir()); 329 } 330 Is_MadeBy_Unix()331 bool Is_MadeBy_Unix() const 332 { 333 if (!FromCentral) 334 return false; 335 return (MadeByVersion.HostOS == NFileHeader::NHostOS::kUnix); 336 } 337 GetCodePage()338 UINT GetCodePage() const 339 { 340 // 18.06: now we use HostOS only from Central::MadeByVersion 341 if (IsUtf8()) 342 return CP_UTF8; 343 if (!FromCentral) 344 return CP_OEMCP; 345 Byte hostOS = MadeByVersion.HostOS; 346 return (UINT)(( 347 hostOS == NFileHeader::NHostOS::kFAT 348 || hostOS == NFileHeader::NHostOS::kNTFS 349 || hostOS == NFileHeader::NHostOS::kUnix // do we need it? 350 ) ? CP_OEMCP : CP_ACP); 351 } 352 }; 353 354 }} 355 356 #endif 357