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; }
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; }