other-licenses/7zstub/src/7zip/Archive/7z/7zIn.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 // 7zIn.cpp
michael@0 2
michael@0 3 #include "StdAfx.h"
michael@0 4
michael@0 5 #include "7zIn.h"
michael@0 6 #include "7zMethods.h"
michael@0 7 #include "7zDecode.h"
michael@0 8 #include "../../Common/StreamObjects.h"
michael@0 9 #include "../../Common/StreamUtils.h"
michael@0 10 #include "../../../Common/CRC.h"
michael@0 11
michael@0 12 namespace NArchive {
michael@0 13 namespace N7z {
michael@0 14
michael@0 15 class CStreamSwitch
michael@0 16 {
michael@0 17 CInArchive *_archive;
michael@0 18 bool _needRemove;
michael@0 19 public:
michael@0 20 CStreamSwitch(): _needRemove(false) {}
michael@0 21 ~CStreamSwitch() { Remove(); }
michael@0 22 void Remove();
michael@0 23 void Set(CInArchive *archive, const Byte *data, size_t size);
michael@0 24 void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
michael@0 25 HRESULT Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
michael@0 26 };
michael@0 27
michael@0 28 void CStreamSwitch::Remove()
michael@0 29 {
michael@0 30 if (_needRemove)
michael@0 31 {
michael@0 32 _archive->DeleteByteStream();
michael@0 33 _needRemove = false;
michael@0 34 }
michael@0 35 }
michael@0 36
michael@0 37 void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
michael@0 38 {
michael@0 39 Remove();
michael@0 40 _archive = archive;
michael@0 41 _archive->AddByteStream(data, size);
michael@0 42 _needRemove = true;
michael@0 43 }
michael@0 44
michael@0 45 void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
michael@0 46 {
michael@0 47 Set(archive, byteBuffer, byteBuffer.GetCapacity());
michael@0 48 }
michael@0 49
michael@0 50 HRESULT CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
michael@0 51 {
michael@0 52 Remove();
michael@0 53 Byte external;
michael@0 54 RINOK(archive->ReadByte(external));
michael@0 55 if (external != 0)
michael@0 56 {
michael@0 57 CNum dataIndex;
michael@0 58 RINOK(archive->ReadNum(dataIndex));
michael@0 59 Set(archive, (*dataVector)[dataIndex]);
michael@0 60 }
michael@0 61 return S_OK;
michael@0 62 }
michael@0 63
michael@0 64
michael@0 65 CInArchiveException::CInArchiveException(CCauseType cause):
michael@0 66 Cause(cause)
michael@0 67 {}
michael@0 68
michael@0 69 HRESULT CInArchive::ReadDirect(IInStream *stream, void *data, UInt32 size,
michael@0 70 UInt32 *processedSize)
michael@0 71 {
michael@0 72 UInt32 realProcessedSize;
michael@0 73 HRESULT result = ReadStream(stream, data, size, &realProcessedSize);
michael@0 74 if(processedSize != NULL)
michael@0 75 *processedSize = realProcessedSize;
michael@0 76 _position += realProcessedSize;
michael@0 77 return result;
michael@0 78 }
michael@0 79
michael@0 80 HRESULT CInArchive::ReadDirect(void *data, UInt32 size, UInt32 *processedSize)
michael@0 81 {
michael@0 82 return ReadDirect(_stream, data, size, processedSize);
michael@0 83 }
michael@0 84
michael@0 85 HRESULT CInArchive::SafeReadDirect(void *data, UInt32 size)
michael@0 86 {
michael@0 87 UInt32 realProcessedSize;
michael@0 88 RINOK(ReadDirect(data, size, &realProcessedSize));
michael@0 89 if (realProcessedSize != size)
michael@0 90 throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
michael@0 91 return S_OK;
michael@0 92 }
michael@0 93
michael@0 94 HRESULT CInArchive::SafeReadDirectByte(Byte &b)
michael@0 95 {
michael@0 96 return SafeReadDirect(&b, 1);
michael@0 97 }
michael@0 98
michael@0 99 HRESULT CInArchive::SafeReadDirectUInt32(UInt32 &value)
michael@0 100 {
michael@0 101 value = 0;
michael@0 102 for (int i = 0; i < 4; i++)
michael@0 103 {
michael@0 104 Byte b;
michael@0 105 RINOK(SafeReadDirectByte(b));
michael@0 106 value |= (UInt32(b) << (8 * i));
michael@0 107 }
michael@0 108 return S_OK;
michael@0 109 }
michael@0 110
michael@0 111 HRESULT CInArchive::SafeReadDirectUInt64(UInt64 &value)
michael@0 112 {
michael@0 113 value = 0;
michael@0 114 for (int i = 0; i < 8; i++)
michael@0 115 {
michael@0 116 Byte b;
michael@0 117 RINOK(SafeReadDirectByte(b));
michael@0 118 value |= (UInt64(b) << (8 * i));
michael@0 119 }
michael@0 120 return S_OK;
michael@0 121 }
michael@0 122
michael@0 123 HRESULT CInArchive::ReadNumber(UInt64 &value)
michael@0 124 {
michael@0 125 Byte firstByte;
michael@0 126 RINOK(ReadByte(firstByte));
michael@0 127 Byte mask = 0x80;
michael@0 128 value = 0;
michael@0 129 for (int i = 0; i < 8; i++)
michael@0 130 {
michael@0 131 if ((firstByte & mask) == 0)
michael@0 132 {
michael@0 133 UInt64 highPart = firstByte & (mask - 1);
michael@0 134 value += (highPart << (i * 8));
michael@0 135 return S_OK;
michael@0 136 }
michael@0 137 Byte b;
michael@0 138 RINOK(ReadByte(b));
michael@0 139 value |= (UInt64(b) << (8 * i));
michael@0 140 mask >>= 1;
michael@0 141 }
michael@0 142 return S_OK;
michael@0 143 }
michael@0 144
michael@0 145 HRESULT CInArchive::ReadNum(CNum &value)
michael@0 146 {
michael@0 147 UInt64 value64;
michael@0 148 RINOK(ReadNumber(value64));
michael@0 149 if (value64 > kNumMax)
michael@0 150 return E_FAIL;
michael@0 151 value = (CNum)value64;
michael@0 152 return S_OK;
michael@0 153 }
michael@0 154
michael@0 155 HRESULT CInArchive::ReadUInt32(UInt32 &value)
michael@0 156 {
michael@0 157 value = 0;
michael@0 158 for (int i = 0; i < 4; i++)
michael@0 159 {
michael@0 160 Byte b;
michael@0 161 RINOK(ReadByte(b));
michael@0 162 value |= (UInt32(b) << (8 * i));
michael@0 163 }
michael@0 164 return S_OK;
michael@0 165 }
michael@0 166
michael@0 167 HRESULT CInArchive::ReadUInt64(UInt64 &value)
michael@0 168 {
michael@0 169 value = 0;
michael@0 170 for (int i = 0; i < 8; i++)
michael@0 171 {
michael@0 172 Byte b;
michael@0 173 RINOK(ReadByte(b));
michael@0 174 value |= (UInt64(b) << (8 * i));
michael@0 175 }
michael@0 176 return S_OK;
michael@0 177 }
michael@0 178
michael@0 179 static inline bool TestSignatureCandidate(const void *testBytes)
michael@0 180 {
michael@0 181 for (int i = 0; i < kSignatureSize; i++)
michael@0 182 if (((const Byte *)testBytes)[i] != kSignature[i])
michael@0 183 return false;
michael@0 184 return true;
michael@0 185 }
michael@0 186
michael@0 187 #ifdef _7Z_VOL
michael@0 188 static inline bool TestFinishSignatureCandidate(const void *testBytes)
michael@0 189 {
michael@0 190 for (int i = 0; i < kSignatureSize; i++)
michael@0 191 if (((const Byte *)testBytes)[i] != kFinishSignature[i])
michael@0 192 return false;
michael@0 193 return true;
michael@0 194 }
michael@0 195 #endif
michael@0 196
michael@0 197 HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
michael@0 198 {
michael@0 199 _position = _arhiveBeginStreamPosition;
michael@0 200 RINOK(stream->Seek(_arhiveBeginStreamPosition, STREAM_SEEK_SET, NULL));
michael@0 201
michael@0 202 Byte signature[kSignatureSize];
michael@0 203 UInt32 processedSize;
michael@0 204 RINOK(ReadDirect(stream, signature, kSignatureSize, &processedSize));
michael@0 205 if(processedSize != kSignatureSize)
michael@0 206 return S_FALSE;
michael@0 207 if (TestSignatureCandidate(signature))
michael@0 208 return S_OK;
michael@0 209
michael@0 210 CByteBuffer byteBuffer;
michael@0 211 const UInt32 kBufferSize = (1 << 16);
michael@0 212 byteBuffer.SetCapacity(kBufferSize);
michael@0 213 Byte *buffer = byteBuffer;
michael@0 214 UInt32 numPrevBytes = kSignatureSize - 1;
michael@0 215 memmove(buffer, signature + 1, numPrevBytes);
michael@0 216 UInt64 curTestPos = _arhiveBeginStreamPosition + 1;
michael@0 217 while(true)
michael@0 218 {
michael@0 219 if (searchHeaderSizeLimit != NULL)
michael@0 220 if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
michael@0 221 return S_FALSE;
michael@0 222 UInt32 numReadBytes = kBufferSize - numPrevBytes;
michael@0 223 RINOK(ReadDirect(stream, buffer + numPrevBytes, numReadBytes, &processedSize));
michael@0 224 UInt32 numBytesInBuffer = numPrevBytes + processedSize;
michael@0 225 if (numBytesInBuffer < kSignatureSize)
michael@0 226 return S_FALSE;
michael@0 227 UInt32 numTests = numBytesInBuffer - kSignatureSize + 1;
michael@0 228 for(UInt32 pos = 0; pos < numTests; pos++, curTestPos++)
michael@0 229 {
michael@0 230 if (TestSignatureCandidate(buffer + pos))
michael@0 231 {
michael@0 232 _arhiveBeginStreamPosition = curTestPos;
michael@0 233 _position = curTestPos + kSignatureSize;
michael@0 234 return stream->Seek(_position, STREAM_SEEK_SET, NULL);
michael@0 235 }
michael@0 236 }
michael@0 237 numPrevBytes = numBytesInBuffer - numTests;
michael@0 238 memmove(buffer, buffer + numTests, numPrevBytes);
michael@0 239 }
michael@0 240 }
michael@0 241
michael@0 242 // Out: _position must point to end of signature
michael@0 243
michael@0 244 #ifdef _7Z_VOL
michael@0 245 HRESULT CInArchive::FindFinishSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
michael@0 246 {
michael@0 247 RINOK(stream->Seek(0, STREAM_SEEK_END, &_position));
michael@0 248 if (_position < kSignatureSize)
michael@0 249 return S_FALSE;
michael@0 250
michael@0 251 CByteBuffer byteBuffer;
michael@0 252 const UInt32 kBufferSize = (1 << 18);
michael@0 253 byteBuffer.SetCapacity(kBufferSize);
michael@0 254 Byte *buffer = byteBuffer;
michael@0 255 UInt32 numPrevBytes = 0;
michael@0 256 UInt64 limitPos = 0;
michael@0 257 if (searchHeaderSizeLimit != NULL)
michael@0 258 if (*searchHeaderSizeLimit < _position)
michael@0 259 limitPos = _position - *searchHeaderSizeLimit;
michael@0 260
michael@0 261 while(_position >= limitPos)
michael@0 262 {
michael@0 263 UInt32 numReadBytes = kBufferSize - numPrevBytes;
michael@0 264 if (numReadBytes > _position)
michael@0 265 numReadBytes = (UInt32)_position;
michael@0 266 UInt32 numBytesInBuffer = numPrevBytes + numReadBytes;
michael@0 267 if (numBytesInBuffer < kSignatureSize)
michael@0 268 return S_FALSE;
michael@0 269 _position -= numReadBytes;
michael@0 270 RINOK(stream->Seek(_position, STREAM_SEEK_SET, &_position));
michael@0 271 UInt32 startPos = kBufferSize - numBytesInBuffer;
michael@0 272 UInt32 processedSize;
michael@0 273 RINOK(ReadDirect(stream, buffer + startPos, numReadBytes, &processedSize));
michael@0 274 if (processedSize != numReadBytes)
michael@0 275 return S_FALSE;
michael@0 276 _position -= processedSize;
michael@0 277 for(UInt32 pos = kBufferSize; pos >= startPos + kSignatureSize; pos--)
michael@0 278 {
michael@0 279 if (TestFinishSignatureCandidate(buffer + pos - kSignatureSize))
michael@0 280 {
michael@0 281 _position += pos - startPos;
michael@0 282 return stream->Seek(_position, STREAM_SEEK_SET, NULL);
michael@0 283 }
michael@0 284 }
michael@0 285 numPrevBytes = kSignatureSize - 1;
michael@0 286 memmove(buffer + kBufferSize - numPrevBytes, buffer + startPos + 1, numPrevBytes);
michael@0 287 }
michael@0 288 return S_FALSE;
michael@0 289 }
michael@0 290 #endif
michael@0 291
michael@0 292 // S_FALSE means that file is not archive
michael@0 293 HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
michael@0 294 {
michael@0 295 Close();
michael@0 296 RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
michael@0 297 _position = _arhiveBeginStreamPosition;
michael@0 298 #ifdef _7Z_VOL
michael@0 299 HRESULT result = FindFinishSignature(stream, searchHeaderSizeLimit);
michael@0 300 if (result == S_OK)
michael@0 301 _finishSignature = true;
michael@0 302 else
michael@0 303 {
michael@0 304 if (result != S_FALSE)
michael@0 305 return result;
michael@0 306 _finishSignature = false;
michael@0 307 RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
michael@0 308 }
michael@0 309 #else
michael@0 310 RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
michael@0 311 #endif
michael@0 312 _stream = stream;
michael@0 313 return S_OK;
michael@0 314 }
michael@0 315
michael@0 316 void CInArchive::Close()
michael@0 317 {
michael@0 318 _stream.Release();
michael@0 319 }
michael@0 320
michael@0 321 HRESULT CInArchive::SkeepData(UInt64 size)
michael@0 322 {
michael@0 323 for (UInt64 i = 0; i < size; i++)
michael@0 324 {
michael@0 325 Byte temp;
michael@0 326 RINOK(ReadByte(temp));
michael@0 327 }
michael@0 328 return S_OK;
michael@0 329 }
michael@0 330
michael@0 331 HRESULT CInArchive::SkeepData()
michael@0 332 {
michael@0 333 UInt64 size;
michael@0 334 RINOK(ReadNumber(size));
michael@0 335 return SkeepData(size);
michael@0 336 }
michael@0 337
michael@0 338 HRESULT CInArchive::ReadArchiveProperties(CInArchiveInfo &archiveInfo)
michael@0 339 {
michael@0 340 while(true)
michael@0 341 {
michael@0 342 UInt64 type;
michael@0 343 RINOK(ReadID(type));
michael@0 344 if (type == NID::kEnd)
michael@0 345 break;
michael@0 346 SkeepData();
michael@0 347 }
michael@0 348 return S_OK;
michael@0 349 }
michael@0 350
michael@0 351 HRESULT CInArchive::GetNextFolderItem(CFolder &folder)
michael@0 352 {
michael@0 353 CNum numCoders;
michael@0 354 RINOK(ReadNum(numCoders));
michael@0 355
michael@0 356 folder.Coders.Clear();
michael@0 357 folder.Coders.Reserve((int)numCoders);
michael@0 358 CNum numInStreams = 0;
michael@0 359 CNum numOutStreams = 0;
michael@0 360 CNum i;
michael@0 361 for (i = 0; i < numCoders; i++)
michael@0 362 {
michael@0 363 folder.Coders.Add(CCoderInfo());
michael@0 364 CCoderInfo &coder = folder.Coders.Back();
michael@0 365
michael@0 366 while (true)
michael@0 367 {
michael@0 368 coder.AltCoders.Add(CAltCoderInfo());
michael@0 369 CAltCoderInfo &altCoder = coder.AltCoders.Back();
michael@0 370 Byte mainByte;
michael@0 371 RINOK(ReadByte(mainByte));
michael@0 372 altCoder.MethodID.IDSize = mainByte & 0xF;
michael@0 373 RINOK(ReadBytes(altCoder.MethodID.ID, altCoder.MethodID.IDSize));
michael@0 374 if ((mainByte & 0x10) != 0)
michael@0 375 {
michael@0 376 RINOK(ReadNum(coder.NumInStreams));
michael@0 377 RINOK(ReadNum(coder.NumOutStreams));
michael@0 378 }
michael@0 379 else
michael@0 380 {
michael@0 381 coder.NumInStreams = 1;
michael@0 382 coder.NumOutStreams = 1;
michael@0 383 }
michael@0 384 if ((mainByte & 0x20) != 0)
michael@0 385 {
michael@0 386 CNum propertiesSize = 0;
michael@0 387 RINOK(ReadNum(propertiesSize));
michael@0 388 altCoder.Properties.SetCapacity((size_t)propertiesSize);
michael@0 389 RINOK(ReadBytes((Byte *)altCoder.Properties, (size_t)propertiesSize));
michael@0 390 }
michael@0 391 if ((mainByte & 0x80) == 0)
michael@0 392 break;
michael@0 393 }
michael@0 394 numInStreams += coder.NumInStreams;
michael@0 395 numOutStreams += coder.NumOutStreams;
michael@0 396 }
michael@0 397
michael@0 398 CNum numBindPairs;
michael@0 399 // RINOK(ReadNumber(numBindPairs));
michael@0 400 numBindPairs = numOutStreams - 1;
michael@0 401 folder.BindPairs.Clear();
michael@0 402 folder.BindPairs.Reserve(numBindPairs);
michael@0 403 for (i = 0; i < numBindPairs; i++)
michael@0 404 {
michael@0 405 CBindPair bindPair;
michael@0 406 RINOK(ReadNum(bindPair.InIndex));
michael@0 407 RINOK(ReadNum(bindPair.OutIndex));
michael@0 408 folder.BindPairs.Add(bindPair);
michael@0 409 }
michael@0 410
michael@0 411 CNum numPackedStreams = numInStreams - numBindPairs;
michael@0 412 folder.PackStreams.Reserve(numPackedStreams);
michael@0 413 if (numPackedStreams == 1)
michael@0 414 {
michael@0 415 for (CNum j = 0; j < numInStreams; j++)
michael@0 416 if (folder.FindBindPairForInStream(j) < 0)
michael@0 417 {
michael@0 418 folder.PackStreams.Add(j);
michael@0 419 break;
michael@0 420 }
michael@0 421 }
michael@0 422 else
michael@0 423 for(i = 0; i < numPackedStreams; i++)
michael@0 424 {
michael@0 425 CNum packStreamInfo;
michael@0 426 RINOK(ReadNum(packStreamInfo));
michael@0 427 folder.PackStreams.Add(packStreamInfo);
michael@0 428 }
michael@0 429
michael@0 430 return S_OK;
michael@0 431 }
michael@0 432
michael@0 433 HRESULT CInArchive::WaitAttribute(UInt64 attribute)
michael@0 434 {
michael@0 435 while(true)
michael@0 436 {
michael@0 437 UInt64 type;
michael@0 438 RINOK(ReadID(type));
michael@0 439 if (type == attribute)
michael@0 440 return S_OK;
michael@0 441 if (type == NID::kEnd)
michael@0 442 return S_FALSE;
michael@0 443 RINOK(SkeepData());
michael@0 444 }
michael@0 445 }
michael@0 446
michael@0 447 HRESULT CInArchive::ReadHashDigests(int numItems,
michael@0 448 CRecordVector<bool> &digestsDefined,
michael@0 449 CRecordVector<UInt32> &digests)
michael@0 450 {
michael@0 451 RINOK(ReadBoolVector2(numItems, digestsDefined));
michael@0 452 digests.Clear();
michael@0 453 digests.Reserve(numItems);
michael@0 454 for(int i = 0; i < numItems; i++)
michael@0 455 {
michael@0 456 UInt32 crc;
michael@0 457 if (digestsDefined[i])
michael@0 458 RINOK(ReadUInt32(crc));
michael@0 459 digests.Add(crc);
michael@0 460 }
michael@0 461 return S_OK;
michael@0 462 }
michael@0 463
michael@0 464 HRESULT CInArchive::ReadPackInfo(
michael@0 465 UInt64 &dataOffset,
michael@0 466 CRecordVector<UInt64> &packSizes,
michael@0 467 CRecordVector<bool> &packCRCsDefined,
michael@0 468 CRecordVector<UInt32> &packCRCs)
michael@0 469 {
michael@0 470 RINOK(ReadNumber(dataOffset));
michael@0 471 CNum numPackStreams;
michael@0 472 RINOK(ReadNum(numPackStreams));
michael@0 473
michael@0 474 RINOK(WaitAttribute(NID::kSize));
michael@0 475 packSizes.Clear();
michael@0 476 packSizes.Reserve(numPackStreams);
michael@0 477 for(CNum i = 0; i < numPackStreams; i++)
michael@0 478 {
michael@0 479 UInt64 size;
michael@0 480 RINOK(ReadNumber(size));
michael@0 481 packSizes.Add(size);
michael@0 482 }
michael@0 483
michael@0 484 UInt64 type;
michael@0 485 while(true)
michael@0 486 {
michael@0 487 RINOK(ReadID(type));
michael@0 488 if (type == NID::kEnd)
michael@0 489 break;
michael@0 490 if (type == NID::kCRC)
michael@0 491 {
michael@0 492 RINOK(ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs));
michael@0 493 continue;
michael@0 494 }
michael@0 495 RINOK(SkeepData());
michael@0 496 }
michael@0 497 if (packCRCsDefined.IsEmpty())
michael@0 498 {
michael@0 499 packCRCsDefined.Reserve(numPackStreams);
michael@0 500 packCRCsDefined.Clear();
michael@0 501 packCRCs.Reserve(numPackStreams);
michael@0 502 packCRCs.Clear();
michael@0 503 for(CNum i = 0; i < numPackStreams; i++)
michael@0 504 {
michael@0 505 packCRCsDefined.Add(false);
michael@0 506 packCRCs.Add(0);
michael@0 507 }
michael@0 508 }
michael@0 509 return S_OK;
michael@0 510 }
michael@0 511
michael@0 512 HRESULT CInArchive::ReadUnPackInfo(
michael@0 513 const CObjectVector<CByteBuffer> *dataVector,
michael@0 514 CObjectVector<CFolder> &folders)
michael@0 515 {
michael@0 516 RINOK(WaitAttribute(NID::kFolder));
michael@0 517 CNum numFolders;
michael@0 518 RINOK(ReadNum(numFolders));
michael@0 519
michael@0 520 {
michael@0 521 CStreamSwitch streamSwitch;
michael@0 522 RINOK(streamSwitch.Set(this, dataVector));
michael@0 523 folders.Clear();
michael@0 524 folders.Reserve((UInt32)numFolders);
michael@0 525 for(CNum i = 0; i < numFolders; i++)
michael@0 526 {
michael@0 527 folders.Add(CFolder());
michael@0 528 RINOK(GetNextFolderItem(folders.Back()));
michael@0 529 }
michael@0 530 }
michael@0 531
michael@0 532 RINOK(WaitAttribute(NID::kCodersUnPackSize));
michael@0 533
michael@0 534 CNum i;
michael@0 535 for(i = 0; i < numFolders; i++)
michael@0 536 {
michael@0 537 CFolder &folder = folders[i];
michael@0 538 CNum numOutStreams = folder.GetNumOutStreams();
michael@0 539 folder.UnPackSizes.Reserve(numOutStreams);
michael@0 540 for(CNum j = 0; j < numOutStreams; j++)
michael@0 541 {
michael@0 542 UInt64 unPackSize;
michael@0 543 RINOK(ReadNumber(unPackSize));
michael@0 544 folder.UnPackSizes.Add(unPackSize);
michael@0 545 }
michael@0 546 }
michael@0 547
michael@0 548 while(true)
michael@0 549 {
michael@0 550 UInt64 type;
michael@0 551 RINOK(ReadID(type));
michael@0 552 if (type == NID::kEnd)
michael@0 553 return S_OK;
michael@0 554 if (type == NID::kCRC)
michael@0 555 {
michael@0 556 CRecordVector<bool> crcsDefined;
michael@0 557 CRecordVector<UInt32> crcs;
michael@0 558 RINOK(ReadHashDigests(numFolders, crcsDefined, crcs));
michael@0 559 for(i = 0; i < numFolders; i++)
michael@0 560 {
michael@0 561 CFolder &folder = folders[i];
michael@0 562 folder.UnPackCRCDefined = crcsDefined[i];
michael@0 563 folder.UnPackCRC = crcs[i];
michael@0 564 }
michael@0 565 continue;
michael@0 566 }
michael@0 567 RINOK(SkeepData());
michael@0 568 }
michael@0 569 }
michael@0 570
michael@0 571 HRESULT CInArchive::ReadSubStreamsInfo(
michael@0 572 const CObjectVector<CFolder> &folders,
michael@0 573 CRecordVector<CNum> &numUnPackStreamsInFolders,
michael@0 574 CRecordVector<UInt64> &unPackSizes,
michael@0 575 CRecordVector<bool> &digestsDefined,
michael@0 576 CRecordVector<UInt32> &digests)
michael@0 577 {
michael@0 578 numUnPackStreamsInFolders.Clear();
michael@0 579 numUnPackStreamsInFolders.Reserve(folders.Size());
michael@0 580 UInt64 type;
michael@0 581 while(true)
michael@0 582 {
michael@0 583 RINOK(ReadID(type));
michael@0 584 if (type == NID::kNumUnPackStream)
michael@0 585 {
michael@0 586 for(int i = 0; i < folders.Size(); i++)
michael@0 587 {
michael@0 588 CNum value;
michael@0 589 RINOK(ReadNum(value));
michael@0 590 numUnPackStreamsInFolders.Add(value);
michael@0 591 }
michael@0 592 continue;
michael@0 593 }
michael@0 594 if (type == NID::kCRC || type == NID::kSize)
michael@0 595 break;
michael@0 596 if (type == NID::kEnd)
michael@0 597 break;
michael@0 598 RINOK(SkeepData());
michael@0 599 }
michael@0 600
michael@0 601 if (numUnPackStreamsInFolders.IsEmpty())
michael@0 602 for(int i = 0; i < folders.Size(); i++)
michael@0 603 numUnPackStreamsInFolders.Add(1);
michael@0 604
michael@0 605 int i;
michael@0 606 for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
michael@0 607 {
michael@0 608 // v3.13 incorrectly worked with empty folders
michael@0 609 // v4.07: we check that folder is empty
michael@0 610 CNum numSubstreams = numUnPackStreamsInFolders[i];
michael@0 611 if (numSubstreams == 0)
michael@0 612 continue;
michael@0 613 UInt64 sum = 0;
michael@0 614 for (CNum j = 1; j < numSubstreams; j++)
michael@0 615 {
michael@0 616 UInt64 size;
michael@0 617 if (type == NID::kSize)
michael@0 618 {
michael@0 619 RINOK(ReadNumber(size));
michael@0 620 unPackSizes.Add(size);
michael@0 621 sum += size;
michael@0 622 }
michael@0 623 }
michael@0 624 unPackSizes.Add(folders[i].GetUnPackSize() - sum);
michael@0 625 }
michael@0 626 if (type == NID::kSize)
michael@0 627 {
michael@0 628 RINOK(ReadID(type));
michael@0 629 }
michael@0 630
michael@0 631 int numDigests = 0;
michael@0 632 int numDigestsTotal = 0;
michael@0 633 for(i = 0; i < folders.Size(); i++)
michael@0 634 {
michael@0 635 CNum numSubstreams = numUnPackStreamsInFolders[i];
michael@0 636 if (numSubstreams != 1 || !folders[i].UnPackCRCDefined)
michael@0 637 numDigests += numSubstreams;
michael@0 638 numDigestsTotal += numSubstreams;
michael@0 639 }
michael@0 640
michael@0 641 while(true)
michael@0 642 {
michael@0 643 if (type == NID::kCRC)
michael@0 644 {
michael@0 645 CRecordVector<bool> digestsDefined2;
michael@0 646 CRecordVector<UInt32> digests2;
michael@0 647 RINOK(ReadHashDigests(numDigests, digestsDefined2, digests2));
michael@0 648 int digestIndex = 0;
michael@0 649 for (i = 0; i < folders.Size(); i++)
michael@0 650 {
michael@0 651 CNum numSubstreams = numUnPackStreamsInFolders[i];
michael@0 652 const CFolder &folder = folders[i];
michael@0 653 if (numSubstreams == 1 && folder.UnPackCRCDefined)
michael@0 654 {
michael@0 655 digestsDefined.Add(true);
michael@0 656 digests.Add(folder.UnPackCRC);
michael@0 657 }
michael@0 658 else
michael@0 659 for (CNum j = 0; j < numSubstreams; j++, digestIndex++)
michael@0 660 {
michael@0 661 digestsDefined.Add(digestsDefined2[digestIndex]);
michael@0 662 digests.Add(digests2[digestIndex]);
michael@0 663 }
michael@0 664 }
michael@0 665 }
michael@0 666 else if (type == NID::kEnd)
michael@0 667 {
michael@0 668 if (digestsDefined.IsEmpty())
michael@0 669 {
michael@0 670 digestsDefined.Clear();
michael@0 671 digests.Clear();
michael@0 672 for (int i = 0; i < numDigestsTotal; i++)
michael@0 673 {
michael@0 674 digestsDefined.Add(false);
michael@0 675 digests.Add(0);
michael@0 676 }
michael@0 677 }
michael@0 678 return S_OK;
michael@0 679 }
michael@0 680 else
michael@0 681 {
michael@0 682 RINOK(SkeepData());
michael@0 683 }
michael@0 684 RINOK(ReadID(type));
michael@0 685 }
michael@0 686 }
michael@0 687
michael@0 688 HRESULT CInArchive::ReadStreamsInfo(
michael@0 689 const CObjectVector<CByteBuffer> *dataVector,
michael@0 690 UInt64 &dataOffset,
michael@0 691 CRecordVector<UInt64> &packSizes,
michael@0 692 CRecordVector<bool> &packCRCsDefined,
michael@0 693 CRecordVector<UInt32> &packCRCs,
michael@0 694 CObjectVector<CFolder> &folders,
michael@0 695 CRecordVector<CNum> &numUnPackStreamsInFolders,
michael@0 696 CRecordVector<UInt64> &unPackSizes,
michael@0 697 CRecordVector<bool> &digestsDefined,
michael@0 698 CRecordVector<UInt32> &digests)
michael@0 699 {
michael@0 700 while(true)
michael@0 701 {
michael@0 702 UInt64 type;
michael@0 703 RINOK(ReadID(type));
michael@0 704 switch(type)
michael@0 705 {
michael@0 706 case NID::kEnd:
michael@0 707 return S_OK;
michael@0 708 case NID::kPackInfo:
michael@0 709 {
michael@0 710 RINOK(ReadPackInfo(dataOffset, packSizes,
michael@0 711 packCRCsDefined, packCRCs));
michael@0 712 break;
michael@0 713 }
michael@0 714 case NID::kUnPackInfo:
michael@0 715 {
michael@0 716 RINOK(ReadUnPackInfo(dataVector, folders));
michael@0 717 break;
michael@0 718 }
michael@0 719 case NID::kSubStreamsInfo:
michael@0 720 {
michael@0 721 RINOK(ReadSubStreamsInfo(folders, numUnPackStreamsInFolders,
michael@0 722 unPackSizes, digestsDefined, digests));
michael@0 723 break;
michael@0 724 }
michael@0 725 }
michael@0 726 }
michael@0 727 }
michael@0 728
michael@0 729 HRESULT CInArchive::ReadFileNames(CObjectVector<CFileItem> &files)
michael@0 730 {
michael@0 731 for(int i = 0; i < files.Size(); i++)
michael@0 732 {
michael@0 733 UString &name = files[i].Name;
michael@0 734 name.Empty();
michael@0 735 while (true)
michael@0 736 {
michael@0 737 wchar_t c;
michael@0 738 RINOK(ReadWideCharLE(c));
michael@0 739 if (c == L'\0')
michael@0 740 break;
michael@0 741 name += c;
michael@0 742 }
michael@0 743 }
michael@0 744 return S_OK;
michael@0 745 }
michael@0 746
michael@0 747 HRESULT CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
michael@0 748 {
michael@0 749 v.Clear();
michael@0 750 v.Reserve(numItems);
michael@0 751 Byte b;
michael@0 752 Byte mask = 0;
michael@0 753 for(int i = 0; i < numItems; i++)
michael@0 754 {
michael@0 755 if (mask == 0)
michael@0 756 {
michael@0 757 RINOK(ReadByte(b));
michael@0 758 mask = 0x80;
michael@0 759 }
michael@0 760 v.Add((b & mask) != 0);
michael@0 761 mask >>= 1;
michael@0 762 }
michael@0 763 return S_OK;
michael@0 764 }
michael@0 765
michael@0 766 HRESULT CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
michael@0 767 {
michael@0 768 Byte allAreDefined;
michael@0 769 RINOK(ReadByte(allAreDefined));
michael@0 770 if (allAreDefined == 0)
michael@0 771 return ReadBoolVector(numItems, v);
michael@0 772 v.Clear();
michael@0 773 v.Reserve(numItems);
michael@0 774 for (int i = 0; i < numItems; i++)
michael@0 775 v.Add(true);
michael@0 776 return S_OK;
michael@0 777 }
michael@0 778
michael@0 779 HRESULT CInArchive::ReadTime(const CObjectVector<CByteBuffer> &dataVector,
michael@0 780 CObjectVector<CFileItem> &files, UInt64 type)
michael@0 781 {
michael@0 782 CBoolVector boolVector;
michael@0 783 RINOK(ReadBoolVector2(files.Size(), boolVector))
michael@0 784
michael@0 785 CStreamSwitch streamSwitch;
michael@0 786 RINOK(streamSwitch.Set(this, &dataVector));
michael@0 787
michael@0 788 for(int i = 0; i < files.Size(); i++)
michael@0 789 {
michael@0 790 CFileItem &file = files[i];
michael@0 791 CArchiveFileTime fileTime;
michael@0 792 bool defined = boolVector[i];
michael@0 793 if (defined)
michael@0 794 {
michael@0 795 UInt32 low, high;
michael@0 796 RINOK(ReadUInt32(low));
michael@0 797 RINOK(ReadUInt32(high));
michael@0 798 fileTime.dwLowDateTime = low;
michael@0 799 fileTime.dwHighDateTime = high;
michael@0 800 }
michael@0 801 switch(type)
michael@0 802 {
michael@0 803 case NID::kCreationTime:
michael@0 804 file.IsCreationTimeDefined = defined;
michael@0 805 if (defined)
michael@0 806 file.CreationTime = fileTime;
michael@0 807 break;
michael@0 808 case NID::kLastWriteTime:
michael@0 809 file.IsLastWriteTimeDefined = defined;
michael@0 810 if (defined)
michael@0 811 file.LastWriteTime = fileTime;
michael@0 812 break;
michael@0 813 case NID::kLastAccessTime:
michael@0 814 file.IsLastAccessTimeDefined = defined;
michael@0 815 if (defined)
michael@0 816 file.LastAccessTime = fileTime;
michael@0 817 break;
michael@0 818 }
michael@0 819 }
michael@0 820 return S_OK;
michael@0 821 }
michael@0 822
michael@0 823 HRESULT CInArchive::ReadAndDecodePackedStreams(UInt64 baseOffset,
michael@0 824 UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
michael@0 825 #ifndef _NO_CRYPTO
michael@0 826 , ICryptoGetTextPassword *getTextPassword
michael@0 827 #endif
michael@0 828 )
michael@0 829 {
michael@0 830 CRecordVector<UInt64> packSizes;
michael@0 831 CRecordVector<bool> packCRCsDefined;
michael@0 832 CRecordVector<UInt32> packCRCs;
michael@0 833 CObjectVector<CFolder> folders;
michael@0 834
michael@0 835 CRecordVector<CNum> numUnPackStreamsInFolders;
michael@0 836 CRecordVector<UInt64> unPackSizes;
michael@0 837 CRecordVector<bool> digestsDefined;
michael@0 838 CRecordVector<UInt32> digests;
michael@0 839
michael@0 840 RINOK(ReadStreamsInfo(NULL,
michael@0 841 dataOffset,
michael@0 842 packSizes,
michael@0 843 packCRCsDefined,
michael@0 844 packCRCs,
michael@0 845 folders,
michael@0 846 numUnPackStreamsInFolders,
michael@0 847 unPackSizes,
michael@0 848 digestsDefined,
michael@0 849 digests));
michael@0 850
michael@0 851 // database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
michael@0 852
michael@0 853 CNum packIndex = 0;
michael@0 854 CDecoder decoder(
michael@0 855 #ifdef _ST_MODE
michael@0 856 false
michael@0 857 #else
michael@0 858 true
michael@0 859 #endif
michael@0 860 );
michael@0 861 UInt64 dataStartPos = baseOffset + dataOffset;
michael@0 862 for(int i = 0; i < folders.Size(); i++)
michael@0 863 {
michael@0 864 const CFolder &folder = folders[i];
michael@0 865 dataVector.Add(CByteBuffer());
michael@0 866 CByteBuffer &data = dataVector.Back();
michael@0 867 UInt64 unPackSize = folder.GetUnPackSize();
michael@0 868 if (unPackSize > kNumMax)
michael@0 869 return E_FAIL;
michael@0 870 if (unPackSize > 0xFFFFFFFF)
michael@0 871 return E_FAIL;
michael@0 872 data.SetCapacity((size_t)unPackSize);
michael@0 873
michael@0 874 CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2;
michael@0 875 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
michael@0 876 outStreamSpec->Init(data, (size_t)unPackSize);
michael@0 877
michael@0 878 HRESULT result = decoder.Decode(_stream, dataStartPos,
michael@0 879 &packSizes[packIndex], folder, outStream, NULL
michael@0 880 #ifndef _NO_CRYPTO
michael@0 881 , getTextPassword
michael@0 882 #endif
michael@0 883 #ifdef COMPRESS_MT
michael@0 884 , false, 1
michael@0 885 #endif
michael@0 886 );
michael@0 887 RINOK(result);
michael@0 888
michael@0 889 if (folder.UnPackCRCDefined)
michael@0 890 if (!CCRC::VerifyDigest(folder.UnPackCRC, data, (UInt32)unPackSize))
michael@0 891 throw CInArchiveException(CInArchiveException::kIncorrectHeader);
michael@0 892 for (int j = 0; j < folder.PackStreams.Size(); j++)
michael@0 893 dataStartPos += packSizes[packIndex++];
michael@0 894 }
michael@0 895 return S_OK;
michael@0 896 }
michael@0 897
michael@0 898 HRESULT CInArchive::ReadHeader(CArchiveDatabaseEx &database
michael@0 899 #ifndef _NO_CRYPTO
michael@0 900 , ICryptoGetTextPassword *getTextPassword
michael@0 901 #endif
michael@0 902 )
michael@0 903 {
michael@0 904 UInt64 type;
michael@0 905 RINOK(ReadID(type));
michael@0 906
michael@0 907 if (type == NID::kArchiveProperties)
michael@0 908 {
michael@0 909 RINOK(ReadArchiveProperties(database.ArchiveInfo));
michael@0 910 RINOK(ReadID(type));
michael@0 911 }
michael@0 912
michael@0 913 CObjectVector<CByteBuffer> dataVector;
michael@0 914
michael@0 915 if (type == NID::kAdditionalStreamsInfo)
michael@0 916 {
michael@0 917 HRESULT result = ReadAndDecodePackedStreams(
michael@0 918 database.ArchiveInfo.StartPositionAfterHeader,
michael@0 919 database.ArchiveInfo.DataStartPosition2,
michael@0 920 dataVector
michael@0 921 #ifndef _NO_CRYPTO
michael@0 922 , getTextPassword
michael@0 923 #endif
michael@0 924 );
michael@0 925 RINOK(result);
michael@0 926 database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
michael@0 927 RINOK(ReadID(type));
michael@0 928 }
michael@0 929
michael@0 930 CRecordVector<UInt64> unPackSizes;
michael@0 931 CRecordVector<bool> digestsDefined;
michael@0 932 CRecordVector<UInt32> digests;
michael@0 933
michael@0 934 if (type == NID::kMainStreamsInfo)
michael@0 935 {
michael@0 936 RINOK(ReadStreamsInfo(&dataVector,
michael@0 937 database.ArchiveInfo.DataStartPosition,
michael@0 938 database.PackSizes,
michael@0 939 database.PackCRCsDefined,
michael@0 940 database.PackCRCs,
michael@0 941 database.Folders,
michael@0 942 database.NumUnPackStreamsVector,
michael@0 943 unPackSizes,
michael@0 944 digestsDefined,
michael@0 945 digests));
michael@0 946 database.ArchiveInfo.DataStartPosition += database.ArchiveInfo.StartPositionAfterHeader;
michael@0 947 RINOK(ReadID(type));
michael@0 948 }
michael@0 949 else
michael@0 950 {
michael@0 951 for(int i = 0; i < database.Folders.Size(); i++)
michael@0 952 {
michael@0 953 database.NumUnPackStreamsVector.Add(1);
michael@0 954 CFolder &folder = database.Folders[i];
michael@0 955 unPackSizes.Add(folder.GetUnPackSize());
michael@0 956 digestsDefined.Add(folder.UnPackCRCDefined);
michael@0 957 digests.Add(folder.UnPackCRC);
michael@0 958 }
michael@0 959 }
michael@0 960
michael@0 961 database.Files.Clear();
michael@0 962
michael@0 963 if (type == NID::kEnd)
michael@0 964 return S_OK;
michael@0 965 if (type != NID::kFilesInfo)
michael@0 966 throw CInArchiveException(CInArchiveException::kIncorrectHeader);
michael@0 967
michael@0 968 CNum numFiles;
michael@0 969 RINOK(ReadNum(numFiles));
michael@0 970 database.Files.Reserve(numFiles);
michael@0 971 CNum i;
michael@0 972 for(i = 0; i < numFiles; i++)
michael@0 973 database.Files.Add(CFileItem());
michael@0 974
michael@0 975 database.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);
michael@0 976 if (!database.PackSizes.IsEmpty())
michael@0 977 database.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);
michael@0 978 if (numFiles > 0 && !digests.IsEmpty())
michael@0 979 database.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);
michael@0 980
michael@0 981 CBoolVector emptyStreamVector;
michael@0 982 emptyStreamVector.Reserve((int)numFiles);
michael@0 983 for(i = 0; i < numFiles; i++)
michael@0 984 emptyStreamVector.Add(false);
michael@0 985 CBoolVector emptyFileVector;
michael@0 986 CBoolVector antiFileVector;
michael@0 987 CNum numEmptyStreams = 0;
michael@0 988
michael@0 989 // int sizePrev = -1;
michael@0 990 // int posPrev = 0;
michael@0 991
michael@0 992 while(true)
michael@0 993 {
michael@0 994 /*
michael@0 995 if (sizePrev >= 0)
michael@0 996 if (sizePrev != _inByteBack->GetProcessedSize() - posPrev)
michael@0 997 throw 2;
michael@0 998 */
michael@0 999 UInt64 type;
michael@0 1000 RINOK(ReadID(type));
michael@0 1001 if (type == NID::kEnd)
michael@0 1002 break;
michael@0 1003 UInt64 size;
michael@0 1004 RINOK(ReadNumber(size));
michael@0 1005
michael@0 1006 // sizePrev = size;
michael@0 1007 // posPrev = _inByteBack->GetProcessedSize();
michael@0 1008
michael@0 1009 database.ArchiveInfo.FileInfoPopIDs.Add(type);
michael@0 1010 switch(type)
michael@0 1011 {
michael@0 1012 case NID::kName:
michael@0 1013 {
michael@0 1014 CStreamSwitch streamSwitch;
michael@0 1015 RINOK(streamSwitch.Set(this, &dataVector));
michael@0 1016 RINOK(ReadFileNames(database.Files))
michael@0 1017 break;
michael@0 1018 }
michael@0 1019 case NID::kWinAttributes:
michael@0 1020 {
michael@0 1021 CBoolVector boolVector;
michael@0 1022 RINOK(ReadBoolVector2(database.Files.Size(), boolVector))
michael@0 1023 CStreamSwitch streamSwitch;
michael@0 1024 RINOK(streamSwitch.Set(this, &dataVector));
michael@0 1025 for(i = 0; i < numFiles; i++)
michael@0 1026 {
michael@0 1027 CFileItem &file = database.Files[i];
michael@0 1028 if (file.AreAttributesDefined = boolVector[i])
michael@0 1029 {
michael@0 1030 RINOK(ReadUInt32(file.Attributes));
michael@0 1031 }
michael@0 1032 }
michael@0 1033 break;
michael@0 1034 }
michael@0 1035 case NID::kStartPos:
michael@0 1036 {
michael@0 1037 CBoolVector boolVector;
michael@0 1038 RINOK(ReadBoolVector2(database.Files.Size(), boolVector))
michael@0 1039 CStreamSwitch streamSwitch;
michael@0 1040 RINOK(streamSwitch.Set(this, &dataVector));
michael@0 1041 for(i = 0; i < numFiles; i++)
michael@0 1042 {
michael@0 1043 CFileItem &file = database.Files[i];
michael@0 1044 if (file.IsStartPosDefined = boolVector[i])
michael@0 1045 {
michael@0 1046 RINOK(ReadUInt64(file.StartPos));
michael@0 1047 }
michael@0 1048 }
michael@0 1049 break;
michael@0 1050 }
michael@0 1051 case NID::kEmptyStream:
michael@0 1052 {
michael@0 1053 RINOK(ReadBoolVector(numFiles, emptyStreamVector))
michael@0 1054 for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
michael@0 1055 if (emptyStreamVector[i])
michael@0 1056 numEmptyStreams++;
michael@0 1057 emptyFileVector.Reserve(numEmptyStreams);
michael@0 1058 antiFileVector.Reserve(numEmptyStreams);
michael@0 1059 for (i = 0; i < numEmptyStreams; i++)
michael@0 1060 {
michael@0 1061 emptyFileVector.Add(false);
michael@0 1062 antiFileVector.Add(false);
michael@0 1063 }
michael@0 1064 break;
michael@0 1065 }
michael@0 1066 case NID::kEmptyFile:
michael@0 1067 {
michael@0 1068 RINOK(ReadBoolVector(numEmptyStreams, emptyFileVector))
michael@0 1069 break;
michael@0 1070 }
michael@0 1071 case NID::kAnti:
michael@0 1072 {
michael@0 1073 RINOK(ReadBoolVector(numEmptyStreams, antiFileVector))
michael@0 1074 break;
michael@0 1075 }
michael@0 1076 case NID::kCreationTime:
michael@0 1077 case NID::kLastWriteTime:
michael@0 1078 case NID::kLastAccessTime:
michael@0 1079 {
michael@0 1080 RINOK(ReadTime(dataVector, database.Files, type))
michael@0 1081 break;
michael@0 1082 }
michael@0 1083 default:
michael@0 1084 {
michael@0 1085 database.ArchiveInfo.FileInfoPopIDs.DeleteBack();
michael@0 1086 RINOK(SkeepData(size));
michael@0 1087 }
michael@0 1088 }
michael@0 1089 }
michael@0 1090
michael@0 1091 CNum emptyFileIndex = 0;
michael@0 1092 CNum sizeIndex = 0;
michael@0 1093 for(i = 0; i < numFiles; i++)
michael@0 1094 {
michael@0 1095 CFileItem &file = database.Files[i];
michael@0 1096 file.HasStream = !emptyStreamVector[i];
michael@0 1097 if(file.HasStream)
michael@0 1098 {
michael@0 1099 file.IsDirectory = false;
michael@0 1100 file.IsAnti = false;
michael@0 1101 file.UnPackSize = unPackSizes[sizeIndex];
michael@0 1102 file.FileCRC = digests[sizeIndex];
michael@0 1103 file.IsFileCRCDefined = digestsDefined[sizeIndex];
michael@0 1104 sizeIndex++;
michael@0 1105 }
michael@0 1106 else
michael@0 1107 {
michael@0 1108 file.IsDirectory = !emptyFileVector[emptyFileIndex];
michael@0 1109 file.IsAnti = antiFileVector[emptyFileIndex];
michael@0 1110 emptyFileIndex++;
michael@0 1111 file.UnPackSize = 0;
michael@0 1112 file.IsFileCRCDefined = false;
michael@0 1113 }
michael@0 1114 }
michael@0 1115 return S_OK;
michael@0 1116 }
michael@0 1117
michael@0 1118
michael@0 1119 void CArchiveDatabaseEx::FillFolderStartPackStream()
michael@0 1120 {
michael@0 1121 FolderStartPackStreamIndex.Clear();
michael@0 1122 FolderStartPackStreamIndex.Reserve(Folders.Size());
michael@0 1123 CNum startPos = 0;
michael@0 1124 for(int i = 0; i < Folders.Size(); i++)
michael@0 1125 {
michael@0 1126 FolderStartPackStreamIndex.Add(startPos);
michael@0 1127 startPos += (CNum)Folders[i].PackStreams.Size();
michael@0 1128 }
michael@0 1129 }
michael@0 1130
michael@0 1131 void CArchiveDatabaseEx::FillStartPos()
michael@0 1132 {
michael@0 1133 PackStreamStartPositions.Clear();
michael@0 1134 PackStreamStartPositions.Reserve(PackSizes.Size());
michael@0 1135 UInt64 startPos = 0;
michael@0 1136 for(int i = 0; i < PackSizes.Size(); i++)
michael@0 1137 {
michael@0 1138 PackStreamStartPositions.Add(startPos);
michael@0 1139 startPos += PackSizes[i];
michael@0 1140 }
michael@0 1141 }
michael@0 1142
michael@0 1143 void CArchiveDatabaseEx::FillFolderStartFileIndex()
michael@0 1144 {
michael@0 1145 FolderStartFileIndex.Clear();
michael@0 1146 FolderStartFileIndex.Reserve(Folders.Size());
michael@0 1147 FileIndexToFolderIndexMap.Clear();
michael@0 1148 FileIndexToFolderIndexMap.Reserve(Files.Size());
michael@0 1149
michael@0 1150 int folderIndex = 0;
michael@0 1151 CNum indexInFolder = 0;
michael@0 1152 for (int i = 0; i < Files.Size(); i++)
michael@0 1153 {
michael@0 1154 const CFileItem &file = Files[i];
michael@0 1155 bool emptyStream = !file.HasStream;
michael@0 1156 if (emptyStream && indexInFolder == 0)
michael@0 1157 {
michael@0 1158 FileIndexToFolderIndexMap.Add(kNumNoIndex);
michael@0 1159 continue;
michael@0 1160 }
michael@0 1161 if (indexInFolder == 0)
michael@0 1162 {
michael@0 1163 // v3.13 incorrectly worked with empty folders
michael@0 1164 // v4.07: Loop for skipping empty folders
michael@0 1165 while(true)
michael@0 1166 {
michael@0 1167 if (folderIndex >= Folders.Size())
michael@0 1168 throw CInArchiveException(CInArchiveException::kIncorrectHeader);
michael@0 1169 FolderStartFileIndex.Add(i); // check it
michael@0 1170 if (NumUnPackStreamsVector[folderIndex] != 0)
michael@0 1171 break;
michael@0 1172 folderIndex++;
michael@0 1173 }
michael@0 1174 }
michael@0 1175 FileIndexToFolderIndexMap.Add(folderIndex);
michael@0 1176 if (emptyStream)
michael@0 1177 continue;
michael@0 1178 indexInFolder++;
michael@0 1179 if (indexInFolder >= NumUnPackStreamsVector[folderIndex])
michael@0 1180 {
michael@0 1181 folderIndex++;
michael@0 1182 indexInFolder = 0;
michael@0 1183 }
michael@0 1184 }
michael@0 1185 }
michael@0 1186
michael@0 1187 HRESULT CInArchive::ReadDatabase(CArchiveDatabaseEx &database
michael@0 1188 #ifndef _NO_CRYPTO
michael@0 1189 , ICryptoGetTextPassword *getTextPassword
michael@0 1190 #endif
michael@0 1191 )
michael@0 1192 {
michael@0 1193 database.Clear();
michael@0 1194 database.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
michael@0 1195
michael@0 1196
michael@0 1197 RINOK(SafeReadDirect(&database.ArchiveInfo.Version.Major, 1));
michael@0 1198 RINOK(SafeReadDirect(&database.ArchiveInfo.Version.Minor, 1));
michael@0 1199 if (database.ArchiveInfo.Version.Major != kMajorVersion)
michael@0 1200 throw CInArchiveException(CInArchiveException::kUnsupportedVersion);
michael@0 1201
michael@0 1202 #ifdef _7Z_VOL
michael@0 1203 if (_finishSignature)
michael@0 1204 {
michael@0 1205 RINOK(_stream->Seek(_position - (4 + kFinishHeaderSize) -
michael@0 1206 (kSignatureSize + 2), STREAM_SEEK_SET, &_position));
michael@0 1207 }
michael@0 1208 #endif
michael@0 1209
michael@0 1210 UInt32 crcFromArchive;
michael@0 1211 RINOK(SafeReadDirectUInt32(crcFromArchive));
michael@0 1212
michael@0 1213 UInt64 nextHeaderOffset;
michael@0 1214 UInt64 nextHeaderSize;
michael@0 1215 UInt32 nextHeaderCRC;
michael@0 1216 CCRC crc;
michael@0 1217 RINOK(SafeReadDirectUInt64(nextHeaderOffset));
michael@0 1218 crc.UpdateUInt64(nextHeaderOffset);
michael@0 1219 RINOK(SafeReadDirectUInt64(nextHeaderSize));
michael@0 1220 crc.UpdateUInt64(nextHeaderSize);
michael@0 1221 RINOK(SafeReadDirectUInt32(nextHeaderCRC));
michael@0 1222 crc.UpdateUInt32(nextHeaderCRC);
michael@0 1223
michael@0 1224 #ifdef _7Z_VOL
michael@0 1225 UInt64 archiveStartOffset; // data offset from end if that struct
michael@0 1226 UInt64 additionalStartBlockSize; // start signature & start header size
michael@0 1227 if (_finishSignature)
michael@0 1228 {
michael@0 1229 RINOK(SafeReadDirectUInt64(archiveStartOffset));
michael@0 1230 crc.UpdateUInt64(archiveStartOffset);
michael@0 1231 RINOK(SafeReadDirectUInt64(additionalStartBlockSize));
michael@0 1232 crc.UpdateUInt64(additionalStartBlockSize);
michael@0 1233 database.ArchiveInfo.StartPositionAfterHeader = _position + archiveStartOffset;
michael@0 1234 }
michael@0 1235 else
michael@0 1236 #endif
michael@0 1237 {
michael@0 1238 database.ArchiveInfo.StartPositionAfterHeader = _position;
michael@0 1239 }
michael@0 1240 if (crc.GetDigest() != crcFromArchive)
michael@0 1241 throw CInArchiveException(CInArchiveException::kIncorrectHeader);
michael@0 1242
michael@0 1243 if (nextHeaderSize == 0)
michael@0 1244 return S_OK;
michael@0 1245
michael@0 1246 if (nextHeaderSize >= 0xFFFFFFFF)
michael@0 1247 return E_FAIL;
michael@0 1248
michael@0 1249 RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, &_position));
michael@0 1250
michael@0 1251 CByteBuffer buffer2;
michael@0 1252 buffer2.SetCapacity((size_t)nextHeaderSize);
michael@0 1253 RINOK(SafeReadDirect(buffer2, (UInt32)nextHeaderSize));
michael@0 1254 if (!CCRC::VerifyDigest(nextHeaderCRC, buffer2, (UInt32)nextHeaderSize))
michael@0 1255 throw CInArchiveException(CInArchiveException::kIncorrectHeader);
michael@0 1256
michael@0 1257 CStreamSwitch streamSwitch;
michael@0 1258 streamSwitch.Set(this, buffer2);
michael@0 1259
michael@0 1260 CObjectVector<CByteBuffer> dataVector;
michael@0 1261
michael@0 1262 while (true)
michael@0 1263 {
michael@0 1264 UInt64 type;
michael@0 1265 RINOK(ReadID(type));
michael@0 1266 if (type == NID::kHeader)
michael@0 1267 break;
michael@0 1268 if (type != NID::kEncodedHeader)
michael@0 1269 throw CInArchiveException(CInArchiveException::kIncorrectHeader);
michael@0 1270 HRESULT result = ReadAndDecodePackedStreams(
michael@0 1271 database.ArchiveInfo.StartPositionAfterHeader,
michael@0 1272 database.ArchiveInfo.DataStartPosition2,
michael@0 1273 dataVector
michael@0 1274 #ifndef _NO_CRYPTO
michael@0 1275 , getTextPassword
michael@0 1276 #endif
michael@0 1277 );
michael@0 1278 RINOK(result);
michael@0 1279 if (dataVector.Size() == 0)
michael@0 1280 return S_OK;
michael@0 1281 if (dataVector.Size() > 1)
michael@0 1282 throw CInArchiveException(CInArchiveException::kIncorrectHeader);
michael@0 1283 streamSwitch.Remove();
michael@0 1284 streamSwitch.Set(this, dataVector.Front());
michael@0 1285 }
michael@0 1286
michael@0 1287 return ReadHeader(database
michael@0 1288 #ifndef _NO_CRYPTO
michael@0 1289 , getTextPassword
michael@0 1290 #endif
michael@0 1291 );
michael@0 1292 }
michael@0 1293
michael@0 1294 }}

mercurial