📄 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, size_t 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, size_t 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->ReadByte(external));
if (external != 0)
{
CNum dataIndex;
RINOK(archive->ReadNum(dataIndex));
Set(archive, (*dataVector)[dataIndex]);
}
return S_OK;
}
CInArchiveException::CInArchiveException(CCauseType cause):
Cause(cause)
{}
HRESULT CInArchive::ReadDirect(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::ReadDirect(void *data, UInt32 size, UInt32 *processedSize)
{
return ReadDirect(_stream, data, size, processedSize);
}
HRESULT CInArchive::SafeReadDirect(void *data, UInt32 size)
{
UInt32 realProcessedSize;
RINOK(ReadDirect(data, size, &realProcessedSize));
if (realProcessedSize != size)
throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
return S_OK;
}
HRESULT CInArchive::SafeReadDirectByte(Byte &b)
{
return SafeReadDirect(&b, 1);
}
HRESULT CInArchive::SafeReadDirectUInt32(UInt32 &value)
{
value = 0;
for (int i = 0; i < 4; i++)
{
Byte b;
RINOK(SafeReadDirectByte(b));
value |= (UInt32(b) << (8 * i));
}
return S_OK;
}
HRESULT CInArchive::SafeReadDirectUInt64(UInt64 &value)
{
value = 0;
for (int i = 0; i < 8; i++)
{
Byte b;
RINOK(SafeReadDirectByte(b));
value |= (UInt64(b) << (8 * i));
}
return S_OK;
}
HRESULT CInArchive::ReadNumber(UInt64 &value)
{
Byte firstByte;
RINOK(ReadByte(firstByte));
Byte mask = 0x80;
value = 0;
for (int i = 0; i < 8; i++)
{
if ((firstByte & mask) == 0)
{
UInt64 highPart = firstByte & (mask - 1);
value += (highPart << (i * 8));
return S_OK;
}
Byte b;
RINOK(ReadByte(b));
value |= (UInt64(b) << (8 * i));
mask >>= 1;
}
return S_OK;
}
HRESULT CInArchive::ReadNum(CNum &value)
{
UInt64 value64;
RINOK(ReadNumber(value64));
if (value64 > kNumMax)
return E_FAIL;
value = (CNum)value64;
return S_OK;
}
HRESULT CInArchive::ReadUInt32(UInt32 &value)
{
value = 0;
for (int i = 0; i < 4; i++)
{
Byte b;
RINOK(ReadByte(b));
value |= (UInt32(b) << (8 * i));
}
return S_OK;
}
HRESULT CInArchive::ReadUInt64(UInt64 &value)
{
value = 0;
for (int i = 0; i < 8; i++)
{
Byte b;
RINOK(ReadByte(b));
value |= (UInt64(b) << (8 * i));
}
return S_OK;
}
static inline bool TestSignatureCandidate(const void *testBytes)
{
for (int i = 0; i < kSignatureSize; i++)
if (((const Byte *)testBytes)[i] != kSignature[i])
return false;
return true;
}
#ifdef _7Z_VOL
static inline bool TestFinishSignatureCandidate(const void *testBytes)
{
for (int i = 0; i < kSignatureSize; i++)
if (((const Byte *)testBytes)[i] != kFinishSignature[i])
return false;
return true;
}
#endif
HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
{
_position = _arhiveBeginStreamPosition;
RINOK(stream->Seek(_arhiveBeginStreamPosition, STREAM_SEEK_SET, NULL));
Byte signature[kSignatureSize];
UInt32 processedSize;
RINOK(ReadDirect(stream, signature, kSignatureSize, &processedSize));
if(processedSize != kSignatureSize)
return S_FALSE;
if (TestSignatureCandidate(signature))
return S_OK;
CByteBuffer byteBuffer;
const UInt32 kBufferSize = (1 << 16);
byteBuffer.SetCapacity(kBufferSize);
Byte *buffer = byteBuffer;
UInt32 numPrevBytes = kSignatureSize - 1;
memmove(buffer, signature + 1, numPrevBytes);
UInt64 curTestPos = _arhiveBeginStreamPosition + 1;
while(true)
{
if (searchHeaderSizeLimit != NULL)
if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
return S_FALSE;
UInt32 numReadBytes = kBufferSize - numPrevBytes;
RINOK(ReadDirect(stream, buffer + numPrevBytes, numReadBytes, &processedSize));
UInt32 numBytesInBuffer = numPrevBytes + 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);
}
}
numPrevBytes = numBytesInBuffer - numTests;
memmove(buffer, buffer + numTests, numPrevBytes);
}
}
// Out: _position must point to end of signature
#ifdef _7Z_VOL
HRESULT CInArchive::FindFinishSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
{
RINOK(stream->Seek(0, STREAM_SEEK_END, &_position));
if (_position < kSignatureSize)
return S_FALSE;
CByteBuffer byteBuffer;
const UInt32 kBufferSize = (1 << 18);
byteBuffer.SetCapacity(kBufferSize);
Byte *buffer = byteBuffer;
UInt32 numPrevBytes = 0;
UInt64 limitPos = 0;
if (searchHeaderSizeLimit != NULL)
if (*searchHeaderSizeLimit < _position)
limitPos = _position - *searchHeaderSizeLimit;
while(_position >= limitPos)
{
UInt32 numReadBytes = kBufferSize - numPrevBytes;
if (numReadBytes > _position)
numReadBytes = (UInt32)_position;
UInt32 numBytesInBuffer = numPrevBytes + numReadBytes;
if (numBytesInBuffer < kSignatureSize)
return S_FALSE;
_position -= numReadBytes;
RINOK(stream->Seek(_position, STREAM_SEEK_SET, &_position));
UInt32 startPos = kBufferSize - numBytesInBuffer;
UInt32 processedSize;
RINOK(ReadDirect(stream, buffer + startPos, numReadBytes, &processedSize));
if (processedSize != numReadBytes)
return S_FALSE;
_position -= processedSize;
for(UInt32 pos = kBufferSize; pos >= startPos + kSignatureSize; pos--)
{
if (TestFinishSignatureCandidate(buffer + pos - kSignatureSize))
{
_position += pos - startPos;
return stream->Seek(_position, STREAM_SEEK_SET, NULL);
}
}
numPrevBytes = kSignatureSize - 1;
memmove(buffer + kBufferSize - numPrevBytes, buffer + startPos + 1, numPrevBytes);
}
return S_FALSE;
}
#endif
// 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;
#ifdef _7Z_VOL
HRESULT result = FindFinishSignature(stream, searchHeaderSizeLimit);
if (result == S_OK)
_finishSignature = true;
else
{
if (result != S_FALSE)
return result;
_finishSignature = false;
RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
}
#else
RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
#endif
_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(ReadByte(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)
{
CNum numCoders;
RINOK(ReadNum(numCoders));
folder.Coders.Clear();
folder.Coders.Reserve((int)numCoders);
CNum numInStreams = 0;
CNum numOutStreams = 0;
CNum i;
for (i = 0; i < numCoders; i++)
{
folder.Coders.Add(CCoderInfo());
CCoderInfo &coder = folder.Coders.Back();
while (true)
{
coder.AltCoders.Add(CAltCoderInfo());
CAltCoderInfo &altCoder = coder.AltCoders.Back();
Byte mainByte;
RINOK(ReadByte(mainByte));
altCoder.MethodID.IDSize = mainByte & 0xF;
RINOK(ReadBytes(altCoder.MethodID.ID, altCoder.MethodID.IDSize));
if ((mainByte & 0x10) != 0)
{
RINOK(ReadNum(coder.NumInStreams));
RINOK(ReadNum(coder.NumOutStreams));
}
else
{
coder.NumInStreams = 1;
coder.NumOutStreams = 1;
}
if ((mainByte & 0x20) != 0)
{
CNum propertiesSize = 0;
RINOK(ReadNum(propertiesSize));
altCoder.Properties.SetCapacity((size_t)propertiesSize);
RINOK(ReadBytes((Byte *)altCoder.Properties, (size_t)propertiesSize));
}
if ((mainByte & 0x80) == 0)
break;
}
numInStreams += coder.NumInStreams;
numOutStreams += coder.NumOutStreams;
}
CNum numBindPairs;
// RINOK(ReadNumber(numBindPairs));
numBindPairs = numOutStreams - 1;
folder.BindPairs.Clear();
folder.BindPairs.Reserve(numBindPairs);
for (i = 0; i < numBindPairs; i++)
{
CBindPair bindPair;
RINOK(ReadNum(bindPair.InIndex));
RINOK(ReadNum(bindPair.OutIndex));
folder.BindPairs.Add(bindPair);
}
CNum numPackedStreams = numInStreams - numBindPairs;
folder.PackStreams.Reserve(numPackedStreams);
if (numPackedStreams == 1)
{
for (CNum j = 0; j < numInStreams; j++)
if (folder.FindBindPairForInStream(j) < 0)
{
folder.PackStreams.Add(j);
break;
}
}
else
for(i = 0; i < numPackedStreams; i++)
{
CNum packStreamInfo;
RINOK(ReadNum(packStreamInfo));
folder.PackStreams.Add(packStreamInfo);
}
return S_OK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -