Mercurial > vba-linux
diff src/win32/7zip/7z/CPP/7zip/Archive/Zip/ZipIn.cpp @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/win32/7zip/7z/CPP/7zip/Archive/Zip/ZipIn.cpp Sat Mar 03 10:31:27 2012 -0600 1.3 @@ -0,0 +1,868 @@ 1.4 +// Archive/ZipIn.cpp 1.5 + 1.6 +#include "StdAfx.h" 1.7 + 1.8 +#include "ZipIn.h" 1.9 +#include "Windows/Defs.h" 1.10 +#include "Common/StringConvert.h" 1.11 +#include "Common/DynamicBuffer.h" 1.12 +#include "../../Common/LimitedStreams.h" 1.13 +#include "../../Common/StreamUtils.h" 1.14 + 1.15 +extern "C" 1.16 +{ 1.17 + #include "../../../../C/CpuArch.h" 1.18 +} 1.19 + 1.20 +#define Get16(p) GetUi16(p) 1.21 +#define Get32(p) GetUi32(p) 1.22 +#define Get64(p) GetUi64(p) 1.23 + 1.24 +namespace NArchive { 1.25 +namespace NZip { 1.26 + 1.27 +// static const char kEndOfString = '\0'; 1.28 + 1.29 +HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) 1.30 +{ 1.31 + Close(); 1.32 + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition)); 1.33 + m_Position = m_StreamStartPosition; 1.34 + RINOK(FindAndReadMarker(stream, searchHeaderSizeLimit)); 1.35 + RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); 1.36 + m_Stream = stream; 1.37 + return S_OK; 1.38 +} 1.39 + 1.40 +void CInArchive::Close() 1.41 +{ 1.42 + m_Stream.Release(); 1.43 +} 1.44 + 1.45 +HRESULT CInArchive::Seek(UInt64 offset) 1.46 +{ 1.47 + return m_Stream->Seek(offset, STREAM_SEEK_SET, NULL); 1.48 +} 1.49 + 1.50 +////////////////////////////////////// 1.51 +// Markers 1.52 + 1.53 +static inline bool TestMarkerCandidate(const Byte *p, UInt32 &value) 1.54 +{ 1.55 + value = Get32(p); 1.56 + return 1.57 + (value == NSignature::kLocalFileHeader) || 1.58 + (value == NSignature::kEndOfCentralDir); 1.59 +} 1.60 + 1.61 +static const UInt32 kNumMarkerAddtionalBytes = 2; 1.62 +static inline bool TestMarkerCandidate2(const Byte *p, UInt32 &value) 1.63 +{ 1.64 + value = Get32(p); 1.65 + if (value == NSignature::kEndOfCentralDir) 1.66 + return (Get16(p + 4) == 0); 1.67 + return (value == NSignature::kLocalFileHeader && p[4] < 128); 1.68 +} 1.69 + 1.70 +HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit) 1.71 +{ 1.72 + m_ArchiveInfo.Clear(); 1.73 + m_Position = m_StreamStartPosition; 1.74 + 1.75 + Byte marker[NSignature::kMarkerSize]; 1.76 + RINOK(ReadStream_FALSE(stream, marker, NSignature::kMarkerSize)); 1.77 + m_Position += NSignature::kMarkerSize; 1.78 + if (TestMarkerCandidate(marker, m_Signature)) 1.79 + return S_OK; 1.80 + 1.81 + CByteDynamicBuffer dynamicBuffer; 1.82 + const UInt32 kSearchMarkerBufferSize = 0x10000; 1.83 + dynamicBuffer.EnsureCapacity(kSearchMarkerBufferSize); 1.84 + Byte *buffer = dynamicBuffer; 1.85 + UInt32 numBytesPrev = NSignature::kMarkerSize - 1; 1.86 + memcpy(buffer, marker + 1, numBytesPrev); 1.87 + UInt64 curTestPos = m_StreamStartPosition + 1; 1.88 + for (;;) 1.89 + { 1.90 + if (searchHeaderSizeLimit != NULL) 1.91 + if (curTestPos - m_StreamStartPosition > *searchHeaderSizeLimit) 1.92 + break; 1.93 + size_t numReadBytes = kSearchMarkerBufferSize - numBytesPrev; 1.94 + RINOK(ReadStream(stream, buffer + numBytesPrev, &numReadBytes)); 1.95 + m_Position += numReadBytes; 1.96 + UInt32 numBytesInBuffer = numBytesPrev + (UInt32)numReadBytes; 1.97 + const UInt32 kMarker2Size = NSignature::kMarkerSize + kNumMarkerAddtionalBytes; 1.98 + if (numBytesInBuffer < kMarker2Size) 1.99 + break; 1.100 + UInt32 numTests = numBytesInBuffer - kMarker2Size + 1; 1.101 + for (UInt32 pos = 0; pos < numTests; pos++) 1.102 + { 1.103 + if (buffer[pos] != 0x50) 1.104 + continue; 1.105 + if (TestMarkerCandidate2(buffer + pos, m_Signature)) 1.106 + { 1.107 + curTestPos += pos; 1.108 + m_ArchiveInfo.StartPosition = curTestPos; 1.109 + m_Position = curTestPos + NSignature::kMarkerSize; 1.110 + return S_OK; 1.111 + } 1.112 + } 1.113 + curTestPos += numTests; 1.114 + numBytesPrev = numBytesInBuffer - numTests; 1.115 + memmove(buffer, buffer + numTests, numBytesPrev); 1.116 + } 1.117 + return S_FALSE; 1.118 +} 1.119 + 1.120 +HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize) 1.121 +{ 1.122 + size_t realProcessedSize = size; 1.123 + HRESULT result = ReadStream(m_Stream, data, &realProcessedSize); 1.124 + if (processedSize != NULL) 1.125 + *processedSize = (UInt32)realProcessedSize; 1.126 + m_Position += realProcessedSize; 1.127 + return result; 1.128 +} 1.129 + 1.130 +void CInArchive::IncreaseRealPosition(UInt64 addValue) 1.131 +{ 1.132 + if (m_Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position) != S_OK) 1.133 + throw CInArchiveException(CInArchiveException::kSeekStreamError); 1.134 +} 1.135 + 1.136 +bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size) 1.137 +{ 1.138 + UInt32 realProcessedSize; 1.139 + if (ReadBytes(data, size, &realProcessedSize) != S_OK) 1.140 + throw CInArchiveException(CInArchiveException::kReadStreamError); 1.141 + return (realProcessedSize == size); 1.142 +} 1.143 + 1.144 +void CInArchive::SafeReadBytes(void *data, UInt32 size) 1.145 +{ 1.146 + if (!ReadBytesAndTestSize(data, size)) 1.147 + throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive); 1.148 +} 1.149 + 1.150 +void CInArchive::ReadBuffer(CByteBuffer &buffer, UInt32 size) 1.151 +{ 1.152 + buffer.SetCapacity(size); 1.153 + if (size > 0) 1.154 + SafeReadBytes(buffer, size); 1.155 +} 1.156 + 1.157 +Byte CInArchive::ReadByte() 1.158 +{ 1.159 + Byte b; 1.160 + SafeReadBytes(&b, 1); 1.161 + return b; 1.162 +} 1.163 + 1.164 +UInt16 CInArchive::ReadUInt16() 1.165 +{ 1.166 + UInt16 value = 0; 1.167 + for (int i = 0; i < 2; i++) 1.168 + value |= (((UInt16)ReadByte()) << (8 * i)); 1.169 + return value; 1.170 +} 1.171 + 1.172 +UInt32 CInArchive::ReadUInt32() 1.173 +{ 1.174 + UInt32 value = 0; 1.175 + for (int i = 0; i < 4; i++) 1.176 + value |= (((UInt32)ReadByte()) << (8 * i)); 1.177 + return value; 1.178 +} 1.179 + 1.180 +UInt64 CInArchive::ReadUInt64() 1.181 +{ 1.182 + UInt64 value = 0; 1.183 + for (int i = 0; i < 8; i++) 1.184 + value |= (((UInt64)ReadByte()) << (8 * i)); 1.185 + return value; 1.186 +} 1.187 + 1.188 +bool CInArchive::ReadUInt32(UInt32 &value) 1.189 +{ 1.190 + value = 0; 1.191 + for (int i = 0; i < 4; i++) 1.192 + { 1.193 + Byte b; 1.194 + if (!ReadBytesAndTestSize(&b, 1)) 1.195 + return false; 1.196 + value |= (UInt32(b) << (8 * i)); 1.197 + } 1.198 + return true; 1.199 +} 1.200 + 1.201 + 1.202 +AString CInArchive::ReadFileName(UInt32 nameSize) 1.203 +{ 1.204 + if (nameSize == 0) 1.205 + return AString(); 1.206 + char *p = m_NameBuffer.GetBuffer(nameSize); 1.207 + SafeReadBytes(p, nameSize); 1.208 + p[nameSize] = 0; 1.209 + m_NameBuffer.ReleaseBuffer(); 1.210 + return m_NameBuffer; 1.211 +} 1.212 + 1.213 +void CInArchive::GetArchiveInfo(CInArchiveInfo &archiveInfo) const 1.214 +{ 1.215 + archiveInfo = m_ArchiveInfo; 1.216 +} 1.217 + 1.218 +/* 1.219 +void CInArchive::ThrowIncorrectArchiveException() 1.220 +{ 1.221 + throw CInArchiveException(CInArchiveException::kIncorrectArchive); 1.222 +} 1.223 +*/ 1.224 + 1.225 +static UInt32 GetUInt32(const Byte *data) 1.226 +{ 1.227 + return 1.228 + ((UInt32)(Byte)data[0]) | 1.229 + (((UInt32)(Byte)data[1]) << 8) | 1.230 + (((UInt32)(Byte)data[2]) << 16) | 1.231 + (((UInt32)(Byte)data[3]) << 24); 1.232 +} 1.233 + 1.234 +/* 1.235 +static UInt16 GetUInt16(const Byte *data) 1.236 +{ 1.237 + return 1.238 + ((UInt16)(Byte)data[0]) | 1.239 + (((UInt16)(Byte)data[1]) << 8); 1.240 +} 1.241 +*/ 1.242 + 1.243 +static UInt64 GetUInt64(const Byte *data) 1.244 +{ 1.245 + return GetUInt32(data) | ((UInt64)GetUInt32(data + 4) << 32); 1.246 +} 1.247 + 1.248 + 1.249 + 1.250 +void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock, 1.251 + UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber) 1.252 +{ 1.253 + extraBlock.Clear(); 1.254 + UInt32 remain = extraSize; 1.255 + while(remain >= 4) 1.256 + { 1.257 + CExtraSubBlock subBlock; 1.258 + subBlock.ID = ReadUInt16(); 1.259 + UInt32 dataSize = ReadUInt16(); 1.260 + remain -= 4; 1.261 + if (dataSize > remain) // it's bug 1.262 + dataSize = remain; 1.263 + if (subBlock.ID == NFileHeader::NExtraID::kZip64) 1.264 + { 1.265 + if (unpackSize == 0xFFFFFFFF) 1.266 + { 1.267 + if (dataSize < 8) 1.268 + break; 1.269 + unpackSize = ReadUInt64(); 1.270 + remain -= 8; 1.271 + dataSize -= 8; 1.272 + } 1.273 + if (packSize == 0xFFFFFFFF) 1.274 + { 1.275 + if (dataSize < 8) 1.276 + break; 1.277 + packSize = ReadUInt64(); 1.278 + remain -= 8; 1.279 + dataSize -= 8; 1.280 + } 1.281 + if (localHeaderOffset == 0xFFFFFFFF) 1.282 + { 1.283 + if (dataSize < 8) 1.284 + break; 1.285 + localHeaderOffset = ReadUInt64(); 1.286 + remain -= 8; 1.287 + dataSize -= 8; 1.288 + } 1.289 + if (diskStartNumber == 0xFFFF) 1.290 + { 1.291 + if (dataSize < 4) 1.292 + break; 1.293 + diskStartNumber = ReadUInt32(); 1.294 + remain -= 4; 1.295 + dataSize -= 4; 1.296 + } 1.297 + for (UInt32 i = 0; i < dataSize; i++) 1.298 + ReadByte(); 1.299 + } 1.300 + else 1.301 + { 1.302 + ReadBuffer(subBlock.Data, dataSize); 1.303 + extraBlock.SubBlocks.Add(subBlock); 1.304 + } 1.305 + remain -= dataSize; 1.306 + } 1.307 + IncreaseRealPosition(remain); 1.308 +} 1.309 + 1.310 +HRESULT CInArchive::ReadLocalItem(CItemEx &item) 1.311 +{ 1.312 + item.ExtractVersion.Version = ReadByte(); 1.313 + item.ExtractVersion.HostOS = ReadByte(); 1.314 + item.Flags = ReadUInt16(); 1.315 + item.CompressionMethod = ReadUInt16(); 1.316 + item.Time = ReadUInt32(); 1.317 + item.FileCRC = ReadUInt32(); 1.318 + item.PackSize = ReadUInt32(); 1.319 + item.UnPackSize = ReadUInt32(); 1.320 + UInt32 fileNameSize = ReadUInt16(); 1.321 + item.LocalExtraSize = ReadUInt16(); 1.322 + item.Name = ReadFileName(fileNameSize); 1.323 + item.FileHeaderWithNameSize = 4 + NFileHeader::kLocalBlockSize + fileNameSize; 1.324 + if (item.LocalExtraSize > 0) 1.325 + { 1.326 + UInt64 localHeaderOffset = 0; 1.327 + UInt32 diskStartNumber = 0; 1.328 + ReadExtra(item.LocalExtraSize, item.LocalExtra, item.UnPackSize, item.PackSize, 1.329 + localHeaderOffset, diskStartNumber); 1.330 + } 1.331 + /* 1.332 + if (item.IsDir()) 1.333 + item.UnPackSize = 0; // check It 1.334 + */ 1.335 + return S_OK; 1.336 +} 1.337 + 1.338 +HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item) 1.339 +{ 1.340 + if (item.FromLocal) 1.341 + return S_OK; 1.342 + try 1.343 + { 1.344 + RINOK(Seek(m_ArchiveInfo.Base + item.LocalHeaderPosition)); 1.345 + CItemEx localItem; 1.346 + if (ReadUInt32() != NSignature::kLocalFileHeader) 1.347 + return S_FALSE; 1.348 + RINOK(ReadLocalItem(localItem)); 1.349 + if (item.Flags != localItem.Flags) 1.350 + { 1.351 + if ( 1.352 + (item.CompressionMethod != NFileHeader::NCompressionMethod::kDeflated || 1.353 + (item.Flags & 0x7FF9) != (localItem.Flags & 0x7FF9)) && 1.354 + (item.CompressionMethod != NFileHeader::NCompressionMethod::kStored || 1.355 + (item.Flags & 0x7FFF) != (localItem.Flags & 0x7FFF)) && 1.356 + (item.CompressionMethod != NFileHeader::NCompressionMethod::kImploded || 1.357 + (item.Flags & 0x7FFF) != (localItem.Flags & 0x7FFF)) 1.358 + ) 1.359 + return S_FALSE; 1.360 + } 1.361 + 1.362 + if (item.CompressionMethod != localItem.CompressionMethod || 1.363 + // item.Time != localItem.Time || 1.364 + (!localItem.HasDescriptor() && 1.365 + ( 1.366 + item.FileCRC != localItem.FileCRC || 1.367 + item.PackSize != localItem.PackSize || 1.368 + item.UnPackSize != localItem.UnPackSize 1.369 + ) 1.370 + ) || 1.371 + item.Name.Length() != localItem.Name.Length() 1.372 + ) 1.373 + return S_FALSE; 1.374 + item.FileHeaderWithNameSize = localItem.FileHeaderWithNameSize; 1.375 + item.LocalExtraSize = localItem.LocalExtraSize; 1.376 + item.LocalExtra = localItem.LocalExtra; 1.377 + item.FromLocal = true; 1.378 + } 1.379 + catch(...) { return S_FALSE; } 1.380 + return S_OK; 1.381 +} 1.382 + 1.383 +HRESULT CInArchive::ReadLocalItemDescriptor(CItemEx &item) 1.384 +{ 1.385 + if (item.HasDescriptor()) 1.386 + { 1.387 + const int kBufferSize = (1 << 12); 1.388 + Byte buffer[kBufferSize]; 1.389 + 1.390 + UInt32 numBytesInBuffer = 0; 1.391 + UInt32 packedSize = 0; 1.392 + 1.393 + bool descriptorWasFound = false; 1.394 + for (;;) 1.395 + { 1.396 + UInt32 processedSize; 1.397 + RINOK(ReadBytes(buffer + numBytesInBuffer, kBufferSize - numBytesInBuffer, &processedSize)); 1.398 + numBytesInBuffer += processedSize; 1.399 + if (numBytesInBuffer < NFileHeader::kDataDescriptorSize) 1.400 + return S_FALSE; 1.401 + UInt32 i; 1.402 + for (i = 0; i <= numBytesInBuffer - NFileHeader::kDataDescriptorSize; i++) 1.403 + { 1.404 + // descriptorSignature field is Info-ZIP's extension 1.405 + // to Zip specification. 1.406 + UInt32 descriptorSignature = GetUInt32(buffer + i); 1.407 + 1.408 + // !!!! It must be fixed for Zip64 archives 1.409 + UInt32 descriptorPackSize = GetUInt32(buffer + i + 8); 1.410 + if (descriptorSignature== NSignature::kDataDescriptor && descriptorPackSize == packedSize + i) 1.411 + { 1.412 + descriptorWasFound = true; 1.413 + item.FileCRC = GetUInt32(buffer + i + 4); 1.414 + item.PackSize = descriptorPackSize; 1.415 + item.UnPackSize = GetUInt32(buffer + i + 12); 1.416 + IncreaseRealPosition(Int64(Int32(0 - (numBytesInBuffer - i - NFileHeader::kDataDescriptorSize)))); 1.417 + break; 1.418 + } 1.419 + } 1.420 + if (descriptorWasFound) 1.421 + break; 1.422 + packedSize += i; 1.423 + int j; 1.424 + for (j = 0; i < numBytesInBuffer; i++, j++) 1.425 + buffer[j] = buffer[i]; 1.426 + numBytesInBuffer = j; 1.427 + } 1.428 + } 1.429 + else 1.430 + IncreaseRealPosition(item.PackSize); 1.431 + return S_OK; 1.432 +} 1.433 + 1.434 +HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) 1.435 +{ 1.436 + if (item.FromLocal) 1.437 + return S_OK; 1.438 + try 1.439 + { 1.440 + RINOK(ReadLocalItemAfterCdItem(item)); 1.441 + if (item.HasDescriptor()) 1.442 + { 1.443 + RINOK(Seek(m_ArchiveInfo.Base + item.GetDataPosition() + item.PackSize)); 1.444 + if (ReadUInt32() != NSignature::kDataDescriptor) 1.445 + return S_FALSE; 1.446 + UInt32 crc = ReadUInt32(); 1.447 + UInt64 packSize, unpackSize; 1.448 + 1.449 + /* 1.450 + if (IsZip64) 1.451 + { 1.452 + packSize = ReadUInt64(); 1.453 + unpackSize = ReadUInt64(); 1.454 + } 1.455 + else 1.456 + */ 1.457 + { 1.458 + packSize = ReadUInt32(); 1.459 + unpackSize = ReadUInt32(); 1.460 + } 1.461 + 1.462 + if (crc != item.FileCRC || item.PackSize != packSize || item.UnPackSize != unpackSize) 1.463 + return S_FALSE; 1.464 + } 1.465 + } 1.466 + catch(...) { return S_FALSE; } 1.467 + return S_OK; 1.468 +} 1.469 + 1.470 +HRESULT CInArchive::ReadCdItem(CItemEx &item) 1.471 +{ 1.472 + item.FromCentral = true; 1.473 + const int kBufSize = 42; 1.474 + Byte p[kBufSize]; 1.475 + SafeReadBytes(p, kBufSize); 1.476 + item.MadeByVersion.Version = p[0]; 1.477 + item.MadeByVersion.HostOS = p[1]; 1.478 + item.ExtractVersion.Version = p[2]; 1.479 + item.ExtractVersion.HostOS = p[3]; 1.480 + item.Flags = Get16(p + 4); 1.481 + item.CompressionMethod = Get16(p + 6); 1.482 + item.Time = Get32(p + 8); 1.483 + item.FileCRC = Get32(p + 12); 1.484 + item.PackSize = Get32(p + 16); 1.485 + item.UnPackSize = Get32(p + 20); 1.486 + UInt16 headerNameSize = Get16(p + 24); 1.487 + UInt16 headerExtraSize = Get16(p + 26); 1.488 + UInt16 headerCommentSize = Get16(p + 28); 1.489 + UInt32 headerDiskNumberStart = Get16(p + 30); 1.490 + item.InternalAttributes = Get16(p + 32); 1.491 + item.ExternalAttributes = Get32(p + 34); 1.492 + item.LocalHeaderPosition = Get32(p + 38); 1.493 + item.Name = ReadFileName(headerNameSize); 1.494 + 1.495 + if (headerExtraSize > 0) 1.496 + { 1.497 + ReadExtra(headerExtraSize, item.CentralExtra, item.UnPackSize, item.PackSize, 1.498 + item.LocalHeaderPosition, headerDiskNumberStart); 1.499 + } 1.500 + 1.501 + if (headerDiskNumberStart != 0) 1.502 + throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported); 1.503 + 1.504 + // May be these strings must be deleted 1.505 + /* 1.506 + if (item.IsDir()) 1.507 + item.UnPackSize = 0; 1.508 + */ 1.509 + 1.510 + ReadBuffer(item.Comment, headerCommentSize); 1.511 + return S_OK; 1.512 +} 1.513 + 1.514 +HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) 1.515 +{ 1.516 + RINOK(Seek(offset)); 1.517 + const UInt32 kEcd64Size = 56; 1.518 + Byte buf[kEcd64Size]; 1.519 + if (!ReadBytesAndTestSize(buf, kEcd64Size)) 1.520 + return S_FALSE; 1.521 + if (GetUInt32(buf) != NSignature::kZip64EndOfCentralDir) 1.522 + return S_FALSE; 1.523 + // cdInfo.NumEntries = GetUInt64(buf + 24); 1.524 + cdInfo.Size = GetUInt64(buf + 40); 1.525 + cdInfo.Offset = GetUInt64(buf + 48); 1.526 + return S_OK; 1.527 +} 1.528 + 1.529 +HRESULT CInArchive::FindCd(CCdInfo &cdInfo) 1.530 +{ 1.531 + UInt64 endPosition; 1.532 + RINOK(m_Stream->Seek(0, STREAM_SEEK_END, &endPosition)); 1.533 + const UInt32 kBufSizeMax = (1 << 16) + kEcdSize + kZip64EcdLocatorSize; 1.534 + Byte buf[kBufSizeMax]; 1.535 + UInt32 bufSize = (endPosition < kBufSizeMax) ? (UInt32)endPosition : kBufSizeMax; 1.536 + if (bufSize < kEcdSize) 1.537 + return S_FALSE; 1.538 + UInt64 startPosition = endPosition - bufSize; 1.539 + RINOK(m_Stream->Seek(startPosition, STREAM_SEEK_SET, &m_Position)); 1.540 + if (m_Position != startPosition) 1.541 + return S_FALSE; 1.542 + if (!ReadBytesAndTestSize(buf, bufSize)) 1.543 + return S_FALSE; 1.544 + for (int i = (int)(bufSize - kEcdSize); i >= 0; i--) 1.545 + { 1.546 + if (GetUInt32(buf + i) == NSignature::kEndOfCentralDir) 1.547 + { 1.548 + if (i >= kZip64EcdLocatorSize) 1.549 + { 1.550 + const Byte *locator = buf + i - kZip64EcdLocatorSize; 1.551 + if (GetUInt32(locator) == NSignature::kZip64EndOfCentralDirLocator) 1.552 + { 1.553 + UInt64 ecd64Offset = GetUInt64(locator + 8); 1.554 + if (TryEcd64(ecd64Offset, cdInfo) == S_OK) 1.555 + return S_OK; 1.556 + if (TryEcd64(m_ArchiveInfo.StartPosition + ecd64Offset, cdInfo) == S_OK) 1.557 + { 1.558 + m_ArchiveInfo.Base = m_ArchiveInfo.StartPosition; 1.559 + return S_OK; 1.560 + } 1.561 + } 1.562 + } 1.563 + if (GetUInt32(buf + i + 4) == 0) 1.564 + { 1.565 + // cdInfo.NumEntries = GetUInt16(buf + i + 10); 1.566 + cdInfo.Size = GetUInt32(buf + i + 12); 1.567 + cdInfo.Offset = GetUInt32(buf + i + 16); 1.568 + UInt64 curPos = endPosition - bufSize + i; 1.569 + UInt64 cdEnd = cdInfo.Size + cdInfo.Offset; 1.570 + if (curPos > cdEnd) 1.571 + m_ArchiveInfo.Base = curPos - cdEnd; 1.572 + return S_OK; 1.573 + } 1.574 + } 1.575 + } 1.576 + return S_FALSE; 1.577 +} 1.578 + 1.579 +HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress) 1.580 +{ 1.581 + items.Clear(); 1.582 + RINOK(m_Stream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position)); 1.583 + if (m_Position != cdOffset) 1.584 + return S_FALSE; 1.585 + while(m_Position - cdOffset < cdSize) 1.586 + { 1.587 + if (ReadUInt32() != NSignature::kCentralFileHeader) 1.588 + return S_FALSE; 1.589 + CItemEx cdItem; 1.590 + RINOK(ReadCdItem(cdItem)); 1.591 + items.Add(cdItem); 1.592 + if (progress && items.Size() % 1000 == 0) 1.593 + RINOK(progress->SetCompleted(items.Size())); 1.594 + } 1.595 + return (m_Position - cdOffset == cdSize) ? S_OK : S_FALSE; 1.596 +} 1.597 + 1.598 +HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress) 1.599 +{ 1.600 + m_ArchiveInfo.Base = 0; 1.601 + CCdInfo cdInfo; 1.602 + RINOK(FindCd(cdInfo)); 1.603 + HRESULT res = S_FALSE; 1.604 + cdSize = cdInfo.Size; 1.605 + cdOffset = cdInfo.Offset; 1.606 + res = TryReadCd(items, m_ArchiveInfo.Base + cdOffset, cdSize, progress); 1.607 + if (res == S_FALSE && m_ArchiveInfo.Base == 0) 1.608 + { 1.609 + res = TryReadCd(items, cdInfo.Offset + m_ArchiveInfo.StartPosition, cdSize, progress); 1.610 + if (res == S_OK) 1.611 + m_ArchiveInfo.Base = m_ArchiveInfo.StartPosition; 1.612 + } 1.613 + if (!ReadUInt32(m_Signature)) 1.614 + return S_FALSE; 1.615 + return res; 1.616 +} 1.617 + 1.618 +HRESULT CInArchive::ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset) 1.619 +{ 1.620 + items.Clear(); 1.621 + while (m_Signature == NSignature::kLocalFileHeader) 1.622 + { 1.623 + // FSeek points to next byte after signature 1.624 + // NFileHeader::CLocalBlock localHeader; 1.625 + CItemEx item; 1.626 + item.LocalHeaderPosition = m_Position - m_StreamStartPosition - 4; // points to signature; 1.627 + RINOK(ReadLocalItem(item)); 1.628 + item.FromLocal = true; 1.629 + ReadLocalItemDescriptor(item); 1.630 + items.Add(item); 1.631 + if (progress && items.Size() % 100 == 0) 1.632 + RINOK(progress->SetCompleted(items.Size())); 1.633 + if (!ReadUInt32(m_Signature)) 1.634 + break; 1.635 + } 1.636 + cdOffset = m_Position - 4; 1.637 + for (int i = 0; i < items.Size(); i++) 1.638 + { 1.639 + if (progress && i % 1000 == 0) 1.640 + RINOK(progress->SetCompleted(items.Size())); 1.641 + if (m_Signature != NSignature::kCentralFileHeader) 1.642 + return S_FALSE; 1.643 + 1.644 + CItemEx cdItem; 1.645 + RINOK(ReadCdItem(cdItem)); 1.646 + 1.647 + if (i == 0) 1.648 + { 1.649 + if (cdItem.LocalHeaderPosition == 0) 1.650 + m_ArchiveInfo.Base = m_ArchiveInfo.StartPosition; 1.651 + } 1.652 + 1.653 + int index; 1.654 + int left = 0, right = items.Size(); 1.655 + for (;;) 1.656 + { 1.657 + if (left >= right) 1.658 + return S_FALSE; 1.659 + index = (left + right) / 2; 1.660 + UInt64 position = items[index].LocalHeaderPosition - m_ArchiveInfo.Base; 1.661 + if (cdItem.LocalHeaderPosition == position) 1.662 + break; 1.663 + if (cdItem.LocalHeaderPosition < position) 1.664 + right = index; 1.665 + else 1.666 + left = index + 1; 1.667 + } 1.668 + CItemEx &item = items[index]; 1.669 + item.LocalHeaderPosition = cdItem.LocalHeaderPosition; 1.670 + item.MadeByVersion = cdItem.MadeByVersion; 1.671 + item.CentralExtra = cdItem.CentralExtra; 1.672 + 1.673 + if ( 1.674 + // item.ExtractVersion != cdItem.ExtractVersion || 1.675 + item.Flags != cdItem.Flags || 1.676 + item.CompressionMethod != cdItem.CompressionMethod || 1.677 + // item.Time != cdItem.Time || 1.678 + item.FileCRC != cdItem.FileCRC) 1.679 + return S_FALSE; 1.680 + 1.681 + if (item.Name.Length() != cdItem.Name.Length() || 1.682 + item.PackSize != cdItem.PackSize || 1.683 + item.UnPackSize != cdItem.UnPackSize 1.684 + ) 1.685 + return S_FALSE; 1.686 + item.Name = cdItem.Name; 1.687 + item.InternalAttributes = cdItem.InternalAttributes; 1.688 + item.ExternalAttributes = cdItem.ExternalAttributes; 1.689 + item.Comment = cdItem.Comment; 1.690 + item.FromCentral = cdItem.FromCentral; 1.691 + if (!ReadUInt32(m_Signature)) 1.692 + return S_FALSE; 1.693 + } 1.694 + return S_OK; 1.695 +} 1.696 + 1.697 +struct CEcd 1.698 +{ 1.699 + UInt16 thisDiskNumber; 1.700 + UInt16 startCDDiskNumber; 1.701 + UInt16 numEntriesInCDOnThisDisk; 1.702 + UInt16 numEntriesInCD; 1.703 + UInt32 cdSize; 1.704 + UInt32 cdStartOffset; 1.705 + UInt16 commentSize; 1.706 + void Parse(const Byte *p); 1.707 +}; 1.708 + 1.709 +void CEcd::Parse(const Byte *p) 1.710 +{ 1.711 + thisDiskNumber = Get16(p); 1.712 + startCDDiskNumber = Get16(p + 2); 1.713 + numEntriesInCDOnThisDisk = Get16(p + 4); 1.714 + numEntriesInCD = Get16(p + 6); 1.715 + cdSize = Get32(p + 8); 1.716 + cdStartOffset = Get32(p + 12); 1.717 + commentSize = Get16(p + 16); 1.718 +} 1.719 + 1.720 +struct CEcd64 1.721 +{ 1.722 + UInt16 versionMade; 1.723 + UInt16 versionNeedExtract; 1.724 + UInt32 thisDiskNumber; 1.725 + UInt32 startCDDiskNumber; 1.726 + UInt64 numEntriesInCDOnThisDisk; 1.727 + UInt64 numEntriesInCD; 1.728 + UInt64 cdSize; 1.729 + UInt64 cdStartOffset; 1.730 + void Parse(const Byte *p); 1.731 + CEcd64() { memset(this, 0, sizeof(*this)); } 1.732 +}; 1.733 + 1.734 +void CEcd64::Parse(const Byte *p) 1.735 +{ 1.736 + versionMade = Get16(p); 1.737 + versionNeedExtract = Get16(p + 2); 1.738 + thisDiskNumber = Get32(p + 4); 1.739 + startCDDiskNumber = Get32(p + 8); 1.740 + numEntriesInCDOnThisDisk = Get64(p + 12); 1.741 + numEntriesInCD = Get64(p + 20); 1.742 + cdSize = Get64(p + 28); 1.743 + cdStartOffset = Get64(p + 36); 1.744 +} 1.745 + 1.746 +#define COPY_ECD_ITEM_16(n) if (!isZip64 || ecd. n != 0xFFFF) ecd64. n = ecd. n; 1.747 +#define COPY_ECD_ITEM_32(n) if (!isZip64 || ecd. n != 0xFFFFFFFF) ecd64. n = ecd. n; 1.748 + 1.749 +HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress) 1.750 +{ 1.751 + // m_Signature must be kLocalFileHeaderSignature or 1.752 + // kEndOfCentralDirSignature 1.753 + // m_Position points to next byte after signature 1.754 + 1.755 + IsZip64 = false; 1.756 + items.Clear(); 1.757 + 1.758 + UInt64 cdSize, cdStartOffset; 1.759 + HRESULT res = ReadCd(items, cdStartOffset, cdSize, progress); 1.760 + if (res != S_FALSE && res != S_OK) 1.761 + return res; 1.762 + 1.763 + /* 1.764 + if (res != S_OK) 1.765 + return res; 1.766 + res = S_FALSE; 1.767 + */ 1.768 + 1.769 + if (res == S_FALSE) 1.770 + { 1.771 + m_ArchiveInfo.Base = 0; 1.772 + RINOK(m_Stream->Seek(m_ArchiveInfo.StartPosition, STREAM_SEEK_SET, &m_Position)); 1.773 + if (m_Position != m_ArchiveInfo.StartPosition) 1.774 + return S_FALSE; 1.775 + if (!ReadUInt32(m_Signature)) 1.776 + return S_FALSE; 1.777 + RINOK(ReadLocalsAndCd(items, progress, cdStartOffset)); 1.778 + cdSize = (m_Position - 4) - cdStartOffset; 1.779 + cdStartOffset -= m_ArchiveInfo.Base; 1.780 + } 1.781 + 1.782 + CEcd64 ecd64; 1.783 + bool isZip64 = false; 1.784 + UInt64 zip64EcdStartOffset = m_Position - 4 - m_ArchiveInfo.Base; 1.785 + if (m_Signature == NSignature::kZip64EndOfCentralDir) 1.786 + { 1.787 + IsZip64 = isZip64 = true; 1.788 + UInt64 recordSize = ReadUInt64(); 1.789 + 1.790 + const int kBufSize = kZip64EcdSize; 1.791 + Byte buf[kBufSize]; 1.792 + SafeReadBytes(buf, kBufSize); 1.793 + ecd64.Parse(buf); 1.794 + 1.795 + IncreaseRealPosition(recordSize - kZip64EcdSize); 1.796 + if (!ReadUInt32(m_Signature)) 1.797 + return S_FALSE; 1.798 + if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) 1.799 + throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported); 1.800 + if (ecd64.numEntriesInCDOnThisDisk != items.Size() || 1.801 + ecd64.numEntriesInCD != items.Size() || 1.802 + ecd64.cdSize != cdSize || 1.803 + (ecd64.cdStartOffset != cdStartOffset && 1.804 + (!items.IsEmpty()))) 1.805 + return S_FALSE; 1.806 + } 1.807 + if (m_Signature == NSignature::kZip64EndOfCentralDirLocator) 1.808 + { 1.809 + /* UInt32 startEndCDDiskNumber = */ ReadUInt32(); 1.810 + UInt64 endCDStartOffset = ReadUInt64(); 1.811 + /* UInt32 numberOfDisks = */ ReadUInt32(); 1.812 + if (zip64EcdStartOffset != endCDStartOffset) 1.813 + return S_FALSE; 1.814 + if (!ReadUInt32(m_Signature)) 1.815 + return S_FALSE; 1.816 + } 1.817 + if (m_Signature != NSignature::kEndOfCentralDir) 1.818 + return S_FALSE; 1.819 + 1.820 + const int kBufSize = kEcdSize - 4; 1.821 + Byte buf[kBufSize]; 1.822 + SafeReadBytes(buf, kBufSize); 1.823 + CEcd ecd; 1.824 + ecd.Parse(buf); 1.825 + 1.826 + COPY_ECD_ITEM_16(thisDiskNumber); 1.827 + COPY_ECD_ITEM_16(startCDDiskNumber); 1.828 + COPY_ECD_ITEM_16(numEntriesInCDOnThisDisk); 1.829 + COPY_ECD_ITEM_16(numEntriesInCD); 1.830 + COPY_ECD_ITEM_32(cdSize); 1.831 + COPY_ECD_ITEM_32(cdStartOffset); 1.832 + 1.833 + ReadBuffer(m_ArchiveInfo.Comment, ecd.commentSize); 1.834 + 1.835 + if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) 1.836 + throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported); 1.837 + if ((UInt16)ecd64.numEntriesInCDOnThisDisk != ((UInt16)items.Size()) || 1.838 + (UInt16)ecd64.numEntriesInCD != ((UInt16)items.Size()) || 1.839 + (UInt32)ecd64.cdSize != (UInt32)cdSize || 1.840 + ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdStartOffset && 1.841 + (!items.IsEmpty()))) 1.842 + return S_FALSE; 1.843 + 1.844 + return S_OK; 1.845 +} 1.846 + 1.847 +ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size) 1.848 +{ 1.849 + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; 1.850 + CMyComPtr<ISequentialInStream> stream(streamSpec); 1.851 + SeekInArchive(m_ArchiveInfo.Base + position); 1.852 + streamSpec->SetStream(m_Stream); 1.853 + streamSpec->Init(size); 1.854 + return stream.Detach(); 1.855 +} 1.856 + 1.857 +IInStream* CInArchive::CreateStream() 1.858 +{ 1.859 + CMyComPtr<IInStream> stream = m_Stream; 1.860 + return stream.Detach(); 1.861 +} 1.862 + 1.863 +bool CInArchive::SeekInArchive(UInt64 position) 1.864 +{ 1.865 + UInt64 newPosition; 1.866 + if (m_Stream->Seek(position, STREAM_SEEK_SET, &newPosition) != S_OK) 1.867 + return false; 1.868 + return (newPosition == position); 1.869 +} 1.870 + 1.871 +}}