⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arjhandler.cpp

📁 7-Zip 是一款号称有着现今最高压缩比的压缩软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// ArjHandler.cpp

#include "StdAfx.h"

#include "Common/ComTry.h"
#include "Common/StringConvert.h"

#include "Windows/PropVariant.h"
#include "Windows/Time.h"

#include "../../../C/CpuArch.h"

#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamObjects.h"
#include "../Common/StreamUtils.h"

#include "../Compress/Arj/ArjDecoder1.h"
#include "../Compress/Arj/ArjDecoder2.h"
#include "../Compress/Copy/CopyCoder.h"

#include "IArchive.h"

#include "Common/ItemNameUtils.h"
#include "Common/OutStreamWithCRC.h"

using namespace NWindows;

#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)

namespace NArchive {
namespace NArj {

const int kBlockSizeMin = 30;
const int kBlockSizeMax = 2600;

namespace NSignature
{
  const Byte kSig0 = 0x60;
  const Byte kSig1 = 0xEA;
}

namespace NFileHeader
{
  namespace NCompressionMethod
  {
    enum
    {
      kStored = 0,
      kCompressed1a = 1,
      kCompressed1b = 2,
      kCompressed1c = 3,
      kCompressed2 = 4,
      kNoDataNoCRC = 8,
      kNoData = 9
    };
  }

  namespace NFileType
  {
    enum
    {
      kBinary = 0,
      k7BitText = 1,
      kArchiveHeader = 2,
      kDirectory = 3,
      kVolumeLablel = 4,
      kChapterLabel = 5
    };
  }
  
  namespace NFlags
  {
    const Byte kGarbled = 1;
    const Byte kVolume = 4;
    const Byte kExtFile = 8;
    const Byte kPathSym = 0x10;
    const Byte kBackup = 0x20;
  }

  namespace NHostOS
  {
    enum EEnum
    {
      kMSDOS = 0,  // filesystem used by MS-DOS, OS/2, Win32
          // pkarj 2.50 (FAT / VFAT / FAT32 file systems)
      kPRIMOS,
      kUnix,
      kAMIGA,
      kMac,
      kOS_2,
      kAPPLE_GS,
      kAtari_ST,
      kNext,
      kVAX_VMS,
      kWIN95
    };
  }
}

struct CArchiveHeader
{
  // Byte ArchiverVersion;
  // Byte ExtractVersion;
  Byte HostOS;
  // Byte Flags;
  // Byte SecuryVersion;
  // Byte FileType;
  // Byte Reserved;
  UInt32 CTime;
  UInt32 MTime;
  UInt32 ArchiveSize;
  // UInt32 SecurityEnvelopeFilePosition;
  // UInt16 FilespecPositionInFilename;
  // UInt16 LengthOfSecurityEnvelopeSata;
  // Byte EncryptionVersion;
  // Byte LastChapter;
  AString Name;
  AString Comment;
  
  HRESULT Parse(const Byte *p, unsigned size);
};

static HRESULT ReadString(const Byte *p, unsigned &size, AString &res)
{
  AString s;
  for (unsigned i = 0; i < size;)
  {
    char c = (char)p[i++];
    if (c == 0)
    {
      size = i;
      res = s;
      return S_OK;
    }
    s += c;
  }
  return S_FALSE;
}

HRESULT CArchiveHeader::Parse(const Byte *p, unsigned size)
{
  if (size < kBlockSizeMin)
    return S_FALSE;
  Byte firstHeaderSize = p[0];
  if (firstHeaderSize > size)
    return S_FALSE;
  // ArchiverVersion = p[1];
  // ExtractVersion = p[2];
  HostOS = p[3];
  // Flags = p[4];
  // SecuryVersion = p[5];
  if (p[6] != NFileHeader::NFileType::kArchiveHeader)
    return S_FALSE;
  // Reserved = p[7];
  CTime = Get32(p + 8);
  MTime = Get32(p + 12);
  ArchiveSize = Get32(p + 16);
  // SecurityEnvelopeFilePosition = Get32(p + 20);
  // UInt16 filespecPositionInFilename = Get16(p + 24);
  // LengthOfSecurityEnvelopeSata = Get16(p + 26);
  // EncryptionVersion = p[28];
  // LastChapter = p[29];
  unsigned pos = firstHeaderSize;
  unsigned size1 = size - pos;
  RINOK(ReadString(p + pos, size1, Name));
  pos += size1;
  size1 = size - pos;
  RINOK(ReadString(p + pos, size1, Comment));
  pos += size1;
  return S_OK;
}

struct CItem
{
  AString Name;
  AString Comment;

