diff options
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/ArjHandler.cpp')
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/ArjHandler.cpp | 798 |
1 files changed, 0 insertions, 798 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/ArjHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/ArjHandler.cpp deleted file mode 100644 index 4dd686ec0..000000000 --- a/src/libs/7zip/win/CPP/7zip/Archive/ArjHandler.cpp +++ /dev/null @@ -1,798 +0,0 @@ -// ArjHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "Common/ComTry.h" -#include "Common/StringConvert.h" - -#include "Windows/PropVariant.h" -#include "Windows/Time.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/ArjDecoder1.h" -#include "../Compress/ArjDecoder2.h" -#include "../Compress/CopyCoder.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; - UInt32 SplitPos; - - 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); } - bool IsSplitAfter() const { return (Flags & NFileHeader::NFlags::kVolume) != 0; } - bool IsSplitBefore() const { return (Flags & NFileHeader::NFlags::kExtFile) != 0; } - 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]; - - SplitPos = 0; - if (IsSplitBefore() && firstHeaderSize >= 34) - SplitPos = Get32(p + 30); - - 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 SkipExtendedHeaders(); - - 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::SkipExtendedHeaders() -{ - for (UInt32 i = 0;; i++) - { - bool filled; - RINOK(ReadBlock(filled)); - if (!filled) - return S_OK; - if (Callback && (i & 0xFF) == 0) - RINOK(Callback->SetCompleted(&NumFiles, &NumBytes)); - } -} - -HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit) -{ - UInt64 position = 0; - RINOK(FindAndReadMarker(Stream, searchHeaderSizeLimit, position)); - RINOK(Stream->Seek(position, STREAM_SEEK_SET, NULL)); - bool filled; - RINOK(ReadSignatureAndBlock(filled)); - if (!filled) - return S_FALSE; - RINOK(Header.Parse(_block, _blockSize)); - return SkipExtendedHeaders(); -} - -HRESULT CInArchive::GetNextItem(bool &filled, CItem &item) -{ - RINOK(ReadSignatureAndBlock(filled)); - if (!filled) - return S_OK; - filled = false; - RINOK(item.Parse(_block, _blockSize)); - /* - UInt32 extraData; - if ((header.Flags & NFileHeader::NFlags::kExtFile) != 0) - extraData = GetUi32(_block + pos); - */ - - RINOK(SkipExtendedHeaders()); - filled = true; - return S_OK; -} - -class CHandler: - public IInArchive, - public CMyUnknownImp -{ -public: - MY_UNKNOWN_IMP1(IInArchive) - - INTERFACE_IInArchive(;) - - HRESULT Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *callback); -private: - CInArchive _archive; - CObjectVector<CItem> _items; - CMyComPtr<IInStream> _stream; -}; - -const wchar_t *kHostOS[] = -{ - L"MSDOS", - L"PRIMOS", - L"UNIX", - L"AMIGA", - L"MAC", - L"OS/2", - L"APPLE GS", - L"ATARI ST", - L"NEXT", - L"VAX VMS", - L"WIN95" -}; - -const wchar_t *kUnknownOS = L"Unknown"; - -const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]); - -STATPROPSTG kArcProps[] = -{ - { NULL, kpidName, VT_BSTR}, - { NULL, kpidCTime, VT_BSTR}, - { NULL, kpidMTime, VT_BSTR}, - { NULL, kpidHostOS, VT_BSTR}, - { NULL, kpidComment, VT_BSTR} -}; - -STATPROPSTG kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI4}, - { NULL, kpidPosition, VT_UI8}, - { NULL, kpidPackSize, VT_UI4}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidEncrypted, VT_BOOL}, - { NULL, kpidCRC, VT_UI4}, - { NULL, kpidMethod, VT_UI1}, - { NULL, kpidHostOS, VT_BSTR}, - { NULL, kpidComment, VT_BSTR} -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static void SetTime(UInt32 dosTime, NWindows::NCOM::CPropVariant &prop) -{ - if (dosTime == 0) - return; - FILETIME localFileTime, utc; - if (NTime::DosTimeToFileTime(dosTime, localFileTime)) - { - if (!LocalFileTimeToFileTime(&localFileTime, &utc)) - utc.dwHighDateTime = utc.dwLowDateTime = 0; - } - else - utc.dwHighDateTime = utc.dwLowDateTime = 0; - prop = utc; -} - -static void SetHostOS(Byte hostOS, NWindows::NCOM::CPropVariant &prop) -{ - prop = hostOS < kNumHostOSes ? kHostOS[hostOS] : kUnknownOS; -} - -static void SetUnicodeString(const AString &s, NWindows::NCOM::CPropVariant &prop) -{ - if (!s.IsEmpty()) - prop = MultiByteToUnicodeString(s, CP_OEMCP); -} - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) - { - case kpidName: SetUnicodeString(_archive.Header.Name, prop); break; - case kpidCTime: SetTime(_archive.Header.CTime, prop); break; - case kpidMTime: SetTime(_archive.Header.MTime, prop); break; - case kpidHostOS: SetHostOS(_archive.Header.HostOS, prop); break; - case kpidComment: SetUnicodeString(_archive.Header.Comment, prop); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = _items[index]; - switch(propID) - { - case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break; - case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: prop = item.Size; break; - case kpidPackSize: prop = item.PackSize; break; - case kpidPosition: if (item.IsSplitBefore() || item.IsSplitAfter()) prop = (UInt64)item.SplitPos; break; - case kpidAttrib: prop = item.GetWinAttributes(); break; - case kpidEncrypted: prop = item.IsEncrypted(); break; - case kpidCRC: prop = item.FileCRC; break; - case kpidMethod: prop = item.Method; break; - case kpidHostOS: SetHostOS(item.HostOS, prop); break; - case kpidMTime: SetTime(item.MTime, prop); break; - case kpidComment: SetUnicodeString(item.Comment, prop); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -HRESULT CHandler::Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *callback) -{ - Close(); - - UInt64 endPos = 0; - if (callback != NULL) - { - RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); - RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); - } - - _archive.Stream = inStream; - _archive.Callback = callback; - _archive.NumFiles = _archive.NumBytes = 0; - - RINOK(_archive.Open(maxCheckStartPosition)); - if (callback != NULL) - RINOK(callback->SetTotal(NULL, &endPos)); - for (;;) - { - CItem item; - bool filled; - - - RINOK(_archive.GetNextItem(filled, item)); - - RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &item.DataPosition)); - - if (!filled) - break; - _items.Add(item); - - if (inStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL) != S_OK) - throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive); - - _archive.NumFiles = _items.Size(); - _archive.NumBytes = item.DataPosition; - - if (callback != NULL && _items.Size() % 100 == 0) - { - RINOK(callback->SetCompleted(&_archive.NumFiles, &_archive.NumBytes)); - } - } - return S_OK; -} - -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - HRESULT res; - try - { - res = Open2(inStream, maxCheckStartPosition, callback); - if (res == S_OK) - { - _stream = inStream; - return S_OK; - } - } - catch(const CInArchiveException &) { res = S_FALSE; } - Close(); - return res; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _items.Clear(); - _stream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - UInt64 totalUnpacked = 0, totalPacked = 0; - bool allFilesMode = (numItems == (UInt32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const CItem &item = _items[allFilesMode ? i : indices[i]]; - totalUnpacked += item.Size; - totalPacked += item.PackSize; - } - extractCallback->SetTotal(totalUnpacked); - - totalUnpacked = totalPacked = 0; - UInt64 curUnpacked, curPacked; - - CMyComPtr<ICompressCoder> arj1Decoder; - CMyComPtr<ICompressCoder> arj2Decoder; - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr<ICompressProgressInfo> progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream; - CMyComPtr<ISequentialInStream> inStream(inStreamSpec); - inStreamSpec->SetStream(_stream); - - for (i = 0; i < numItems; i++, totalUnpacked += curUnpacked, totalPacked += curPacked) - { - lps->InSize = totalPacked; - lps->OutSize = totalUnpacked; - RINOK(lps->SetCur()); - - curUnpacked = curPacked = 0; - - CMyComPtr<ISequentialOutStream> realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - - if (item.IsDir()) - { - // if (!testMode) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - } - continue; - } - - if (!testMode && !realOutStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)); - curUnpacked = item.Size; - curPacked = item.PackSize; - - { - COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; - CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - realOutStream.Release(); - outStreamSpec->Init(); - - inStreamSpec->Init(item.PackSize); - - UInt64 pos; - _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos); - - HRESULT result = S_OK; - Int32 opRes = NExtract::NOperationResult::kOK; - - if (item.IsEncrypted()) - opRes = NExtract::NOperationResult::kUnSupportedMethod; - else - { - switch(item.Method) - { - case NFileHeader::NCompressionMethod::kStored: - { - result = copyCoder->Code(inStream, outStream, NULL, NULL, progress); - if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize) - result = S_FALSE; - break; - } - case NFileHeader::NCompressionMethod::kCompressed1a: - case NFileHeader::NCompressionMethod::kCompressed1b: - case NFileHeader::NCompressionMethod::kCompressed1c: - { - if (!arj1Decoder) - arj1Decoder = new NCompress::NArj::NDecoder1::CCoder; - result = arj1Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress); - break; - } - case NFileHeader::NCompressionMethod::kCompressed2: - { - if (!arj2Decoder) - arj2Decoder = new NCompress::NArj::NDecoder2::CCoder; - result = arj2Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress); - break; - } - default: - opRes = NExtract::NOperationResult::kUnSupportedMethod; - } - } - if (opRes == NExtract::NOperationResult::kOK) - { - if (result == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else - { - RINOK(result); - opRes = (outStreamSpec->GetCRC() == item.FileCRC) ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kCRCError; - } - } - outStream.Release(); - RINOK(extractCallback->SetOperationResult(opRes)); - } - } - return S_OK; - COM_TRY_END -} - -static IInArchive *CreateArc() { return new CHandler; } - -static CArcInfo g_ArcInfo = - { L"Arj", L"arj", 0, 4, { 0x60, 0xEA }, 2, false, CreateArc, 0 }; - -REGISTER_ARC(Arj) - -}} |