7zin.cpp
来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 1,295 行 · 第 1/3 页
CPP
1,295 行
// 7zIn.cpp#include "StdAfx.h"#include "7zIn.h"#include "7zMethods.h"#include "7zDecode.h"#include "../../Common/StreamObjects.h"#include "../../Common/StreamUtils.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 = ReadStream(stream, 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_VOLstatic inline bool TestFinishSignatureCandidate(const void *testBytes){ for (int i = 0; i < kSignatureSize; i++) if (((const Byte *)testBytes)[i] != kFinishSignature[i]) return false; return true;}#endifHRESULT 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_VOLHRESULT 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 archiveHRESULT 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 + =
减小字号Ctrl + -
显示快捷键?