in other-licenses/7zstub/src/CPP/7zip/UI/Common/OpenArchive.cpp [1568:2903]
HRESULT CArc::OpenStream2(const COpenOptions &op)
{
// fprintf(stdout, "\nOpen: %S", Path); fflush(stdout);
Archive.Release();
GetRawProps.Release();
GetRootProps.Release();
ErrorInfo.ClearErrors();
ErrorInfo.ErrorFormatIndex = -1;
IsParseArc = false;
ArcStreamOffset = 0;
// OutputDebugStringA("1");
// OutputDebugStringW(Path);
const UString fileName = ExtractFileNameFromPath(Path);
UString extension;
{
int dotPos = fileName.ReverseFind_Dot();
if (dotPos >= 0)
extension = fileName.Ptr(dotPos + 1);
}
CIntVector orderIndices;
bool searchMarkerInHandler = false;
#ifdef _SFX
searchMarkerInHandler = true;
#endif
CBoolArr isMainFormatArr(op.codecs->Formats.Size());
{
FOR_VECTOR(i, op.codecs->Formats)
isMainFormatArr[i] = false;
}
UInt64 maxStartOffset =
op.openType.MaxStartOffset_Defined ?
op.openType.MaxStartOffset :
kMaxCheckStartPosition;
#ifndef _SFX
bool isUnknownExt = false;
#endif
bool isForced = false;
unsigned numMainTypes = 0;
int formatIndex = op.openType.FormatIndex;
if (formatIndex >= 0)
{
isForced = true;
orderIndices.Add(formatIndex);
numMainTypes = 1;
isMainFormatArr[(unsigned)formatIndex] = true;
searchMarkerInHandler = true;
}
else
{
unsigned numFinded = 0;
#ifndef _SFX
bool isPrearcExt = false;
#endif
{
#ifndef _SFX
bool isZip = false;
bool isRar = false;
const wchar_t c = extension[0];
if (c == 'z' || c == 'Z' || c == 'r' || c == 'R')
{
bool isNumber = false;
for (unsigned k = 1;; k++)
{
const wchar_t d = extension[k];
if (d == 0)
break;
if (d < '0' || d > '9')
{
isNumber = false;
break;
}
isNumber = true;
}
if (isNumber)
if (c == 'z' || c == 'Z')
isZip = true;
else
isRar = true;
}
#endif
FOR_VECTOR (i, op.codecs->Formats)
{
const CArcInfoEx &ai = op.codecs->Formats[i];
if (IgnoreSplit || !op.openType.CanReturnArc)
if (ai.IsSplit())
continue;
if (op.excludedFormats->FindInSorted(i) >= 0)
continue;
#ifndef _SFX
if (IsPreArcFormat(ai))
isPrearcExt = true;
#endif
if (ai.FindExtension(extension) >= 0
#ifndef _SFX
|| isZip && StringsAreEqualNoCase_Ascii(ai.Name, "zip")
|| isRar && StringsAreEqualNoCase_Ascii(ai.Name, "rar")
#endif
)
{
// PrintNumber("orderIndices.Insert", i);
orderIndices.Insert(numFinded++, i);
isMainFormatArr[i] = true;
}
else
orderIndices.Add(i);
}
}
if (!op.stream)
{
if (numFinded != 1)
return E_NOTIMPL;
orderIndices.DeleteFrom(1);
}
// PrintNumber("numFinded", numFinded );
/*
if (op.openOnlySpecifiedByExtension)
{
if (numFinded != 0 && !IsExeExt(extension))
orderIndices.DeleteFrom(numFinded);
}
*/
#ifndef _SFX
if (op.stream && orderIndices.Size() >= 2)
{
RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
CByteBuffer byteBuffer;
CIntVector orderIndices2;
if (numFinded == 0 || IsExeExt(extension))
{
// signature search was here
}
else if (extension.IsEqualTo("000") || extension.IsEqualTo("001"))
{
int i = FindFormatForArchiveType(op.codecs, orderIndices, "rar");
if (i >= 0)
{
const size_t kBufSize = (1 << 10);
byteBuffer.Alloc(kBufSize);
size_t processedSize = kBufSize;
RINOK(ReadStream(op.stream, byteBuffer, &processedSize));
if (processedSize >= 16)
{
const Byte *buf = byteBuffer;
const Byte kRarHeader[] = { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 };
if (TestSignature(buf, kRarHeader, 7) && buf[9] == 0x73 && (buf[10] & 1) != 0)
{
orderIndices2.Add(orderIndices[i]);
orderIndices[i] = -1;
if (i >= (int)numFinded)
numFinded++;
}
}
}
}
else
{
const size_t kBufSize = (1 << 10);
byteBuffer.Alloc(kBufSize);
size_t processedSize = kBufSize;
RINOK(ReadStream(op.stream, byteBuffer, &processedSize));
if (processedSize == 0)
return S_FALSE;
/*
check type order:
1) matched extension, no signuature
2) matched extension, matched signuature
// 3) no signuature
// 4) matched signuature
*/
MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0);
MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize);
// MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, NULL, 0);
// MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, byteBuffer, processedSize);
}
FOR_VECTOR (i, orderIndices)
{
int val = orderIndices[i];
if (val != -1)
orderIndices2.Add(val);
}
orderIndices = orderIndices2;
}
if (orderIndices.Size() >= 2)
{
int iIso = FindFormatForArchiveType(op.codecs, orderIndices, "iso");
int iUdf = FindFormatForArchiveType(op.codecs, orderIndices, "udf");
if (iUdf > iIso && iIso >= 0)
{
int isoIndex = orderIndices[iIso];
int udfIndex = orderIndices[iUdf];
orderIndices[iUdf] = isoIndex;
orderIndices[iIso] = udfIndex;
}
}
numMainTypes = numFinded;
isUnknownExt = (numMainTypes == 0) || isPrearcExt;
#else // _SFX
numMainTypes = orderIndices.Size();
// we need correct numMainTypes for mutlivolume SFX (if some volume is missing)
if (numFinded != 0)
numMainTypes = numFinded;
#endif
}
UInt64 fileSize = 0;
if (op.stream)
{
RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize));
RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
}
FileSize = fileSize;
#ifndef _SFX
CBoolArr skipFrontalFormat(op.codecs->Formats.Size());
{
FOR_VECTOR(i, op.codecs->Formats)
skipFrontalFormat[i] = false;
}
#endif
const COpenType &mode = op.openType;
if (mode.CanReturnArc)
{
// ---------- OPEN main type by extenssion ----------
unsigned numCheckTypes = orderIndices.Size();
if (formatIndex >= 0)
numCheckTypes = numMainTypes;
for (unsigned i = 0; i < numCheckTypes; i++)
{
FormatIndex = orderIndices[i];
bool exactOnly = false;
#ifndef _SFX
const CArcInfoEx &ai = op.codecs->Formats[FormatIndex];
// OutputDebugStringW(ai.Name);
if (i >= numMainTypes)
{
if (!ai.Flags_BackwardOpen()
// && !ai.Flags_PureStartOpen()
)
continue;
exactOnly = true;
}
#endif
// Some handlers do not set total bytes. So we set it here
if (op.callback)
RINOK(op.callback->SetTotal(NULL, &fileSize));
if (op.stream)
{
RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
}
CMyComPtr<IInArchive> archive;
RINOK(PrepareToOpen(op, FormatIndex, archive));
if (!archive)
continue;
HRESULT result;
if (op.stream)
{
UInt64 searchLimit = (!exactOnly && searchMarkerInHandler) ? maxStartOffset: 0;
result = archive->Open(op.stream, &searchLimit, op.callback);
}
else
{
CMyComPtr<IArchiveOpenSeq> openSeq;
archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq);
if (!openSeq)
return E_NOTIMPL;
result = openSeq->OpenSeq(op.seqStream);
}
RINOK(ReadBasicProps(archive, 0, result));
if (result == S_FALSE)
{
bool isArc = ErrorInfo.IsArc_After_NonOpen();
#ifndef _SFX
// if it's archive, we allow another open attempt for parser
if (!mode.CanReturnParser || !isArc)
skipFrontalFormat[(unsigned)FormatIndex] = true;
#endif
if (exactOnly)
continue;
if (i == 0 && numMainTypes == 1)
{
// we set NonOpenErrorInfo, only if there is only one main format (defined by extension).
ErrorInfo.ErrorFormatIndex = FormatIndex;
NonOpen_ErrorInfo = ErrorInfo;
if (!mode.CanReturnParser && isArc)
{
// if (formatIndex < 0 && !searchMarkerInHandler)
{
// if bad archive was detected, we don't need additional open attempts
#ifndef _SFX
if (!IsPreArcFormat(ai) /* || !mode.SkipSfxStub */)
#endif
return S_FALSE;
}
}
}
/*
#ifndef _SFX
if (IsExeExt(extension) || ai.Flags_PreArc())
{
// openOnlyFullArc = false;
// canReturnTailArc = true;
// limitSignatureSearch = true;
}
#endif
*/
continue;
}
RINOK(result);
#ifndef _SFX
bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex];
const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);
bool thereIsTail = ErrorInfo.ThereIsTail;
if (thereIsTail && mode.ZerosTailIsAllowed)
{
RINOK(CheckZerosTail(op, Offset + PhySize));
if (ErrorInfo.IgnoreTail)
thereIsTail = false;
}
if (Offset > 0)
{
if (exactOnly
|| !searchMarkerInHandler
|| !specFlags.CanReturn_NonStart()
|| (mode.MaxStartOffset_Defined && (UInt64)Offset > mode.MaxStartOffset))
continue;
}
if (thereIsTail)
{
if (Offset > 0)
{
if (!specFlags.CanReturnMid)
continue;
}
else if (!specFlags.CanReturnFrontal)
continue;
}
if (Offset > 0 || thereIsTail)
{
if (formatIndex < 0)
{
if (IsPreArcFormat(ai))
{
// openOnlyFullArc = false;
// canReturnTailArc = true;
/*
if (mode.SkipSfxStub)
limitSignatureSearch = true;
*/
// if (mode.SkipSfxStub)
{
// skipFrontalFormat[FormatIndex] = true;
continue;
}
}
}
}
#endif
Archive = archive;
return S_OK;
}
}
#ifndef _SFX
if (!op.stream)
return S_FALSE;
if (formatIndex >= 0 && !mode.CanReturnParser)
{
if (mode.MaxStartOffset_Defined)
{
if (mode.MaxStartOffset == 0)
return S_FALSE;
}
else
{
const CArcInfoEx &ai = op.codecs->Formats[formatIndex];
if (ai.FindExtension(extension) >= 0)
{
if (ai.Flags_FindSignature() && searchMarkerInHandler)
return S_FALSE;
}
}
}
NArchive::NParser::CHandler *handlerSpec = new NArchive::NParser::CHandler;
CMyComPtr<IInArchive> handler = handlerSpec;
CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback;
CMyComPtr<IArchiveExtractCallback> extractCallback_To_OpenCallback = extractCallback_To_OpenCallback_Spec;
extractCallback_To_OpenCallback_Spec->Init(op.callback);
{
// ---------- Check all possible START archives ----------
// this code is better for full file archives than Parser's code.
CByteBuffer byteBuffer;
bool endOfFile = false;
size_t processedSize;
{
size_t bufSize = 1 << 20; // it must be larger than max signature offset or IsArcFunc offset ((1 << 19) + x for UDF)
if (bufSize > fileSize)
{
bufSize = (size_t)fileSize;
endOfFile = true;
}
byteBuffer.Alloc(bufSize);
RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
processedSize = bufSize;
RINOK(ReadStream(op.stream, byteBuffer, &processedSize));
if (processedSize == 0)
return S_FALSE;
if (processedSize < bufSize)
endOfFile = true;
}
CUIntVector sortedFormats;
unsigned i;
int splitIndex = -1;
for (i = 0; i < orderIndices.Size(); i++)
{
unsigned form = orderIndices[i];
if (skipFrontalFormat[form])
continue;
const CArcInfoEx &ai = op.codecs->Formats[form];
if (ai.IsSplit())
{
splitIndex = form;
continue;
}
if (ai.IsArcFunc)
{
UInt32 isArcRes = ai.IsArcFunc(byteBuffer, processedSize);
if (isArcRes == k_IsArc_Res_NO)
continue;
if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile)
continue;
// if (isArcRes == k_IsArc_Res_YES_LOW_PROB) continue;
sortedFormats.Insert(0, form);
continue;
}
bool isNewStyleSignature = IsNewStyleSignature(ai);
bool needCheck = !isNewStyleSignature
|| ai.Signatures.IsEmpty()
|| ai.Flags_PureStartOpen()
|| ai.Flags_StartOpen()
|| ai.Flags_BackwardOpen();
if (isNewStyleSignature && !ai.Signatures.IsEmpty())
{
unsigned k;
for (k = 0; k < ai.Signatures.Size(); k++)
{
const CByteBuffer &sig = ai.Signatures[k];
UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size();
if (processedSize < signatureEnd)
{
if (!endOfFile)
needCheck = true;
}
else if (memcmp(sig, byteBuffer + ai.SignatureOffset, sig.Size()) == 0)
break;
}
if (k != ai.Signatures.Size())
{
sortedFormats.Insert(0, form);
continue;
}
}
if (needCheck)
sortedFormats.Add(form);
}
if (splitIndex >= 0)
sortedFormats.Insert(0, splitIndex);
for (i = 0; i < sortedFormats.Size(); i++)
{
FormatIndex = sortedFormats[i];
const CArcInfoEx &ai = op.codecs->Formats[FormatIndex];
if (op.callback)
RINOK(op.callback->SetTotal(NULL, &fileSize));
RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
CMyComPtr<IInArchive> archive;
RINOK(PrepareToOpen(op, FormatIndex, archive));
if (!archive)
continue;
PRF(printf("\nSorted Open %S", (const wchar_t *)ai.Name));
HRESULT result;
{
UInt64 searchLimit = 0;
/*
if (mode.CanReturnArc)
result = archive->Open(op.stream, &searchLimit, op.callback);
else
*/
result = OpenArchiveSpec(archive, !mode.CanReturnArc, op.stream, &searchLimit, op.callback, extractCallback_To_OpenCallback);
}
if (result == S_FALSE)
{
skipFrontalFormat[(unsigned)FormatIndex] = true;
// FIXME: maybe we must use LenIsUnknown.
// printf(" OpenForSize Error");
continue;
}
RINOK(result);
RINOK(ReadBasicProps(archive, 0, result));
if (Offset > 0)
{
continue; // good handler doesn't return such Offset > 0
// but there are some cases like false prefixed PK00 archive, when
// we can support it?
}
NArchive::NParser::CParseItem pi;
pi.Offset = Offset;
pi.Size = AvailPhySize;
// bool needScan = false;
if (!PhySizeDefined)
{
// it's for Z format
pi.LenIsUnknown = true;
// needScan = true;
// phySize = arcRem;
// nextNeedCheckStartOpen = false;
}
/*
if (OkPhySize_Defined)
pi.OkSize = pi.OkPhySize;
else
pi.OkSize = pi.Size;
*/
pi.NormalizeOffset();
// printf(" phySize = %8d", (unsigned)phySize);
if (mode.CanReturnArc)
{
bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex];
const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);
bool openCur = false;
if (!ErrorInfo.ThereIsTail)
openCur = true;
else
{
if (mode.ZerosTailIsAllowed)
{
RINOK(CheckZerosTail(op, Offset + PhySize));
if (ErrorInfo.IgnoreTail)
openCur = true;
}
if (!openCur)
{
openCur = specFlags.CanReturnFrontal;
if (formatIndex < 0) // format is not forced
{
if (IsPreArcFormat(ai))
{
// if (mode.SkipSfxStub)
{
openCur = false;
}
}
}
}
}
if (openCur)
{
InStream = op.stream;
Archive = archive;
return S_OK;
}
}
skipFrontalFormat[(unsigned)FormatIndex] = true;
// if (!mode.CanReturnArc)
/*
if (!ErrorInfo.ThereIsTail)
continue;
*/
if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize)
continue;
// printf("\nAdd offset = %d", (int)pi.Offset);
RINOK(ReadParseItemProps(archive, ai, pi));
handlerSpec->AddItem(pi);
}
}
// ---------- PARSER ----------
CUIntVector arc2sig; // formatIndex to signatureIndex
CUIntVector sig2arc; // signatureIndex to formatIndex;
{
unsigned sum = 0;
FOR_VECTOR (i, op.codecs->Formats)
{
arc2sig.Add(sum);
const CObjectVector<CByteBuffer> &sigs = op.codecs->Formats[i].Signatures;
sum += sigs.Size();
FOR_VECTOR (k, sigs)
sig2arc.Add(i);
}
}
{
const size_t kBeforeSize = 1 << 16;
const size_t kAfterSize = 1 << 20;
const size_t kBufSize = 1 << 22; // it must be more than kBeforeSize + kAfterSize
const UInt32 kNumVals = (UInt32)1 << (kNumHashBytes * 8);
CByteArr hashBuffer(kNumVals);
Byte *hash = hashBuffer;
memset(hash, 0xFF, kNumVals);
Byte prevs[256];
memset(prevs, 0xFF, sizeof(prevs));
if (sig2arc.Size() >= 0xFF)
return S_FALSE;
CUIntVector difficultFormats;
CBoolArr difficultBools(256);
{
for (unsigned i = 0; i < 256; i++)
difficultBools[i] = false;
}
bool thereAreHandlersForSearch = false;
// UInt32 maxSignatureEnd = 0;
FOR_VECTOR (i, orderIndices)
{
int index = orderIndices[i];
if (index < 0)
continue;
const CArcInfoEx &ai = op.codecs->Formats[(unsigned)index];
bool isDifficult = false;
// if (ai.Version < 0x91F) // we don't use parser with old DLL (before 9.31)
if (!ai.NewInterface)
isDifficult = true;
else
{
if (ai.Flags_StartOpen())
isDifficult = true;
FOR_VECTOR (k, ai.Signatures)
{
const CByteBuffer &sig = ai.Signatures[k];
/*
UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size();
if (maxSignatureEnd < signatureEnd)
maxSignatureEnd = signatureEnd;
*/
if (sig.Size() < kNumHashBytes)
{
isDifficult = true;
continue;
}
thereAreHandlersForSearch = true;
UInt32 v = HASH_VAL(sig);
unsigned sigIndex = arc2sig[(unsigned)index] + k;
prevs[sigIndex] = hash[v];
hash[v] = (Byte)sigIndex;
}
}
if (isDifficult)
{
difficultFormats.Add(index);
difficultBools[(unsigned)index] = true;
}
}
if (!thereAreHandlersForSearch)
{
// openOnlyFullArc = true;
// canReturnTailArc = true;
}
RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
CLimitedCachedInStream *limitedStreamSpec = new CLimitedCachedInStream;
CMyComPtr<IInStream> limitedStream = limitedStreamSpec;
limitedStreamSpec->SetStream(op.stream);
CArchiveOpenCallback_Offset *openCallback_Offset_Spec = NULL;
CMyComPtr<IArchiveOpenCallback> openCallback_Offset;
if (op.callback)
{
openCallback_Offset_Spec = new CArchiveOpenCallback_Offset;
openCallback_Offset = openCallback_Offset_Spec;
openCallback_Offset_Spec->Callback = op.callback;
openCallback_Offset_Spec->Callback.QueryInterface(IID_IArchiveOpenVolumeCallback, &openCallback_Offset_Spec->OpenVolumeCallback);
#ifndef _NO_CRYPTO
openCallback_Offset_Spec->Callback.QueryInterface(IID_ICryptoGetTextPassword, &openCallback_Offset_Spec->GetTextPassword);
#endif
}
if (op.callback)
RINOK(op.callback->SetTotal(NULL, &fileSize));
CByteBuffer &byteBuffer = limitedStreamSpec->Buffer;
byteBuffer.Alloc(kBufSize);
UInt64 callbackPrev = 0;
bool needCheckStartOpen = true; // = true, if we need to test all archives types for current pos.
bool endOfFile = false;
UInt64 bufPhyPos = 0;
size_t bytesInBuf = 0;
// UInt64 prevPos = 0;
// ---------- Main Scan Loop ----------
UInt64 pos = 0;
if (!mode.EachPos && handlerSpec->_items.Size() == 1)
{
NArchive::NParser::CParseItem &pi = handlerSpec->_items[0];
if (!pi.LenIsUnknown && pi.Offset == 0)
pos = pi.Size;
}
for (;;)
{
// printf("\nPos = %d", (int)pos);
UInt64 posInBuf = pos - bufPhyPos;
// if (pos > ((UInt64)1 << 35)) break;
if (!endOfFile)
{
if (bytesInBuf < kBufSize)
{
size_t processedSize = kBufSize - bytesInBuf;
// printf("\nRead ask = %d", (unsigned)processedSize);
UInt64 seekPos = bufPhyPos + bytesInBuf;
RINOK(op.stream->Seek(bufPhyPos + bytesInBuf, STREAM_SEEK_SET, NULL));
RINOK(ReadStream(op.stream, byteBuffer + bytesInBuf, &processedSize));
// printf(" processed = %d", (unsigned)processedSize);
if (processedSize == 0)
{
fileSize = seekPos;
endOfFile = true;
}
else
{
bytesInBuf += processedSize;
limitedStreamSpec->SetCache(processedSize, (size_t)bufPhyPos);
}
continue;
}
if (bytesInBuf < posInBuf)
{
UInt64 skipSize = posInBuf - bytesInBuf;
if (skipSize <= kBeforeSize)
{
size_t keepSize = (size_t)(kBeforeSize - skipSize);
// printf("\nmemmove skip = %d", (int)keepSize);
memmove(byteBuffer, byteBuffer + bytesInBuf - keepSize, keepSize);
bytesInBuf = keepSize;
bufPhyPos = pos - keepSize;
continue;
}
// printf("\nSkip %d", (int)(skipSize - kBeforeSize));
// RINOK(op.stream->Seek(skipSize - kBeforeSize, STREAM_SEEK_CUR, NULL));
bytesInBuf = 0;
bufPhyPos = pos - kBeforeSize;
continue;
}
if (bytesInBuf - posInBuf < kAfterSize)
{
size_t beg = (size_t)posInBuf - kBeforeSize;
// printf("\nmemmove for after beg = %d", (int)beg);
memmove(byteBuffer, byteBuffer + beg, bytesInBuf - beg);
bufPhyPos += beg;
bytesInBuf -= beg;
continue;
}
}
if (bytesInBuf <= (size_t)posInBuf)
break;
bool useOffsetCallback = false;
if (openCallback_Offset)
{
openCallback_Offset_Spec->Files = handlerSpec->_items.Size();
openCallback_Offset_Spec->Offset = pos;
useOffsetCallback = (!op.openType.CanReturnArc || handlerSpec->_items.Size() > 1);
if (pos >= callbackPrev + (1 << 23))
{
RINOK(openCallback_Offset_Spec->SetCompleted(NULL, NULL));
callbackPrev = pos;
}
}
{
UInt64 endPos = bufPhyPos + bytesInBuf;
if (fileSize < endPos)
{
FileSize = fileSize; // why ????
fileSize = endPos;
}
}
size_t availSize = bytesInBuf - (size_t)posInBuf;
if (availSize < kNumHashBytes)
break;
size_t scanSize = availSize -
((availSize >= kAfterSize) ? kAfterSize : kNumHashBytes);
{
/*
UInt64 scanLimit = openOnlyFullArc ?
maxSignatureEnd :
op.openType.ScanSize + maxSignatureEnd;
*/
if (!mode.CanReturnParser)
{
if (pos > maxStartOffset)
break;
UInt64 remScan = maxStartOffset - pos;
if (scanSize > remScan)
scanSize = (size_t)remScan;
}
}
scanSize++;
const Byte *buf = byteBuffer + (size_t)posInBuf;
const Byte *bufLimit = buf + scanSize;
size_t ppp = 0;
if (!needCheckStartOpen)
{
for (; buf < bufLimit && hash[HASH_VAL(buf)] == 0xFF; buf++);
ppp = buf - (byteBuffer + (size_t)posInBuf);
pos += ppp;
if (buf == bufLimit)
continue;
}
UInt32 v = HASH_VAL(buf);
bool nextNeedCheckStartOpen = true;
unsigned i = hash[v];
unsigned indexOfDifficult = 0;
// ---------- Open Loop for Current Pos ----------
bool wasOpen = false;
for (;;)
{
unsigned index;
bool isDifficult;
if (needCheckStartOpen && indexOfDifficult < difficultFormats.Size())
{
index = difficultFormats[indexOfDifficult++];
isDifficult = true;
}
else
{
if (i == 0xFF)
break;
index = sig2arc[i];
unsigned sigIndex = i - arc2sig[index];
i = prevs[i];
if (needCheckStartOpen && difficultBools[index])
continue;
const CArcInfoEx &ai = op.codecs->Formats[index];
if (pos < ai.SignatureOffset)
continue;
/*
if (openOnlyFullArc)
if (pos != ai.SignatureOffset)
continue;
*/
const CByteBuffer &sig = ai.Signatures[sigIndex];
if (ppp + sig.Size() > availSize
|| !TestSignature(buf, sig, sig.Size()))
continue;
// printf("\nSignature OK: %10S %8x %5d", (const wchar_t *)ai.Name, (int)pos, (int)(pos - prevPos));
// prevPos = pos;
isDifficult = false;
}
const CArcInfoEx &ai = op.codecs->Formats[index];
if ((isDifficult && pos == 0) || ai.SignatureOffset == pos)
{
// we don't check same archive second time */
if (skipFrontalFormat[index])
continue;
}
UInt64 startArcPos = pos;
if (!isDifficult)
{
if (pos < ai.SignatureOffset)
continue;
startArcPos = pos - ai.SignatureOffset;
/*
// we don't need the check for Z files
if (startArcPos < handlerSpec->GetLastEnd())
continue;
*/
}
if (ai.IsArcFunc && startArcPos >= bufPhyPos)
{
size_t offsetInBuf = (size_t)(startArcPos - bufPhyPos);
if (offsetInBuf < bytesInBuf)
{
UInt32 isArcRes = ai.IsArcFunc(byteBuffer + offsetInBuf, bytesInBuf - offsetInBuf);
if (isArcRes == k_IsArc_Res_NO)
continue;
if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile)
continue;
/*
if (isArcRes == k_IsArc_Res_YES_LOW_PROB)
{
// if (pos != ai.SignatureOffset)
continue;
}
*/
}
// printf("\nIsArc OK: %S", (const wchar_t *)ai.Name);
}
/*
if (pos == 67109888)
pos = pos;
*/
PRF(printf("\npos = %9I64d : %S", pos, (const wchar_t *)ai.Name));
bool isMainFormat = isMainFormatArr[index];
const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);
CMyComPtr<IInArchive> archive;
RINOK(PrepareToOpen(op, index, archive));
if (!archive)
return E_FAIL;
// OutputDebugStringW(ai.Name);
UInt64 rem = fileSize - startArcPos;
UInt64 arcStreamOffset = 0;
if (ai.Flags_UseGlobalOffset())
{
limitedStreamSpec->InitAndSeek(0, fileSize);
limitedStream->Seek(startArcPos, STREAM_SEEK_SET, NULL);
}
else
{
limitedStreamSpec->InitAndSeek(startArcPos, rem);
arcStreamOffset = startArcPos;
}
UInt64 maxCheckStartPosition = 0;
if (openCallback_Offset)
{
openCallback_Offset_Spec->Files = handlerSpec->_items.Size();
openCallback_Offset_Spec->Offset = startArcPos;
}
// HRESULT result = archive->Open(limitedStream, &maxCheckStartPosition, openCallback_Offset);
extractCallback_To_OpenCallback_Spec->Files = 0;
extractCallback_To_OpenCallback_Spec->Offset = startArcPos;
HRESULT result = OpenArchiveSpec(archive, true, limitedStream, &maxCheckStartPosition,
useOffsetCallback ? (IArchiveOpenCallback *)openCallback_Offset : (IArchiveOpenCallback *)op.callback,
extractCallback_To_OpenCallback);
RINOK(ReadBasicProps(archive, ai.Flags_UseGlobalOffset() ? 0 : startArcPos, result));
bool isOpen = false;
if (result == S_FALSE)
{
if (!mode.CanReturnParser)
{
if (formatIndex < 0 && ErrorInfo.IsArc_After_NonOpen())
{
ErrorInfo.ErrorFormatIndex = index;
NonOpen_ErrorInfo = ErrorInfo;
// if archive was detected, we don't need additional open attempts
return S_FALSE;
}
continue;
}
if (!ErrorInfo.IsArc_After_NonOpen() || !PhySizeDefined || PhySize == 0)
continue;
}
else
{
isOpen = true;
RINOK(result);
PRF(printf(" OK "));
}
// fprintf(stderr, "\n %8X %S", startArcPos, Path);
// printf("\nOpen OK: %S", ai.Name);
NArchive::NParser::CParseItem pi;
pi.Offset = startArcPos;
if (ai.Flags_UseGlobalOffset())
pi.Offset = Offset;
else if (Offset != 0)
return E_FAIL;
UInt64 arcRem = FileSize - pi.Offset;
UInt64 phySize = arcRem;
bool phySizeDefined = PhySizeDefined;
if (phySizeDefined)
{
if (pi.Offset + PhySize > FileSize)
{
// ErrorInfo.ThereIsTail = true;
PhySize = FileSize - pi.Offset;
}
phySize = PhySize;
}
if (phySize == 0 || (UInt64)phySize > ((UInt64)1 << 63))
return E_FAIL;
/*
if (!ai.UseGlobalOffset)
{
if (phySize > arcRem)
{
ThereIsTail = true;
phySize = arcRem;
}
}
*/
bool needScan = false;
if (isOpen && !phySizeDefined)
{
// it's for Z format
pi.LenIsUnknown = true;
needScan = true;
phySize = arcRem;
nextNeedCheckStartOpen = false;
}
pi.Size = phySize;
/*
if (OkPhySize_Defined)
pi.OkSize = OkPhySize;
*/
pi.NormalizeOffset();
// printf(" phySize = %8d", (unsigned)phySize);
/*
if (needSkipFullArc)
if (pi.Offset == 0 && phySizeDefined && pi.Size >= fileSize)
continue;
*/
if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize)
{
// it's possible for dmg archives
if (!mode.CanReturnArc)
continue;
}
if (mode.EachPos)
pos++;
else if (needScan)
{
pos++;
/*
if (!OkPhySize_Defined)
pos++;
else
pos = pi.Offset + pi.OkSize;
*/
}
else
pos = pi.Offset + pi.Size;
RINOK(ReadParseItemProps(archive, ai, pi));
if (pi.Offset < startArcPos && !mode.EachPos /* && phySizeDefined */)
{
/* It's for DMG format.
This code deletes all previous items that are included to current item */
while (!handlerSpec->_items.IsEmpty())
{
{
const NArchive::NParser::CParseItem &back = handlerSpec->_items.Back();
if (back.Offset < pi.Offset)
break;
if (back.Offset + back.Size > pi.Offset + pi.Size)
break;
}
handlerSpec->_items.DeleteBack();
}
}
if (isOpen && mode.CanReturnArc && phySizeDefined)
{
// if (pi.Offset + pi.Size >= fileSize)
bool openCur = false;
bool thereIsTail = ErrorInfo.ThereIsTail;
if (thereIsTail && mode.ZerosTailIsAllowed)
{
RINOK(CheckZerosTail(op, arcStreamOffset + Offset + PhySize));
if (ErrorInfo.IgnoreTail)
thereIsTail = false;
}
if (pi.Offset != 0)
{
if (!pi.IsNotArcType)
if (thereIsTail)
openCur = specFlags.CanReturnMid;
else
openCur = specFlags.CanReturnTail;
}
else
{
if (!thereIsTail)
openCur = true;
else
openCur = specFlags.CanReturnFrontal;
if (formatIndex >= -2)
openCur = true;
}
if (formatIndex < 0 && pi.IsSelfExe /* && mode.SkipSfxStub */)
openCur = false;
// We open file as SFX, if there is front archive or first archive is "Self Executable"
if (!openCur && !pi.IsSelfExe && !thereIsTail &&
(!pi.IsNotArcType || pi.Offset == 0))
{
if (handlerSpec->_items.IsEmpty())
{
if (specFlags.CanReturnTail)
openCur = true;
}
else if (handlerSpec->_items.Size() == 1)
{
if (handlerSpec->_items[0].IsSelfExe)
{
if (mode.SpecUnknownExt.CanReturnTail)
openCur = true;
}
}
}
if (openCur)
{
InStream = op.stream;
Archive = archive;
FormatIndex = index;
ArcStreamOffset = arcStreamOffset;
return S_OK;
}
}
/*
if (openOnlyFullArc)
{
ErrorInfo.ClearErrors();
return S_FALSE;
}
*/
pi.FormatIndex = index;
// printf("\nAdd offset = %d", (int)pi.Offset);
handlerSpec->AddItem(pi);
wasOpen = true;
break;
}
// ---------- End of Open Loop for Current Pos ----------
if (!wasOpen)
pos++;
needCheckStartOpen = (nextNeedCheckStartOpen && wasOpen);
}
// ---------- End of Main Scan Loop ----------
/*
if (handlerSpec->_items.Size() == 1)
{
const NArchive::NParser::CParseItem &pi = handlerSpec->_items[0];
if (pi.Size == fileSize && pi.Offset == 0)
{
Archive = archive;
FormatIndex2 = pi.FormatIndex;
return S_OK;
}
}
*/
if (mode.CanReturnParser)
{
bool returnParser = (handlerSpec->_items.Size() == 1); // it's possible if fileSize was not correct at start of parsing
handlerSpec->AddUnknownItem(fileSize);
if (handlerSpec->_items.Size() == 0)
return S_FALSE;
if (returnParser || handlerSpec->_items.Size() != 1)
{
// return S_FALSE;
handlerSpec->_stream = op.stream;
Archive = handler;
ErrorInfo.ClearErrors();
IsParseArc = true;
FormatIndex = -1; // It's parser
Offset = 0;
return S_OK;
}
}
}
#endif
if (!Archive)
return S_FALSE;
return S_OK;
}