annotate src/win32/7zip/7z/CPP/7zip/Archive/7z/7zIn.cpp @ 1:f9f4f1b99eed

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