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 + -
显示快捷键?