1 // Archive/ZipIn.h 2 3 #ifndef ZIP7_INC_ZIP_IN_H 4 #define ZIP7_INC_ZIP_IN_H 5 6 #include "../../../Common/MyBuffer2.h" 7 #include "../../../Common/MyCom.h" 8 9 #include "../../Common/StreamUtils.h" 10 #include "../../IStream.h" 11 12 #include "ZipHeader.h" 13 #include "ZipItem.h" 14 15 API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size); 16 17 namespace NArchive { 18 namespace NZip { 19 20 class CItemEx: public CItem 21 { 22 public: 23 UInt32 LocalFullHeaderSize; // including Name and Extra 24 // int ParentOfAltStream; // -1, if not AltStream 25 26 bool DescriptorWasRead; 27 CItemEx()28 CItemEx(): 29 // ParentOfAltStream(-1), 30 DescriptorWasRead(false) {} 31 GetLocalFullSize()32 UInt64 GetLocalFullSize() const 33 { return LocalFullHeaderSize + GetPackSizeWithDescriptor(); } GetDataPosition()34 UInt64 GetDataPosition() const 35 { return LocalHeaderPos + LocalFullHeaderSize; } 36 IsBadDescriptor()37 bool IsBadDescriptor() const 38 { 39 return !FromCentral && FromLocal && HasDescriptor() && !DescriptorWasRead; 40 } 41 }; 42 43 44 struct CInArchiveInfo 45 { 46 Int64 Base; /* Base offset of start of archive in stream. 47 Offsets in headers must be calculated from that Base. 48 Base is equal to MarkerPos for normal ZIPs. 49 Base can point to PE stub for some ZIP SFXs. 50 if CentralDir was read, 51 Base can be negative, if start of data is not available, 52 if CentralDirs was not read, 53 Base = ArcInfo.MarkerPos; */ 54 55 /* The following *Pos variables contain absolute offsets in Stream */ 56 57 UInt64 MarkerPos; /* Pos of first signature, it can point to kSpan/kNoSpan signature 58 = MarkerPos2 in most archives 59 = MarkerPos2 - 4 if there is kSpan/kNoSpan signature */ 60 UInt64 MarkerPos2; // Pos of first local item signature in stream 61 UInt64 FinishPos; // Finish pos of archive data in starting volume 62 UInt64 FileEndPos; // Finish pos of stream 63 64 UInt64 FirstItemRelatOffset; /* Relative offset of first local (read from cd) (relative to Base). 65 = 0 in most archives 66 = size of stub for some SFXs */ 67 68 69 int MarkerVolIndex; 70 71 bool CdWasRead; 72 bool IsSpanMode; 73 bool ThereIsTail; 74 75 // UInt32 BaseVolIndex; 76 77 CByteBuffer Comment; 78 79 CInArchiveInfoCInArchiveInfo80 CInArchiveInfo(): 81 Base(0), 82 MarkerPos(0), 83 MarkerPos2(0), 84 FinishPos(0), 85 FileEndPos(0), 86 FirstItemRelatOffset(0), 87 MarkerVolIndex(-1), 88 CdWasRead(false), 89 IsSpanMode(false), 90 ThereIsTail(false) 91 // BaseVolIndex(0) 92 {} 93 ClearCInArchiveInfo94 void Clear() 95 { 96 // BaseVolIndex = 0; 97 Base = 0; 98 MarkerPos = 0; 99 MarkerPos2 = 0; 100 FinishPos = 0; 101 FileEndPos = 0; 102 MarkerVolIndex = -1; 103 ThereIsTail = false; 104 105 FirstItemRelatOffset = 0; 106 107 CdWasRead = false; 108 IsSpanMode = false; 109 110 Comment.Free(); 111 } 112 }; 113 114 115 struct CCdInfo 116 { 117 bool IsFromEcd64; 118 119 UInt16 CommentSize; 120 121 // 64 122 UInt16 VersionMade; 123 UInt16 VersionNeedExtract; 124 125 // old zip 126 UInt32 ThisDisk; 127 UInt32 CdDisk; 128 UInt64 NumEntries_in_ThisDisk; 129 UInt64 NumEntries; 130 UInt64 Size; 131 UInt64 Offset; 132 CCdInfoCCdInfo133 CCdInfo() { memset(this, 0, sizeof(*this)); IsFromEcd64 = false; } 134 135 void ParseEcd32(const Byte *p); // (p) includes signature 136 void ParseEcd64e(const Byte *p); // (p) exclude signature 137 IsEmptyArcCCdInfo138 bool IsEmptyArc() const 139 { 140 return ThisDisk == 0 141 && CdDisk == 0 142 && NumEntries_in_ThisDisk == 0 143 && NumEntries == 0 144 && Size == 0 145 && Offset == 0 // test it 146 ; 147 } 148 }; 149 150 151 struct CVols 152 { 153 struct CSubStreamInfo 154 { 155 CMyComPtr<IInStream> Stream; 156 UInt64 Size; 157 SeekToStartCVols::CSubStreamInfo158 HRESULT SeekToStart() const { return InStream_SeekToBegin(Stream); } 159 CSubStreamInfoCVols::CSubStreamInfo160 CSubStreamInfo(): Size(0) {} 161 }; 162 163 CObjectVector<CSubStreamInfo> Streams; 164 165 int StreamIndex; // -1 for StartStream 166 // -2 for ZipStream at multivol detection code 167 // >=0 volume index in multivol 168 169 bool NeedSeek; 170 171 bool DisableVolsSearch; 172 bool StartIsExe; // is .exe 173 bool StartIsZ; // is .zip or .zNN 174 bool StartIsZip; // is .zip 175 bool IsUpperCase; 176 bool MissingZip; 177 178 bool ecd_wasRead; 179 180 Int32 StartVolIndex; // -1, if unknown vol index 181 // = (NN - 1), if StartStream is .zNN 182 // = 0, if start vol is exe 183 184 Int32 StartParsingVol; // if we need local parsing, we must use that stream 185 unsigned NumVols; 186 187 int EndVolIndex; // index of last volume (ecd volume), 188 // -1, if is not multivol 189 190 UString BaseName; // name of archive including '.' 191 UString MissingName; 192 193 CMyComPtr<IInStream> ZipStream; 194 195 CCdInfo ecd; 196 197 UInt64 TotalBytesSize; // for MultiVol only 198 ClearRefsCVols199 void ClearRefs() 200 { 201 Streams.Clear(); 202 ZipStream.Release(); 203 TotalBytesSize = 0; 204 } 205 ClearCVols206 void Clear() 207 { 208 StreamIndex = -1; 209 NeedSeek = false; 210 211 DisableVolsSearch = false; 212 StartIsExe = false; 213 StartIsZ = false; 214 StartIsZip = false; 215 IsUpperCase = false; 216 217 StartVolIndex = -1; 218 StartParsingVol = 0; 219 NumVols = 0; 220 EndVolIndex = -1; 221 222 BaseName.Empty(); 223 MissingName.Empty(); 224 225 MissingZip = false; 226 ecd_wasRead = false; 227 228 ClearRefs(); 229 } 230 231 HRESULT ParseArcName(IArchiveOpenVolumeCallback *volCallback); 232 233 HRESULT Read(void *data, UInt32 size, UInt32 *processedSize); 234 }; 235 236 237 Z7_CLASS_IMP_COM_1( 238 CVolStream 239 , ISequentialInStream 240 ) 241 public: 242 CVols *Vols; 243 }; 244 245 246 class CInArchive 247 { 248 CMidBuffer Buffer; 249 size_t _bufPos; 250 size_t _bufCached; 251 252 UInt64 _streamPos; 253 UInt64 _cnt; 254 255 // UInt32 _startLocalFromCd_Disk; 256 // UInt64 _startLocalFromCd_Offset; 257 258 size_t GetAvail() const { return _bufCached - _bufPos; } 259 260 void InitBuf() { _bufPos = 0; _bufCached = 0; } 261 void DisableBufMode() { InitBuf(); _inBufMode = false; } 262 263 void SkipLookahed(size_t skip) 264 { 265 _bufPos += skip; 266 _cnt += skip; 267 } 268 269 HRESULT AllocateBuffer(size_t size); 270 271 UInt64 GetVirtStreamPos() { return _streamPos - _bufCached + _bufPos; } 272 273 bool _inBufMode; 274 275 bool IsArcOpen; 276 bool CanStartNewVol; 277 278 UInt32 _signature; 279 280 CMyComPtr<IInStream> StreamRef; 281 IInStream *Stream; 282 IInStream *StartStream; 283 IArchiveOpenCallback *Callback; 284 285 HRESULT Seek_SavePos(UInt64 offset); 286 HRESULT SeekToVol(int volIndex, UInt64 offset); 287 288 HRESULT ReadFromCache(Byte *data, unsigned size, unsigned &processed); 289 HRESULT ReadFromCache_FALSE(Byte *data, unsigned size); 290 291 HRESULT ReadVols2(IArchiveOpenVolumeCallback *volCallback, 292 unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols); 293 HRESULT ReadVols(); 294 295 HRESULT FindMarker(const UInt64 *searchLimit); 296 HRESULT IncreaseRealPosition(UInt64 addValue, bool &isFinished); 297 298 HRESULT LookAhead(size_t minRequiredInBuffer); 299 void SafeRead(Byte *data, unsigned size); 300 void ReadBuffer(CByteBuffer &buffer, unsigned size); 301 // Byte ReadByte(); 302 // UInt16 ReadUInt16(); 303 UInt32 ReadUInt32(); 304 UInt64 ReadUInt64(); 305 306 void ReadSignature(); 307 308 void Skip(size_t num); 309 HRESULT Skip64(UInt64 num, unsigned numFiles); 310 311 bool ReadFileName(unsigned nameSize, AString &dest); 312 313 bool ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra, 314 UInt64 &unpackSize, UInt64 &packSize, CItem *cdItem); 315 bool ReadLocalItem(CItemEx &item); 316 HRESULT FindDescriptor(CItemEx &item, unsigned numFiles); 317 HRESULT ReadCdItem(CItemEx &item); 318 HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo); 319 HRESULT FindCd(bool checkOffsetMode); 320 HRESULT TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize); 321 HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize); 322 HRESULT ReadLocals(CObjectVector<CItemEx> &localItems); 323 324 HRESULT ReadHeaders(CObjectVector<CItemEx> &items); 325 326 HRESULT GetVolStream(unsigned vol, UInt64 pos, CMyComPtr<ISequentialInStream> &stream); 327 328 public: 329 CInArchiveInfo ArcInfo; 330 331 bool IsArc; 332 bool IsZip64; 333 334 bool IsApk; 335 bool IsCdUnsorted; 336 337 bool HeadersError; 338 bool HeadersWarning; 339 bool ExtraMinorError; 340 bool UnexpectedEnd; 341 bool LocalsWereRead; 342 bool LocalsCenterMerged; 343 bool NoCentralDir; 344 bool Overflow32bit; // = true, if zip without Zip64 extension support and it has some fields values truncated to 32-bits. 345 bool Cd_NumEntries_Overflow_16bit; // = true, if no Zip64 and 16-bit ecd:NumEntries was overflowed. 346 347 bool MarkerIsFound; 348 bool MarkerIsSafe; 349 350 bool IsMultiVol; 351 bool UseDisk_in_SingleVol; 352 UInt32 EcdVolIndex; 353 354 CVols Vols; 355 356 bool Force_ReadLocals_Mode; 357 bool Disable_VolsRead; 358 bool Disable_FindMarker; 359 360 CInArchive(): 361 IsArcOpen(false), 362 Stream(NULL), 363 StartStream(NULL), 364 Callback(NULL), 365 Force_ReadLocals_Mode(false), 366 Disable_VolsRead(false), 367 Disable_FindMarker(false) 368 {} 369 370 UInt64 GetPhySize() const 371 { 372 if (IsMultiVol) 373 return ArcInfo.FinishPos; 374 else 375 return (UInt64)((Int64)ArcInfo.FinishPos - ArcInfo.Base); 376 } 377 378 UInt64 GetOffset() const 379 { 380 if (IsMultiVol) 381 return 0; 382 else 383 return (UInt64)ArcInfo.Base; 384 } 385 386 387 void ClearRefs(); 388 void Close(); 389 HRESULT Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector<CItemEx> &items); 390 391 bool IsOpen() const { return IsArcOpen; } 392 393 bool AreThereErrors() const 394 { 395 return HeadersError 396 || UnexpectedEnd 397 || !Vols.MissingName.IsEmpty(); 398 } 399 400 bool IsLocalOffsetOK(const CItemEx &item) const 401 { 402 if (item.FromLocal) 403 return true; 404 return (Int64)GetOffset() + (Int64)item.LocalHeaderPos >= 0; 405 } 406 407 UInt64 GetEmbeddedStubSize() const 408 { 409 // it's possible that first item in CD doesn refers to first local item 410 // so FirstItemRelatOffset is not first local item 411 412 if (ArcInfo.CdWasRead) 413 return ArcInfo.FirstItemRelatOffset; 414 if (IsMultiVol) 415 return 0; 416 return (UInt64)((Int64)ArcInfo.MarkerPos2 - ArcInfo.Base); 417 } 418 419 420 HRESULT CheckDescriptor(const CItemEx &item); 421 HRESULT Read_LocalItem_After_CdItem(CItemEx &item, bool &isAvail, bool &headersError); 422 HRESULT Read_LocalItem_After_CdItem_Full(CItemEx &item); 423 424 HRESULT GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr<ISequentialInStream> &stream); 425 426 IInStream *GetBaseStream() { return StreamRef; } 427 428 bool CanUpdate() const 429 { 430 if (AreThereErrors() 431 || IsMultiVol 432 || ArcInfo.Base < 0 433 || (Int64)ArcInfo.MarkerPos2 < ArcInfo.Base 434 || ArcInfo.ThereIsTail 435 || GetEmbeddedStubSize() != 0 436 || IsApk 437 || IsCdUnsorted) 438 return false; 439 440 // 7-zip probably can update archives with embedded stubs. 441 // we just disable that feature for more safety. 442 443 return true; 444 } 445 }; 446 447 }} 448 449 #endif 450