CabHandler.cpp (p7zip_15.14.1_src_all) | : | CabHandler.cpp (p7zip_16.02_src_all) | ||
---|---|---|---|---|
skipping to change at line 351 | skipping to change at line 351 | |||
{ | { | |||
COM_TRY_BEGIN | COM_TRY_BEGIN | |||
Close(); | Close(); | |||
CInArchive archive; | CInArchive archive; | |||
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; | CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; | |||
callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeC allback); | callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeC allback); | |||
CMyComPtr<IInStream> nextStream = inStream; | CMyComPtr<IInStream> nextStream = inStream; | |||
bool prevChecked = false; | bool prevChecked = false; | |||
UString startVolName; | ||||
bool startVolName_was_Requested = false; | ||||
UInt64 numItems = 0; | UInt64 numItems = 0; | |||
unsigned numTempVolumes = 0; | unsigned numTempVolumes = 0; | |||
// try | // try | |||
{ | { | |||
while (nextStream != NULL) | while (nextStream) | |||
{ | { | |||
CDatabaseEx db; | CDatabaseEx db; | |||
db.Stream = nextStream; | db.Stream = nextStream; | |||
HRESULT res = archive.Open(db, maxCheckStartPosition); | HRESULT res = archive.Open(db, maxCheckStartPosition); | |||
_errorInHeaders |= archive.HeaderError; | _errorInHeaders |= archive.HeaderError; | |||
_errorInHeaders |= archive.ErrorInNames; | _errorInHeaders |= archive.ErrorInNames; | |||
_unexpectedEnd |= archive.UnexpectedEnd; | _unexpectedEnd |= archive.UnexpectedEnd; | |||
if (res == S_OK && !m_Database.Volumes.IsEmpty()) | if (res == S_OK && !m_Database.Volumes.IsEmpty()) | |||
{ | { | |||
const CArchInfo &lastArc = m_Database.Volumes.Back().ArcInfo; | const CArchInfo &lastArc = m_Database.Volumes.Back().ArcInfo; | |||
unsigned cabNumber = db.ArcInfo.CabinetNumber; | unsigned cabNumber = db.ArcInfo.CabinetNumber; | |||
if (lastArc.SetID != db.ArcInfo.SetID) | if (lastArc.SetID != db.ArcInfo.SetID) | |||
res = S_FALSE; | res = S_FALSE; | |||
skipping to change at line 429 | skipping to change at line 433 | |||
} | } | |||
} | } | |||
RINOK(callback->SetCompleted(&numItems, NULL)); | RINOK(callback->SetCompleted(&numItems, NULL)); | |||
nextStream = NULL; | nextStream = NULL; | |||
for (;;) | for (;;) | |||
{ | { | |||
const COtherArc *otherArc = NULL; | const COtherArc *otherArc = NULL; | |||
if (!prevChecked) | if (!prevChecked) | |||
{ | { | |||
if (numTempVolumes == 0) | if (numTempVolumes == 0) | |||
{ | { | |||
const CInArcInfo &ai = m_Database.Volumes[0].ArcInfo; | const CInArcInfo &ai = m_Database.Volumes[0].ArcInfo; | |||
if (ai.IsTherePrev()) | if (ai.IsTherePrev()) | |||
otherArc = &ai.PrevArc; | otherArc = &ai.PrevArc; | |||
else | else | |||
prevChecked = true; | prevChecked = true; | |||
} | } | |||
skipping to change at line 452 | skipping to change at line 457 | |||
if (ai.IsThereNext()) | if (ai.IsThereNext()) | |||
otherArc = &ai.NextArc; | otherArc = &ai.NextArc; | |||
else | else | |||
{ | { | |||
prevChecked = true; | prevChecked = true; | |||
m_Database.Volumes.DeleteFrontal(numTempVolumes); | m_Database.Volumes.DeleteFrontal(numTempVolumes); | |||
numTempVolumes = 0; | numTempVolumes = 0; | |||
} | } | |||
} | } | |||
} | } | |||
if (!otherArc) | if (!otherArc) | |||
{ | { | |||
const CInArcInfo &ai = m_Database.Volumes.Back().ArcInfo; | const CInArcInfo &ai = m_Database.Volumes.Back().ArcInfo; | |||
if (ai.IsThereNext()) | if (ai.IsThereNext()) | |||
otherArc = &ai.NextArc; | otherArc = &ai.NextArc; | |||
} | } | |||
if (!otherArc) | if (!otherArc) | |||
break; | break; | |||
if (!openVolumeCallback) | if (!openVolumeCallback) | |||
break; | break; | |||
// printf("\n%s", otherArc->FileName); | // printf("\n%s", otherArc->FileName); | |||
const UString fullName = MultiByteToUnicodeString(otherArc->FileName, CP _ACP); | const UString fullName = MultiByteToUnicodeString(otherArc->FileName, CP _ACP); | |||
if (!startVolName_was_Requested) | ||||
{ | ||||
// some "bad" cab example can contain the link to itself. | ||||
startVolName_was_Requested = true; | ||||
{ | ||||
NCOM::CPropVariant prop; | ||||
RINOK(openVolumeCallback->GetProperty(kpidName, &prop)); | ||||
if (prop.vt == VT_BSTR) | ||||
startVolName = prop.bstrVal; | ||||
} | ||||
if (fullName == startVolName) | ||||
break; | ||||
} | ||||
HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream); | HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream); | |||
if (result == S_OK) | if (result == S_OK) | |||
break; | break; | |||
if (result != S_FALSE) | if (result != S_FALSE) | |||
return result; | return result; | |||
if (!_errorMessage.IsEmpty()) | if (!_errorMessage.IsEmpty()) | |||
_errorMessage.Add_LF(); | _errorMessage.Add_LF(); | |||
_errorMessage.AddAscii("Can't open volume: "); | _errorMessage.AddAscii("Can't open volume: "); | |||
_errorMessage += fullName; | _errorMessage += fullName; | |||
skipping to change at line 988 | skipping to change at line 1010 | |||
extractStatuses.Clear(); | extractStatuses.Clear(); | |||
for (; startIndex < index; startIndex++) | for (; startIndex < index; startIndex++) | |||
extractStatuses.Add(false); | extractStatuses.Add(false); | |||
extractStatuses.Add(true); | extractStatuses.Add(true); | |||
startIndex++; | startIndex++; | |||
UInt64 curUnpack = item.GetEndOffset(); | UInt64 curUnpack = item.GetEndOffset(); | |||
for (; i < numItems; i++) | for (; i < numItems; i++) | |||
{ | { | |||
unsigned indexNext = allFilesMode ? i : indices[i]; | unsigned indexNext = allFilesMode ? i : indices[i]; | |||
const CMvItem &mvItem = m_Database.Items[indexNext]; | const CMvItem &mvItem2 = m_Database.Items[indexNext]; | |||
const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.It | const CItem &item2 = m_Database.Volumes[mvItem2.VolumeIndex].Items[mvItem2 | |||
emIndex]; | .ItemIndex]; | |||
if (item.IsDir()) | if (item2.IsDir()) | |||
continue; | continue; | |||
int newFolderIndex = m_Database.GetFolderIndex(&mvItem); | int newFolderIndex = m_Database.GetFolderIndex(&mvItem2); | |||
if (newFolderIndex != folderIndex) | if (newFolderIndex != folderIndex) | |||
break; | break; | |||
for (; startIndex < indexNext; startIndex++) | for (; startIndex < indexNext; startIndex++) | |||
extractStatuses.Add(false); | extractStatuses.Add(false); | |||
extractStatuses.Add(true); | extractStatuses.Add(true); | |||
startIndex++; | startIndex++; | |||
curUnpack = item.GetEndOffset(); | curUnpack = item2.GetEndOffset(); | |||
} | } | |||
CFolderOutStream *cabFolderOutStream = new CFolderOutStream; | CFolderOutStream *cabFolderOutStream = new CFolderOutStream; | |||
CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream); | CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream); | |||
unsigned folderIndex2 = item.GetFolderIndex(db.Folders.Size()); | unsigned folderIndex2 = item.GetFolderIndex(db.Folders.Size()); | |||
const CFolder &folder = db.Folders[folderIndex2]; | const CFolder &folder = db.Folders[folderIndex2]; | |||
cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2, | cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2, | |||
curUnpack, extractCallback, testMode); | curUnpack, extractCallback, testMode); | |||
skipping to change at line 1075 | skipping to change at line 1097 | |||
bool thereWasNotAlignedChunk = false; | bool thereWasNotAlignedChunk = false; | |||
for (UInt32 bl = 0; cabFolderOutStream->NeedMoreWrite();) | for (UInt32 bl = 0; cabFolderOutStream->NeedMoreWrite();) | |||
{ | { | |||
if (volIndex >= m_Database.Volumes.Size()) | if (volIndex >= m_Database.Volumes.Size()) | |||
{ | { | |||
res = S_FALSE; | res = S_FALSE; | |||
break; | break; | |||
} | } | |||
const CDatabaseEx &db = m_Database.Volumes[volIndex]; | const CDatabaseEx &db2 = m_Database.Volumes[volIndex]; | |||
const CFolder &folder = db.Folders[locFolderIndex]; | const CFolder &folder2 = db2.Folders[locFolderIndex]; | |||
if (bl == 0) | if (bl == 0) | |||
{ | { | |||
cabBlockInStreamSpec->ReservedSize = db.ArcInfo.GetDataBlockReserveSiz | cabBlockInStreamSpec->ReservedSize = db2.ArcInfo.GetDataBlockReserveSi | |||
e(); | ze(); | |||
RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK | RINOK(db2.Stream->Seek(db2.StartPosition + folder2.DataStart, STREAM_S | |||
_SET, NULL)); | EEK_SET, NULL)); | |||
} | } | |||
if (bl == folder.NumDataBlocks) | if (bl == folder2.NumDataBlocks) | |||
{ | { | |||
/* | /* | |||
CFolder::NumDataBlocks (CFFOLDER::cCFData in CAB specification) is 1 6-bit. | CFolder::NumDataBlocks (CFFOLDER::cCFData in CAB specification) is 1 6-bit. | |||
But there are some big CAB archives from MS that contain more | But there are some big CAB archives from MS that contain more | |||
than (0xFFFF) CFDATA blocks in folder. | than (0xFFFF) CFDATA blocks in folder. | |||
Old cab extracting software can show error (or ask next volume) | Old cab extracting software can show error (or ask next volume) | |||
but cab extracting library in new Windows ignores this error. | but cab extracting library in new Windows ignores this error. | |||
15.00 : We also try to ignore such error, if archive is not multi-vo lume. | 15.00 : We also try to ignore such error, if archive is not multi-vo lume. | |||
*/ | */ | |||
if (m_Database.Volumes.Size() > 1) | if (m_Database.Volumes.Size() > 1) | |||
skipping to change at line 1109 | skipping to change at line 1131 | |||
continue; | continue; | |||
} | } | |||
} | } | |||
bl++; | bl++; | |||
if (!keepInputBuffer) | if (!keepInputBuffer) | |||
cabBlockInStreamSpec->InitForNewBlock(); | cabBlockInStreamSpec->InitForNewBlock(); | |||
UInt32 packSize, unpackSize; | UInt32 packSize, unpackSize; | |||
res = cabBlockInStreamSpec->PreRead(db.Stream, packSize, unpackSize); | res = cabBlockInStreamSpec->PreRead(db2.Stream, packSize, unpackSize); | |||
if (res == S_FALSE) | if (res == S_FALSE) | |||
break; | break; | |||
RINOK(res); | RINOK(res); | |||
keepInputBuffer = (unpackSize == 0); | keepInputBuffer = (unpackSize == 0); | |||
if (keepInputBuffer) | if (keepInputBuffer) | |||
continue; | continue; | |||
UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFold er(); | UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFold er(); | |||
totalPacked += packSize; | totalPacked += packSize; | |||
skipping to change at line 1151 | skipping to change at line 1173 | |||
{ | { | |||
res = S_FALSE; | res = S_FALSE; | |||
break; | break; | |||
} | } | |||
thereWasNotAlignedChunk = true; | thereWasNotAlignedChunk = true; | |||
} | } | |||
UInt64 unpackSize64 = unpackSize; | UInt64 unpackSize64 = unpackSize; | |||
UInt32 packSizeChunk = cabBlockInStreamSpec->GetPackSizeAvail(); | UInt32 packSizeChunk = cabBlockInStreamSpec->GetPackSizeAvail(); | |||
switch (folder.GetMethod()) | switch (folder2.GetMethod()) | |||
{ | { | |||
case NHeader::NMethod::kNone: | case NHeader::NMethod::kNone: | |||
res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackSize 64, NULL); | res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackSize 64, NULL); | |||
break; | break; | |||
case NHeader::NMethod::kMSZip: | case NHeader::NMethod::kMSZip: | |||
deflateDecoderSpec->Set_KeepHistory(keepHistory); | deflateDecoderSpec->Set_KeepHistory(keepHistory); | |||
/* v9.31: now we follow MSZIP specification that requires to finish deflate stream at the end of each block. | /* v9.31: now we follow MSZIP specification that requires to finish deflate stream at the end of each block. | |||
But PyCabArc can create CAB archives that doesn't have finish mar ker at the end of block. | But PyCabArc can create CAB archives that doesn't have finish mar ker at the end of block. | |||
Cabarc probably ignores such errors in cab archives. | Cabarc probably ignores such errors in cab archives. | |||
End of changes. 16 change blocks. | ||||
16 lines changed or deleted | 38 lines changed or added |