📄 arjhandler.cpp
字号:
// 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 + -