  UInt32 MTime;
  UInt32 PackSize;
  UInt32 Size;
  UInt32 FileCRC;

  Byte Version;
  Byte ExtractVersion;
  Byte HostOS;
  Byte Flags;
  Byte Method;
  Byte FileType;

  // UInt16 FilespecPositionInFilename;
  UInt16 FileAccessMode;
  // Byte FirstChapter;
  // Byte LastChapter;
  
  UInt64 DataPosition;
  
  bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kGarbled) != 0; }
  bool IsDir() const { return (FileType == NFileHeader::NFileType::kDirectory); }
  UInt32 GetWinAttributes() const
  {
    UInt32 winAtrributes;
    switch(HostOS)
    {
      case NFileHeader::NHostOS::kMSDOS:
      case NFileHeader::NHostOS::kWIN95:
        winAtrributes = FileAccessMode;
        break;
      default:
        winAtrributes = 0;
    }
    if (IsDir())
      winAtrributes |= FILE_ATTRIBUTE_DIRECTORY;
    return winAtrributes;
  }

  HRESULT Parse(const Byte *p, unsigned size);
};

HRESULT CItem::Parse(const Byte *p, unsigned size)
{
  if (size < kBlockSizeMin)
    return S_FALSE;

  Byte firstHeaderSize = p[0];

  Version = p[1];
  ExtractVersion = p[2];
  HostOS = p[3];
  Flags = p[4];
  Method = p[5];
  FileType = p[6];
  // Reserved = p[7];
  MTime = Get32(p + 8);
  PackSize = Get32(p + 12);
  Size = Get32(p + 16);
  FileCRC = Get32(p + 20);
  // FilespecPositionInFilename = Get16(p + 24);
  FileAccessMode = Get16(p + 26);
  // FirstChapter = p[28];
  // FirstChapter = p[29];

  unsigned pos = firstHeaderSize;
  unsigned size1 = size - pos;
  RINOK(ReadString(p + pos, size1, Name));
  pos += size1;
  size1 = size - pos;
  RINOK(ReadString(p + pos, size1, Comment));
  pos += size1;

  return S_OK;
}

struct CInArchiveException
{
  enum CCauseType
  {
    kUnexpectedEndOfArchive = 0,
    kCRCError,
    kIncorrectArchive,
  }
  Cause;
  CInArchiveException(CCauseType cause): Cause(cause) {};
};

class CInArchive
{
  UInt32 _blockSize;
  Byte _block[kBlockSizeMax + 4];
  
  HRESULT ReadBlock(bool &filled);
  HRESULT ReadSignatureAndBlock(bool &filled);
  HRESULT SkeepExtendedHeaders();

  HRESULT SafeReadBytes(void *data, UInt32 size);
    
public:
  CArchiveHeader Header;

  IInStream *Stream;
  IArchiveOpenCallback *Callback;
  UInt64 NumFiles;
  UInt64 NumBytes;

  HRESULT Open(const UInt64 *searchHeaderSizeLimit);
  HRESULT GetNextItem(bool &filled, CItem &item);
};

