1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/other-licenses/7zstub/src/7zip/Archive/7z/7zIn.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1294 @@ 1.4 +// 7zIn.cpp 1.5 + 1.6 +#include "StdAfx.h" 1.7 + 1.8 +#include "7zIn.h" 1.9 +#include "7zMethods.h" 1.10 +#include "7zDecode.h" 1.11 +#include "../../Common/StreamObjects.h" 1.12 +#include "../../Common/StreamUtils.h" 1.13 +#include "../../../Common/CRC.h" 1.14 + 1.15 +namespace NArchive { 1.16 +namespace N7z { 1.17 + 1.18 +class CStreamSwitch 1.19 +{ 1.20 + CInArchive *_archive; 1.21 + bool _needRemove; 1.22 +public: 1.23 + CStreamSwitch(): _needRemove(false) {} 1.24 + ~CStreamSwitch() { Remove(); } 1.25 + void Remove(); 1.26 + void Set(CInArchive *archive, const Byte *data, size_t size); 1.27 + void Set(CInArchive *archive, const CByteBuffer &byteBuffer); 1.28 + HRESULT Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector); 1.29 +}; 1.30 + 1.31 +void CStreamSwitch::Remove() 1.32 +{ 1.33 + if (_needRemove) 1.34 + { 1.35 + _archive->DeleteByteStream(); 1.36 + _needRemove = false; 1.37 + } 1.38 +} 1.39 + 1.40 +void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size) 1.41 +{ 1.42 + Remove(); 1.43 + _archive = archive; 1.44 + _archive->AddByteStream(data, size); 1.45 + _needRemove = true; 1.46 +} 1.47 + 1.48 +void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer) 1.49 +{ 1.50 + Set(archive, byteBuffer, byteBuffer.GetCapacity()); 1.51 +} 1.52 + 1.53 +HRESULT CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector) 1.54 +{ 1.55 + Remove(); 1.56 + Byte external; 1.57 + RINOK(archive->ReadByte(external)); 1.58 + if (external != 0) 1.59 + { 1.60 + CNum dataIndex; 1.61 + RINOK(archive->ReadNum(dataIndex)); 1.62 + Set(archive, (*dataVector)[dataIndex]); 1.63 + } 1.64 + return S_OK; 1.65 +} 1.66 + 1.67 + 1.68 +CInArchiveException::CInArchiveException(CCauseType cause): 1.69 + Cause(cause) 1.70 +{} 1.71 + 1.72 +HRESULT CInArchive::ReadDirect(IInStream *stream, void *data, UInt32 size, 1.73 + UInt32 *processedSize) 1.74 +{ 1.75 + UInt32 realProcessedSize; 1.76 + HRESULT result = ReadStream(stream, data, size, &realProcessedSize); 1.77 + if(processedSize != NULL) 1.78 + *processedSize = realProcessedSize; 1.79 + _position += realProcessedSize; 1.80 + return result; 1.81 +} 1.82 + 1.83 +HRESULT CInArchive::ReadDirect(void *data, UInt32 size, UInt32 *processedSize) 1.84 +{ 1.85 + return ReadDirect(_stream, data, size, processedSize); 1.86 +} 1.87 + 1.88 +HRESULT CInArchive::SafeReadDirect(void *data, UInt32 size) 1.89 +{ 1.90 + UInt32 realProcessedSize; 1.91 + RINOK(ReadDirect(data, size, &realProcessedSize)); 1.92 + if (realProcessedSize != size) 1.93 + throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive); 1.94 + return S_OK; 1.95 +} 1.96 + 1.97 +HRESULT CInArchive::SafeReadDirectByte(Byte &b) 1.98 +{ 1.99 + return SafeReadDirect(&b, 1); 1.100 +} 1.101 + 1.102 +HRESULT CInArchive::SafeReadDirectUInt32(UInt32 &value) 1.103 +{ 1.104 + value = 0; 1.105 + for (int i = 0; i < 4; i++) 1.106 + { 1.107 + Byte b; 1.108 + RINOK(SafeReadDirectByte(b)); 1.109 + value |= (UInt32(b) << (8 * i)); 1.110 + } 1.111 + return S_OK; 1.112 +} 1.113 + 1.114 +HRESULT CInArchive::SafeReadDirectUInt64(UInt64 &value) 1.115 +{ 1.116 + value = 0; 1.117 + for (int i = 0; i < 8; i++) 1.118 + { 1.119 + Byte b; 1.120 + RINOK(SafeReadDirectByte(b)); 1.121 + value |= (UInt64(b) << (8 * i)); 1.122 + } 1.123 + return S_OK; 1.124 +} 1.125 + 1.126 +HRESULT CInArchive::ReadNumber(UInt64 &value) 1.127 +{ 1.128 + Byte firstByte; 1.129 + RINOK(ReadByte(firstByte)); 1.130 + Byte mask = 0x80; 1.131 + value = 0; 1.132 + for (int i = 0; i < 8; i++) 1.133 + { 1.134 + if ((firstByte & mask) == 0) 1.135 + { 1.136 + UInt64 highPart = firstByte & (mask - 1); 1.137 + value += (highPart << (i * 8)); 1.138 + return S_OK; 1.139 + } 1.140 + Byte b; 1.141 + RINOK(ReadByte(b)); 1.142 + value |= (UInt64(b) << (8 * i)); 1.143 + mask >>= 1; 1.144 + } 1.145 + return S_OK; 1.146 +} 1.147 + 1.148 +HRESULT CInArchive::ReadNum(CNum &value) 1.149 +{ 1.150 + UInt64 value64; 1.151 + RINOK(ReadNumber(value64)); 1.152 + if (value64 > kNumMax) 1.153 + return E_FAIL; 1.154 + value = (CNum)value64; 1.155 + return S_OK; 1.156 +} 1.157 + 1.158 +HRESULT CInArchive::ReadUInt32(UInt32 &value) 1.159 +{ 1.160 + value = 0; 1.161 + for (int i = 0; i < 4; i++) 1.162 + { 1.163 + Byte b; 1.164 + RINOK(ReadByte(b)); 1.165 + value |= (UInt32(b) << (8 * i)); 1.166 + } 1.167 + return S_OK; 1.168 +} 1.169 + 1.170 +HRESULT CInArchive::ReadUInt64(UInt64 &value) 1.171 +{ 1.172 + value = 0; 1.173 + for (int i = 0; i < 8; i++) 1.174 + { 1.175 + Byte b; 1.176 + RINOK(ReadByte(b)); 1.177 + value |= (UInt64(b) << (8 * i)); 1.178 + } 1.179 + return S_OK; 1.180 +} 1.181 + 1.182 +static inline bool TestSignatureCandidate(const void *testBytes) 1.183 +{ 1.184 + for (int i = 0; i < kSignatureSize; i++) 1.185 + if (((const Byte *)testBytes)[i] != kSignature[i]) 1.186 + return false; 1.187 + return true; 1.188 +} 1.189 + 1.190 +#ifdef _7Z_VOL 1.191 +static inline bool TestFinishSignatureCandidate(const void *testBytes) 1.192 +{ 1.193 + for (int i = 0; i < kSignatureSize; i++) 1.194 + if (((const Byte *)testBytes)[i] != kFinishSignature[i]) 1.195 + return false; 1.196 + return true; 1.197 +} 1.198 +#endif 1.199 + 1.200 +HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) 1.201 +{ 1.202 + _position = _arhiveBeginStreamPosition; 1.203 + RINOK(stream->Seek(_arhiveBeginStreamPosition, STREAM_SEEK_SET, NULL)); 1.204 + 1.205 + Byte signature[kSignatureSize]; 1.206 + UInt32 processedSize; 1.207 + RINOK(ReadDirect(stream, signature, kSignatureSize, &processedSize)); 1.208 + if(processedSize != kSignatureSize) 1.209 + return S_FALSE; 1.210 + if (TestSignatureCandidate(signature)) 1.211 + return S_OK; 1.212 + 1.213 + CByteBuffer byteBuffer; 1.214 + const UInt32 kBufferSize = (1 << 16); 1.215 + byteBuffer.SetCapacity(kBufferSize); 1.216 + Byte *buffer = byteBuffer; 1.217 + UInt32 numPrevBytes = kSignatureSize - 1; 1.218 + memmove(buffer, signature + 1, numPrevBytes); 1.219 + UInt64 curTestPos = _arhiveBeginStreamPosition + 1; 1.220 + while(true) 1.221 + { 1.222 + if (searchHeaderSizeLimit != NULL) 1.223 + if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit) 1.224 + return S_FALSE; 1.225 + UInt32 numReadBytes = kBufferSize - numPrevBytes; 1.226 + RINOK(ReadDirect(stream, buffer + numPrevBytes, numReadBytes, &processedSize)); 1.227 + UInt32 numBytesInBuffer = numPrevBytes + processedSize; 1.228 + if (numBytesInBuffer < kSignatureSize) 1.229 + return S_FALSE; 1.230 + UInt32 numTests = numBytesInBuffer - kSignatureSize + 1; 1.231 + for(UInt32 pos = 0; pos < numTests; pos++, curTestPos++) 1.232 + { 1.233 + if (TestSignatureCandidate(buffer + pos)) 1.234 + { 1.235 + _arhiveBeginStreamPosition = curTestPos; 1.236 + _position = curTestPos + kSignatureSize; 1.237 + return stream->Seek(_position, STREAM_SEEK_SET, NULL); 1.238 + } 1.239 + } 1.240 + numPrevBytes = numBytesInBuffer - numTests; 1.241 + memmove(buffer, buffer + numTests, numPrevBytes); 1.242 + } 1.243 +} 1.244 + 1.245 +// Out: _position must point to end of signature 1.246 + 1.247 +#ifdef _7Z_VOL 1.248 +HRESULT CInArchive::FindFinishSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) 1.249 +{ 1.250 + RINOK(stream->Seek(0, STREAM_SEEK_END, &_position)); 1.251 + if (_position < kSignatureSize) 1.252 + return S_FALSE; 1.253 + 1.254 + CByteBuffer byteBuffer; 1.255 + const UInt32 kBufferSize = (1 << 18); 1.256 + byteBuffer.SetCapacity(kBufferSize); 1.257 + Byte *buffer = byteBuffer; 1.258 + UInt32 numPrevBytes = 0; 1.259 + UInt64 limitPos = 0; 1.260 + if (searchHeaderSizeLimit != NULL) 1.261 + if (*searchHeaderSizeLimit < _position) 1.262 + limitPos = _position - *searchHeaderSizeLimit; 1.263 + 1.264 + while(_position >= limitPos) 1.265 + { 1.266 + UInt32 numReadBytes = kBufferSize - numPrevBytes; 1.267 + if (numReadBytes > _position) 1.268 + numReadBytes = (UInt32)_position; 1.269 + UInt32 numBytesInBuffer = numPrevBytes + numReadBytes; 1.270 + if (numBytesInBuffer < kSignatureSize) 1.271 + return S_FALSE; 1.272 + _position -= numReadBytes; 1.273 + RINOK(stream->Seek(_position, STREAM_SEEK_SET, &_position)); 1.274 + UInt32 startPos = kBufferSize - numBytesInBuffer; 1.275 + UInt32 processedSize; 1.276 + RINOK(ReadDirect(stream, buffer + startPos, numReadBytes, &processedSize)); 1.277 + if (processedSize != numReadBytes) 1.278 + return S_FALSE; 1.279 + _position -= processedSize; 1.280 + for(UInt32 pos = kBufferSize; pos >= startPos + kSignatureSize; pos--) 1.281 + { 1.282 + if (TestFinishSignatureCandidate(buffer + pos - kSignatureSize)) 1.283 + { 1.284 + _position += pos - startPos; 1.285 + return stream->Seek(_position, STREAM_SEEK_SET, NULL); 1.286 + } 1.287 + } 1.288 + numPrevBytes = kSignatureSize - 1; 1.289 + memmove(buffer + kBufferSize - numPrevBytes, buffer + startPos + 1, numPrevBytes); 1.290 + } 1.291 + return S_FALSE; 1.292 +} 1.293 +#endif 1.294 + 1.295 +// S_FALSE means that file is not archive 1.296 +HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) 1.297 +{ 1.298 + Close(); 1.299 + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition)) 1.300 + _position = _arhiveBeginStreamPosition; 1.301 + #ifdef _7Z_VOL 1.302 + HRESULT result = FindFinishSignature(stream, searchHeaderSizeLimit); 1.303 + if (result == S_OK) 1.304 + _finishSignature = true; 1.305 + else 1.306 + { 1.307 + if (result != S_FALSE) 1.308 + return result; 1.309 + _finishSignature = false; 1.310 + RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)); 1.311 + } 1.312 + #else 1.313 + RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)); 1.314 + #endif 1.315 + _stream = stream; 1.316 + return S_OK; 1.317 +} 1.318 + 1.319 +void CInArchive::Close() 1.320 +{ 1.321 + _stream.Release(); 1.322 +} 1.323 + 1.324 +HRESULT CInArchive::SkeepData(UInt64 size) 1.325 +{ 1.326 + for (UInt64 i = 0; i < size; i++) 1.327 + { 1.328 + Byte temp; 1.329 + RINOK(ReadByte(temp)); 1.330 + } 1.331 + return S_OK; 1.332 +} 1.333 + 1.334 +HRESULT CInArchive::SkeepData() 1.335 +{ 1.336 + UInt64 size; 1.337 + RINOK(ReadNumber(size)); 1.338 + return SkeepData(size); 1.339 +} 1.340 + 1.341 +HRESULT CInArchive::ReadArchiveProperties(CInArchiveInfo &archiveInfo) 1.342 +{ 1.343 + while(true) 1.344 + { 1.345 + UInt64 type; 1.346 + RINOK(ReadID(type)); 1.347 + if (type == NID::kEnd) 1.348 + break; 1.349 + SkeepData(); 1.350 + } 1.351 + return S_OK; 1.352 +} 1.353 + 1.354 +HRESULT CInArchive::GetNextFolderItem(CFolder &folder) 1.355 +{ 1.356 + CNum numCoders; 1.357 + RINOK(ReadNum(numCoders)); 1.358 + 1.359 + folder.Coders.Clear(); 1.360 + folder.Coders.Reserve((int)numCoders); 1.361 + CNum numInStreams = 0; 1.362 + CNum numOutStreams = 0; 1.363 + CNum i; 1.364 + for (i = 0; i < numCoders; i++) 1.365 + { 1.366 + folder.Coders.Add(CCoderInfo()); 1.367 + CCoderInfo &coder = folder.Coders.Back(); 1.368 + 1.369 + while (true) 1.370 + { 1.371 + coder.AltCoders.Add(CAltCoderInfo()); 1.372 + CAltCoderInfo &altCoder = coder.AltCoders.Back(); 1.373 + Byte mainByte; 1.374 + RINOK(ReadByte(mainByte)); 1.375 + altCoder.MethodID.IDSize = mainByte & 0xF; 1.376 + RINOK(ReadBytes(altCoder.MethodID.ID, altCoder.MethodID.IDSize)); 1.377 + if ((mainByte & 0x10) != 0) 1.378 + { 1.379 + RINOK(ReadNum(coder.NumInStreams)); 1.380 + RINOK(ReadNum(coder.NumOutStreams)); 1.381 + } 1.382 + else 1.383 + { 1.384 + coder.NumInStreams = 1; 1.385 + coder.NumOutStreams = 1; 1.386 + } 1.387 + if ((mainByte & 0x20) != 0) 1.388 + { 1.389 + CNum propertiesSize = 0; 1.390 + RINOK(ReadNum(propertiesSize)); 1.391 + altCoder.Properties.SetCapacity((size_t)propertiesSize); 1.392 + RINOK(ReadBytes((Byte *)altCoder.Properties, (size_t)propertiesSize)); 1.393 + } 1.394 + if ((mainByte & 0x80) == 0) 1.395 + break; 1.396 + } 1.397 + numInStreams += coder.NumInStreams; 1.398 + numOutStreams += coder.NumOutStreams; 1.399 + } 1.400 + 1.401 + CNum numBindPairs; 1.402 + // RINOK(ReadNumber(numBindPairs)); 1.403 + numBindPairs = numOutStreams - 1; 1.404 + folder.BindPairs.Clear(); 1.405 + folder.BindPairs.Reserve(numBindPairs); 1.406 + for (i = 0; i < numBindPairs; i++) 1.407 + { 1.408 + CBindPair bindPair; 1.409 + RINOK(ReadNum(bindPair.InIndex)); 1.410 + RINOK(ReadNum(bindPair.OutIndex)); 1.411 + folder.BindPairs.Add(bindPair); 1.412 + } 1.413 + 1.414 + CNum numPackedStreams = numInStreams - numBindPairs; 1.415 + folder.PackStreams.Reserve(numPackedStreams); 1.416 + if (numPackedStreams == 1) 1.417 + { 1.418 + for (CNum j = 0; j < numInStreams; j++) 1.419 + if (folder.FindBindPairForInStream(j) < 0) 1.420 + { 1.421 + folder.PackStreams.Add(j); 1.422 + break; 1.423 + } 1.424 + } 1.425 + else 1.426 + for(i = 0; i < numPackedStreams; i++) 1.427 + { 1.428 + CNum packStreamInfo; 1.429 + RINOK(ReadNum(packStreamInfo)); 1.430 + folder.PackStreams.Add(packStreamInfo); 1.431 + } 1.432 + 1.433 + return S_OK; 1.434 +} 1.435 + 1.436 +HRESULT CInArchive::WaitAttribute(UInt64 attribute) 1.437 +{ 1.438 + while(true) 1.439 + { 1.440 + UInt64 type; 1.441 + RINOK(ReadID(type)); 1.442 + if (type == attribute) 1.443 + return S_OK; 1.444 + if (type == NID::kEnd) 1.445 + return S_FALSE; 1.446 + RINOK(SkeepData()); 1.447 + } 1.448 +} 1.449 + 1.450 +HRESULT CInArchive::ReadHashDigests(int numItems, 1.451 + CRecordVector<bool> &digestsDefined, 1.452 + CRecordVector<UInt32> &digests) 1.453 +{ 1.454 + RINOK(ReadBoolVector2(numItems, digestsDefined)); 1.455 + digests.Clear(); 1.456 + digests.Reserve(numItems); 1.457 + for(int i = 0; i < numItems; i++) 1.458 + { 1.459 + UInt32 crc; 1.460 + if (digestsDefined[i]) 1.461 + RINOK(ReadUInt32(crc)); 1.462 + digests.Add(crc); 1.463 + } 1.464 + return S_OK; 1.465 +} 1.466 + 1.467 +HRESULT CInArchive::ReadPackInfo( 1.468 + UInt64 &dataOffset, 1.469 + CRecordVector<UInt64> &packSizes, 1.470 + CRecordVector<bool> &packCRCsDefined, 1.471 + CRecordVector<UInt32> &packCRCs) 1.472 +{ 1.473 + RINOK(ReadNumber(dataOffset)); 1.474 + CNum numPackStreams; 1.475 + RINOK(ReadNum(numPackStreams)); 1.476 + 1.477 + RINOK(WaitAttribute(NID::kSize)); 1.478 + packSizes.Clear(); 1.479 + packSizes.Reserve(numPackStreams); 1.480 + for(CNum i = 0; i < numPackStreams; i++) 1.481 + { 1.482 + UInt64 size; 1.483 + RINOK(ReadNumber(size)); 1.484 + packSizes.Add(size); 1.485 + } 1.486 + 1.487 + UInt64 type; 1.488 + while(true) 1.489 + { 1.490 + RINOK(ReadID(type)); 1.491 + if (type == NID::kEnd) 1.492 + break; 1.493 + if (type == NID::kCRC) 1.494 + { 1.495 + RINOK(ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs)); 1.496 + continue; 1.497 + } 1.498 + RINOK(SkeepData()); 1.499 + } 1.500 + if (packCRCsDefined.IsEmpty()) 1.501 + { 1.502 + packCRCsDefined.Reserve(numPackStreams); 1.503 + packCRCsDefined.Clear(); 1.504 + packCRCs.Reserve(numPackStreams); 1.505 + packCRCs.Clear(); 1.506 + for(CNum i = 0; i < numPackStreams; i++) 1.507 + { 1.508 + packCRCsDefined.Add(false); 1.509 + packCRCs.Add(0); 1.510 + } 1.511 + } 1.512 + return S_OK; 1.513 +} 1.514 + 1.515 +HRESULT CInArchive::ReadUnPackInfo( 1.516 + const CObjectVector<CByteBuffer> *dataVector, 1.517 + CObjectVector<CFolder> &folders) 1.518 +{ 1.519 + RINOK(WaitAttribute(NID::kFolder)); 1.520 + CNum numFolders; 1.521 + RINOK(ReadNum(numFolders)); 1.522 + 1.523 + { 1.524 + CStreamSwitch streamSwitch; 1.525 + RINOK(streamSwitch.Set(this, dataVector)); 1.526 + folders.Clear(); 1.527 + folders.Reserve((UInt32)numFolders); 1.528 + for(CNum i = 0; i < numFolders; i++) 1.529 + { 1.530 + folders.Add(CFolder()); 1.531 + RINOK(GetNextFolderItem(folders.Back())); 1.532 + } 1.533 + } 1.534 + 1.535 + RINOK(WaitAttribute(NID::kCodersUnPackSize)); 1.536 + 1.537 + CNum i; 1.538 + for(i = 0; i < numFolders; i++) 1.539 + { 1.540 + CFolder &folder = folders[i]; 1.541 + CNum numOutStreams = folder.GetNumOutStreams(); 1.542 + folder.UnPackSizes.Reserve(numOutStreams); 1.543 + for(CNum j = 0; j < numOutStreams; j++) 1.544 + { 1.545 + UInt64 unPackSize; 1.546 + RINOK(ReadNumber(unPackSize)); 1.547 + folder.UnPackSizes.Add(unPackSize); 1.548 + } 1.549 + } 1.550 + 1.551 + while(true) 1.552 + { 1.553 + UInt64 type; 1.554 + RINOK(ReadID(type)); 1.555 + if (type == NID::kEnd) 1.556 + return S_OK; 1.557 + if (type == NID::kCRC) 1.558 + { 1.559 + CRecordVector<bool> crcsDefined; 1.560 + CRecordVector<UInt32> crcs; 1.561 + RINOK(ReadHashDigests(numFolders, crcsDefined, crcs)); 1.562 + for(i = 0; i < numFolders; i++) 1.563 + { 1.564 + CFolder &folder = folders[i]; 1.565 + folder.UnPackCRCDefined = crcsDefined[i]; 1.566 + folder.UnPackCRC = crcs[i]; 1.567 + } 1.568 + continue; 1.569 + } 1.570 + RINOK(SkeepData()); 1.571 + } 1.572 +} 1.573 + 1.574 +HRESULT CInArchive::ReadSubStreamsInfo( 1.575 + const CObjectVector<CFolder> &folders, 1.576 + CRecordVector<CNum> &numUnPackStreamsInFolders, 1.577 + CRecordVector<UInt64> &unPackSizes, 1.578 + CRecordVector<bool> &digestsDefined, 1.579 + CRecordVector<UInt32> &digests) 1.580 +{ 1.581 + numUnPackStreamsInFolders.Clear(); 1.582 + numUnPackStreamsInFolders.Reserve(folders.Size()); 1.583 + UInt64 type; 1.584 + while(true) 1.585 + { 1.586 + RINOK(ReadID(type)); 1.587 + if (type == NID::kNumUnPackStream) 1.588 + { 1.589 + for(int i = 0; i < folders.Size(); i++) 1.590 + { 1.591 + CNum value; 1.592 + RINOK(ReadNum(value)); 1.593 + numUnPackStreamsInFolders.Add(value); 1.594 + } 1.595 + continue; 1.596 + } 1.597 + if (type == NID::kCRC || type == NID::kSize) 1.598 + break; 1.599 + if (type == NID::kEnd) 1.600 + break; 1.601 + RINOK(SkeepData()); 1.602 + } 1.603 + 1.604 + if (numUnPackStreamsInFolders.IsEmpty()) 1.605 + for(int i = 0; i < folders.Size(); i++) 1.606 + numUnPackStreamsInFolders.Add(1); 1.607 + 1.608 + int i; 1.609 + for(i = 0; i < numUnPackStreamsInFolders.Size(); i++) 1.610 + { 1.611 + // v3.13 incorrectly worked with empty folders 1.612 + // v4.07: we check that folder is empty 1.613 + CNum numSubstreams = numUnPackStreamsInFolders[i]; 1.614 + if (numSubstreams == 0) 1.615 + continue; 1.616 + UInt64 sum = 0; 1.617 + for (CNum j = 1; j < numSubstreams; j++) 1.618 + { 1.619 + UInt64 size; 1.620 + if (type == NID::kSize) 1.621 + { 1.622 + RINOK(ReadNumber(size)); 1.623 + unPackSizes.Add(size); 1.624 + sum += size; 1.625 + } 1.626 + } 1.627 + unPackSizes.Add(folders[i].GetUnPackSize() - sum); 1.628 + } 1.629 + if (type == NID::kSize) 1.630 + { 1.631 + RINOK(ReadID(type)); 1.632 + } 1.633 + 1.634 + int numDigests = 0; 1.635 + int numDigestsTotal = 0; 1.636 + for(i = 0; i < folders.Size(); i++) 1.637 + { 1.638 + CNum numSubstreams = numUnPackStreamsInFolders[i]; 1.639 + if (numSubstreams != 1 || !folders[i].UnPackCRCDefined) 1.640 + numDigests += numSubstreams; 1.641 + numDigestsTotal += numSubstreams; 1.642 + } 1.643 + 1.644 + while(true) 1.645 + { 1.646 + if (type == NID::kCRC) 1.647 + { 1.648 + CRecordVector<bool> digestsDefined2; 1.649 + CRecordVector<UInt32> digests2; 1.650 + RINOK(ReadHashDigests(numDigests, digestsDefined2, digests2)); 1.651 + int digestIndex = 0; 1.652 + for (i = 0; i < folders.Size(); i++) 1.653 + { 1.654 + CNum numSubstreams = numUnPackStreamsInFolders[i]; 1.655 + const CFolder &folder = folders[i]; 1.656 + if (numSubstreams == 1 && folder.UnPackCRCDefined) 1.657 + { 1.658 + digestsDefined.Add(true); 1.659 + digests.Add(folder.UnPackCRC); 1.660 + } 1.661 + else 1.662 + for (CNum j = 0; j < numSubstreams; j++, digestIndex++) 1.663 + { 1.664 + digestsDefined.Add(digestsDefined2[digestIndex]); 1.665 + digests.Add(digests2[digestIndex]); 1.666 + } 1.667 + } 1.668 + } 1.669 + else if (type == NID::kEnd) 1.670 + { 1.671 + if (digestsDefined.IsEmpty()) 1.672 + { 1.673 + digestsDefined.Clear(); 1.674 + digests.Clear(); 1.675 + for (int i = 0; i < numDigestsTotal; i++) 1.676 + { 1.677 + digestsDefined.Add(false); 1.678 + digests.Add(0); 1.679 + } 1.680 + } 1.681 + return S_OK; 1.682 + } 1.683 + else 1.684 + { 1.685 + RINOK(SkeepData()); 1.686 + } 1.687 + RINOK(ReadID(type)); 1.688 + } 1.689 +} 1.690 + 1.691 +HRESULT CInArchive::ReadStreamsInfo( 1.692 + const CObjectVector<CByteBuffer> *dataVector, 1.693 + UInt64 &dataOffset, 1.694 + CRecordVector<UInt64> &packSizes, 1.695 + CRecordVector<bool> &packCRCsDefined, 1.696 + CRecordVector<UInt32> &packCRCs, 1.697 + CObjectVector<CFolder> &folders, 1.698 + CRecordVector<CNum> &numUnPackStreamsInFolders, 1.699 + CRecordVector<UInt64> &unPackSizes, 1.700 + CRecordVector<bool> &digestsDefined, 1.701 + CRecordVector<UInt32> &digests) 1.702 +{ 1.703 + while(true) 1.704 + { 1.705 + UInt64 type; 1.706 + RINOK(ReadID(type)); 1.707 + switch(type) 1.708 + { 1.709 + case NID::kEnd: 1.710 + return S_OK; 1.711 + case NID::kPackInfo: 1.712 + { 1.713 + RINOK(ReadPackInfo(dataOffset, packSizes, 1.714 + packCRCsDefined, packCRCs)); 1.715 + break; 1.716 + } 1.717 + case NID::kUnPackInfo: 1.718 + { 1.719 + RINOK(ReadUnPackInfo(dataVector, folders)); 1.720 + break; 1.721 + } 1.722 + case NID::kSubStreamsInfo: 1.723 + { 1.724 + RINOK(ReadSubStreamsInfo(folders, numUnPackStreamsInFolders, 1.725 + unPackSizes, digestsDefined, digests)); 1.726 + break; 1.727 + } 1.728 + } 1.729 + } 1.730 +} 1.731 + 1.732 +HRESULT CInArchive::ReadFileNames(CObjectVector<CFileItem> &files) 1.733 +{ 1.734 + for(int i = 0; i < files.Size(); i++) 1.735 + { 1.736 + UString &name = files[i].Name; 1.737 + name.Empty(); 1.738 + while (true) 1.739 + { 1.740 + wchar_t c; 1.741 + RINOK(ReadWideCharLE(c)); 1.742 + if (c == L'\0') 1.743 + break; 1.744 + name += c; 1.745 + } 1.746 + } 1.747 + return S_OK; 1.748 +} 1.749 + 1.750 +HRESULT CInArchive::ReadBoolVector(int numItems, CBoolVector &v) 1.751 +{ 1.752 + v.Clear(); 1.753 + v.Reserve(numItems); 1.754 + Byte b; 1.755 + Byte mask = 0; 1.756 + for(int i = 0; i < numItems; i++) 1.757 + { 1.758 + if (mask == 0) 1.759 + { 1.760 + RINOK(ReadByte(b)); 1.761 + mask = 0x80; 1.762 + } 1.763 + v.Add((b & mask) != 0); 1.764 + mask >>= 1; 1.765 + } 1.766 + return S_OK; 1.767 +} 1.768 + 1.769 +HRESULT CInArchive::ReadBoolVector2(int numItems, CBoolVector &v) 1.770 +{ 1.771 + Byte allAreDefined; 1.772 + RINOK(ReadByte(allAreDefined)); 1.773 + if (allAreDefined == 0) 1.774 + return ReadBoolVector(numItems, v); 1.775 + v.Clear(); 1.776 + v.Reserve(numItems); 1.777 + for (int i = 0; i < numItems; i++) 1.778 + v.Add(true); 1.779 + return S_OK; 1.780 +} 1.781 + 1.782 +HRESULT CInArchive::ReadTime(const CObjectVector<CByteBuffer> &dataVector, 1.783 + CObjectVector<CFileItem> &files, UInt64 type) 1.784 +{ 1.785 + CBoolVector boolVector; 1.786 + RINOK(ReadBoolVector2(files.Size(), boolVector)) 1.787 + 1.788 + CStreamSwitch streamSwitch; 1.789 + RINOK(streamSwitch.Set(this, &dataVector)); 1.790 + 1.791 + for(int i = 0; i < files.Size(); i++) 1.792 + { 1.793 + CFileItem &file = files[i]; 1.794 + CArchiveFileTime fileTime; 1.795 + bool defined = boolVector[i]; 1.796 + if (defined) 1.797 + { 1.798 + UInt32 low, high; 1.799 + RINOK(ReadUInt32(low)); 1.800 + RINOK(ReadUInt32(high)); 1.801 + fileTime.dwLowDateTime = low; 1.802 + fileTime.dwHighDateTime = high; 1.803 + } 1.804 + switch(type) 1.805 + { 1.806 + case NID::kCreationTime: 1.807 + file.IsCreationTimeDefined = defined; 1.808 + if (defined) 1.809 + file.CreationTime = fileTime; 1.810 + break; 1.811 + case NID::kLastWriteTime: 1.812 + file.IsLastWriteTimeDefined = defined; 1.813 + if (defined) 1.814 + file.LastWriteTime = fileTime; 1.815 + break; 1.816 + case NID::kLastAccessTime: 1.817 + file.IsLastAccessTimeDefined = defined; 1.818 + if (defined) 1.819 + file.LastAccessTime = fileTime; 1.820 + break; 1.821 + } 1.822 + } 1.823 + return S_OK; 1.824 +} 1.825 + 1.826 +HRESULT CInArchive::ReadAndDecodePackedStreams(UInt64 baseOffset, 1.827 + UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector 1.828 + #ifndef _NO_CRYPTO 1.829 + , ICryptoGetTextPassword *getTextPassword 1.830 + #endif 1.831 + ) 1.832 +{ 1.833 + CRecordVector<UInt64> packSizes; 1.834 + CRecordVector<bool> packCRCsDefined; 1.835 + CRecordVector<UInt32> packCRCs; 1.836 + CObjectVector<CFolder> folders; 1.837 + 1.838 + CRecordVector<CNum> numUnPackStreamsInFolders; 1.839 + CRecordVector<UInt64> unPackSizes; 1.840 + CRecordVector<bool> digestsDefined; 1.841 + CRecordVector<UInt32> digests; 1.842 + 1.843 + RINOK(ReadStreamsInfo(NULL, 1.844 + dataOffset, 1.845 + packSizes, 1.846 + packCRCsDefined, 1.847 + packCRCs, 1.848 + folders, 1.849 + numUnPackStreamsInFolders, 1.850 + unPackSizes, 1.851 + digestsDefined, 1.852 + digests)); 1.853 + 1.854 + // database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader; 1.855 + 1.856 + CNum packIndex = 0; 1.857 + CDecoder decoder( 1.858 + #ifdef _ST_MODE 1.859 + false 1.860 + #else 1.861 + true 1.862 + #endif 1.863 + ); 1.864 + UInt64 dataStartPos = baseOffset + dataOffset; 1.865 + for(int i = 0; i < folders.Size(); i++) 1.866 + { 1.867 + const CFolder &folder = folders[i]; 1.868 + dataVector.Add(CByteBuffer()); 1.869 + CByteBuffer &data = dataVector.Back(); 1.870 + UInt64 unPackSize = folder.GetUnPackSize(); 1.871 + if (unPackSize > kNumMax) 1.872 + return E_FAIL; 1.873 + if (unPackSize > 0xFFFFFFFF) 1.874 + return E_FAIL; 1.875 + data.SetCapacity((size_t)unPackSize); 1.876 + 1.877 + CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2; 1.878 + CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; 1.879 + outStreamSpec->Init(data, (size_t)unPackSize); 1.880 + 1.881 + HRESULT result = decoder.Decode(_stream, dataStartPos, 1.882 + &packSizes[packIndex], folder, outStream, NULL 1.883 + #ifndef _NO_CRYPTO 1.884 + , getTextPassword 1.885 + #endif 1.886 + #ifdef COMPRESS_MT 1.887 + , false, 1 1.888 + #endif 1.889 + ); 1.890 + RINOK(result); 1.891 + 1.892 + if (folder.UnPackCRCDefined) 1.893 + if (!CCRC::VerifyDigest(folder.UnPackCRC, data, (UInt32)unPackSize)) 1.894 + throw CInArchiveException(CInArchiveException::kIncorrectHeader); 1.895 + for (int j = 0; j < folder.PackStreams.Size(); j++) 1.896 + dataStartPos += packSizes[packIndex++]; 1.897 + } 1.898 + return S_OK; 1.899 +} 1.900 + 1.901 +HRESULT CInArchive::ReadHeader(CArchiveDatabaseEx &database 1.902 + #ifndef _NO_CRYPTO 1.903 + , ICryptoGetTextPassword *getTextPassword 1.904 + #endif 1.905 + ) 1.906 +{ 1.907 + UInt64 type; 1.908 + RINOK(ReadID(type)); 1.909 + 1.910 + if (type == NID::kArchiveProperties) 1.911 + { 1.912 + RINOK(ReadArchiveProperties(database.ArchiveInfo)); 1.913 + RINOK(ReadID(type)); 1.914 + } 1.915 + 1.916 + CObjectVector<CByteBuffer> dataVector; 1.917 + 1.918 + if (type == NID::kAdditionalStreamsInfo) 1.919 + { 1.920 + HRESULT result = ReadAndDecodePackedStreams( 1.921 + database.ArchiveInfo.StartPositionAfterHeader, 1.922 + database.ArchiveInfo.DataStartPosition2, 1.923 + dataVector 1.924 + #ifndef _NO_CRYPTO 1.925 + , getTextPassword 1.926 + #endif 1.927 + ); 1.928 + RINOK(result); 1.929 + database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader; 1.930 + RINOK(ReadID(type)); 1.931 + } 1.932 + 1.933 + CRecordVector<UInt64> unPackSizes; 1.934 + CRecordVector<bool> digestsDefined; 1.935 + CRecordVector<UInt32> digests; 1.936 + 1.937 + if (type == NID::kMainStreamsInfo) 1.938 + { 1.939 + RINOK(ReadStreamsInfo(&dataVector, 1.940 + database.ArchiveInfo.DataStartPosition, 1.941 + database.PackSizes, 1.942 + database.PackCRCsDefined, 1.943 + database.PackCRCs, 1.944 + database.Folders, 1.945 + database.NumUnPackStreamsVector, 1.946 + unPackSizes, 1.947 + digestsDefined, 1.948 + digests)); 1.949 + database.ArchiveInfo.DataStartPosition += database.ArchiveInfo.StartPositionAfterHeader; 1.950 + RINOK(ReadID(type)); 1.951 + } 1.952 + else 1.953 + { 1.954 + for(int i = 0; i < database.Folders.Size(); i++) 1.955 + { 1.956 + database.NumUnPackStreamsVector.Add(1); 1.957 + CFolder &folder = database.Folders[i]; 1.958 + unPackSizes.Add(folder.GetUnPackSize()); 1.959 + digestsDefined.Add(folder.UnPackCRCDefined); 1.960 + digests.Add(folder.UnPackCRC); 1.961 + } 1.962 + } 1.963 + 1.964 + database.Files.Clear(); 1.965 + 1.966 + if (type == NID::kEnd) 1.967 + return S_OK; 1.968 + if (type != NID::kFilesInfo) 1.969 + throw CInArchiveException(CInArchiveException::kIncorrectHeader); 1.970 + 1.971 + CNum numFiles; 1.972 + RINOK(ReadNum(numFiles)); 1.973 + database.Files.Reserve(numFiles); 1.974 + CNum i; 1.975 + for(i = 0; i < numFiles; i++) 1.976 + database.Files.Add(CFileItem()); 1.977 + 1.978 + database.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize); 1.979 + if (!database.PackSizes.IsEmpty()) 1.980 + database.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo); 1.981 + if (numFiles > 0 && !digests.IsEmpty()) 1.982 + database.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC); 1.983 + 1.984 + CBoolVector emptyStreamVector; 1.985 + emptyStreamVector.Reserve((int)numFiles); 1.986 + for(i = 0; i < numFiles; i++) 1.987 + emptyStreamVector.Add(false); 1.988 + CBoolVector emptyFileVector; 1.989 + CBoolVector antiFileVector; 1.990 + CNum numEmptyStreams = 0; 1.991 + 1.992 + // int sizePrev = -1; 1.993 + // int posPrev = 0; 1.994 + 1.995 + while(true) 1.996 + { 1.997 + /* 1.998 + if (sizePrev >= 0) 1.999 + if (sizePrev != _inByteBack->GetProcessedSize() - posPrev) 1.1000 + throw 2; 1.1001 + */ 1.1002 + UInt64 type; 1.1003 + RINOK(ReadID(type)); 1.1004 + if (type == NID::kEnd) 1.1005 + break; 1.1006 + UInt64 size; 1.1007 + RINOK(ReadNumber(size)); 1.1008 + 1.1009 + // sizePrev = size; 1.1010 + // posPrev = _inByteBack->GetProcessedSize(); 1.1011 + 1.1012 + database.ArchiveInfo.FileInfoPopIDs.Add(type); 1.1013 + switch(type) 1.1014 + { 1.1015 + case NID::kName: 1.1016 + { 1.1017 + CStreamSwitch streamSwitch; 1.1018 + RINOK(streamSwitch.Set(this, &dataVector)); 1.1019 + RINOK(ReadFileNames(database.Files)) 1.1020 + break; 1.1021 + } 1.1022 + case NID::kWinAttributes: 1.1023 + { 1.1024 + CBoolVector boolVector; 1.1025 + RINOK(ReadBoolVector2(database.Files.Size(), boolVector)) 1.1026 + CStreamSwitch streamSwitch; 1.1027 + RINOK(streamSwitch.Set(this, &dataVector)); 1.1028 + for(i = 0; i < numFiles; i++) 1.1029 + { 1.1030 + CFileItem &file = database.Files[i]; 1.1031 + if (file.AreAttributesDefined = boolVector[i]) 1.1032 + { 1.1033 + RINOK(ReadUInt32(file.Attributes)); 1.1034 + } 1.1035 + } 1.1036 + break; 1.1037 + } 1.1038 + case NID::kStartPos: 1.1039 + { 1.1040 + CBoolVector boolVector; 1.1041 + RINOK(ReadBoolVector2(database.Files.Size(), boolVector)) 1.1042 + CStreamSwitch streamSwitch; 1.1043 + RINOK(streamSwitch.Set(this, &dataVector)); 1.1044 + for(i = 0; i < numFiles; i++) 1.1045 + { 1.1046 + CFileItem &file = database.Files[i]; 1.1047 + if (file.IsStartPosDefined = boolVector[i]) 1.1048 + { 1.1049 + RINOK(ReadUInt64(file.StartPos)); 1.1050 + } 1.1051 + } 1.1052 + break; 1.1053 + } 1.1054 + case NID::kEmptyStream: 1.1055 + { 1.1056 + RINOK(ReadBoolVector(numFiles, emptyStreamVector)) 1.1057 + for (i = 0; i < (CNum)emptyStreamVector.Size(); i++) 1.1058 + if (emptyStreamVector[i]) 1.1059 + numEmptyStreams++; 1.1060 + emptyFileVector.Reserve(numEmptyStreams); 1.1061 + antiFileVector.Reserve(numEmptyStreams); 1.1062 + for (i = 0; i < numEmptyStreams; i++) 1.1063 + { 1.1064 + emptyFileVector.Add(false); 1.1065 + antiFileVector.Add(false); 1.1066 + } 1.1067 + break; 1.1068 + } 1.1069 + case NID::kEmptyFile: 1.1070 + { 1.1071 + RINOK(ReadBoolVector(numEmptyStreams, emptyFileVector)) 1.1072 + break; 1.1073 + } 1.1074 + case NID::kAnti: 1.1075 + { 1.1076 + RINOK(ReadBoolVector(numEmptyStreams, antiFileVector)) 1.1077 + break; 1.1078 + } 1.1079 + case NID::kCreationTime: 1.1080 + case NID::kLastWriteTime: 1.1081 + case NID::kLastAccessTime: 1.1082 + { 1.1083 + RINOK(ReadTime(dataVector, database.Files, type)) 1.1084 + break; 1.1085 + } 1.1086 + default: 1.1087 + { 1.1088 + database.ArchiveInfo.FileInfoPopIDs.DeleteBack(); 1.1089 + RINOK(SkeepData(size)); 1.1090 + } 1.1091 + } 1.1092 + } 1.1093 + 1.1094 + CNum emptyFileIndex = 0; 1.1095 + CNum sizeIndex = 0; 1.1096 + for(i = 0; i < numFiles; i++) 1.1097 + { 1.1098 + CFileItem &file = database.Files[i]; 1.1099 + file.HasStream = !emptyStreamVector[i]; 1.1100 + if(file.HasStream) 1.1101 + { 1.1102 + file.IsDirectory = false; 1.1103 + file.IsAnti = false; 1.1104 + file.UnPackSize = unPackSizes[sizeIndex]; 1.1105 + file.FileCRC = digests[sizeIndex]; 1.1106 + file.IsFileCRCDefined = digestsDefined[sizeIndex]; 1.1107 + sizeIndex++; 1.1108 + } 1.1109 + else 1.1110 + { 1.1111 + file.IsDirectory = !emptyFileVector[emptyFileIndex]; 1.1112 + file.IsAnti = antiFileVector[emptyFileIndex]; 1.1113 + emptyFileIndex++; 1.1114 + file.UnPackSize = 0; 1.1115 + file.IsFileCRCDefined = false; 1.1116 + } 1.1117 + } 1.1118 + return S_OK; 1.1119 +} 1.1120 + 1.1121 + 1.1122 +void CArchiveDatabaseEx::FillFolderStartPackStream() 1.1123 +{ 1.1124 + FolderStartPackStreamIndex.Clear(); 1.1125 + FolderStartPackStreamIndex.Reserve(Folders.Size()); 1.1126 + CNum startPos = 0; 1.1127 + for(int i = 0; i < Folders.Size(); i++) 1.1128 + { 1.1129 + FolderStartPackStreamIndex.Add(startPos); 1.1130 + startPos += (CNum)Folders[i].PackStreams.Size(); 1.1131 + } 1.1132 +} 1.1133 + 1.1134 +void CArchiveDatabaseEx::FillStartPos() 1.1135 +{ 1.1136 + PackStreamStartPositions.Clear(); 1.1137 + PackStreamStartPositions.Reserve(PackSizes.Size()); 1.1138 + UInt64 startPos = 0; 1.1139 + for(int i = 0; i < PackSizes.Size(); i++) 1.1140 + { 1.1141 + PackStreamStartPositions.Add(startPos); 1.1142 + startPos += PackSizes[i]; 1.1143 + } 1.1144 +} 1.1145 + 1.1146 +void CArchiveDatabaseEx::FillFolderStartFileIndex() 1.1147 +{ 1.1148 + FolderStartFileIndex.Clear(); 1.1149 + FolderStartFileIndex.Reserve(Folders.Size()); 1.1150 + FileIndexToFolderIndexMap.Clear(); 1.1151 + FileIndexToFolderIndexMap.Reserve(Files.Size()); 1.1152 + 1.1153 + int folderIndex = 0; 1.1154 + CNum indexInFolder = 0; 1.1155 + for (int i = 0; i < Files.Size(); i++) 1.1156 + { 1.1157 + const CFileItem &file = Files[i]; 1.1158 + bool emptyStream = !file.HasStream; 1.1159 + if (emptyStream && indexInFolder == 0) 1.1160 + { 1.1161 + FileIndexToFolderIndexMap.Add(kNumNoIndex); 1.1162 + continue; 1.1163 + } 1.1164 + if (indexInFolder == 0) 1.1165 + { 1.1166 + // v3.13 incorrectly worked with empty folders 1.1167 + // v4.07: Loop for skipping empty folders 1.1168 + while(true) 1.1169 + { 1.1170 + if (folderIndex >= Folders.Size()) 1.1171 + throw CInArchiveException(CInArchiveException::kIncorrectHeader); 1.1172 + FolderStartFileIndex.Add(i); // check it 1.1173 + if (NumUnPackStreamsVector[folderIndex] != 0) 1.1174 + break; 1.1175 + folderIndex++; 1.1176 + } 1.1177 + } 1.1178 + FileIndexToFolderIndexMap.Add(folderIndex); 1.1179 + if (emptyStream) 1.1180 + continue; 1.1181 + indexInFolder++; 1.1182 + if (indexInFolder >= NumUnPackStreamsVector[folderIndex]) 1.1183 + { 1.1184 + folderIndex++; 1.1185 + indexInFolder = 0; 1.1186 + } 1.1187 + } 1.1188 +} 1.1189 + 1.1190 +HRESULT CInArchive::ReadDatabase(CArchiveDatabaseEx &database 1.1191 + #ifndef _NO_CRYPTO 1.1192 + , ICryptoGetTextPassword *getTextPassword 1.1193 + #endif 1.1194 + ) 1.1195 +{ 1.1196 + database.Clear(); 1.1197 + database.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition; 1.1198 + 1.1199 + 1.1200 + RINOK(SafeReadDirect(&database.ArchiveInfo.Version.Major, 1)); 1.1201 + RINOK(SafeReadDirect(&database.ArchiveInfo.Version.Minor, 1)); 1.1202 + if (database.ArchiveInfo.Version.Major != kMajorVersion) 1.1203 + throw CInArchiveException(CInArchiveException::kUnsupportedVersion); 1.1204 + 1.1205 + #ifdef _7Z_VOL 1.1206 + if (_finishSignature) 1.1207 + { 1.1208 + RINOK(_stream->Seek(_position - (4 + kFinishHeaderSize) - 1.1209 + (kSignatureSize + 2), STREAM_SEEK_SET, &_position)); 1.1210 + } 1.1211 + #endif 1.1212 + 1.1213 + UInt32 crcFromArchive; 1.1214 + RINOK(SafeReadDirectUInt32(crcFromArchive)); 1.1215 + 1.1216 + UInt64 nextHeaderOffset; 1.1217 + UInt64 nextHeaderSize; 1.1218 + UInt32 nextHeaderCRC; 1.1219 + CCRC crc; 1.1220 + RINOK(SafeReadDirectUInt64(nextHeaderOffset)); 1.1221 + crc.UpdateUInt64(nextHeaderOffset); 1.1222 + RINOK(SafeReadDirectUInt64(nextHeaderSize)); 1.1223 + crc.UpdateUInt64(nextHeaderSize); 1.1224 + RINOK(SafeReadDirectUInt32(nextHeaderCRC)); 1.1225 + crc.UpdateUInt32(nextHeaderCRC); 1.1226 + 1.1227 + #ifdef _7Z_VOL 1.1228 + UInt64 archiveStartOffset; // data offset from end if that struct 1.1229 + UInt64 additionalStartBlockSize; // start signature & start header size 1.1230 + if (_finishSignature) 1.1231 + { 1.1232 + RINOK(SafeReadDirectUInt64(archiveStartOffset)); 1.1233 + crc.UpdateUInt64(archiveStartOffset); 1.1234 + RINOK(SafeReadDirectUInt64(additionalStartBlockSize)); 1.1235 + crc.UpdateUInt64(additionalStartBlockSize); 1.1236 + database.ArchiveInfo.StartPositionAfterHeader = _position + archiveStartOffset; 1.1237 + } 1.1238 + else 1.1239 + #endif 1.1240 + { 1.1241 + database.ArchiveInfo.StartPositionAfterHeader = _position; 1.1242 + } 1.1243 + if (crc.GetDigest() != crcFromArchive) 1.1244 + throw CInArchiveException(CInArchiveException::kIncorrectHeader); 1.1245 + 1.1246 + if (nextHeaderSize == 0) 1.1247 + return S_OK; 1.1248 + 1.1249 + if (nextHeaderSize >= 0xFFFFFFFF) 1.1250 + return E_FAIL; 1.1251 + 1.1252 + RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, &_position)); 1.1253 + 1.1254 + CByteBuffer buffer2; 1.1255 + buffer2.SetCapacity((size_t)nextHeaderSize); 1.1256 + RINOK(SafeReadDirect(buffer2, (UInt32)nextHeaderSize)); 1.1257 + if (!CCRC::VerifyDigest(nextHeaderCRC, buffer2, (UInt32)nextHeaderSize)) 1.1258 + throw CInArchiveException(CInArchiveException::kIncorrectHeader); 1.1259 + 1.1260 + CStreamSwitch streamSwitch; 1.1261 + streamSwitch.Set(this, buffer2); 1.1262 + 1.1263 + CObjectVector<CByteBuffer> dataVector; 1.1264 + 1.1265 + while (true) 1.1266 + { 1.1267 + UInt64 type; 1.1268 + RINOK(ReadID(type)); 1.1269 + if (type == NID::kHeader) 1.1270 + break; 1.1271 + if (type != NID::kEncodedHeader) 1.1272 + throw CInArchiveException(CInArchiveException::kIncorrectHeader); 1.1273 + HRESULT result = ReadAndDecodePackedStreams( 1.1274 + database.ArchiveInfo.StartPositionAfterHeader, 1.1275 + database.ArchiveInfo.DataStartPosition2, 1.1276 + dataVector 1.1277 + #ifndef _NO_CRYPTO 1.1278 + , getTextPassword 1.1279 + #endif 1.1280 + ); 1.1281 + RINOK(result); 1.1282 + if (dataVector.Size() == 0) 1.1283 + return S_OK; 1.1284 + if (dataVector.Size() > 1) 1.1285 + throw CInArchiveException(CInArchiveException::kIncorrectHeader); 1.1286 + streamSwitch.Remove(); 1.1287 + streamSwitch.Set(this, dataVector.Front()); 1.1288 + } 1.1289 + 1.1290 + return ReadHeader(database 1.1291 + #ifndef _NO_CRYPTO 1.1292 + , getTextPassword 1.1293 + #endif 1.1294 + ); 1.1295 +} 1.1296 + 1.1297 +}}