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