static inline bool TestMarkerCandidate(const Byte *p, unsigned maxSize)
{
  if (p[0] != NSignature::kSig0 || p[1] != NSignature::kSig1)
    return false;
  UInt32 blockSize = Get16(p + 2);
  p += 4;
  if (p[6] != NFileHeader::NFileType::kArchiveHeader ||
      p[0] > blockSize ||
      maxSize < 2 + 2 + blockSize + 4 ||
      blockSize < kBlockSizeMin || blockSize > kBlockSizeMax ||
      p[28] > 8) // EncryptionVersion
    return false;
  // return (Get32(p + blockSize) == CrcCalc(p, blockSize));
  return true;
}

static HRESULT FindAndReadMarker(ISequentialInStream *stream, const UInt64 *searchHeaderSizeLimit, UInt64 &position)
{
  position = 0;

  const int kMarkerSizeMin = 2 + 2 + kBlockSizeMin + 4;
  const int kMarkerSizeMax = 2 + 2 + kBlockSizeMax + 4;

  CByteBuffer byteBuffer;
  const UInt32 kBufSize = 1 << 16;
  byteBuffer.SetCapacity(kBufSize);
  Byte *buf = byteBuffer;

  size_t processedSize = kMarkerSizeMax;
  RINOK(ReadStream(stream, buf, &processedSize));
  if (processedSize < kMarkerSizeMin)
    return S_FALSE;
  if (TestMarkerCandidate(buf, (unsigned)processedSize))
    return S_OK;

  UInt32 numBytesPrev = (UInt32)processedSize - 1;
  memmove(buf, buf + 1, numBytesPrev);
  UInt64 curTestPos = 1;
  for (;;)
  {
    if (searchHeaderSizeLimit != NULL)
      if (curTestPos > *searchHeaderSizeLimit)
        return S_FALSE;
    processedSize = kBufSize - numBytesPrev;
    RINOK(ReadStream(stream, buf + numBytesPrev, &processedSize));
    UInt32 numBytesInBuffer = numBytesPrev + (UInt32)processedSize;
    if (numBytesInBuffer < kMarkerSizeMin)
      return S_FALSE;
    UInt32 numTests = numBytesInBuffer - kMarkerSizeMin + 1;
    UInt32 pos;
    for (pos = 0; pos < numTests; pos++)
    {
      for (; buf[pos] != NSignature::kSig0 && pos < numTests; pos++);
      if (pos == numTests)
        break;
      if (TestMarkerCandidate(buf + pos, numBytesInBuffer - pos))
      {
        position = curTestPos + pos;
        return S_OK;
      }
    }
    curTestPos += pos;
    numBytesPrev = numBytesInBuffer - numTests;
    memmove(buf, buf + numTests, numBytesPrev);
  }
}

HRESULT CInArchive::SafeReadBytes(void *data, UInt32 size)
{
  size_t processed = size;
  RINOK(ReadStream(Stream, data, &processed));
  if (processed != size)
    throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive);
  return S_OK;
}

HRESULT CInArchive::ReadBlock(bool &filled)
{
  filled = false;
  Byte buf[2];
  RINOK(SafeReadBytes(buf, 2));
  _blockSize = Get16(buf);
  if (_blockSize == 0)
    return S_OK;
  if (_blockSize > kBlockSizeMax)
    throw CInArchiveException(CInArchiveException::kIncorrectArchive);
  RINOK(SafeReadBytes(_block, _blockSize + 4));
  NumBytes += _blockSize + 6;
  if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize))
    throw CInArchiveException(CInArchiveException::kCRCError);
  filled = true;
  return S_OK;
}

HRESULT CInArchive::ReadSignatureAndBlock(bool &filled)
{
  Byte id[2];
  RINOK(SafeReadBytes(id, 2));
  if (id[0] != NSignature::kSig0 || id[1] != NSignature::kSig1)
    throw CInArchiveException(CInArchiveException::kIncorrectArchive);
  return ReadBlock(filled);
}

HRESULT CInArchive::SkeepExtendedHeaders()
{
  for (UInt32 i = 0;; i++)
  {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -