📄 7zin.cpp
字号:
// 7zIn.cpp
#include "StdAfx.h"
#include "7zIn.h"
#include "7zMethods.h"
#include "7zDecode.h"
#include "../../Common/StreamObjects.h"
#include "../../../Common/CRC.h"
namespace NArchive {
namespace N7z {
class CStreamSwitch
{
CInArchive *_archive;
bool _needRemove;
public:
CStreamSwitch(): _needRemove(false) {}
~CStreamSwitch() { Remove(); }
void Remove();
void Set(CInArchive *archive, const BYTE *data, UINT32 size);
void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
HRESULT Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
};
void CStreamSwitch::Remove()
{
if (_needRemove)
{
_archive->DeleteByteStream();
_needRemove = false;
}
}
void CStreamSwitch::Set(CInArchive *archive, const BYTE *data, UINT32 size)
{
Remove();
_archive = archive;
_archive->AddByteStream(data, size);
_needRemove = true;
}
void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
{
Set(archive, byteBuffer, byteBuffer.GetCapacity());
}
HRESULT CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
{
Remove();
BYTE external;
RINOK(archive->SafeReadByte2(external));
if (external != 0)
{
UINT64 dataIndex;
RINOK(archive->ReadNumber(dataIndex));
Set(archive, (*dataVector)[(UINT32)dataIndex]);
}
return S_OK;
}
CInArchiveException::CInArchiveException(CCauseType cause):
Cause(cause)
{}
HRESULT CInArchive::ReadBytes(IInStream *stream, void *data, UINT32 size,
UINT32 *processedSize)
{
UINT32 realProcessedSize;
HRESULT result = stream->Read(data, size, &realProcessedSize);
if(processedSize != NULL)
*processedSize = realProcessedSize;
_position += realProcessedSize;
return result;
}
HRESULT CInArchive::ReadBytes(void *data, UINT32 size, UINT32 *processedSize)
{
return ReadBytes(_stream, data, size, processedSize);
}
HRESULT CInArchive::SafeReadBytes(void *data, UINT32 size)
{
UINT32 realProcessedSize;
RINOK(ReadBytes(data, size, &realProcessedSize));
if (realProcessedSize != size)
throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
return S_OK;
}
HRESULT CInArchive::ReadNumber(UINT64 &value)
{
BYTE firstByte;
RINOK(SafeReadByte2(firstByte));
BYTE mask = 0x80;
for (int i = 0; i < 8; i++)
{
if ((firstByte & mask) == 0)
{
value = 0;
RINOK(SafeReadBytes2(&value, i));
UINT64 highPart = firstByte & (mask - 1);
value += (highPart << (i * 8));
return S_OK;
}
mask >>= 1;
}
return SafeReadBytes2(&value, 8);
}
static inline bool TestSignatureCandidate(const void *testBytes)
{
// return (memcmp(testBytes, kSignature, kSignatureSize) == 0);
for (UINT32 i = 0; i < kSignatureSize; i++)
if (((const BYTE *)testBytes)[i] != kSignature[i])
return false;
return true;
}
HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UINT64 *searchHeaderSizeLimit)
{
_position = _arhiveBeginStreamPosition;
RINOK(stream->Seek(_arhiveBeginStreamPosition, STREAM_SEEK_SET, NULL));
BYTE signature[kSignatureSize];
UINT32 processedSize;
RINOK(ReadBytes(stream, signature, kSignatureSize, &processedSize));
if(processedSize != kSignatureSize)
return S_FALSE;
if (TestSignatureCandidate(signature))
return S_OK;
CByteBuffer byteBuffer;
static const UINT32 kSearchSignatureBufferSize = 0x10000;
byteBuffer.SetCapacity(kSearchSignatureBufferSize);
BYTE *buffer = byteBuffer;
UINT32 numBytesPrev = kSignatureSize - 1;
memmove(buffer, signature + 1, numBytesPrev);
UINT64 curTestPos = _arhiveBeginStreamPosition + 1;
while(true)
{
if (searchHeaderSizeLimit != NULL)
if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
return false;
UINT32 numReadBytes = kSearchSignatureBufferSize - numBytesPrev;
RINOK(ReadBytes(stream, buffer + numBytesPrev, numReadBytes, &processedSize));
UINT32 numBytesInBuffer = numBytesPrev + processedSize;
if (numBytesInBuffer < kSignatureSize)
return S_FALSE;
UINT32 numTests = numBytesInBuffer - kSignatureSize + 1;
for(UINT32 pos = 0; pos < numTests; pos++, curTestPos++)
{
if (TestSignatureCandidate(buffer + pos))
{
_arhiveBeginStreamPosition = curTestPos;
_position = curTestPos + kSignatureSize;
return stream->Seek(_position, STREAM_SEEK_SET, NULL);
}
}
numBytesPrev = numBytesInBuffer - numTests;
memmove(buffer, buffer + numTests, numBytesPrev);
}
}
// S_FALSE means that file is not archive
HRESULT CInArchive::Open(IInStream *stream, const UINT64 *searchHeaderSizeLimit)
{
Close();
RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
_position = _arhiveBeginStreamPosition;
RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
_stream = stream;
return S_OK;
}
void CInArchive::Close()
{
_stream.Release();
}
HRESULT CInArchive::SkeepData(UINT64 size)
{
for (UINT64 i = 0; i < size; i++)
{
BYTE temp;
RINOK(SafeReadByte2(temp));
}
return S_OK;
}
HRESULT CInArchive::SkeepData()
{
UINT64 size;
RINOK(ReadNumber(size));
return SkeepData(size);
}
HRESULT CInArchive::ReadArchiveProperties(CInArchiveInfo &archiveInfo)
{
while(true)
{
UINT64 type;
RINOK(ReadID(type));
if (type == NID::kEnd)
break;
SkeepData();
}
return S_OK;
}
HRESULT CInArchive::GetNextFolderItem(CFolder &folder)
{
UINT64 numCoders;
RINOK(ReadNumber(numCoders));
folder.Coders.Clear();
folder.Coders.Reserve((int)numCoders);
UINT32 numInStreams = 0;
UINT32 numOutStreams = 0;
UINT32 i;
for (i = 0; i < numCoders; i++)
{
folder.Coders.Add(CCoderInfo());
CCoderInfo &coderInfo = folder.Coders.Back();
while (true)
{
coderInfo.AltCoders.Add(CAltCoderInfo());
CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Back();
BYTE mainByte;
RINOK(SafeReadByte2(mainByte));
altCoderInfo.MethodID.IDSize = mainByte & 0xF;
bool isComplex = (mainByte & 0x10) != 0;
bool tereAreProperties = (mainByte & 0x20) != 0;
RINOK(SafeReadBytes2(&altCoderInfo.MethodID.ID[0],
altCoderInfo.MethodID.IDSize));
if (isComplex)
{
RINOK(ReadNumber(coderInfo.NumInStreams));
RINOK(ReadNumber(coderInfo.NumOutStreams));
}
else
{
coderInfo.NumInStreams = 1;
coderInfo.NumOutStreams = 1;
}
UINT64 propertiesSize = 0;
if (tereAreProperties)
{
RINOK(ReadNumber(propertiesSize));
}
altCoderInfo.Properties.SetCapacity((UINT32)propertiesSize);
RINOK(SafeReadBytes2((BYTE *)altCoderInfo.Properties,
(UINT32)propertiesSize));
// coderInfo.AltCoders.Add(coderInfo.AltCoders.Back());
if ((mainByte & 0x80) == 0)
break;
}
numInStreams += (UINT32)coderInfo.NumInStreams;
numOutStreams += (UINT32)coderInfo.NumOutStreams;
}
UINT64 numBindPairs;
// RINOK(ReadNumber(numBindPairs));
numBindPairs = numOutStreams - 1;
folder.BindPairs.Clear();
folder.BindPairs.Reserve((UINT32)numBindPairs);
for (i = 0; i < numBindPairs; i++)
{
CBindPair bindPair;
RINOK(ReadNumber(bindPair.InIndex));
RINOK(ReadNumber(bindPair.OutIndex));
folder.BindPairs.Add(bindPair);
}
UINT32 numPackedStreams = numInStreams - (UINT32)numBindPairs;
folder.PackStreams.Reserve(numPackedStreams);
if (numPackedStreams == 1)
{
for (UINT32 j = 0; j < numInStreams; j++)
if (folder.FindBindPairForInStream(j) < 0)
{
CPackStreamInfo packStreamInfo;
packStreamInfo.Index = j;
folder.PackStreams.Add(packStreamInfo);
break;
}
}
else
for(i = 0; i < numPackedStreams; i++)
{
CPackStreamInfo packStreamInfo;
RINOK(ReadNumber(packStreamInfo.Index));
folder.PackStreams.Add(packStreamInfo);
}
return S_OK;
}
HRESULT CInArchive::WaitAttribute(UINT64 attribute)
{
while(true)
{
UINT64 type;
RINOK(ReadID(type));
if (type == attribute)
return S_OK;
if (type == NID::kEnd)
return S_FALSE;
RINOK(SkeepData());
}
}
HRESULT CInArchive::ReadHashDigests(int numItems,
CRecordVector<bool> &digestsDefined,
CRecordVector<UINT32> &digests)
{
RINOK(ReadBoolVector2(numItems, digestsDefined));
digests.Clear();
digests.Reserve(numItems);
for(int i = 0; i < numItems; i++)
{
UINT32 crc;
if (digestsDefined[i])
RINOK(SafeReadBytes2(&crc, sizeof(crc)));
digests.Add(crc);
}
return S_OK;
}
HRESULT CInArchive::ReadPackInfo(
UINT64 &dataOffset,
CRecordVector<UINT64> &packSizes,
CRecordVector<bool> &packCRCsDefined,
CRecordVector<UINT32> &packCRCs)
{
RINOK(ReadNumber(dataOffset));
UINT64 numPackStreams;
RINOK(ReadNumber(numPackStreams));
RINOK(WaitAttribute(NID::kSize));
packSizes.Clear();
packSizes.Reserve((UINT32)numPackStreams);
for(UINT64 i = 0; i < numPackStreams; i++)
{
UINT64 size;
RINOK(ReadNumber(size));
packSizes.Add(size);
}
UINT64 type;
while(true)
{
RINOK(ReadID(type));
if (type == NID::kEnd)
break;
if (type == NID::kCRC)
{
RINOK(ReadHashDigests(
(UINT32)numPackStreams, packCRCsDefined, packCRCs));
continue;
}
RINOK(SkeepData());
}
if (packCRCsDefined.IsEmpty())
{
packCRCsDefined.Reserve((UINT32)numPackStreams);
packCRCsDefined.Clear();
packCRCs.Reserve((UINT32)numPackStreams);
packCRCs.Clear();
for(UINT64 i = 0; i < numPackStreams; i++)
{
packCRCsDefined.Add(false);
packCRCs.Add(0);
}
}
return S_OK;
}
HRESULT CInArchive::ReadUnPackInfo(
const CObjectVector<CByteBuffer> *dataVector,
CObjectVector<CFolder> &folders)
{
RINOK(WaitAttribute(NID::kFolder));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -