Example #1
0
STDMETHODIMP CHandler::Open(IInStream *inStream,
    const UInt64 *maxCheckStartPosition,
    IArchiveOpenCallback *callback)
{
  COM_TRY_BEGIN
  Close();
  HRESULT res = S_FALSE;
  CInArchive archive;
  CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
  callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
  
  CMyComPtr<IInStream> nextStream = inStream;
  bool prevChecked = false;
  UInt64 numItems = 0;
  try
  {
    while (nextStream != 0)
    {
      CDatabaseEx db;
      db.Stream = nextStream;
      res = archive.Open(maxCheckStartPosition, db);
      if (res == S_OK)
      {
        if (!m_Database.Volumes.IsEmpty())
        {
          const CDatabaseEx &dbPrev = m_Database.Volumes[prevChecked ? m_Database.Volumes.Size() - 1 : 0];
          if (dbPrev.ArchiveInfo.SetID != db.ArchiveInfo.SetID ||
              dbPrev.ArchiveInfo.CabinetNumber + (prevChecked ? 1: - 1) !=
              db.ArchiveInfo.CabinetNumber)
            res = S_FALSE;
        }
      }
      if (res == S_OK)
        m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : 0, db);
      else if (res != S_FALSE)
        return res;
      else
      {
        if (m_Database.Volumes.IsEmpty())
          return S_FALSE;
        if (prevChecked)
          break;
        prevChecked = true;
      }

      numItems += db.Items.Size();
      RINOK(callback->SetCompleted(&numItems, NULL));
        
      nextStream = 0;
      for (;;)
      {
        const COtherArchive *otherArchive = 0;
        if (!prevChecked)
        {
          const CInArchiveInfo &ai = m_Database.Volumes.Front().ArchiveInfo;
          if (ai.IsTherePrev())
            otherArchive = &ai.PrevArc;
          else
            prevChecked = true;
        }
        if (otherArchive == 0)
        {
          const CInArchiveInfo &ai = m_Database.Volumes.Back().ArchiveInfo;
          if (ai.IsThereNext())
            otherArchive = &ai.NextArc;
        }
        if (!otherArchive)
          break;
        const UString fullName = MultiByteToUnicodeString(otherArchive->FileName, CP_ACP);
        if (!openVolumeCallback)
          break;

        HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream);
        if (result == S_OK)
          break;
        if (result != S_FALSE)
          return result;
        if (prevChecked)
          break;
        prevChecked = true;
      }
    }
    if (res == S_OK)
    {
      m_Database.FillSortAndShrink();
      if (!m_Database.Check())
        res = S_FALSE;
    }
  }
  catch(...)
  {
    res = S_FALSE;
  }
  if (res != S_OK)
  {
    Close();
    return res;
  }
  COM_TRY_END
  return S_OK;
}
Example #2
0
STDMETHODIMP CHandler::Open(IInStream *inStream,
    const UInt64 *maxCheckStartPosition,
    IArchiveOpenCallback *callback)
{
  COM_TRY_BEGIN
  Close();

  CInArchive archive;
  CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
  callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
  
  CMyComPtr<IInStream> nextStream = inStream;
  bool prevChecked = false;
  UInt64 numItems = 0;
  unsigned numTempVolumes = 0;
  // try
  {
    while (nextStream != NULL)
    {
      CDatabaseEx db;
      db.Stream = nextStream;
      HRESULT res = archive.Open(db, maxCheckStartPosition);
      _errorInHeaders |= archive.HeaderError;
      _errorInHeaders |= archive.ErrorInNames;
      _unexpectedEnd |= archive.UnexpectedEnd;
      
      if (res == S_OK && !m_Database.Volumes.IsEmpty())
      {
        const CArchInfo &lastArc = m_Database.Volumes.Back().ArcInfo;
        unsigned cabNumber = db.ArcInfo.CabinetNumber;
        if (lastArc.SetID != db.ArcInfo.SetID)
          res = S_FALSE;
        else if (prevChecked)
        {
          if (cabNumber != lastArc.CabinetNumber + 1)
            res = S_FALSE;
        }
        else if (cabNumber >= lastArc.CabinetNumber)
          res = S_FALSE;
        else if (numTempVolumes != 0)
        {
          const CArchInfo &prevArc = m_Database.Volumes[numTempVolumes - 1].ArcInfo;
          if (cabNumber != prevArc.CabinetNumber + 1)
            res = S_FALSE;
        }
      }
      
      if (archive.IsArc || res == S_OK)
      {
        _isArc = true;
        if (m_Database.Volumes.IsEmpty())
        {
          _offset = db.StartPosition;
          _phySize = db.ArcInfo.Size;
        }
      }
      
      if (res == S_OK)
      {
        numItems += db.Items.Size();
        m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : numTempVolumes, db);
        if (!prevChecked && m_Database.Volumes.Size() > 1)
        {
          numTempVolumes++;
          if (db.ArcInfo.CabinetNumber + 1 == m_Database.Volumes[numTempVolumes].ArcInfo.CabinetNumber)
            numTempVolumes = 0;
        }
      }
      else
      {
        if (res != S_FALSE)
          return res;
        if (m_Database.Volumes.IsEmpty())
          return S_FALSE;
        if (prevChecked)
          break;
        prevChecked = true;
        if (numTempVolumes != 0)
        {
          m_Database.Volumes.DeleteFrontal(numTempVolumes);
          numTempVolumes = 0;
        }
      }

      RINOK(callback->SetCompleted(&numItems, NULL));
        
      nextStream = NULL;
      
      for (;;)
      {
        const COtherArc *otherArc = NULL;
        if (!prevChecked)
        {
          if (numTempVolumes == 0)
          {
            const CInArcInfo &ai = m_Database.Volumes[0].ArcInfo;
            if (ai.IsTherePrev())
              otherArc = &ai.PrevArc;
            else
              prevChecked = true;
          }
          else
          {
            const CInArcInfo &ai = m_Database.Volumes[numTempVolumes - 1].ArcInfo;
            if (ai.IsThereNext())
              otherArc = &ai.NextArc;
            else
            {
              prevChecked = true;
              m_Database.Volumes.DeleteFrontal(numTempVolumes);
              numTempVolumes = 0;
            }
          }
        }
        if (!otherArc)
        {
          const CInArcInfo &ai = m_Database.Volumes.Back().ArcInfo;
          if (ai.IsThereNext())
            otherArc = &ai.NextArc;
        }
        if (!otherArc)
          break;
        if (!openVolumeCallback)
          break;
        // printf("\n%s", otherArc->FileName);
        const UString fullName = MultiByteToUnicodeString(otherArc->FileName, CP_ACP);
        HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream);
        if (result == S_OK)
          break;
        if (result != S_FALSE)
          return result;

        if (!_errorMessage.IsEmpty())
          _errorMessage.Add_LF();
        _errorMessage.AddAscii("Can't open volume: ");
        _errorMessage += fullName;
        
        if (prevChecked)
          break;
        prevChecked = true;
        if (numTempVolumes != 0)
        {
          m_Database.Volumes.DeleteFrontal(numTempVolumes);
          numTempVolumes = 0;
        }
      }

    } // read nextStream iteration

    if (numTempVolumes != 0)
    {
      m_Database.Volumes.DeleteFrontal(numTempVolumes);
      numTempVolumes = 0;
    }
    if (m_Database.Volumes.IsEmpty())
      return S_FALSE;
    else
    {
      m_Database.FillSortAndShrink();
      if (!m_Database.Check())
        return S_FALSE;
    }
  }
  COM_TRY_END
  return S_OK;
}