mirror of
https://github.com/Xevion/easy7zip.git
synced 2026-01-31 12:24:08 -06:00
9.04 beta
This commit is contained in:
committed by
Kornel Lesiński
parent
8874e4fbc9
commit
829409452d
@@ -598,11 +598,11 @@ SOURCE=..\..\..\Windows\Thread.h
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Copy\CopyCoder.cpp
|
||||
SOURCE=..\..\Compress\CopyCoder.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Compress\Copy\CopyCoder.h
|
||||
SOURCE=..\..\Compress\CopyCoder.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "C"
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
// Encode.cpp
|
||||
// 7zEncode.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "../../Common/FilterCoder.h"
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/InOutTempBuffer.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamObjects.h"
|
||||
|
||||
#include "7zEncode.h"
|
||||
#include "7zSpecStream.h"
|
||||
|
||||
#include "../../IPassword.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/InOutTempBuffer.h"
|
||||
#include "../../Common/StreamObjects.h"
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "../../Common/FilterCoder.h"
|
||||
|
||||
static const UInt64 k_AES = 0x06F10701;
|
||||
static const UInt64 k_BCJ = 0x03030103;
|
||||
static const UInt64 k_Delta = 0x03;
|
||||
static const UInt64 k_BCJ = 0x03030103;
|
||||
static const UInt64 k_BCJ2 = 0x0303011B;
|
||||
static const UInt64 k_AES = 0x06F10701;
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
@@ -240,10 +240,10 @@ HRESULT CEncoder::Encode(
|
||||
|
||||
UInt32 progressIndex = mainCoderIndex;
|
||||
|
||||
for (i = 0; i < _codersInfo.Size(); i++)
|
||||
for (i = 0; i + 1 < _codersInfo.Size(); i++)
|
||||
{
|
||||
const CCoderInfo &e = _codersInfo[i];
|
||||
if ((e.MethodID == k_BCJ || e.MethodID == k_BCJ2) && i + 1 < _codersInfo.Size())
|
||||
UInt64 m = _codersInfo[i].MethodID;
|
||||
if (m == k_Delta || m == k_BCJ || m == k_BCJ2)
|
||||
progressIndex = i + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,156 +9,132 @@ namespace N7z {
|
||||
|
||||
CFolderOutStream::CFolderOutStream()
|
||||
{
|
||||
_outStreamWithHashSpec = new COutStreamWithCRC;
|
||||
_outStreamWithHash = _outStreamWithHashSpec;
|
||||
_crcStreamSpec = new COutStreamWithCRC;
|
||||
_crcStream = _crcStreamSpec;
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::Init(
|
||||
const CArchiveDatabaseEx *archiveDatabase,
|
||||
UInt32 ref2Offset,
|
||||
UInt32 startIndex,
|
||||
UInt32 ref2Offset, UInt32 startIndex,
|
||||
const CBoolVector *extractStatuses,
|
||||
IArchiveExtractCallback *extractCallback,
|
||||
bool testMode,
|
||||
bool checkCrc)
|
||||
bool testMode, bool checkCrc)
|
||||
{
|
||||
_archiveDatabase = archiveDatabase;
|
||||
_db = archiveDatabase;
|
||||
_ref2Offset = ref2Offset;
|
||||
_startIndex = startIndex;
|
||||
|
||||
_extractStatuses = extractStatuses;
|
||||
_extractCallback = extractCallback;
|
||||
_testMode = testMode;
|
||||
|
||||
_checkCrc = checkCrc;
|
||||
|
||||
_currentIndex = 0;
|
||||
_fileIsOpen = false;
|
||||
return WriteEmptyFiles();
|
||||
return ProcessEmptyFiles();
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::OpenFile()
|
||||
{
|
||||
Int32 askMode;
|
||||
if((*_extractStatuses)[_currentIndex])
|
||||
askMode = _testMode ?
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
else
|
||||
askMode = NArchive::NExtract::NAskMode::kSkip;
|
||||
Int32 askMode = ((*_extractStatuses)[_currentIndex]) ? (_testMode ?
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract):
|
||||
NArchive::NExtract::NAskMode::kSkip;
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
|
||||
UInt32 index = _startIndex + _currentIndex;
|
||||
RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode));
|
||||
|
||||
_outStreamWithHashSpec->SetStream(realOutStream);
|
||||
_outStreamWithHashSpec->Init(_checkCrc);
|
||||
if (askMode == NArchive::NExtract::NAskMode::kExtract &&
|
||||
(!realOutStream))
|
||||
{
|
||||
const CFileItem &fi = _archiveDatabase->Files[index];
|
||||
if (!_archiveDatabase->IsItemAnti(index) && !fi.IsDir)
|
||||
askMode = NArchive::NExtract::NAskMode::kSkip;
|
||||
}
|
||||
_crcStreamSpec->SetStream(realOutStream);
|
||||
_crcStreamSpec->Init(_checkCrc);
|
||||
_fileIsOpen = true;
|
||||
const CFileItem &fi = _db->Files[index];
|
||||
_rem = fi.Size;
|
||||
if (askMode == NArchive::NExtract::NAskMode::kExtract && !realOutStream &&
|
||||
!_db->IsItemAnti(index) && !fi.IsDir)
|
||||
askMode = NArchive::NExtract::NAskMode::kSkip;
|
||||
return _extractCallback->PrepareOperation(askMode);
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::WriteEmptyFiles()
|
||||
HRESULT CFolderOutStream::CloseFileAndSetResult(Int32 res)
|
||||
{
|
||||
for(;_currentIndex < _extractStatuses->Size(); _currentIndex++)
|
||||
_crcStreamSpec->ReleaseStream();
|
||||
_fileIsOpen = false;
|
||||
_currentIndex++;
|
||||
return _extractCallback->SetOperationResult(res);
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::CloseFileAndSetResult()
|
||||
{
|
||||
const CFileItem &fi = _db->Files[_startIndex + _currentIndex];
|
||||
return CloseFileAndSetResult(
|
||||
(fi.IsDir || !fi.CrcDefined || !_checkCrc || fi.Crc == _crcStreamSpec->GetCRC()) ?
|
||||
NArchive::NExtract::NOperationResult::kOK :
|
||||
NArchive::NExtract::NOperationResult::kCRCError);
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::ProcessEmptyFiles()
|
||||
{
|
||||
while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)
|
||||
{
|
||||
UInt32 index = _startIndex + _currentIndex;
|
||||
const CFileItem &fi = _archiveDatabase->Files[index];
|
||||
if (!_archiveDatabase->IsItemAnti(index) && !fi.IsDir && fi.Size != 0)
|
||||
return S_OK;
|
||||
RINOK(OpenFile());
|
||||
RINOK(_extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
_outStreamWithHashSpec->ReleaseStream();
|
||||
RINOK(CloseFileAndSetResult());
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CFolderOutStream::Write(const void *data,
|
||||
UInt32 size, UInt32 *processedSize)
|
||||
STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessedSize = 0;
|
||||
while(_currentIndex < _extractStatuses->Size())
|
||||
if (processedSize != NULL)
|
||||
*processedSize = 0;
|
||||
while (size != 0)
|
||||
{
|
||||
if (_fileIsOpen)
|
||||
{
|
||||
UInt32 index = _startIndex + _currentIndex;
|
||||
const CFileItem &fi = _archiveDatabase->Files[index];
|
||||
UInt64 fileSize = fi.Size;
|
||||
|
||||
UInt32 numBytesToWrite = (UInt32)MyMin(fileSize - _filePos,
|
||||
UInt64(size - realProcessedSize));
|
||||
|
||||
UInt32 processedSizeLocal;
|
||||
RINOK(_outStreamWithHash->Write((const Byte *)data + realProcessedSize,
|
||||
numBytesToWrite, &processedSizeLocal));
|
||||
|
||||
_filePos += processedSizeLocal;
|
||||
realProcessedSize += processedSizeLocal;
|
||||
if (_filePos == fileSize)
|
||||
UInt32 cur = size < _rem ? size : (UInt32)_rem;
|
||||
RINOK(_crcStream->Write(data, cur, &cur));
|
||||
if (cur == 0)
|
||||
break;
|
||||
data = (const Byte *)data + cur;
|
||||
size -= cur;
|
||||
_rem -= cur;
|
||||
if (processedSize != NULL)
|
||||
*processedSize += cur;
|
||||
if (_rem == 0)
|
||||
{
|
||||
bool digestsAreEqual;
|
||||
if (fi.CrcDefined && _checkCrc)
|
||||
digestsAreEqual = fi.Crc == _outStreamWithHashSpec->GetCRC();
|
||||
else
|
||||
digestsAreEqual = true;
|
||||
|
||||
RINOK(_extractCallback->SetOperationResult(
|
||||
digestsAreEqual ?
|
||||
NArchive::NExtract::NOperationResult::kOK :
|
||||
NArchive::NExtract::NOperationResult::kCRCError));
|
||||
_outStreamWithHashSpec->ReleaseStream();
|
||||
_fileIsOpen = false;
|
||||
_currentIndex++;
|
||||
}
|
||||
if (realProcessedSize == size)
|
||||
{
|
||||
if (processedSize != NULL)
|
||||
*processedSize = realProcessedSize;
|
||||
return WriteEmptyFiles();
|
||||
RINOK(CloseFileAndSetResult());
|
||||
RINOK(ProcessEmptyFiles());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(ProcessEmptyFiles());
|
||||
if (_currentIndex == _extractStatuses->Size())
|
||||
{
|
||||
// we support partial extracting
|
||||
if (processedSize != NULL)
|
||||
*processedSize += size;
|
||||
break;
|
||||
}
|
||||
RINOK(OpenFile());
|
||||
_fileIsOpen = true;
|
||||
_filePos = 0;
|
||||
}
|
||||
}
|
||||
if (processedSize != NULL)
|
||||
*processedSize = size;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult)
|
||||
{
|
||||
while(_currentIndex < _extractStatuses->Size())
|
||||
while (_currentIndex < _extractStatuses->Size())
|
||||
{
|
||||
if (_fileIsOpen)
|
||||
{
|
||||
RINOK(_extractCallback->SetOperationResult(resultEOperationResult));
|
||||
_outStreamWithHashSpec->ReleaseStream();
|
||||
_fileIsOpen = false;
|
||||
_currentIndex++;
|
||||
RINOK(CloseFileAndSetResult(resultEOperationResult));
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(OpenFile());
|
||||
_fileIsOpen = true;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CFolderOutStream::WasWritingFinished()
|
||||
{
|
||||
if (_currentIndex == _extractStatuses->Size())
|
||||
return S_OK;
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// 7zFolderOutStream.h
|
||||
|
||||
#ifndef __7Z_FOLDEROUTSTREAM_H
|
||||
#define __7Z_FOLDEROUTSTREAM_H
|
||||
#ifndef __7Z_FOLDER_OUT_STREAM_H
|
||||
#define __7Z_FOLDER_OUT_STREAM_H
|
||||
|
||||
#include "7zIn.h"
|
||||
|
||||
@@ -16,43 +16,39 @@ class CFolderOutStream:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
COutStreamWithCRC *_crcStreamSpec;
|
||||
CMyComPtr<ISequentialOutStream> _crcStream;
|
||||
const CArchiveDatabaseEx *_db;
|
||||
const CBoolVector *_extractStatuses;
|
||||
CMyComPtr<IArchiveExtractCallback> _extractCallback;
|
||||
UInt32 _ref2Offset;
|
||||
UInt32 _startIndex;
|
||||
int _currentIndex;
|
||||
bool _testMode;
|
||||
bool _checkCrc;
|
||||
bool _fileIsOpen;
|
||||
UInt64 _rem;
|
||||
|
||||
HRESULT OpenFile();
|
||||
HRESULT CloseFileAndSetResult(Int32 res);
|
||||
HRESULT CloseFileAndSetResult();
|
||||
HRESULT ProcessEmptyFiles();
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
CFolderOutStream();
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
private:
|
||||
|
||||
COutStreamWithCRC *_outStreamWithHashSpec;
|
||||
CMyComPtr<ISequentialOutStream> _outStreamWithHash;
|
||||
const CArchiveDatabaseEx *_archiveDatabase;
|
||||
const CBoolVector *_extractStatuses;
|
||||
UInt32 _startIndex;
|
||||
UInt32 _ref2Offset;
|
||||
int _currentIndex;
|
||||
// UInt64 _currentDataPos;
|
||||
CMyComPtr<IArchiveExtractCallback> _extractCallback;
|
||||
bool _testMode;
|
||||
|
||||
bool _fileIsOpen;
|
||||
|
||||
bool _checkCrc;
|
||||
UInt64 _filePos;
|
||||
|
||||
HRESULT OpenFile();
|
||||
HRESULT WriteEmptyFiles();
|
||||
public:
|
||||
HRESULT Init(
|
||||
const CArchiveDatabaseEx *archiveDatabase,
|
||||
UInt32 ref2Offset,
|
||||
UInt32 startIndex,
|
||||
UInt32 ref2Offset, UInt32 startIndex,
|
||||
const CBoolVector *extractStatuses,
|
||||
IArchiveExtractCallback *extractCallback,
|
||||
bool testMode,
|
||||
bool checkCrc);
|
||||
bool testMode, bool checkCrc);
|
||||
HRESULT FlushCorrupted(Int32 resultEOperationResult);
|
||||
HRESULT WasWritingFinished();
|
||||
HRESULT WasWritingFinished() const
|
||||
{ return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../../../../C/CpuArch.h"
|
||||
}
|
||||
#include "../../../../C/CpuArch.h"
|
||||
|
||||
#include "../../../Common/ComTry.h"
|
||||
#include "../../../Common/IntToString.h"
|
||||
@@ -176,6 +173,8 @@ static UString GetStringForSizeValue(UInt32 value)
|
||||
}
|
||||
|
||||
static const UInt64 k_Copy = 0x0;
|
||||
static const UInt64 k_Delta = 3;
|
||||
static const UInt64 k_LZMA2 = 0x21;
|
||||
static const UInt64 k_LZMA = 0x030101;
|
||||
static const UInt64 k_PPMD = 0x030401;
|
||||
|
||||
@@ -183,12 +182,10 @@ static wchar_t GetHex(Byte value)
|
||||
{
|
||||
return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10)));
|
||||
}
|
||||
static inline UString GetHex2(Byte value)
|
||||
static inline void AddHexToString(UString &res, Byte value)
|
||||
{
|
||||
UString result;
|
||||
result += GetHex((Byte)(value >> 4));
|
||||
result += GetHex((Byte)(value & 0xF));
|
||||
return result;
|
||||
res += GetHex((Byte)(value >> 4));
|
||||
res += GetHex((Byte)(value & 0xF));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -273,89 +270,82 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va
|
||||
UString methodsString;
|
||||
for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--)
|
||||
{
|
||||
const CCoderInfo &coderInfo = folderInfo.Coders[i];
|
||||
const CCoderInfo &coder = folderInfo.Coders[i];
|
||||
if (!methodsString.IsEmpty())
|
||||
methodsString += L' ';
|
||||
|
||||
UString methodName, propsString;
|
||||
bool methodIsKnown = FindMethod(
|
||||
EXTERNAL_CODECS_VARS
|
||||
coder.MethodID, methodName);
|
||||
|
||||
if (!methodIsKnown)
|
||||
methodsString += ConvertMethodIdToString(coder.MethodID);
|
||||
else
|
||||
{
|
||||
UString methodName;
|
||||
bool methodIsKnown = FindMethod(
|
||||
EXTERNAL_CODECS_VARS
|
||||
coderInfo.MethodID, methodName);
|
||||
|
||||
if (methodIsKnown)
|
||||
methodsString += methodName;
|
||||
if (coder.MethodID == k_Delta && coder.Props.GetCapacity() == 1)
|
||||
propsString = ConvertUInt32ToString((UInt32)coder.Props[0] + 1);
|
||||
else if (coder.MethodID == k_LZMA && coder.Props.GetCapacity() == 5)
|
||||
{
|
||||
methodsString += methodName;
|
||||
if (coderInfo.MethodID == k_LZMA)
|
||||
UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1);
|
||||
propsString = GetStringForSizeValue(dicSize);
|
||||
}
|
||||
else if (coder.MethodID == k_LZMA2 && coder.Props.GetCapacity() == 1)
|
||||
{
|
||||
Byte p = coder.Props[0];
|
||||
UInt32 dicSize = (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11));
|
||||
propsString = GetStringForSizeValue(dicSize);
|
||||
}
|
||||
else if (coder.MethodID == k_PPMD && coder.Props.GetCapacity() == 5)
|
||||
{
|
||||
Byte order = *(const Byte *)coder.Props;
|
||||
methodsString += L'o';
|
||||
methodsString += ConvertUInt32ToString(order);
|
||||
methodsString += L":mem";
|
||||
UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1);
|
||||
propsString = GetStringForSizeValue(dicSize);
|
||||
}
|
||||
else if (coder.MethodID == k_AES && coder.Props.GetCapacity() >= 1)
|
||||
{
|
||||
const Byte *data = (const Byte *)coder.Props;
|
||||
Byte firstByte = *data++;
|
||||
UInt32 numCyclesPower = firstByte & 0x3F;
|
||||
propsString = ConvertUInt32ToString(numCyclesPower);
|
||||
/*
|
||||
if ((firstByte & 0xC0) != 0)
|
||||
{
|
||||
if (coderInfo.Props.GetCapacity() >= 5)
|
||||
UInt32 saltSize = (firstByte >> 7) & 1;
|
||||
UInt32 ivSize = (firstByte >> 6) & 1;
|
||||
if (coder.Props.GetCapacity() >= 2)
|
||||
{
|
||||
methodsString += L":";
|
||||
UInt32 dicSize = GetUi32((const Byte *)coderInfo.Props + 1);
|
||||
methodsString += GetStringForSizeValue(dicSize);
|
||||
Byte secondByte = *data++;
|
||||
saltSize += (secondByte >> 4);
|
||||
ivSize += (secondByte & 0x0F);
|
||||
}
|
||||
}
|
||||
else if (coderInfo.MethodID == k_PPMD)
|
||||
*/
|
||||
}
|
||||
}
|
||||
if (!propsString.IsEmpty())
|
||||
{
|
||||
methodsString += L':';
|
||||
methodsString += propsString;
|
||||
}
|
||||
else if (coder.Props.GetCapacity() > 0)
|
||||
{
|
||||
methodsString += L":[";
|
||||
for (size_t bi = 0; bi < coder.Props.GetCapacity(); bi++)
|
||||
{
|
||||
if (bi > 5 && bi + 1 < coder.Props.GetCapacity())
|
||||
{
|
||||
if (coderInfo.Props.GetCapacity() >= 5)
|
||||
{
|
||||
Byte order = *(const Byte *)coderInfo.Props;
|
||||
methodsString += L":o";
|
||||
methodsString += ConvertUInt32ToString(order);
|
||||
methodsString += L":mem";
|
||||
UInt32 dicSize = GetUi32((const Byte *)coderInfo.Props + 1);
|
||||
methodsString += GetStringForSizeValue(dicSize);
|
||||
}
|
||||
}
|
||||
else if (coderInfo.MethodID == k_AES)
|
||||
{
|
||||
if (coderInfo.Props.GetCapacity() >= 1)
|
||||
{
|
||||
methodsString += L":";
|
||||
const Byte *data = (const Byte *)coderInfo.Props;
|
||||
Byte firstByte = *data++;
|
||||
UInt32 numCyclesPower = firstByte & 0x3F;
|
||||
methodsString += ConvertUInt32ToString(numCyclesPower);
|
||||
/*
|
||||
if ((firstByte & 0xC0) != 0)
|
||||
{
|
||||
methodsString += L":";
|
||||
return S_OK;
|
||||
UInt32 saltSize = (firstByte >> 7) & 1;
|
||||
UInt32 ivSize = (firstByte >> 6) & 1;
|
||||
if (coderInfo.Props.GetCapacity() >= 2)
|
||||
{
|
||||
Byte secondByte = *data++;
|
||||
saltSize += (secondByte >> 4);
|
||||
ivSize += (secondByte & 0x0F);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
methodsString += L"..";
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (coderInfo.Props.GetCapacity() > 0)
|
||||
{
|
||||
methodsString += L":[";
|
||||
for (size_t bi = 0; bi < coderInfo.Props.GetCapacity(); bi++)
|
||||
{
|
||||
if (bi > 5 && bi + 1 < coderInfo.Props.GetCapacity())
|
||||
{
|
||||
methodsString += L"..";
|
||||
break;
|
||||
}
|
||||
else
|
||||
methodsString += GetHex2(coderInfo.Props[bi]);
|
||||
}
|
||||
methodsString += L"]";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodsString += ConvertMethodIdToString(coderInfo.MethodID);
|
||||
AddHexToString(methodsString, coder.Props[bi]);
|
||||
}
|
||||
methodsString += L']';
|
||||
}
|
||||
}
|
||||
prop = methodsString;
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
|
||||
#include "../../ICoder.h"
|
||||
#include "../IArchive.h"
|
||||
#include "7zIn.h"
|
||||
|
||||
#include "7zCompressionMode.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
@@ -15,6 +12,9 @@
|
||||
#include "../Common/HandlerOut.h"
|
||||
#endif
|
||||
|
||||
#include "7zCompressionMode.h"
|
||||
#include "7zIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace N7z {
|
||||
|
||||
@@ -90,8 +90,6 @@ private:
|
||||
|
||||
CRecordVector<CBind> _binds;
|
||||
|
||||
HRESULT SetPassword(CCompressionMethodMode &methodMode, IArchiveUpdateCallback *updateCallback);
|
||||
|
||||
HRESULT SetCompressionMethod(CCompressionMethodMode &method,
|
||||
CObjectVector<COneMethodInfo> &methodsInfo
|
||||
#ifdef COMPRESS_MT
|
||||
|
||||
@@ -40,31 +40,6 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CHandler::SetPassword(CCompressionMethodMode &methodMode,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
|
||||
if (!getTextPassword)
|
||||
{
|
||||
CMyComPtr<IArchiveUpdateCallback> udateCallback2(updateCallback);
|
||||
udateCallback2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
|
||||
}
|
||||
|
||||
if (getTextPassword)
|
||||
{
|
||||
CMyComBSTR password;
|
||||
Int32 passwordIsDefined;
|
||||
RINOK(getTextPassword->CryptoGetTextPassword2(
|
||||
&passwordIsDefined, &password));
|
||||
methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
|
||||
if (methodMode.PasswordIsDefined)
|
||||
methodMode.Password = password;
|
||||
}
|
||||
else
|
||||
methodMode.PasswordIsDefined = false;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CHandler::SetCompressionMethod(
|
||||
CCompressionMethodMode &methodMode,
|
||||
CCompressionMethodMode &headerMethod)
|
||||
@@ -210,7 +185,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
|
||||
const CArchiveDatabaseEx *db = 0;
|
||||
#ifdef _7Z_VOL
|
||||
if(_volumes.Size() > 1)
|
||||
if (_volumes.Size() > 1)
|
||||
return E_FAIL;
|
||||
const CVolume *volume = 0;
|
||||
if (_volumes.Size() == 1)
|
||||
@@ -227,14 +202,13 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
Int32 newData;
|
||||
Int32 newProperties;
|
||||
Int32 newData, newProps;
|
||||
UInt32 indexInArchive;
|
||||
if (!updateCallback)
|
||||
return E_FAIL;
|
||||
RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProperties, &indexInArchive));
|
||||
RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
|
||||
CUpdateItem ui;
|
||||
ui.NewProperties = IntToBool(newProperties);
|
||||
ui.NewProps = IntToBool(newProps);
|
||||
ui.NewData = IntToBool(newData);
|
||||
ui.IndexInArchive = indexInArchive;
|
||||
ui.IndexInClient = i;
|
||||
@@ -243,6 +217,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
|
||||
if (ui.IndexInArchive != -1)
|
||||
{
|
||||
if (db == 0 || ui.IndexInArchive >= db->Files.Size())
|
||||
return E_INVALIDARG;
|
||||
const CFileItem &fi = db->Files[ui.IndexInArchive];
|
||||
ui.Name = fi.Name;
|
||||
ui.IsDir = fi.IsDir;
|
||||
@@ -254,7 +230,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime);
|
||||
}
|
||||
|
||||
if (ui.NewProperties)
|
||||
if (ui.NewProps)
|
||||
{
|
||||
bool nameIsDefined;
|
||||
bool folderStatusIsDefined;
|
||||
@@ -350,7 +326,20 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
headerMethod.NumThreads = 1;
|
||||
#endif
|
||||
|
||||
RINOK(SetPassword(methodMode, updateCallback));
|
||||
CMyComPtr<ICryptoGetTextPassword2> getPassword2;
|
||||
updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2);
|
||||
|
||||
if (getPassword2)
|
||||
{
|
||||
CMyComBSTR password;
|
||||
Int32 passwordIsDefined;
|
||||
RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password));
|
||||
methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
|
||||
if (methodMode.PasswordIsDefined)
|
||||
methodMode.Password = password;
|
||||
}
|
||||
else
|
||||
methodMode.PasswordIsDefined = false;
|
||||
|
||||
bool compressMainHeader = _compressHeaders; // check it
|
||||
|
||||
@@ -365,8 +354,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
encryptHeaders = _passwordIsDefined;
|
||||
#endif
|
||||
compressMainHeader = true;
|
||||
if(encryptHeaders)
|
||||
RINOK(SetPassword(headerMethod, updateCallback));
|
||||
if (encryptHeaders)
|
||||
{
|
||||
headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;
|
||||
headerMethod.Password = methodMode.Password;
|
||||
}
|
||||
}
|
||||
|
||||
if (numItems < 2)
|
||||
@@ -391,6 +383,10 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
|
||||
COutArchive archive;
|
||||
CArchiveDatabase newDatabase;
|
||||
|
||||
CMyComPtr<ICryptoGetTextPassword> getPassword;
|
||||
updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword);
|
||||
|
||||
HRESULT res = Update(
|
||||
EXTERNAL_CODECS_VARS
|
||||
#ifdef _7Z_VOL
|
||||
@@ -401,7 +397,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
db,
|
||||
#endif
|
||||
updateItems,
|
||||
archive, newDatabase, outStream, updateCallback, options);
|
||||
archive, newDatabase, outStream, updateCallback, options
|
||||
#ifndef _NO_CRYPTO
|
||||
, getPassword
|
||||
#endif
|
||||
);
|
||||
|
||||
RINOK(res);
|
||||
|
||||
|
||||
@@ -2,11 +2,8 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../../../../C/7zCrc.h"
|
||||
#include "../../../../C/CpuArch.h"
|
||||
}
|
||||
#include "../../../../C/7zCrc.h"
|
||||
#include "../../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/StreamObjects.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
@@ -198,16 +195,16 @@ void CInByte2::ReadBytes(Byte *data, size_t size)
|
||||
data[i] = _buffer[_pos++];
|
||||
}
|
||||
|
||||
void CInByte2::SkeepData(UInt64 size)
|
||||
void CInByte2::SkipData(UInt64 size)
|
||||
{
|
||||
if (size > _size - _pos)
|
||||
ThrowEndOfData();
|
||||
_pos += (size_t)size;
|
||||
}
|
||||
|
||||
void CInByte2::SkeepData()
|
||||
void CInByte2::SkipData()
|
||||
{
|
||||
SkeepData(ReadNumber());
|
||||
SkipData(ReadNumber());
|
||||
}
|
||||
|
||||
UInt64 CInByte2::ReadNumber()
|
||||
@@ -363,7 +360,7 @@ void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
|
||||
{
|
||||
if (ReadID() == NID::kEnd)
|
||||
break;
|
||||
SkeepData();
|
||||
SkipData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,7 +453,7 @@ void CInArchive::WaitAttribute(UInt64 attribute)
|
||||
return;
|
||||
if (type == NID::kEnd)
|
||||
ThrowIncorrect();
|
||||
SkeepData();
|
||||
SkipData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,7 +499,7 @@ void CInArchive::ReadPackInfo(
|
||||
ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs);
|
||||
continue;
|
||||
}
|
||||
SkeepData();
|
||||
SkipData();
|
||||
}
|
||||
if (packCRCsDefined.IsEmpty())
|
||||
{
|
||||
@@ -563,7 +560,7 @@ void CInArchive::ReadUnpackInfo(
|
||||
}
|
||||
continue;
|
||||
}
|
||||
SkeepData();
|
||||
SkipData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,7 +587,7 @@ void CInArchive::ReadSubStreamsInfo(
|
||||
break;
|
||||
if (type == NID::kEnd)
|
||||
break;
|
||||
SkeepData();
|
||||
SkipData();
|
||||
}
|
||||
|
||||
if (numUnpackStreamsInFolders.IsEmpty())
|
||||
@@ -665,7 +662,7 @@ void CInArchive::ReadSubStreamsInfo(
|
||||
return;
|
||||
}
|
||||
else
|
||||
SkeepData();
|
||||
SkipData();
|
||||
type = ReadID();
|
||||
}
|
||||
}
|
||||
@@ -1006,7 +1003,7 @@ HRESULT CInArchive::ReadHeader(
|
||||
db.ArchiveInfo.FileInfoPopIDs.Add(type);
|
||||
}
|
||||
else
|
||||
SkeepData(size);
|
||||
SkipData(size);
|
||||
bool checkRecordsSize = (db.ArchiveInfo.Version.Major > 0 ||
|
||||
db.ArchiveInfo.Version.Minor > 2);
|
||||
if (checkRecordsSize && _inByteBack->_pos - ppp != size)
|
||||
|
||||
@@ -110,8 +110,8 @@ public:
|
||||
}
|
||||
Byte ReadByte();
|
||||
void ReadBytes(Byte *data, size_t size);
|
||||
void SkeepData(UInt64 size);
|
||||
void SkeepData();
|
||||
void SkipData(UInt64 size);
|
||||
void SkipData();
|
||||
UInt64 ReadNumber();
|
||||
CNum ReadNum();
|
||||
UInt32 ReadUInt32();
|
||||
@@ -162,8 +162,8 @@ private:
|
||||
UInt64 ReadID() { return _inByteBack->ReadNumber(); }
|
||||
UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); }
|
||||
UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); }
|
||||
void SkeepData(UInt64 size) { _inByteBack->SkeepData(size); }
|
||||
void SkeepData() { _inByteBack->SkeepData(); }
|
||||
void SkipData(UInt64 size) { _inByteBack->SkipData(size); }
|
||||
void SkipData() { _inByteBack->SkipData(); }
|
||||
void WaitAttribute(UInt64 attribute);
|
||||
|
||||
void ReadArchiveProperties(CInArchiveInfo &archiveInfo);
|
||||
|
||||
@@ -2,16 +2,14 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Common/AutoPtr.h"
|
||||
|
||||
#include "../../Common/StreamObjects.h"
|
||||
|
||||
#include "7zOut.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../../../../C/7zCrc.h"
|
||||
}
|
||||
|
||||
static HRESULT WriteBytes(ISequentialOutStream *stream, const void *data, size_t size)
|
||||
{
|
||||
while (size > 0)
|
||||
@@ -141,7 +139,7 @@ void COutArchive::Close()
|
||||
Stream.Release();
|
||||
}
|
||||
|
||||
HRESULT COutArchive::SkeepPrefixArchiveHeader()
|
||||
HRESULT COutArchive::SkipPrefixArchiveHeader()
|
||||
{
|
||||
#ifdef _7Z_VOL
|
||||
if (_endMarker)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// 7z/Out.h
|
||||
// 7zOut.h
|
||||
|
||||
#ifndef __7Z_OUT_H
|
||||
#define __7Z_OUT_H
|
||||
|
||||
#include "7zHeader.h"
|
||||
#include "7zItem.h"
|
||||
#include "7zCompressionMode.h"
|
||||
#include "7zEncode.h"
|
||||
#include "7zHeader.h"
|
||||
#include "7zItem.h"
|
||||
|
||||
#include "../../Common/OutBuffer.h"
|
||||
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
CMyComPtr<ISequentialOutStream> SeqStream;
|
||||
HRESULT Create(ISequentialOutStream *stream, bool endMarker);
|
||||
void Close();
|
||||
HRESULT SkeepPrefixArchiveHeader();
|
||||
HRESULT SkipPrefixArchiveHeader();
|
||||
HRESULT WriteDatabase(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
const CArchiveDatabase &db,
|
||||
|
||||
+575
-226
File diff suppressed because it is too large
Load Diff
@@ -3,9 +3,9 @@
|
||||
#ifndef __7Z_UPDATE_H
|
||||
#define __7Z_UPDATE_H
|
||||
|
||||
#include "7zCompressionMode.h"
|
||||
#include "7zIn.h"
|
||||
#include "7zOut.h"
|
||||
#include "7zCompressionMode.h"
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
@@ -27,7 +27,7 @@ struct CUpdateItem
|
||||
UInt32 Attrib;
|
||||
|
||||
bool NewData;
|
||||
bool NewProperties;
|
||||
bool NewProps;
|
||||
|
||||
bool IsAnti;
|
||||
bool IsDir;
|
||||
@@ -78,7 +78,11 @@ HRESULT Update(
|
||||
CArchiveDatabase &newDatabase,
|
||||
ISequentialOutStream *seqOutStream,
|
||||
IArchiveUpdateCallback *updateCallback,
|
||||
const CUpdateOptions &options);
|
||||
const CUpdateOptions &options
|
||||
#ifndef _NO_CRYPTO
|
||||
, ICryptoGetTextPassword *getDecoderPassword
|
||||
#endif
|
||||
);
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -104,7 +104,7 @@ $(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
|
||||
$(COMPL)
|
||||
$(AR_COMMON_OBJS): ../Common/$(*B).cpp
|
||||
$(COMPL)
|
||||
$O\CopyCoder.obj: ../../Compress/Copy/$(*B).cpp
|
||||
$O\CopyCoder.obj: ../../Compress/$(*B).cpp
|
||||
$(COMPL)
|
||||
$(C_OBJS): ../../../../C/$(*B).c
|
||||
$(COMPL_O2)
|
||||
|
||||
@@ -3,15 +3,12 @@
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
#include "../../Common/Types.h"
|
||||
|
||||
#include "../../Windows/PropVariant.h"
|
||||
|
||||
#include "../Common/RegisterArc.h"
|
||||
|
||||
#include "IArchive.h"
|
||||
#include "../ICoder.h"
|
||||
#include "../IPassword.h"
|
||||
|
||||
static const unsigned int kNumArcsMax = 32;
|
||||
static const unsigned int kNumArcsMax = 48;
|
||||
static unsigned int g_NumArcs = 0;
|
||||
static const CArcInfo *g_Arcs[kNumArcsMax];
|
||||
void RegisterArc(const CArcInfo *arcInfo)
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.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"
|
||||
@@ -180,6 +180,7 @@ struct CItem
|
||||
UInt32 PackSize;
|
||||
UInt32 Size;
|
||||
UInt32 FileCRC;
|
||||
UInt32 SplitPos;
|
||||
|
||||
Byte Version;
|
||||
Byte ExtractVersion;
|
||||
@@ -197,6 +198,8 @@ struct CItem
|
||||
|
||||
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;
|
||||
@@ -240,6 +243,10 @@ HRESULT CItem::Parse(const Byte *p, unsigned size)
|
||||
// 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));
|
||||
@@ -270,7 +277,7 @@ class CInArchive
|
||||
|
||||
HRESULT ReadBlock(bool &filled);
|
||||
HRESULT ReadSignatureAndBlock(bool &filled);
|
||||
HRESULT SkeepExtendedHeaders();
|
||||
HRESULT SkipExtendedHeaders();
|
||||
|
||||
HRESULT SafeReadBytes(void *data, UInt32 size);
|
||||
|
||||
@@ -389,7 +396,7 @@ HRESULT CInArchive::ReadSignatureAndBlock(bool &filled)
|
||||
return ReadBlock(filled);
|
||||
}
|
||||
|
||||
HRESULT CInArchive::SkeepExtendedHeaders()
|
||||
HRESULT CInArchive::SkipExtendedHeaders()
|
||||
{
|
||||
for (UInt32 i = 0;; i++)
|
||||
{
|
||||
@@ -412,7 +419,7 @@ HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit)
|
||||
if (!filled)
|
||||
return S_FALSE;
|
||||
RINOK(Header.Parse(_block, _blockSize));
|
||||
return SkeepExtendedHeaders();
|
||||
return SkipExtendedHeaders();
|
||||
}
|
||||
|
||||
HRESULT CInArchive::GetNextItem(bool &filled, CItem &item)
|
||||
@@ -428,7 +435,7 @@ HRESULT CInArchive::GetNextItem(bool &filled, CItem &item)
|
||||
extraData = GetUi32(_block + pos);
|
||||
*/
|
||||
|
||||
RINOK(SkeepExtendedHeaders());
|
||||
RINOK(SkipExtendedHeaders());
|
||||
filled = true;
|
||||
return S_OK;
|
||||
}
|
||||
@@ -482,8 +489,9 @@ STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidSize, VT_UI4},
|
||||
{ NULL, kpidPosition, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI4},
|
||||
{ NULL, kpidMTime, VT_FILETIME},
|
||||
{ NULL, kpidAttrib, VT_UI4},
|
||||
{ NULL, kpidEncrypted, VT_BOOL},
|
||||
@@ -556,6 +564,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
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;
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
// BZip2Handler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "../Common/DummyOutStream.h"
|
||||
|
||||
#include "BZip2Handler.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NBZip2 {
|
||||
|
||||
static const CMethodId kMethodId_BZip2 = 0x040202;
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPackSize, VT_UI8}
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = 1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPackSize: prop = _item.PackSize; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
const UInt64 * /* maxCheckStartPosition */,
|
||||
IArchiveOpenCallback * /* openArchiveCallback */)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
try
|
||||
{
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_streamStartPosition));
|
||||
const int kSignatureSize = 3;
|
||||
Byte buffer[kSignatureSize];
|
||||
RINOK(ReadStream_FALSE(stream, buffer, kSignatureSize));
|
||||
if (buffer[0] != 'B' || buffer[1] != 'Z' || buffer[2] != 'h')
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 endPosition;
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_END, &endPosition));
|
||||
_item.PackSize = endPosition - _streamStartPosition;
|
||||
|
||||
_stream = stream;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == UInt32(-1));
|
||||
if (!allFilesMode)
|
||||
{
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
if (numItems != 1)
|
||||
return E_INVALIDARG;
|
||||
if (indices[0] != 0)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
bool testMode = (testModeSpec != 0);
|
||||
|
||||
extractCallback->SetTotal(_item.PackSize);
|
||||
|
||||
UInt64 currentTotalPacked = 0;
|
||||
|
||||
RINOK(extractCallback->SetCompleted(¤tTotalPacked));
|
||||
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode;
|
||||
askMode = testMode ? NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
|
||||
RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
|
||||
|
||||
if(!testMode && !realOutStream)
|
||||
return S_OK;
|
||||
|
||||
|
||||
extractCallback->PrepareOperation(askMode);
|
||||
|
||||
CMyComPtr<ICompressCoder> decoder;
|
||||
HRESULT loadResult = CreateCoder(
|
||||
EXTERNAL_CODECS_VARS
|
||||
kMethodId_BZip2, decoder, false);
|
||||
if (loadResult != S_OK || !decoder)
|
||||
{
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef COMPRESS_MT
|
||||
{
|
||||
CMyComPtr<ICompressSetCoderMt> setCoderMt;
|
||||
decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
|
||||
if (setCoderMt)
|
||||
{
|
||||
RINOK(setCoderMt->SetNumberOfThreads(_numThreads));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
CDummyOutStream *outStreamSpec = new CDummyOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
outStreamSpec->Init();
|
||||
|
||||
realOutStream.Release();
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, true);
|
||||
|
||||
RINOK(_stream->Seek(_streamStartPosition, STREAM_SEEK_SET, NULL));
|
||||
|
||||
HRESULT result = S_OK;
|
||||
|
||||
bool firstItem = true;
|
||||
for (;;)
|
||||
{
|
||||
lps->InSize = currentTotalPacked;
|
||||
lps->OutSize = outStreamSpec->GetSize();
|
||||
|
||||
RINOK(lps->SetCur());
|
||||
|
||||
const int kSignatureSize = 3;
|
||||
Byte buffer[kSignatureSize];
|
||||
size_t processedSize = kSignatureSize;
|
||||
RINOK(ReadStream(_stream, buffer, &processedSize));
|
||||
if (processedSize != kSignatureSize)
|
||||
{
|
||||
if (firstItem)
|
||||
return E_FAIL;
|
||||
break;
|
||||
}
|
||||
if (buffer[0] != 'B' || buffer[1] != 'Z' || buffer[2] != 'h')
|
||||
{
|
||||
if (firstItem)
|
||||
return E_FAIL;
|
||||
break;
|
||||
}
|
||||
firstItem = false;
|
||||
|
||||
UInt64 dataStartPos;
|
||||
RINOK(_stream->Seek((UInt64)(Int64)(-3), STREAM_SEEK_CUR, &dataStartPos));
|
||||
|
||||
result = decoder->Code(_stream, outStream, NULL, NULL, progress);
|
||||
|
||||
if (result != S_OK)
|
||||
break;
|
||||
|
||||
CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize;
|
||||
decoder.QueryInterface(IID_ICompressGetInStreamProcessedSize, &getInStreamProcessedSize);
|
||||
if (!getInStreamProcessedSize)
|
||||
break;
|
||||
UInt64 packSize;
|
||||
RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&packSize));
|
||||
UInt64 pos;
|
||||
RINOK(_stream->Seek(dataStartPos + packSize, STREAM_SEEK_SET, &pos));
|
||||
currentTotalPacked = pos - _streamStartPosition;
|
||||
}
|
||||
outStream.Release();
|
||||
|
||||
Int32 retResult;
|
||||
if (result == S_OK)
|
||||
retResult = NExtract::NOperationResult::kOK;
|
||||
else if (result == S_FALSE)
|
||||
retResult = NExtract::NOperationResult::kDataError;
|
||||
else
|
||||
return result;
|
||||
return extractCallback->SetOperationResult(retResult);
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
IMPL_ISetCompressCodecsInfo
|
||||
|
||||
}}
|
||||
@@ -1,68 +0,0 @@
|
||||
// BZip2/Handler.h
|
||||
|
||||
#ifndef __BZIP2_HANDLER_H
|
||||
#define __BZIP2_HANDLER_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "../IArchive.h"
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "BZip2Item.h"
|
||||
|
||||
#ifdef COMPRESS_MT
|
||||
#include "../../../Windows/System.h"
|
||||
#endif
|
||||
|
||||
namespace NArchive {
|
||||
namespace NBZip2 {
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IOutArchive,
|
||||
public ISetProperties,
|
||||
PUBLIC_ISetCompressCodecsInfo
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<IInStream> _stream;
|
||||
NArchive::NBZip2::CItem _item;
|
||||
UInt64 _streamStartPosition;
|
||||
|
||||
UInt32 _level;
|
||||
UInt32 _dicSize;
|
||||
UInt32 _numPasses;
|
||||
#ifdef COMPRESS_MT
|
||||
UInt32 _numThreads;
|
||||
#endif
|
||||
|
||||
DECL_EXTERNAL_CODECS_VARS
|
||||
|
||||
void InitMethodProperties()
|
||||
{
|
||||
_level = 5;
|
||||
_dicSize =
|
||||
_numPasses = 0xFFFFFFFF;
|
||||
#ifdef COMPRESS_MT
|
||||
_numThreads = NWindows::NSystem::GetNumberOfProcessors();;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
MY_QUERYINTERFACE_BEGIN2(IInArchive)
|
||||
MY_QUERYINTERFACE_ENTRY(IOutArchive)
|
||||
MY_QUERYINTERFACE_ENTRY(ISetProperties)
|
||||
QUERY_ENTRY_ISetCompressCodecsInfo
|
||||
MY_QUERYINTERFACE_END
|
||||
MY_ADDREF_RELEASE
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
INTERFACE_IOutArchive(;)
|
||||
|
||||
STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties);
|
||||
|
||||
DECL_ISetCompressCodecsInfo
|
||||
|
||||
CHandler() { InitMethodProperties(); }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,156 +0,0 @@
|
||||
// BZip2HandlerOut.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "BZip2Handler.h"
|
||||
#include "BZip2Update.h"
|
||||
|
||||
#include "Common/Defs.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
#include "../Common/ParseProperties.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
static const UInt32 kNumPassesX1 = 1;
|
||||
static const UInt32 kNumPassesX7 = 2;
|
||||
static const UInt32 kNumPassesX9 = 7;
|
||||
|
||||
static const UInt32 kDicSizeX1 = 100000;
|
||||
static const UInt32 kDicSizeX3 = 500000;
|
||||
static const UInt32 kDicSizeX5 = 900000;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NBZip2 {
|
||||
|
||||
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
|
||||
{
|
||||
*type = NFileTimeType::kUnix;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT CopyStreams(ISequentialInStream *inStream, ISequentialOutStream *outStream)
|
||||
{
|
||||
CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
|
||||
return copyCoder->Code(inStream, outStream, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
if (numItems != 1)
|
||||
return E_INVALIDARG;
|
||||
|
||||
Int32 newData;
|
||||
Int32 newProperties;
|
||||
UInt32 indexInArchive;
|
||||
if (!updateCallback)
|
||||
return E_FAIL;
|
||||
RINOK(updateCallback->GetUpdateItemInfo(0,&newData, &newProperties, &indexInArchive));
|
||||
|
||||
if (IntToBool(newProperties))
|
||||
{
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
|
||||
if (prop.vt == VT_BOOL)
|
||||
{
|
||||
if (prop.boolVal != VARIANT_FALSE)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
if (IntToBool(newData))
|
||||
{
|
||||
UInt64 size;
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
|
||||
if (prop.vt != VT_UI8)
|
||||
return E_INVALIDARG;
|
||||
size = prop.uhVal.QuadPart;
|
||||
}
|
||||
|
||||
UInt32 dicSize = _dicSize;
|
||||
if (dicSize == 0xFFFFFFFF)
|
||||
dicSize = (_level >= 5 ? kDicSizeX5 :
|
||||
(_level >= 3 ? kDicSizeX3 :
|
||||
kDicSizeX1));
|
||||
|
||||
UInt32 numPasses = _numPasses;
|
||||
if (numPasses == 0xFFFFFFFF)
|
||||
numPasses = (_level >= 9 ? kNumPassesX9 :
|
||||
(_level >= 7 ? kNumPassesX7 :
|
||||
kNumPassesX1));
|
||||
|
||||
return UpdateArchive(
|
||||
EXTERNAL_CODECS_VARS
|
||||
size, outStream, 0, dicSize, numPasses,
|
||||
#ifdef COMPRESS_MT
|
||||
_numThreads,
|
||||
#endif
|
||||
updateCallback);
|
||||
}
|
||||
if (indexInArchive != 0)
|
||||
return E_INVALIDARG;
|
||||
RINOK(_stream->Seek(_streamStartPosition, STREAM_SEEK_SET, NULL));
|
||||
return CopyStreams(_stream, outStream);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
|
||||
{
|
||||
InitMethodProperties();
|
||||
#ifdef COMPRESS_MT
|
||||
const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
|
||||
_numThreads = numProcessors;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < numProperties; i++)
|
||||
{
|
||||
UString name = UString(names[i]);
|
||||
name.MakeUpper();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
|
||||
const PROPVARIANT &prop = values[i];
|
||||
|
||||
if (name[0] == 'X')
|
||||
{
|
||||
UInt32 level = 9;
|
||||
RINOK(ParsePropValue(name.Mid(1), prop, level));
|
||||
_level = level;
|
||||
continue;
|
||||
}
|
||||
if (name[0] == 'D')
|
||||
{
|
||||
UInt32 dicSize = kDicSizeX5;
|
||||
RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize));
|
||||
_dicSize = dicSize;
|
||||
continue;
|
||||
}
|
||||
if (name.Left(4) == L"PASS")
|
||||
{
|
||||
UInt32 num = kNumPassesX9;
|
||||
RINOK(ParsePropValue(name.Mid(4), prop, num));
|
||||
_numPasses = num;
|
||||
continue;
|
||||
}
|
||||
if (name.Left(2) == L"MT")
|
||||
{
|
||||
#ifdef COMPRESS_MT
|
||||
RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads));
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Archive/BZip2Item.h
|
||||
|
||||
#ifndef __ARCHIVE_BZIP2_ITEM_H
|
||||
#define __ARCHIVE_BZIP2_ITEM_H
|
||||
|
||||
namespace NArchive {
|
||||
namespace NBZip2 {
|
||||
|
||||
struct CItem
|
||||
{
|
||||
UInt64 PackSize;
|
||||
UInt64 UnPackSize;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
// BZip2Update.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
#include "BZip2Update.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NBZip2 {
|
||||
|
||||
static const CMethodId kMethodId_BZip2 = 0x040202;
|
||||
|
||||
HRESULT UpdateArchive(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
UInt64 unpackSize,
|
||||
ISequentialOutStream *outStream,
|
||||
int indexInClient,
|
||||
UInt32 dictionary,
|
||||
UInt32 numPasses,
|
||||
#ifdef COMPRESS_MT
|
||||
UInt32 numThreads,
|
||||
#endif
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
RINOK(updateCallback->SetTotal(unpackSize));
|
||||
UInt64 complexity = 0;
|
||||
RINOK(updateCallback->SetCompleted(&complexity));
|
||||
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
|
||||
RINOK(updateCallback->GetStream(indexInClient, &fileInStream));
|
||||
|
||||
CLocalProgress *localProgressSpec = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
|
||||
localProgressSpec->Init(updateCallback, true);
|
||||
|
||||
CMyComPtr<ICompressCoder> encoder;
|
||||
RINOK(CreateCoder(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
kMethodId_BZip2, encoder, true));
|
||||
if (!encoder)
|
||||
return E_NOTIMPL;
|
||||
CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
|
||||
encoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties);
|
||||
if (setCoderProperties)
|
||||
{
|
||||
NWindows::NCOM::CPropVariant properties[] =
|
||||
{
|
||||
dictionary,
|
||||
numPasses
|
||||
#ifdef COMPRESS_MT
|
||||
, numThreads
|
||||
#endif
|
||||
};
|
||||
PROPID propIDs[] =
|
||||
{
|
||||
NCoderPropID::kDictionarySize,
|
||||
NCoderPropID::kNumPasses
|
||||
#ifdef COMPRESS_MT
|
||||
, NCoderPropID::kNumThreads
|
||||
#endif
|
||||
};
|
||||
RINOK(setCoderProperties->SetCoderProperties(propIDs, properties, sizeof(propIDs) / sizeof(propIDs[0])));
|
||||
}
|
||||
|
||||
RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress));
|
||||
|
||||
return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,26 +0,0 @@
|
||||
// BZip2Update.h
|
||||
|
||||
#ifndef __BZIP2_UPDATE_H
|
||||
#define __BZIP2_UPDATE_H
|
||||
|
||||
#include "../IArchive.h"
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NBZip2 {
|
||||
|
||||
HRESULT UpdateArchive(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
UInt64 unpackSize,
|
||||
ISequentialOutStream *outStream,
|
||||
int indexInClient,
|
||||
UInt32 dictionary,
|
||||
UInt32 numPasses,
|
||||
#ifdef COMPRESS_MT
|
||||
UInt32 numThreads,
|
||||
#endif
|
||||
IArchiveUpdateCallback *updateCallback);
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,8 +0,0 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/MyWindows.h"
|
||||
|
||||
#endif
|
||||
@@ -1,18 +0,0 @@
|
||||
// BZip2Register.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "BZip2Handler.h"
|
||||
static IInArchive *CreateArc() { return new NArchive::NBZip2::CHandler; }
|
||||
#ifndef EXTRACT_ONLY
|
||||
static IOutArchive *CreateArcOut() { return new NArchive::NBZip2::CHandler; }
|
||||
#else
|
||||
#define CreateArcOut 0
|
||||
#endif
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"BZip2", L"bz2 bzip2 tbz2 tbz", L"* * .tar .tar", 2, { 'B', 'Z', 'h' }, 3, true, CreateArc, CreateArcOut };
|
||||
|
||||
REGISTER_ARC(BZip2)
|
||||
Executable
+428
@@ -0,0 +1,428 @@
|
||||
// Bz2Handler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
#ifdef COMPRESS_MT
|
||||
#include "../../Windows/System.h"
|
||||
#endif
|
||||
|
||||
#include "../Common/CreateCoder.h"
|
||||
#include "../Common/ProgressUtils.h"
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "../Compress/BZip2Decoder.h"
|
||||
#include "../Compress/BZip2Encoder.h"
|
||||
#include "../Compress/CopyCoder.h"
|
||||
|
||||
#include "Common/DummyOutStream.h"
|
||||
#include "Common/ParseProperties.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NBz2 {
|
||||
|
||||
static const UInt32 kNumPassesX1 = 1;
|
||||
static const UInt32 kNumPassesX7 = 2;
|
||||
static const UInt32 kNumPassesX9 = 7;
|
||||
|
||||
static const UInt32 kDicSizeX1 = 100000;
|
||||
static const UInt32 kDicSizeX3 = 500000;
|
||||
static const UInt32 kDicSizeX5 = 900000;
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IArchiveOpenSeq,
|
||||
public IOutArchive,
|
||||
public ISetProperties,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CMyComPtr<ISequentialInStream> _seqStream;
|
||||
UInt64 _packSize;
|
||||
UInt64 _startPosition;
|
||||
bool _packSizeDefined;
|
||||
|
||||
UInt32 _level;
|
||||
UInt32 _dicSize;
|
||||
UInt32 _numPasses;
|
||||
#ifdef COMPRESS_MT
|
||||
UInt32 _numThreads;
|
||||
#endif
|
||||
|
||||
void InitMethodProperties()
|
||||
{
|
||||
_level = 5;
|
||||
_dicSize =
|
||||
_numPasses = 0xFFFFFFFF;
|
||||
#ifdef COMPRESS_MT
|
||||
_numThreads = NWindows::NSystem::GetNumberOfProcessors();;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties)
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
INTERFACE_IOutArchive(;)
|
||||
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
|
||||
STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
|
||||
|
||||
CHandler() { InitMethodProperties(); }
|
||||
};
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPackSize, VT_UI8}
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO_Table
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = 1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
const UInt64 * /* maxCheckStartPosition */,
|
||||
IArchiveOpenCallback * /* openArchiveCallback */)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
try
|
||||
{
|
||||
Close();
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
|
||||
const int kSignatureSize = 3;
|
||||
Byte buf[kSignatureSize];
|
||||
RINOK(ReadStream_FALSE(stream, buf, kSignatureSize));
|
||||
if (buf[0] != 'B' || buf[1] != 'Z' || buf[2] != 'h')
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 endPosition;
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_END, &endPosition));
|
||||
_packSize = endPosition - _startPosition;
|
||||
_packSizeDefined = true;
|
||||
_stream = stream;
|
||||
_seqStream = stream;
|
||||
}
|
||||
catch(...) { return S_FALSE; }
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
|
||||
{
|
||||
Close();
|
||||
_seqStream = stream;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_packSizeDefined = false;
|
||||
_seqStream.Release();
|
||||
_stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == (UInt32)-1);
|
||||
if (!allFilesMode)
|
||||
{
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
if (numItems != 1 || indices[0] != 0)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
bool testMode = (_aTestMode != 0);
|
||||
if (_stream)
|
||||
extractCallback->SetTotal(_packSize);
|
||||
UInt64 currentTotalPacked = 0;
|
||||
RINOK(extractCallback->SetCompleted(¤tTotalPacked));
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode = testMode ?
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
|
||||
if (!testMode && !realOutStream)
|
||||
return S_OK;
|
||||
|
||||
extractCallback->PrepareOperation(askMode);
|
||||
|
||||
NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder;
|
||||
CMyComPtr<ICompressCoder> decoder = decoderSpec;
|
||||
|
||||
if (_stream)
|
||||
{
|
||||
RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
|
||||
decoderSpec->SetInStream(_seqStream);
|
||||
|
||||
#if defined( COMPRESS_MT) && defined( COMPRESS_BZIP2_MT)
|
||||
RINOK(decoderSpec->SetNumberOfThreads(_numThreads));
|
||||
#endif
|
||||
|
||||
CDummyOutStream *outStreamSpec = new CDummyOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
outStreamSpec->Init();
|
||||
|
||||
realOutStream.Release();
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, true);
|
||||
|
||||
HRESULT result = S_OK;
|
||||
|
||||
bool firstItem = true;
|
||||
for (;;)
|
||||
{
|
||||
lps->InSize = currentTotalPacked;
|
||||
lps->OutSize = outStreamSpec->GetSize();
|
||||
|
||||
RINOK(lps->SetCur());
|
||||
|
||||
bool isBz2;
|
||||
result = decoderSpec->CodeResume(outStream, isBz2, progress);
|
||||
|
||||
if (result != S_OK)
|
||||
break;
|
||||
if (!isBz2)
|
||||
{
|
||||
if (firstItem)
|
||||
result = S_FALSE;
|
||||
break;
|
||||
}
|
||||
firstItem = false;
|
||||
|
||||
_packSize = currentTotalPacked = decoderSpec->GetInputProcessedSize();
|
||||
_packSizeDefined = true;
|
||||
}
|
||||
decoderSpec->ReleaseInStream();
|
||||
outStream.Release();
|
||||
|
||||
Int32 retResult;
|
||||
if (result == S_OK)
|
||||
retResult = NExtract::NOperationResult::kOK;
|
||||
else if (result == S_FALSE)
|
||||
retResult = NExtract::NOperationResult::kDataError;
|
||||
else
|
||||
return result;
|
||||
return extractCallback->SetOperationResult(retResult);
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
static HRESULT UpdateArchive(
|
||||
UInt64 unpackSize,
|
||||
ISequentialOutStream *outStream,
|
||||
int indexInClient,
|
||||
UInt32 dictionary,
|
||||
UInt32 numPasses,
|
||||
#ifdef COMPRESS_MT
|
||||
UInt32 numThreads,
|
||||
#endif
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
RINOK(updateCallback->SetTotal(unpackSize));
|
||||
UInt64 complexity = 0;
|
||||
RINOK(updateCallback->SetCompleted(&complexity));
|
||||
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
|
||||
RINOK(updateCallback->GetStream(indexInClient, &fileInStream));
|
||||
|
||||
CLocalProgress *localProgressSpec = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
|
||||
localProgressSpec->Init(updateCallback, true);
|
||||
|
||||
NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder;
|
||||
CMyComPtr<ICompressCoder> encoder = encoderSpec;
|
||||
{
|
||||
NWindows::NCOM::CPropVariant properties[] =
|
||||
{
|
||||
dictionary,
|
||||
numPasses
|
||||
#ifdef COMPRESS_MT
|
||||
, numThreads
|
||||
#endif
|
||||
};
|
||||
PROPID propIDs[] =
|
||||
{
|
||||
NCoderPropID::kDictionarySize,
|
||||
NCoderPropID::kNumPasses
|
||||
#ifdef COMPRESS_MT
|
||||
, NCoderPropID::kNumThreads
|
||||
#endif
|
||||
};
|
||||
RINOK(encoderSpec->SetCoderProperties(propIDs, properties, sizeof(propIDs) / sizeof(propIDs[0])));
|
||||
}
|
||||
|
||||
RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress));
|
||||
|
||||
return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
|
||||
{
|
||||
*type = NFileTimeType::kUnix;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
if (numItems != 1)
|
||||
return E_INVALIDARG;
|
||||
|
||||
Int32 newData, newProps;
|
||||
UInt32 indexInArchive;
|
||||
if (!updateCallback)
|
||||
return E_FAIL;
|
||||
RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
|
||||
|
||||
if (IntToBool(newProps))
|
||||
{
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
|
||||
if (prop.vt == VT_BOOL)
|
||||
{
|
||||
if (prop.boolVal != VARIANT_FALSE)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
if (IntToBool(newData))
|
||||
{
|
||||
UInt64 size;
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
|
||||
if (prop.vt != VT_UI8)
|
||||
return E_INVALIDARG;
|
||||
size = prop.uhVal.QuadPart;
|
||||
}
|
||||
|
||||
UInt32 dicSize = _dicSize;
|
||||
if (dicSize == 0xFFFFFFFF)
|
||||
dicSize = (_level >= 5 ? kDicSizeX5 :
|
||||
(_level >= 3 ? kDicSizeX3 :
|
||||
kDicSizeX1));
|
||||
|
||||
UInt32 numPasses = _numPasses;
|
||||
if (numPasses == 0xFFFFFFFF)
|
||||
numPasses = (_level >= 9 ? kNumPassesX9 :
|
||||
(_level >= 7 ? kNumPassesX7 :
|
||||
kNumPassesX1));
|
||||
|
||||
return UpdateArchive(
|
||||
size, outStream, 0, dicSize, numPasses,
|
||||
#ifdef COMPRESS_MT
|
||||
_numThreads,
|
||||
#endif
|
||||
updateCallback);
|
||||
}
|
||||
if (indexInArchive != 0)
|
||||
return E_INVALIDARG;
|
||||
if (_stream)
|
||||
RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
|
||||
return NCompress::CopyStream(_stream, outStream, NULL);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
|
||||
{
|
||||
InitMethodProperties();
|
||||
#ifdef COMPRESS_MT
|
||||
const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
|
||||
_numThreads = numProcessors;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < numProps; i++)
|
||||
{
|
||||
UString name = names[i];
|
||||
name.MakeUpper();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
const PROPVARIANT &prop = values[i];
|
||||
if (name[0] == L'X')
|
||||
{
|
||||
UInt32 level = 9;
|
||||
RINOK(ParsePropValue(name.Mid(1), prop, level));
|
||||
_level = level;
|
||||
}
|
||||
else if (name[0] == L'D')
|
||||
{
|
||||
UInt32 dicSize = kDicSizeX5;
|
||||
RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize));
|
||||
_dicSize = dicSize;
|
||||
}
|
||||
else if (name.Left(4) == L"PASS")
|
||||
{
|
||||
UInt32 num = kNumPassesX9;
|
||||
RINOK(ParsePropValue(name.Mid(4), prop, num));
|
||||
_numPasses = num;
|
||||
}
|
||||
else if (name.Left(2) == L"MT")
|
||||
{
|
||||
#ifdef COMPRESS_MT
|
||||
RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static IInArchive *CreateArc() { return new CHandler; }
|
||||
#ifndef EXTRACT_ONLY
|
||||
static IOutArchive *CreateArcOut() { return new CHandler; }
|
||||
#else
|
||||
#define CreateArcOut 0
|
||||
#endif
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"BZip2", L"bz2 bzip2 tbz2 tbz", L"* * .tar .tar", 2, { 'B', 'Z', 'h' }, 3, true, CreateArc, CreateArcOut };
|
||||
|
||||
REGISTER_ARC(BZip2)
|
||||
|
||||
}}
|
||||
@@ -2,10 +2,7 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../../../../C/Alloc.h"
|
||||
}
|
||||
|
||||
#include "Common/Defs.h"
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ void CInArchive::ReadOtherArchive(COtherArchive &oa)
|
||||
oa.DiskName = SafeReadName();
|
||||
}
|
||||
|
||||
void CInArchive::Skeep(size_t size)
|
||||
void CInArchive::Skip(size_t size)
|
||||
{
|
||||
while (size-- != 0)
|
||||
ReadByte();
|
||||
@@ -104,7 +104,7 @@ HRESULT CInArchive::Open2(IInStream *stream,
|
||||
ai.PerFolderAreaSize = ReadByte();
|
||||
ai.PerDataBlockAreaSize = ReadByte();
|
||||
|
||||
Skeep(ai.PerCabinetAreaSize);
|
||||
Skip(ai.PerCabinetAreaSize);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -124,7 +124,7 @@ HRESULT CInArchive::Open2(IInStream *stream,
|
||||
folder.CompressionTypeMajor = ReadByte();
|
||||
folder.CompressionTypeMinor = ReadByte();
|
||||
|
||||
Skeep(ai.PerFolderAreaSize);
|
||||
Skip(ai.PerFolderAreaSize);
|
||||
database.Folders.Add(folder);
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ class CInArchive
|
||||
UInt16 ReadUInt16();
|
||||
UInt32 ReadUInt32();
|
||||
AString SafeReadName();
|
||||
void Skeep(size_t size);
|
||||
void Skip(size_t size);
|
||||
void ReadOtherArchive(COtherArchive &oa);
|
||||
|
||||
HRESULT Open2(IInStream *inStream,
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/MyCom.h"
|
||||
#include "Common/UTFConvert.h"
|
||||
#include "Common/IntToString.h"
|
||||
#include "Windows/Defs.h"
|
||||
#include "Common/UTFConvert.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
|
||||
#include "ChmIn.h"
|
||||
|
||||
namespace NArchive{
|
||||
@@ -96,9 +94,8 @@ UString CMethodInfo::GetName() const
|
||||
if (IsLzx())
|
||||
{
|
||||
s = L"LZX:";
|
||||
UInt32 numDictBits = LzxInfo.GetNumDictBits();
|
||||
wchar_t temp[32];
|
||||
ConvertUInt64ToString(numDictBits, temp);
|
||||
wchar_t temp[16];
|
||||
ConvertUInt32ToString(LzxInfo.GetNumDictBits(), temp);
|
||||
s += temp;
|
||||
}
|
||||
else
|
||||
@@ -111,7 +108,7 @@ UString CMethodInfo::GetName() const
|
||||
s2 = GetGuidString();
|
||||
if (ControlData.GetCapacity() > 0)
|
||||
{
|
||||
s2 += ":";
|
||||
s2 += ':';
|
||||
for (size_t i = 0; i < ControlData.GetCapacity(); i++)
|
||||
PrintByte(ControlData[i], s2);
|
||||
}
|
||||
@@ -141,7 +138,7 @@ UString CSectionInfo::GetMethodName() const
|
||||
for (int i = 0; i < Methods.Size(); i++)
|
||||
{
|
||||
if (i != 0)
|
||||
s += L" ";
|
||||
s += L' ';
|
||||
s += Methods[i].GetName();
|
||||
}
|
||||
return s;
|
||||
@@ -155,7 +152,7 @@ Byte CInArchive::ReadByte()
|
||||
return b;
|
||||
}
|
||||
|
||||
void CInArchive::Skeep(size_t size)
|
||||
void CInArchive::Skip(size_t size)
|
||||
{
|
||||
while (size-- != 0)
|
||||
ReadByte();
|
||||
@@ -221,7 +218,7 @@ void CInArchive::ReadString(int size, AString &s)
|
||||
char c = (char)ReadByte();
|
||||
if (c == 0)
|
||||
{
|
||||
Skeep(size);
|
||||
Skip(size);
|
||||
return;
|
||||
}
|
||||
s += c;
|
||||
@@ -236,7 +233,7 @@ void CInArchive::ReadUString(int size, UString &s)
|
||||
wchar_t c = ReadUInt16();
|
||||
if (c == 0)
|
||||
{
|
||||
Skeep(2 * size);
|
||||
Skip(2 * size);
|
||||
return;
|
||||
}
|
||||
s += c;
|
||||
@@ -372,12 +369,12 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database)
|
||||
RINOK(ReadDirEntry(database));
|
||||
numItems++;
|
||||
}
|
||||
Skeep(quickrefLength - 2);
|
||||
Skip(quickrefLength - 2);
|
||||
if (ReadUInt16() != numItems)
|
||||
return S_FALSE;
|
||||
}
|
||||
else
|
||||
Skeep(dirChunkSize - 4);
|
||||
Skip(dirChunkSize - 4);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@@ -579,7 +576,7 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
|
||||
}
|
||||
numItems++;
|
||||
}
|
||||
Skeep(quickrefLength - 2);
|
||||
Skip(quickrefLength - 2);
|
||||
if (ReadUInt16() != numItems)
|
||||
return S_FALSE;
|
||||
if (numItems > numDirEntries)
|
||||
@@ -587,7 +584,7 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database)
|
||||
numDirEntries -= numItems;
|
||||
}
|
||||
else
|
||||
Skeep(dirChunkSize - 4);
|
||||
Skip(dirChunkSize - 4);
|
||||
}
|
||||
return numDirEntries == 0 ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
#ifndef __ARCHIVE_CHM_IN_H
|
||||
#define __ARCHIVE_CHM_IN_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
#include "Common/Buffer.h"
|
||||
#include "Common/MyString.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
#include "../../Common/InBuffer.h"
|
||||
|
||||
#include "ChmHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
@@ -215,7 +217,7 @@ class CInArchive
|
||||
|
||||
Byte ReadByte();
|
||||
void ReadBytes(Byte *data, UInt32 size);
|
||||
void Skeep(size_t size);
|
||||
void Skip(size_t size);
|
||||
UInt16 ReadUInt16();
|
||||
UInt32 ReadUInt32();
|
||||
UInt64 ReadUInt64();
|
||||
|
||||
@@ -3,8 +3,15 @@
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
#include "ComHandler.h"
|
||||
|
||||
namespace NArchive {
|
||||
@@ -15,16 +22,15 @@ STATPROPSTG kProps[] =
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
// { NULL, kpidAttributes, VT_UI4},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidCTime, VT_FILETIME},
|
||||
{ NULL, kpidMTime, VT_FILETIME}
|
||||
};
|
||||
|
||||
|
||||
STATPROPSTG kArcProps[] =
|
||||
{
|
||||
{ NULL, kpidClusterSize, VT_UI4}
|
||||
{ NULL, kpidClusterSize, VT_UI4},
|
||||
{ NULL, kpidSectorSize, VT_UI4}
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
@@ -37,6 +43,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
switch(propID)
|
||||
{
|
||||
case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break;
|
||||
case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
@@ -52,33 +59,12 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath:
|
||||
{
|
||||
UString name = _db.GetItemPath(index);
|
||||
prop = name;
|
||||
break;
|
||||
}
|
||||
case kpidPath: prop = _db.GetItemPath(index); break;
|
||||
case kpidIsDir: prop = item.IsDir(); break;
|
||||
case kpidCTime: prop = item.CTime; break;
|
||||
case kpidMTime: prop = item.MTime; break;
|
||||
/*
|
||||
case kpidAttributes:
|
||||
prop = item.Falgs;
|
||||
break;
|
||||
*/
|
||||
case kpidPackSize:
|
||||
if (!item.IsDir())
|
||||
{
|
||||
int numBits = _db.IsLargeStream(item.Size) ?
|
||||
_db.SectorSizeBits :
|
||||
_db.MiniSectorSizeBits;
|
||||
prop = (item.Size + ((UInt64)1 << numBits) - 1) >> numBits << numBits;
|
||||
break;
|
||||
}
|
||||
case kpidSize:
|
||||
if (!item.IsDir())
|
||||
prop = (UInt64)item.Size;
|
||||
break;
|
||||
case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break;
|
||||
case kpidSize: if (!item.IsDir()) prop = item.Size; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
@@ -93,7 +79,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
Close();
|
||||
try
|
||||
{
|
||||
if (OpenArchive(inStream, _db) != S_OK)
|
||||
if (_db.Open(inStream) != S_OK)
|
||||
return S_FALSE;
|
||||
_stream = inStream;
|
||||
}
|
||||
@@ -129,25 +115,29 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
}
|
||||
RINOK(extractCallback->SetTotal(totalSize));
|
||||
|
||||
UInt64 currentTotalSize = 0, currentItemSize = 0;
|
||||
UInt64 totalPackSize;
|
||||
totalSize = totalPackSize = 0;
|
||||
|
||||
CByteBuffer sect;
|
||||
sect.SetCapacity((UInt32)1 << _db.SectorSizeBits);
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
RINOK(extractCallback->SetCompleted(¤tTotalSize));
|
||||
lps->InSize = totalPackSize;
|
||||
lps->OutSize = totalSize;
|
||||
RINOK(lps->SetCur());
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
const CItem &item = _db.Items[_db.Refs[index].Did];
|
||||
currentItemSize = 0;
|
||||
if (!item.IsDir())
|
||||
currentItemSize = item.Size;
|
||||
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
Int32 askMode = testMode ?
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
RINOK(extractCallback->GetStream(index, &outStream, askMode));
|
||||
|
||||
if (item.IsDir())
|
||||
{
|
||||
@@ -155,75 +145,31 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
if (!testMode && (!realOutStream))
|
||||
|
||||
totalPackSize += _db.GetItemPackSize(item.Size);
|
||||
totalSize += item.Size;
|
||||
|
||||
if (!testMode && (!outStream))
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
Int32 res = NArchive::NExtract::NOperationResult::kDataError;
|
||||
CMyComPtr<ISequentialInStream> inStream;
|
||||
HRESULT hres = GetStream(index, &inStream);
|
||||
if (hres == S_FALSE)
|
||||
res = NArchive::NExtract::NOperationResult::kDataError;
|
||||
else if (hres == E_NOTIMPL)
|
||||
res = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
|
||||
else
|
||||
{
|
||||
UInt32 sid = item.Sid;
|
||||
UInt64 prev = 0;
|
||||
for (UInt64 pos = 0;;)
|
||||
RINOK(hres);
|
||||
if (inStream)
|
||||
{
|
||||
if (sid == NFatID::kEndOfChain)
|
||||
{
|
||||
if (pos != item.Size)
|
||||
break;
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
if (copyCoderSpec->TotalSize == item.Size)
|
||||
res = NArchive::NExtract::NOperationResult::kOK;
|
||||
break;
|
||||
}
|
||||
if (pos >= item.Size)
|
||||
break;
|
||||
|
||||
UInt64 offset;
|
||||
UInt32 size;
|
||||
|
||||
if (_db.IsLargeStream(item.Size))
|
||||
{
|
||||
if (pos - prev > (1 << 20))
|
||||
{
|
||||
UInt64 processed = currentTotalSize + pos;
|
||||
RINOK(extractCallback->SetCompleted(&processed));
|
||||
prev = pos;
|
||||
}
|
||||
size = 1 << _db.SectorSizeBits;
|
||||
offset = ((UInt64)sid + 1) << _db.SectorSizeBits;
|
||||
if (sid >= _db.FatSize)
|
||||
break;
|
||||
sid = _db.Fat[sid];
|
||||
}
|
||||
else
|
||||
{
|
||||
int subBits = (_db.SectorSizeBits - _db.MiniSectorSizeBits);
|
||||
UInt32 fid = sid >> subBits;
|
||||
if (fid >= _db.NumSectorsInMiniStream)
|
||||
break;
|
||||
size = 1 << _db.MiniSectorSizeBits;
|
||||
offset = (((UInt64)_db.MiniSids[fid] + 1) << _db.SectorSizeBits) +
|
||||
((sid & ((1 << subBits) - 1)) << _db.MiniSectorSizeBits);
|
||||
if (sid >= _db.MatSize)
|
||||
break;
|
||||
sid = _db.Mat[sid];
|
||||
}
|
||||
|
||||
// last sector can be smaller than sector size (it can contain requied data only).
|
||||
UInt64 rem = item.Size - pos;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
|
||||
RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
|
||||
size_t realProcessedSize = size;
|
||||
RINOK(ReadStream(_stream, sect, &realProcessedSize));
|
||||
if (realProcessedSize != size)
|
||||
break;
|
||||
|
||||
if (realOutStream)
|
||||
{
|
||||
RINOK(WriteStream(realOutStream, sect, size));
|
||||
}
|
||||
pos += size;
|
||||
}
|
||||
}
|
||||
realOutStream.Release();
|
||||
outStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(res));
|
||||
}
|
||||
return S_OK;
|
||||
@@ -236,4 +182,58 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
*stream = 0;
|
||||
const CItem &item = _db.Items[_db.Refs[index].Did];
|
||||
CClusterInStream *streamSpec = new CClusterInStream;
|
||||
CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
|
||||
streamSpec->Stream = _stream;
|
||||
streamSpec->StartOffset = 0;
|
||||
|
||||
bool isLargeStream = _db.IsLargeStream(item.Size);
|
||||
int bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits;
|
||||
streamSpec->BlockSizeLog = bsLog;
|
||||
streamSpec->Size = item.Size;
|
||||
|
||||
UInt32 clusterSize = (UInt32)1 << bsLog;
|
||||
UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
|
||||
if (numClusters64 >= ((UInt32)1 << 31))
|
||||
return E_NOTIMPL;
|
||||
streamSpec->Vector.Reserve((int)numClusters64);
|
||||
UInt32 sid = item.Sid;
|
||||
UInt64 size = item.Size;
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
for (;; size -= clusterSize)
|
||||
{
|
||||
if (isLargeStream)
|
||||
{
|
||||
if (sid >= _db.FatSize)
|
||||
return S_FALSE;
|
||||
streamSpec->Vector.Add(sid + 1);
|
||||
sid = _db.Fat[sid];
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt64 val;
|
||||
if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32)
|
||||
return S_FALSE;
|
||||
streamSpec->Vector.Add((UInt32)val);
|
||||
sid = _db.Mat[sid];
|
||||
}
|
||||
if (size <= clusterSize)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sid != NFatID::kEndOfChain)
|
||||
return S_FALSE;
|
||||
RINOK(streamSpec->InitAndSeek());
|
||||
*stream = streamTemp.Detach();
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -12,15 +12,15 @@ namespace NCom {
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IInArchive)
|
||||
INTERFACE_IInArchive(;)
|
||||
|
||||
private:
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CDatabase _db;
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
||||
INTERFACE_IInArchive(;)
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../../../../C/Alloc.h"
|
||||
}
|
||||
|
||||
#include "../../../../C/CpuArch.h"
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
#include "Common/IntToString.h"
|
||||
#include "Common/MyCom.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "ComIn.h"
|
||||
|
||||
#define Get16(p) GetUi16(p)
|
||||
#define Get32(p) GetUi32(p)
|
||||
|
||||
namespace NArchive{
|
||||
namespace NCom{
|
||||
|
||||
@@ -50,31 +50,40 @@ static HRESULT ReadIDs(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt3
|
||||
RINOK(ReadSector(inStream, buf, sectorSizeBits, sid));
|
||||
UInt32 sectorSize = (UInt32)1 << sectorSizeBits;
|
||||
for (UInt32 t = 0; t < sectorSize; t += 4)
|
||||
*dest++ = GetUi32(buf + t);
|
||||
*dest++ = Get32(buf + t);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
|
||||
{
|
||||
ft->dwLowDateTime = GetUi32(p);
|
||||
ft->dwHighDateTime = GetUi32(p + 4);
|
||||
ft->dwLowDateTime = Get32(p);
|
||||
ft->dwHighDateTime = Get32(p + 4);
|
||||
}
|
||||
|
||||
static void ReadItem(Byte *p, CItem &item, bool mode64bit)
|
||||
void CItem::Parse(const Byte *p, bool mode64bit)
|
||||
{
|
||||
memcpy(item.Name, p, 64);
|
||||
// item.NameSize = GetUi16(p + 64);
|
||||
item.Type = p[66];
|
||||
item.LeftDid = GetUi32(p + 68);
|
||||
item.RightDid = GetUi32(p + 72);
|
||||
item.SonDid = GetUi32(p + 76);
|
||||
// item.Flags = GetUi32(p + 96);
|
||||
GetFileTimeFromMem(p + 100, &item.CTime);
|
||||
GetFileTimeFromMem(p + 108, &item.MTime);
|
||||
item.Sid = GetUi32(p + 116);
|
||||
item.Size = GetUi32(p + 120);
|
||||
memcpy(Name, p, kNameSizeMax);
|
||||
// NameSize = Get16(p + 64);
|
||||
Type = p[66];
|
||||
LeftDid = Get32(p + 68);
|
||||
RightDid = Get32(p + 72);
|
||||
SonDid = Get32(p + 76);
|
||||
// Flags = Get32(p + 96);
|
||||
GetFileTimeFromMem(p + 100, &CTime);
|
||||
GetFileTimeFromMem(p + 108, &MTime);
|
||||
Sid = Get32(p + 116);
|
||||
Size = Get32(p + 120);
|
||||
if (mode64bit)
|
||||
item.Size |= ((UInt64)GetUi32(p + 124) << 32);
|
||||
Size |= ((UInt64)Get32(p + 124) << 32);
|
||||
}
|
||||
|
||||
void CDatabase::Clear()
|
||||
{
|
||||
Fat.Free();
|
||||
MiniSids.Free();
|
||||
Mat.Free();
|
||||
Items.Clear();
|
||||
Refs.Clear();
|
||||
}
|
||||
|
||||
static const UInt32 kNoDid = 0xFFFFFFFF;
|
||||
@@ -106,13 +115,6 @@ HRESULT CDatabase::AddNode(int parent, UInt32 did)
|
||||
static const char kCharOpenBracket = '[';
|
||||
static const char kCharCloseBracket = ']';
|
||||
|
||||
UString DWORDToString(UInt32 val)
|
||||
{
|
||||
wchar_t buf[32];
|
||||
ConvertUInt64ToString(val, buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static UString CompoundNameToFileName(const UString &s)
|
||||
{
|
||||
UString res;
|
||||
@@ -122,7 +124,9 @@ static UString CompoundNameToFileName(const UString &s)
|
||||
if (c < 0x20)
|
||||
{
|
||||
res += kCharOpenBracket;
|
||||
res += DWORDToString(c);
|
||||
wchar_t buf[32];
|
||||
ConvertUInt32ToString(c, buf);
|
||||
res += buf;
|
||||
res += kCharCloseBracket;
|
||||
}
|
||||
else
|
||||
@@ -201,31 +205,30 @@ UString CDatabase::GetItemPath(UInt32 index) const
|
||||
return s;
|
||||
}
|
||||
|
||||
HRESULT OpenArchive(IInStream *inStream, CDatabase &db)
|
||||
HRESULT CDatabase::Open(IInStream *inStream)
|
||||
{
|
||||
static const UInt32 kHeaderSize = 512;
|
||||
Byte p[kHeaderSize];
|
||||
RINOK(ReadStream_FALSE(inStream, p, kHeaderSize));
|
||||
if (memcmp(p, kSignature, kSignatureSize) != 0)
|
||||
return S_FALSE;
|
||||
UInt16 majorVer = GetUi16(p + 0x1A);
|
||||
if (majorVer > 4)
|
||||
if (Get16(p + 0x1A) > 4) // majorVer
|
||||
return S_FALSE;
|
||||
if (GetUi16(p + 0x1C) != 0xFFFE)
|
||||
if (Get16(p + 0x1C) != 0xFFFE)
|
||||
return S_FALSE;
|
||||
UInt16 sectorSizeBits = GetUi16(p + 0x1E);
|
||||
int sectorSizeBits = Get16(p + 0x1E);
|
||||
bool mode64bit = (sectorSizeBits >= 12);
|
||||
UInt16 miniSectorSizeBits = GetUi16(p + 0x20);
|
||||
db.SectorSizeBits = sectorSizeBits;
|
||||
db.MiniSectorSizeBits = miniSectorSizeBits;
|
||||
int miniSectorSizeBits = Get16(p + 0x20);
|
||||
SectorSizeBits = sectorSizeBits;
|
||||
MiniSectorSizeBits = miniSectorSizeBits;
|
||||
|
||||
if (sectorSizeBits > 28 || miniSectorSizeBits > 28 ||
|
||||
sectorSizeBits < 7 || miniSectorSizeBits < 2 || miniSectorSizeBits > sectorSizeBits)
|
||||
return S_FALSE;
|
||||
UInt32 numSectorsForFAT = GetUi32(p + 0x2C);
|
||||
db.LongStreamMinSize = GetUi32(p + 0x38);
|
||||
UInt32 numSectorsForFAT = Get32(p + 0x2C);
|
||||
LongStreamMinSize = Get32(p + 0x38);
|
||||
|
||||
UInt32 sectSize = (UInt32)1 << (int)(sectorSizeBits);
|
||||
UInt32 sectSize = (UInt32)1 << (int)sectorSizeBits;
|
||||
|
||||
CByteBuffer sect;
|
||||
sect.SetCapacity(sectSize);
|
||||
@@ -235,11 +238,11 @@ HRESULT OpenArchive(IInStream *inStream, CDatabase &db)
|
||||
UInt32 numFatItems = numSectorsForFAT << ssb2;
|
||||
if ((numFatItems >> ssb2) != numSectorsForFAT)
|
||||
return S_FALSE;
|
||||
db.FatSize = numFatItems;
|
||||
FatSize = numFatItems;
|
||||
|
||||
{
|
||||
CUInt32Buf bat;
|
||||
UInt32 numSectorsForBat = GetUi32(p + 0x48);
|
||||
UInt32 numSectorsForBat = Get32(p + 0x48);
|
||||
const UInt32 kNumHeaderBatItems = 109;
|
||||
UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2);
|
||||
if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat)
|
||||
@@ -248,8 +251,8 @@ HRESULT OpenArchive(IInStream *inStream, CDatabase &db)
|
||||
return S_FALSE;
|
||||
UInt32 i;
|
||||
for (i = 0; i < kNumHeaderBatItems; i++)
|
||||
bat[i] = GetUi32(p + 0x4c + i * 4);
|
||||
UInt32 sid = GetUi32(p + 0x44);
|
||||
bat[i] = Get32(p + 0x4c + i * 4);
|
||||
UInt32 sid = Get32(p + 0x44);
|
||||
for (UInt32 s = 0; s < numSectorsForBat; s++)
|
||||
{
|
||||
RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i));
|
||||
@@ -258,7 +261,7 @@ HRESULT OpenArchive(IInStream *inStream, CDatabase &db)
|
||||
}
|
||||
numBatItems = i;
|
||||
|
||||
if (!db.Fat.Allocate(numFatItems))
|
||||
if (!Fat.Allocate(numFatItems))
|
||||
return S_FALSE;
|
||||
UInt32 j = 0;
|
||||
|
||||
@@ -266,33 +269,33 @@ HRESULT OpenArchive(IInStream *inStream, CDatabase &db)
|
||||
{
|
||||
if (j >= numBatItems)
|
||||
return S_FALSE;
|
||||
RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], db.Fat + i));
|
||||
RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i));
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 numMatItems;
|
||||
{
|
||||
UInt32 numSectorsForMat = GetUi32(p + 0x40);
|
||||
UInt32 numSectorsForMat = Get32(p + 0x40);
|
||||
numMatItems = (UInt32)numSectorsForMat << ssb2;
|
||||
if ((numMatItems >> ssb2) != numSectorsForMat)
|
||||
return S_FALSE;
|
||||
if (!db.Mat.Allocate(numMatItems))
|
||||
if (!Mat.Allocate(numMatItems))
|
||||
return S_FALSE;
|
||||
UInt32 i;
|
||||
UInt32 sid = GetUi32(p + 0x3C);
|
||||
UInt32 sid = Get32(p + 0x3C);
|
||||
for (i = 0; i < numMatItems; i += numSidsInSec)
|
||||
{
|
||||
RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, db.Mat + i));
|
||||
RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i));
|
||||
if (sid >= numFatItems)
|
||||
return S_FALSE;
|
||||
sid = db.Fat[sid];
|
||||
sid = Fat[sid];
|
||||
}
|
||||
if (sid != NFatID::kEndOfChain)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 sid = GetUi32(p + 0x30);
|
||||
UInt32 sid = Get32(p + 0x30);
|
||||
for (;;)
|
||||
{
|
||||
if (sid >= numFatItems)
|
||||
@@ -301,16 +304,16 @@ HRESULT OpenArchive(IInStream *inStream, CDatabase &db)
|
||||
for (UInt32 i = 0; i < sectSize; i += 128)
|
||||
{
|
||||
CItem item;
|
||||
ReadItem(sect + i, item, mode64bit);
|
||||
db.Items.Add(item);
|
||||
item.Parse(sect + i, mode64bit);
|
||||
Items.Add(item);
|
||||
}
|
||||
sid = db.Fat[sid];
|
||||
sid = Fat[sid];
|
||||
if (sid == NFatID::kEndOfChain)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CItem root = db.Items[0];
|
||||
CItem root = Items[0];
|
||||
|
||||
{
|
||||
UInt32 numSectorsInMiniStream;
|
||||
@@ -320,19 +323,18 @@ HRESULT OpenArchive(IInStream *inStream, CDatabase &db)
|
||||
return S_FALSE;
|
||||
numSectorsInMiniStream = (UInt32)numSatSects64;
|
||||
}
|
||||
db.NumSectorsInMiniStream = numSectorsInMiniStream;
|
||||
if (!db.MiniSids.Allocate(numSectorsInMiniStream))
|
||||
NumSectorsInMiniStream = numSectorsInMiniStream;
|
||||
if (!MiniSids.Allocate(numSectorsInMiniStream))
|
||||
return S_FALSE;
|
||||
{
|
||||
UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits;
|
||||
if (matSize64 > NFatID::kMaxValue)
|
||||
return S_FALSE;
|
||||
db.MatSize = (UInt32)matSize64;
|
||||
if (numMatItems < db.MatSize)
|
||||
MatSize = (UInt32)matSize64;
|
||||
if (numMatItems < MatSize)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
|
||||
UInt32 sid = root.Sid;
|
||||
for (UInt32 i = 0; ; i++)
|
||||
{
|
||||
@@ -344,14 +346,14 @@ HRESULT OpenArchive(IInStream *inStream, CDatabase &db)
|
||||
}
|
||||
if (i >= numSectorsInMiniStream)
|
||||
return S_FALSE;
|
||||
db.MiniSids[i] = sid;
|
||||
MiniSids[i] = sid;
|
||||
if (sid >= numFatItems)
|
||||
return S_FALSE;
|
||||
sid = db.Fat[sid];
|
||||
sid = Fat[sid];
|
||||
}
|
||||
}
|
||||
|
||||
return db.AddNode(-1, root.SonDid);
|
||||
return AddNode(-1, root.SonDid);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -57,6 +57,8 @@ struct CItem
|
||||
|
||||
bool IsEmpty() const { return Type == NItemType::kEmpty; }
|
||||
bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; }
|
||||
|
||||
void Parse(const Byte *p, bool mode64bit);
|
||||
};
|
||||
|
||||
struct CRef
|
||||
@@ -67,15 +69,15 @@ struct CRef
|
||||
|
||||
class CDatabase
|
||||
{
|
||||
public:
|
||||
UInt32 NumSectorsInMiniStream;
|
||||
CUInt32Buf MiniSids;
|
||||
|
||||
HRESULT AddNode(int parent, UInt32 did);
|
||||
public:
|
||||
|
||||
CUInt32Buf Fat;
|
||||
UInt32 FatSize;
|
||||
|
||||
CUInt32Buf MiniSids;
|
||||
UInt32 NumSectorsInMiniStream;
|
||||
|
||||
CUInt32Buf Mat;
|
||||
UInt32 MatSize;
|
||||
|
||||
@@ -86,20 +88,29 @@ public:
|
||||
int SectorSizeBits;
|
||||
int MiniSectorSizeBits;
|
||||
|
||||
void Clear()
|
||||
void Clear();
|
||||
bool IsLargeStream(UInt64 size) const { return size >= LongStreamMinSize; }
|
||||
UString GetItemPath(UInt32 index) const;
|
||||
|
||||
UInt64 GetItemPackSize(UInt64 size) const
|
||||
{
|
||||
Fat.Free();
|
||||
MiniSids.Free();
|
||||
Mat.Free();
|
||||
Items.Clear();
|
||||
Refs.Clear();
|
||||
UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1;
|
||||
return (size + mask) & ~mask;
|
||||
}
|
||||
|
||||
bool IsLargeStream(UInt64 size) { return size >= LongStreamMinSize; }
|
||||
UString GetItemPath(UInt32 index) const;
|
||||
bool GetMiniCluster(UInt32 sid, UInt64 &res) const
|
||||
{
|
||||
int subBits = SectorSizeBits - MiniSectorSizeBits;
|
||||
UInt32 fid = sid >> subBits;
|
||||
if (fid >= NumSectorsInMiniStream)
|
||||
return false;
|
||||
res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
HRESULT Open(IInStream *inStream);
|
||||
};
|
||||
|
||||
HRESULT OpenArchive(IInStream *inStream, CDatabase &database);
|
||||
|
||||
}}
|
||||
|
||||
|
||||
@@ -82,11 +82,11 @@ static const UInt32 kAlgorithmForHeaders = kLzmaAlgoX5;
|
||||
static bool AreEqual(const UString &methodName, const wchar_t *s)
|
||||
{ return (methodName.CompareNoCase(s) == 0); }
|
||||
|
||||
static inline bool IsLZMAMethod(const UString &methodName)
|
||||
bool COneMethodInfo::IsLzma() const
|
||||
{
|
||||
return
|
||||
AreEqual(methodName, kLZMAMethodName) ||
|
||||
AreEqual(methodName, kLZMA2MethodName);
|
||||
AreEqual(MethodName, kLZMAMethodName) ||
|
||||
AreEqual(MethodName, kLZMA2MethodName);
|
||||
}
|
||||
|
||||
static inline bool IsBZip2Method(const UString &methodName)
|
||||
@@ -109,8 +109,12 @@ struct CNameToPropID
|
||||
const wchar_t *Name;
|
||||
};
|
||||
|
||||
CNameToPropID g_NameToPropID[] =
|
||||
static CNameToPropID g_NameToPropID[] =
|
||||
{
|
||||
{ NCoderPropID::kBlockSize, VT_UI4, L"C" },
|
||||
{ NCoderPropID::kDictionarySize, VT_UI4, L"D" },
|
||||
{ NCoderPropID::kUsedMemorySize, VT_UI4, L"MEM" },
|
||||
|
||||
{ NCoderPropID::kOrder, VT_UI4, L"O" },
|
||||
{ NCoderPropID::kPosStateBits, VT_UI4, L"PB" },
|
||||
{ NCoderPropID::kLitContextBits, VT_UI4, L"LC" },
|
||||
@@ -122,7 +126,8 @@ CNameToPropID g_NameToPropID[] =
|
||||
{ NCoderPropID::kMatchFinderCycles, VT_UI4, L"mc" },
|
||||
{ NCoderPropID::kAlgorithm, VT_UI4, L"a" },
|
||||
{ NCoderPropID::kMatchFinder, VT_BSTR, L"mf" },
|
||||
{ NCoderPropID::kNumThreads, VT_UI4, L"mt" }
|
||||
{ NCoderPropID::kNumThreads, VT_UI4, L"mt" },
|
||||
{ NCoderPropID::kDefaultProp, VT_UI4, L"" }
|
||||
};
|
||||
|
||||
static bool ConvertProperty(PROPVARIANT srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
|
||||
@@ -154,7 +159,7 @@ static bool ConvertProperty(PROPVARIANT srcProp, VARTYPE varType, NCOM::CPropVar
|
||||
return false;
|
||||
}
|
||||
|
||||
static int FindPropIdFromStringName(const UString &name)
|
||||
static int FindPropIdExact(const UString &name)
|
||||
{
|
||||
for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++)
|
||||
if (name.CompareNoCase(g_NameToPropID[i].Name) == 0)
|
||||
@@ -162,16 +167,26 @@ static int FindPropIdFromStringName(const UString &name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void SetOneMethodProp(COneMethodInfo &oneMethodInfo, PROPID propID,
|
||||
const NWindows::NCOM::CPropVariant &value)
|
||||
static int FindPropIdStart(const UString &name)
|
||||
{
|
||||
for (int j = 0; j < oneMethodInfo.Props.Size(); j++)
|
||||
if (oneMethodInfo.Props[j].Id == propID)
|
||||
for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++)
|
||||
{
|
||||
UString t = g_NameToPropID[i].Name;
|
||||
if (t.CompareNoCase(name.Left(t.Length())) == 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void SetMethodProp(COneMethodInfo &m, PROPID propID, const NCOM::CPropVariant &value)
|
||||
{
|
||||
for (int j = 0; j < m.Props.Size(); j++)
|
||||
if (m.Props[j].Id == propID)
|
||||
return;
|
||||
CProp prop;
|
||||
prop.Id = propID;
|
||||
prop.Value = value;
|
||||
oneMethodInfo.Props.Add(prop);
|
||||
m.Props.Add(prop);
|
||||
}
|
||||
|
||||
void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo
|
||||
@@ -184,7 +199,7 @@ void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo
|
||||
if (oneMethodInfo.MethodName.IsEmpty())
|
||||
oneMethodInfo.MethodName = kDefaultMethodName;
|
||||
|
||||
if (IsLZMAMethod(oneMethodInfo.MethodName))
|
||||
if (oneMethodInfo.IsLzma())
|
||||
{
|
||||
UInt32 dicSize =
|
||||
(level >= 9 ? kLzmaDicSizeX9 :
|
||||
@@ -205,12 +220,12 @@ void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo
|
||||
(level >= 5 ? kLzmaMatchFinderX5 :
|
||||
kLzmaMatchFinderX1);
|
||||
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder);
|
||||
#ifdef COMPRESS_MT
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
|
||||
#endif
|
||||
}
|
||||
else if (IsDeflateMethod(oneMethodInfo.MethodName))
|
||||
@@ -229,9 +244,9 @@ void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo
|
||||
(level >= 5 ? kDeflateAlgoX5 :
|
||||
kDeflateAlgoX1);
|
||||
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
|
||||
}
|
||||
else if (IsBZip2Method(oneMethodInfo.MethodName))
|
||||
{
|
||||
@@ -245,10 +260,10 @@ void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo
|
||||
(level >= 3 ? kBZip2DicSizeX3 :
|
||||
kBZip2DicSizeX1));
|
||||
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
|
||||
#ifdef COMPRESS_MT
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
|
||||
#endif
|
||||
}
|
||||
else if (IsPpmdMethod(oneMethodInfo.MethodName))
|
||||
@@ -265,8 +280,8 @@ void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo
|
||||
(level >= 5 ? kPpmdOrderX5 :
|
||||
kPpmdOrderX1)));
|
||||
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize);
|
||||
SetOneMethodProp(oneMethodInfo, NCoderPropID::kOrder, order);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize);
|
||||
SetMethodProp(oneMethodInfo, NCoderPropID::kOrder, order);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,25 +331,22 @@ static void SplitParam(const UString ¶m, UString &name, UString &value)
|
||||
HRESULT COutHandler::SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value)
|
||||
{
|
||||
CProp prop;
|
||||
if (name.CompareNoCase(L"D") == 0 ||
|
||||
name.CompareNoCase(L"MEM") == 0)
|
||||
int index = FindPropIdExact(name);
|
||||
if (index < 0)
|
||||
return E_INVALIDARG;
|
||||
const CNameToPropID &nameToPropID = g_NameToPropID[index];
|
||||
prop.Id = nameToPropID.PropID;
|
||||
|
||||
if (prop.Id == NCoderPropID::kBlockSize ||
|
||||
prop.Id == NCoderPropID::kDictionarySize ||
|
||||
prop.Id == NCoderPropID::kUsedMemorySize)
|
||||
{
|
||||
UInt32 dicSize;
|
||||
RINOK(ParsePropDictionaryValue(value, dicSize));
|
||||
prop.Id = (name.CompareNoCase(L"D") == 0) ?
|
||||
NCoderPropID::kDictionarySize :
|
||||
NCoderPropID::kUsedMemorySize;
|
||||
prop.Value = dicSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = FindPropIdFromStringName(name);
|
||||
if (index < 0)
|
||||
return E_INVALIDARG;
|
||||
|
||||
const CNameToPropID &nameToPropID = g_NameToPropID[index];
|
||||
prop.Id = nameToPropID.PropID;
|
||||
|
||||
NCOM::CPropVariant propValue;
|
||||
|
||||
if (nameToPropID.VarType == VT_BSTR)
|
||||
@@ -465,7 +477,7 @@ void COutHandler::Init()
|
||||
WriteMTime = true;
|
||||
|
||||
#ifdef COMPRESS_MT
|
||||
_numThreads = NWindows::NSystem::GetNumberOfProcessors();
|
||||
_numThreads = NSystem::GetNumberOfProcessors();
|
||||
#endif
|
||||
|
||||
_level = 5;
|
||||
@@ -576,35 +588,26 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = FindPropIdStart(realName);
|
||||
if (index < 0)
|
||||
return E_INVALIDARG;
|
||||
const CNameToPropID &nameToPropID = g_NameToPropID[index];
|
||||
CProp prop;
|
||||
if (realName.Left(1).CompareNoCase(L"D") == 0)
|
||||
prop.Id = nameToPropID.PropID;
|
||||
|
||||
if (prop.Id == NCoderPropID::kBlockSize ||
|
||||
prop.Id == NCoderPropID::kDictionarySize ||
|
||||
prop.Id == NCoderPropID::kUsedMemorySize)
|
||||
{
|
||||
UInt32 dicSize;
|
||||
RINOK(ParsePropDictionaryValue(realName.Mid(1), value, dicSize));
|
||||
prop.Id = NCoderPropID::kDictionarySize;
|
||||
prop.Value = dicSize;
|
||||
if (number <= mainDicMethodIndex)
|
||||
mainDicSize = dicSize;
|
||||
}
|
||||
else if (realName.Left(1).CompareNoCase(L"C") == 0)
|
||||
{
|
||||
UInt32 blockSize;
|
||||
RINOK(ParsePropDictionaryValue(realName.Mid(1), value, blockSize));
|
||||
prop.Id = NCoderPropID::kBlockSize;
|
||||
prop.Value = blockSize;
|
||||
}
|
||||
else if (realName.Left(3).CompareNoCase(L"MEM") == 0)
|
||||
{
|
||||
UInt32 dicSize;
|
||||
RINOK(ParsePropDictionaryValue(realName.Mid(3), value, dicSize));
|
||||
prop.Id = NCoderPropID::kUsedMemorySize;
|
||||
RINOK(ParsePropDictionaryValue(realName.Mid(MyStringLen(nameToPropID.Name)), value, dicSize));
|
||||
prop.Value = dicSize;
|
||||
if (number <= mainDicMethodIndex)
|
||||
mainDicSize = dicSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = FindPropIdFromStringName(realName);
|
||||
int index = FindPropIdExact(realName);
|
||||
if (index < 0)
|
||||
return E_INVALIDARG;
|
||||
const CNameToPropID &nameToPropID = g_NameToPropID[index];
|
||||
|
||||
@@ -12,6 +12,8 @@ struct COneMethodInfo
|
||||
{
|
||||
CObjectVector<CProp> Props;
|
||||
UString MethodName;
|
||||
|
||||
bool IsLzma() const;
|
||||
};
|
||||
|
||||
class COutHandler
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
// InStreamWithCRC.h
|
||||
|
||||
#ifndef __INSTREAMWITHCRC_H
|
||||
#define __INSTREAMWITHCRC_H
|
||||
#ifndef __IN_STREAM_WITH_CRC_H
|
||||
#define __IN_STREAM_WITH_CRC_H
|
||||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../../../../C/7zCrc.h"
|
||||
}
|
||||
#include "../../IStream.h"
|
||||
|
||||
class CSequentialInStreamWithCRC:
|
||||
public ISequentialInStream,
|
||||
|
||||
@@ -6,19 +6,13 @@
|
||||
|
||||
STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessedSize;
|
||||
HRESULT result;
|
||||
if(!_stream)
|
||||
{
|
||||
realProcessedSize = size;
|
||||
result = S_OK;
|
||||
}
|
||||
else
|
||||
result = _stream->Write(data, size, &realProcessedSize);
|
||||
HRESULT result = S_OK;
|
||||
if (_stream)
|
||||
result = _stream->Write(data, size, &size);
|
||||
if (_calculate)
|
||||
_crc = CrcUpdate(_crc, data, realProcessedSize);
|
||||
_size += realProcessedSize;
|
||||
if(processedSize != NULL)
|
||||
*processedSize = realProcessedSize;
|
||||
_crc = CrcUpdate(_crc, data, size);
|
||||
_size += size;
|
||||
if (processedSize != NULL)
|
||||
*processedSize = size;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
#ifndef __OUT_STREAM_WITH_CRC_H
|
||||
#define __OUT_STREAM_WITH_CRC_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../../../../C/7zCrc.h"
|
||||
}
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
class COutStreamWithCRC:
|
||||
public ISequentialOutStream,
|
||||
|
||||
@@ -6,19 +6,13 @@
|
||||
|
||||
STDMETHODIMP COutStreamWithSha1::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessedSize;
|
||||
HRESULT result;
|
||||
if(!_stream)
|
||||
{
|
||||
realProcessedSize = size;
|
||||
result = S_OK;
|
||||
}
|
||||
else
|
||||
result = _stream->Write(data, size, &realProcessedSize);
|
||||
HRESULT result = S_OK;
|
||||
if (_stream)
|
||||
result = _stream->Write(data, size, &size);
|
||||
if (_calculate)
|
||||
_sha.Update((const Byte *)data, realProcessedSize);
|
||||
_size += realProcessedSize;
|
||||
if(processedSize != NULL)
|
||||
*processedSize = realProcessedSize;
|
||||
_sha.Update((const Byte *)data, size);
|
||||
_size += size;
|
||||
if (processedSize != NULL)
|
||||
*processedSize = size;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
#ifndef __OUT_STREAM_WITH_SHA1_H
|
||||
#define __OUT_STREAM_WITH_SHA1_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
|
||||
|
||||
#include "../../Crypto/Sha1.h"
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
class COutStreamWithSha1:
|
||||
public ISequentialOutStream,
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
// CpioHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/NewHandler.h"
|
||||
#include "Common/StringConvert.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/Time.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
|
||||
#include "CpioHandler.h"
|
||||
#include "CpioIn.h"
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NTime;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCpio {
|
||||
|
||||
/*
|
||||
enum
|
||||
{
|
||||
kpidinode = kpidUserDefined,
|
||||
kpidiChkSum
|
||||
};
|
||||
*/
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidMTime, VT_FILETIME},
|
||||
// { NULL, kpidUser, VT_BSTR},
|
||||
// { NULL, kpidGroup, VT_BSTR},
|
||||
// { L"inode", kpidinode, VT_UI4}
|
||||
// { L"CheckSum", kpidiChkSum, VT_UI4}
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
const UInt64 * /* maxCheckStartPosition */,
|
||||
IArchiveOpenCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
// try
|
||||
{
|
||||
CInArchive archive;
|
||||
|
||||
UInt64 endPos = 0;
|
||||
bool needSetTotal = true;
|
||||
|
||||
if (callback != NULL)
|
||||
{
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
|
||||
RINOK(archive.Open(stream));
|
||||
|
||||
_items.Clear();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
CItemEx item;
|
||||
bool filled;
|
||||
HRESULT result = archive.GetNextItem(filled, item);
|
||||
if (result == S_FALSE)
|
||||
return S_FALSE;
|
||||
if (result != S_OK)
|
||||
return S_FALSE;
|
||||
if (!filled)
|
||||
break;
|
||||
_items.Add(item);
|
||||
archive.SkeepDataRecords(item.Size, item.Align);
|
||||
if (callback != NULL)
|
||||
{
|
||||
if (needSetTotal)
|
||||
{
|
||||
RINOK(callback->SetTotal(NULL, &endPos));
|
||||
needSetTotal = false;
|
||||
}
|
||||
if (_items.Size() % 100 == 0)
|
||||
{
|
||||
UInt64 numFiles = _items.Size();
|
||||
UInt64 numBytes = item.HeaderPosition;
|
||||
RINOK(callback->SetCompleted(&numFiles, &numBytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_items.Size() == 0)
|
||||
return S_FALSE;
|
||||
|
||||
_inStream = stream;
|
||||
}
|
||||
/*
|
||||
catch(...)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
*/
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_items.Clear();
|
||||
_inStream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
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 CItemEx &item = _items[index];
|
||||
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath:
|
||||
prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP));
|
||||
break;
|
||||
case kpidIsDir:
|
||||
prop = item.IsDir();
|
||||
break;
|
||||
case kpidSize:
|
||||
case kpidPackSize:
|
||||
prop = (UInt64)item.Size;
|
||||
break;
|
||||
case kpidMTime:
|
||||
{
|
||||
FILETIME utcFileTime;
|
||||
if (item.ModificationTime != 0)
|
||||
NTime::UnixTimeToFileTime(item.ModificationTime, utcFileTime);
|
||||
else
|
||||
{
|
||||
utcFileTime.dwLowDateTime = 0;
|
||||
utcFileTime.dwHighDateTime = 0;
|
||||
}
|
||||
prop = utcFileTime;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case kpidinode: prop = item.inode; break;
|
||||
case kpidiChkSum: prop = item.ChkSum; break;
|
||||
*/
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool testMode = (_aTestMode != 0);
|
||||
bool allFilesMode = (numItems == UInt32(-1));
|
||||
if (allFilesMode)
|
||||
numItems = _items.Size();
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
UInt64 totalSize = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
totalSize += _items[allFilesMode ? i : indices[i]].Size;
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
UInt64 currentTotalSize = 0;
|
||||
UInt64 currentItemSize;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(_inStream);
|
||||
|
||||
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
|
||||
{
|
||||
lps->InSize = lps->OutSize = currentTotalSize;
|
||||
RINOK(lps->SetCur());
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode = testMode ?
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
const CItemEx &item = _items[index];
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
currentItemSize = item.Size;
|
||||
if (item.IsDir())
|
||||
{
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
if (!testMode && (!realOutStream))
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
if (testMode)
|
||||
{
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
RINOK(_inStream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(item.Size);
|
||||
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
|
||||
realOutStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
|
||||
NArchive::NExtract::NOperationResult::kOK:
|
||||
NArchive::NExtract::NOperationResult::kDataError));
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Archive/cpio/Handler.h
|
||||
|
||||
#ifndef __ARCHIVE_CPIO_HANDLER_H
|
||||
#define __ARCHIVE_CPIO_HANDLER_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "CpioItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCpio {
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IInArchive)
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
|
||||
private:
|
||||
CObjectVector<CItemEx> _items;
|
||||
CMyComPtr<IInStream> _inStream;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,23 +0,0 @@
|
||||
// Archive/cpio/Header.h
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "CpioHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCpio {
|
||||
namespace NFileHeader {
|
||||
|
||||
namespace NMagic
|
||||
{
|
||||
extern const char *kMagic1 = "070701";
|
||||
extern const char *kMagic2 = "070702";
|
||||
extern const char *kMagic3 = "070707";
|
||||
extern const char *kEndName = "TRAILER!!!";
|
||||
|
||||
const Byte kMagicForRecord2[2] = { 0xC7, 0x71 };
|
||||
// unsigned short kMagicForRecord2BE = 0xC771;
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
// Archive/cpio/Header.h
|
||||
|
||||
#ifndef __ARCHIVE_CPIO_HEADER_H
|
||||
#define __ARCHIVE_CPIO_HEADER_H
|
||||
|
||||
#include "Common/Types.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCpio {
|
||||
|
||||
namespace NFileHeader
|
||||
{
|
||||
namespace NMagic
|
||||
{
|
||||
extern const char *kMagic1;
|
||||
extern const char *kMagic2;
|
||||
extern const char *kMagic3;
|
||||
extern const char *kEndName;
|
||||
extern const Byte kMagicForRecord2[2];
|
||||
}
|
||||
|
||||
const UInt32 kRecord2Size = 26;
|
||||
/*
|
||||
struct CRecord2
|
||||
{
|
||||
unsigned short c_magic;
|
||||
short c_dev;
|
||||
unsigned short c_ino;
|
||||
unsigned short c_mode;
|
||||
unsigned short c_uid;
|
||||
unsigned short c_gid;
|
||||
unsigned short c_nlink;
|
||||
short c_rdev;
|
||||
unsigned short c_mtimes[2];
|
||||
unsigned short c_namesize;
|
||||
unsigned short c_filesizes[2];
|
||||
};
|
||||
*/
|
||||
|
||||
const UInt32 kRecordSize = 110;
|
||||
/*
|
||||
struct CRecord
|
||||
{
|
||||
char Magic[6]; // "070701" for "new" portable format, "070702" for CRC format
|
||||
char inode[8];
|
||||
char Mode[8];
|
||||
char UID[8];
|
||||
char GID[8];
|
||||
char nlink[8];
|
||||
char mtime[8];
|
||||
char Size[8]; // must be 0 for FIFOs and directories
|
||||
char DevMajor[8];
|
||||
char DevMinor[8];
|
||||
char RDevMajor[8]; //only valid for chr and blk special files
|
||||
char RDevMinor[8]; //only valid for chr and blk special files
|
||||
char NameSize[8]; // count includes terminating NUL in pathname
|
||||
char ChkSum[8]; // 0 for "new" portable format; for CRC format the sum of all the bytes in the file
|
||||
bool CheckMagic() const
|
||||
{ return memcmp(Magic, NMagic::kMagic1, 6) == 0 ||
|
||||
memcmp(Magic, NMagic::kMagic2, 6) == 0; };
|
||||
};
|
||||
*/
|
||||
|
||||
const UInt32 kOctRecordSize = 76;
|
||||
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,272 +0,0 @@
|
||||
// Archive/cpioIn.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "CpioIn.h"
|
||||
|
||||
#include "Common/StringToInt.h"
|
||||
#include "Windows/Defs.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "CpioHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCpio {
|
||||
|
||||
HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
|
||||
{
|
||||
size_t realProcessedSize = size;
|
||||
RINOK(ReadStream(m_Stream, data, &realProcessedSize));
|
||||
processedSize = (UInt32)realProcessedSize;
|
||||
m_Position += processedSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Byte CInArchive::ReadByte()
|
||||
{
|
||||
if (_blockPos >= _blockSize)
|
||||
throw "Incorrect cpio archive";
|
||||
return _block[_blockPos++];
|
||||
}
|
||||
|
||||
UInt16 CInArchive::ReadUInt16()
|
||||
{
|
||||
UInt16 value = 0;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Byte b = ReadByte();
|
||||
value |= (UInt16(b) << (8 * i));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
UInt32 CInArchive::ReadUInt32()
|
||||
{
|
||||
UInt32 value = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Byte b = ReadByte();
|
||||
value |= (UInt32(b) << (8 * i));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::Open(IInStream *inStream)
|
||||
{
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
|
||||
m_Stream = inStream;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool CInArchive::ReadNumber(UInt32 &resultValue)
|
||||
{
|
||||
resultValue = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
char c = char(ReadByte());
|
||||
int d;
|
||||
if (c >= '0' && c <= '9')
|
||||
d = c - '0';
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
d = 10 + c - 'A';
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
d = 10 + c - 'a';
|
||||
else
|
||||
return false;
|
||||
resultValue *= 0x10;
|
||||
resultValue += d;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool OctalToNumber(const char *s, UInt64 &res)
|
||||
{
|
||||
const char *end;
|
||||
res = ConvertOctStringToUInt64(s, &end);
|
||||
return (*end == ' ' || *end == 0);
|
||||
}
|
||||
|
||||
static bool OctalToNumber32(const char *s, UInt32 &res)
|
||||
{
|
||||
UInt64 res64;
|
||||
if (!OctalToNumber(s, res64))
|
||||
return false;
|
||||
res = (UInt32)res64;
|
||||
return (res64 <= 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
bool CInArchive::ReadOctNumber(int size, UInt32 &resultValue)
|
||||
{
|
||||
char sz[32 + 4];
|
||||
int i;
|
||||
for (i = 0; i < size && i < 32; i++)
|
||||
sz[i] = (char)ReadByte();
|
||||
sz[i] = 0;
|
||||
return OctalToNumber32(sz, resultValue);
|
||||
}
|
||||
|
||||
#define GetFromHex(y) { if (!ReadNumber(y)) return S_FALSE; }
|
||||
#define GetFromOct6(y) { if (!ReadOctNumber(6, y)) return S_FALSE; }
|
||||
#define GetFromOct11(y) { if (!ReadOctNumber(11, y)) return S_FALSE; }
|
||||
|
||||
static unsigned short ConvertValue(unsigned short value, bool convert)
|
||||
{
|
||||
if (!convert)
|
||||
return value;
|
||||
return (unsigned short)((((unsigned short)(value & 0xFF)) << 8) | (value >> 8));
|
||||
}
|
||||
|
||||
static UInt32 GetAlignedSize(UInt32 size, UInt32 align)
|
||||
{
|
||||
while ((size & (align - 1)) != 0)
|
||||
size++;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
|
||||
{
|
||||
filled = false;
|
||||
|
||||
UInt32 processedSize;
|
||||
item.HeaderPosition = m_Position;
|
||||
|
||||
_blockSize = kMaxBlockSize;
|
||||
RINOK(ReadBytes(_block, 2, processedSize));
|
||||
if (processedSize != 2)
|
||||
return S_FALSE;
|
||||
_blockPos = 0;
|
||||
|
||||
UInt32 nameSize;
|
||||
|
||||
bool oldBE =
|
||||
_block[0] == NFileHeader::NMagic::kMagicForRecord2[1] &&
|
||||
_block[1] == NFileHeader::NMagic::kMagicForRecord2[0];
|
||||
|
||||
bool binMode = (_block[0] == NFileHeader::NMagic::kMagicForRecord2[0] &&
|
||||
_block[1] == NFileHeader::NMagic::kMagicForRecord2[1]) ||
|
||||
oldBE;
|
||||
|
||||
if (binMode)
|
||||
{
|
||||
RINOK(ReadBytes(_block + 2, NFileHeader::kRecord2Size - 2, processedSize));
|
||||
if (processedSize != NFileHeader::kRecord2Size - 2)
|
||||
return S_FALSE;
|
||||
item.Align = 2;
|
||||
_blockPos = 2;
|
||||
item.DevMajor = 0;
|
||||
item.DevMinor = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.inode = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.Mode = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.UID = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.GID = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.NumLinks = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.RDevMajor =0;
|
||||
item.RDevMinor = ConvertValue(ReadUInt16(), oldBE);
|
||||
UInt16 timeHigh = ConvertValue(ReadUInt16(), oldBE);
|
||||
UInt16 timeLow = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.ModificationTime = (UInt32(timeHigh) << 16) + timeLow;
|
||||
nameSize = ConvertValue(ReadUInt16(), oldBE);
|
||||
UInt16 sizeHigh = ConvertValue(ReadUInt16(), oldBE);
|
||||
UInt16 sizeLow = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.Size = (UInt32(sizeHigh) << 16) + sizeLow;
|
||||
|
||||
item.ChkSum = 0;
|
||||
item.HeaderSize = GetAlignedSize(
|
||||
nameSize + NFileHeader::kRecord2Size, item.Align);
|
||||
nameSize = item.HeaderSize - NFileHeader::kRecord2Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(ReadBytes(_block + 2, 4, processedSize));
|
||||
if (processedSize != 4)
|
||||
return S_FALSE;
|
||||
|
||||
bool magicOK =
|
||||
memcmp(_block, NFileHeader::NMagic::kMagic1, 6) == 0 ||
|
||||
memcmp(_block, NFileHeader::NMagic::kMagic2, 6) == 0;
|
||||
_blockPos = 6;
|
||||
if (magicOK)
|
||||
{
|
||||
RINOK(ReadBytes(_block + 6, NFileHeader::kRecordSize - 6, processedSize));
|
||||
if (processedSize != NFileHeader::kRecordSize - 6)
|
||||
return S_FALSE;
|
||||
item.Align = 4;
|
||||
|
||||
GetFromHex(item.inode);
|
||||
GetFromHex(item.Mode);
|
||||
GetFromHex(item.UID);
|
||||
GetFromHex(item.GID);
|
||||
GetFromHex(item.NumLinks);
|
||||
UInt32 modificationTime;
|
||||
GetFromHex(modificationTime);
|
||||
item.ModificationTime = modificationTime;
|
||||
GetFromHex(item.Size);
|
||||
GetFromHex(item.DevMajor);
|
||||
GetFromHex(item.DevMinor);
|
||||
GetFromHex(item.RDevMajor);
|
||||
GetFromHex(item.RDevMinor);
|
||||
GetFromHex(nameSize);
|
||||
GetFromHex(item.ChkSum);
|
||||
item.HeaderSize = GetAlignedSize(
|
||||
nameSize + NFileHeader::kRecordSize, item.Align);
|
||||
nameSize = item.HeaderSize - NFileHeader::kRecordSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!memcmp(_block, NFileHeader::NMagic::kMagic3, 6) == 0)
|
||||
return S_FALSE;
|
||||
RINOK(ReadBytes(_block + 6, NFileHeader::kOctRecordSize - 6, processedSize));
|
||||
if (processedSize != NFileHeader::kOctRecordSize - 6)
|
||||
return S_FALSE;
|
||||
item.Align = 1;
|
||||
item.DevMajor = 0;
|
||||
GetFromOct6(item.DevMinor);
|
||||
GetFromOct6(item.inode);
|
||||
GetFromOct6(item.Mode);
|
||||
GetFromOct6(item.UID);
|
||||
GetFromOct6(item.GID);
|
||||
GetFromOct6(item.NumLinks);
|
||||
item.RDevMajor = 0;
|
||||
GetFromOct6(item.RDevMinor);
|
||||
UInt32 modificationTime;
|
||||
GetFromOct11(modificationTime);
|
||||
item.ModificationTime = modificationTime;
|
||||
GetFromOct6(nameSize);
|
||||
GetFromOct11(item.Size); // ?????
|
||||
item.HeaderSize = GetAlignedSize(
|
||||
nameSize + NFileHeader::kOctRecordSize, item.Align);
|
||||
nameSize = item.HeaderSize - NFileHeader::kOctRecordSize;
|
||||
}
|
||||
}
|
||||
if (nameSize == 0 || nameSize >= (1 << 27))
|
||||
return E_FAIL;
|
||||
RINOK(ReadBytes(item.Name.GetBuffer(nameSize), nameSize, processedSize));
|
||||
if (processedSize != nameSize)
|
||||
return E_FAIL;
|
||||
item.Name.ReleaseBuffer();
|
||||
if (strcmp(item.Name, NFileHeader::NMagic::kEndName) == 0)
|
||||
return S_OK;
|
||||
filled = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::Skeep(UInt64 numBytes)
|
||||
{
|
||||
UInt64 newPostion;
|
||||
RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
|
||||
m_Position += numBytes;
|
||||
if (m_Position != newPostion)
|
||||
return E_FAIL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::SkeepDataRecords(UInt64 dataSize, UInt32 align)
|
||||
{
|
||||
while ((dataSize & (align - 1)) != 0)
|
||||
dataSize++;
|
||||
return Skeep(dataSize);
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,41 +0,0 @@
|
||||
// CpioIn.h
|
||||
|
||||
#ifndef __ARCHIVE_CPIO_IN_H
|
||||
#define __ARCHIVE_CPIO_IN_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "Common/Types.h"
|
||||
#include "../../IStream.h"
|
||||
#include "CpioItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCpio {
|
||||
|
||||
const UInt32 kMaxBlockSize = NFileHeader::kRecordSize;
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
CMyComPtr<IInStream> m_Stream;
|
||||
UInt64 m_Position;
|
||||
|
||||
UInt16 _blockSize;
|
||||
Byte _block[kMaxBlockSize];
|
||||
UInt32 _blockPos;
|
||||
Byte ReadByte();
|
||||
UInt16 ReadUInt16();
|
||||
UInt32 ReadUInt32();
|
||||
|
||||
bool ReadNumber(UInt32 &resultValue);
|
||||
bool ReadOctNumber(int size, UInt32 &resultValue);
|
||||
|
||||
HRESULT ReadBytes(void *data, UInt32 size, UInt32 &processedSize);
|
||||
public:
|
||||
HRESULT Open(IInStream *inStream);
|
||||
HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
|
||||
HRESULT Skeep(UInt64 numBytes);
|
||||
HRESULT SkeepDataRecords(UInt64 dataSize, UInt32 align);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,55 +0,0 @@
|
||||
// Archive/cpio/ItemInfo.h
|
||||
|
||||
#ifndef __ARCHIVE_CPIO_ITEMINFO_H
|
||||
#define __ARCHIVE_CPIO_ITEMINFO_H
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "Common/Types.h"
|
||||
#include "Common/MyString.h"
|
||||
#include "CpioHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCpio {
|
||||
|
||||
struct CItem
|
||||
{
|
||||
AString Name;
|
||||
UInt32 inode;
|
||||
UInt32 Mode;
|
||||
UInt32 UID;
|
||||
UInt32 GID;
|
||||
UInt32 Size;
|
||||
UInt32 ModificationTime;
|
||||
|
||||
// char LinkFlag;
|
||||
// AString LinkName; ?????
|
||||
char Magic[8];
|
||||
UInt32 NumLinks;
|
||||
UInt32 DevMajor;
|
||||
UInt32 DevMinor;
|
||||
UInt32 RDevMajor;
|
||||
UInt32 RDevMinor;
|
||||
UInt32 ChkSum;
|
||||
|
||||
UInt32 Align;
|
||||
|
||||
bool IsDir() const
|
||||
#ifdef _WIN32
|
||||
{ return (Mode & _S_IFMT) == _S_IFDIR; }
|
||||
#else
|
||||
{ return (Mode & S_IFMT) == S_IFDIR; }
|
||||
#endif
|
||||
};
|
||||
|
||||
class CItemEx: public CItem
|
||||
{
|
||||
public:
|
||||
UInt64 HeaderPosition;
|
||||
UInt32 HeaderSize;
|
||||
UInt64 GetDataPosition() const { return HeaderPosition + HeaderSize; };
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,13 +0,0 @@
|
||||
// CpioRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "CpioHandler.h"
|
||||
static IInArchive *CreateArc() { return new NArchive::NCpio::CHandler; }
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"Cpio", L"cpio", 0, 0xED, { 0 }, 0, false, CreateArc, 0 };
|
||||
|
||||
REGISTER_ARC(Cpio)
|
||||
@@ -1,8 +0,0 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/MyWindows.h"
|
||||
|
||||
#endif
|
||||
Executable
+625
@@ -0,0 +1,625 @@
|
||||
// CpioHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/StringToInt.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/StreamUtils.h"
|
||||
|
||||
#include "../Compress/CopyCoder.h"
|
||||
|
||||
#include "Common/ItemNameUtils.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NCpio {
|
||||
|
||||
namespace NFileHeader
|
||||
{
|
||||
namespace NMagic
|
||||
{
|
||||
extern const char *kMagic1 = "070701";
|
||||
extern const char *kMagic2 = "070702";
|
||||
extern const char *kMagic3 = "070707";
|
||||
extern const char *kEndName = "TRAILER!!!";
|
||||
|
||||
const Byte kMagicForRecord2[2] = { 0xC7, 0x71 };
|
||||
}
|
||||
|
||||
const UInt32 kRecord2Size = 26;
|
||||
/*
|
||||
struct CRecord2
|
||||
{
|
||||
unsigned short c_magic;
|
||||
short c_dev;
|
||||
unsigned short c_ino;
|
||||
unsigned short c_mode;
|
||||
unsigned short c_uid;
|
||||
unsigned short c_gid;
|
||||
unsigned short c_nlink;
|
||||
short c_rdev;
|
||||
unsigned short c_mtimes[2];
|
||||
unsigned short c_namesize;
|
||||
unsigned short c_filesizes[2];
|
||||
};
|
||||
*/
|
||||
|
||||
const UInt32 kRecordSize = 110;
|
||||
/*
|
||||
struct CRecord
|
||||
{
|
||||
char Magic[6]; // "070701" for "new" portable format, "070702" for CRC format
|
||||
char inode[8];
|
||||
char Mode[8];
|
||||
char UID[8];
|
||||
char GID[8];
|
||||
char nlink[8];
|
||||
char mtime[8];
|
||||
char Size[8]; // must be 0 for FIFOs and directories
|
||||
char DevMajor[8];
|
||||
char DevMinor[8];
|
||||
char RDevMajor[8]; //only valid for chr and blk special files
|
||||
char RDevMinor[8]; //only valid for chr and blk special files
|
||||
char NameSize[8]; // count includes terminating NUL in pathname
|
||||
char ChkSum[8]; // 0 for "new" portable format; for CRC format the sum of all the bytes in the file
|
||||
bool CheckMagic() const
|
||||
{ return memcmp(Magic, NMagic::kMagic1, 6) == 0 ||
|
||||
memcmp(Magic, NMagic::kMagic2, 6) == 0; };
|
||||
};
|
||||
*/
|
||||
|
||||
const UInt32 kOctRecordSize = 76;
|
||||
|
||||
}
|
||||
|
||||
struct CItem
|
||||
{
|
||||
AString Name;
|
||||
UInt32 inode;
|
||||
UInt32 Mode;
|
||||
UInt32 UID;
|
||||
UInt32 GID;
|
||||
UInt32 Size;
|
||||
UInt32 MTime;
|
||||
|
||||
// char LinkFlag;
|
||||
// AString LinkName; ?????
|
||||
char Magic[8];
|
||||
UInt32 NumLinks;
|
||||
UInt32 DevMajor;
|
||||
UInt32 DevMinor;
|
||||
UInt32 RDevMajor;
|
||||
UInt32 RDevMinor;
|
||||
UInt32 ChkSum;
|
||||
|
||||
UInt32 Align;
|
||||
|
||||
bool IsDir() const { return (Mode & 0170000) == 0040000; }
|
||||
};
|
||||
|
||||
class CItemEx: public CItem
|
||||
{
|
||||
public:
|
||||
UInt64 HeaderPosition;
|
||||
UInt32 HeaderSize;
|
||||
UInt64 GetDataPosition() const { return HeaderPosition + HeaderSize; };
|
||||
};
|
||||
|
||||
const UInt32 kMaxBlockSize = NFileHeader::kRecordSize;
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
CMyComPtr<IInStream> m_Stream;
|
||||
UInt64 m_Position;
|
||||
|
||||
UInt16 _blockSize;
|
||||
Byte _block[kMaxBlockSize];
|
||||
UInt32 _blockPos;
|
||||
Byte ReadByte();
|
||||
UInt16 ReadUInt16();
|
||||
UInt32 ReadUInt32();
|
||||
|
||||
bool ReadNumber(UInt32 &resultValue);
|
||||
bool ReadOctNumber(int size, UInt32 &resultValue);
|
||||
|
||||
HRESULT ReadBytes(void *data, UInt32 size, UInt32 &processedSize);
|
||||
public:
|
||||
HRESULT Open(IInStream *inStream);
|
||||
HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
|
||||
HRESULT Skip(UInt64 numBytes);
|
||||
HRESULT SkipDataRecords(UInt64 dataSize, UInt32 align);
|
||||
};
|
||||
|
||||
HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
|
||||
{
|
||||
size_t realProcessedSize = size;
|
||||
RINOK(ReadStream(m_Stream, data, &realProcessedSize));
|
||||
processedSize = (UInt32)realProcessedSize;
|
||||
m_Position += processedSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Byte CInArchive::ReadByte()
|
||||
{
|
||||
if (_blockPos >= _blockSize)
|
||||
throw "Incorrect cpio archive";
|
||||
return _block[_blockPos++];
|
||||
}
|
||||
|
||||
UInt16 CInArchive::ReadUInt16()
|
||||
{
|
||||
UInt16 value = 0;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Byte b = ReadByte();
|
||||
value |= (UInt16(b) << (8 * i));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
UInt32 CInArchive::ReadUInt32()
|
||||
{
|
||||
UInt32 value = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Byte b = ReadByte();
|
||||
value |= (UInt32(b) << (8 * i));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::Open(IInStream *inStream)
|
||||
{
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
|
||||
m_Stream = inStream;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool CInArchive::ReadNumber(UInt32 &resultValue)
|
||||
{
|
||||
resultValue = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
char c = char(ReadByte());
|
||||
int d;
|
||||
if (c >= '0' && c <= '9')
|
||||
d = c - '0';
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
d = 10 + c - 'A';
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
d = 10 + c - 'a';
|
||||
else
|
||||
return false;
|
||||
resultValue *= 0x10;
|
||||
resultValue += d;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool OctalToNumber(const char *s, UInt64 &res)
|
||||
{
|
||||
const char *end;
|
||||
res = ConvertOctStringToUInt64(s, &end);
|
||||
return (*end == ' ' || *end == 0);
|
||||
}
|
||||
|
||||
static bool OctalToNumber32(const char *s, UInt32 &res)
|
||||
{
|
||||
UInt64 res64;
|
||||
if (!OctalToNumber(s, res64))
|
||||
return false;
|
||||
res = (UInt32)res64;
|
||||
return (res64 <= 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
bool CInArchive::ReadOctNumber(int size, UInt32 &resultValue)
|
||||
{
|
||||
char sz[32 + 4];
|
||||
int i;
|
||||
for (i = 0; i < size && i < 32; i++)
|
||||
sz[i] = (char)ReadByte();
|
||||
sz[i] = 0;
|
||||
return OctalToNumber32(sz, resultValue);
|
||||
}
|
||||
|
||||
#define GetFromHex(y) { if (!ReadNumber(y)) return S_FALSE; }
|
||||
#define GetFromOct6(y) { if (!ReadOctNumber(6, y)) return S_FALSE; }
|
||||
#define GetFromOct11(y) { if (!ReadOctNumber(11, y)) return S_FALSE; }
|
||||
|
||||
static unsigned short ConvertValue(unsigned short value, bool convert)
|
||||
{
|
||||
if (!convert)
|
||||
return value;
|
||||
return (unsigned short)((((unsigned short)(value & 0xFF)) << 8) | (value >> 8));
|
||||
}
|
||||
|
||||
static UInt32 GetAlignedSize(UInt32 size, UInt32 align)
|
||||
{
|
||||
while ((size & (align - 1)) != 0)
|
||||
size++;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
|
||||
{
|
||||
filled = false;
|
||||
|
||||
UInt32 processedSize;
|
||||
item.HeaderPosition = m_Position;
|
||||
|
||||
_blockSize = kMaxBlockSize;
|
||||
RINOK(ReadBytes(_block, 2, processedSize));
|
||||
if (processedSize != 2)
|
||||
return S_FALSE;
|
||||
_blockPos = 0;
|
||||
|
||||
UInt32 nameSize;
|
||||
|
||||
bool oldBE =
|
||||
_block[0] == NFileHeader::NMagic::kMagicForRecord2[1] &&
|
||||
_block[1] == NFileHeader::NMagic::kMagicForRecord2[0];
|
||||
|
||||
bool binMode = (_block[0] == NFileHeader::NMagic::kMagicForRecord2[0] &&
|
||||
_block[1] == NFileHeader::NMagic::kMagicForRecord2[1]) ||
|
||||
oldBE;
|
||||
|
||||
if (binMode)
|
||||
{
|
||||
RINOK(ReadBytes(_block + 2, NFileHeader::kRecord2Size - 2, processedSize));
|
||||
if (processedSize != NFileHeader::kRecord2Size - 2)
|
||||
return S_FALSE;
|
||||
item.Align = 2;
|
||||
_blockPos = 2;
|
||||
item.DevMajor = 0;
|
||||
item.DevMinor = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.inode = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.Mode = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.UID = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.GID = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.NumLinks = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.RDevMajor =0;
|
||||
item.RDevMinor = ConvertValue(ReadUInt16(), oldBE);
|
||||
UInt16 timeHigh = ConvertValue(ReadUInt16(), oldBE);
|
||||
UInt16 timeLow = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.MTime = (UInt32(timeHigh) << 16) + timeLow;
|
||||
nameSize = ConvertValue(ReadUInt16(), oldBE);
|
||||
UInt16 sizeHigh = ConvertValue(ReadUInt16(), oldBE);
|
||||
UInt16 sizeLow = ConvertValue(ReadUInt16(), oldBE);
|
||||
item.Size = (UInt32(sizeHigh) << 16) + sizeLow;
|
||||
|
||||
item.ChkSum = 0;
|
||||
item.HeaderSize = GetAlignedSize(
|
||||
nameSize + NFileHeader::kRecord2Size, item.Align);
|
||||
nameSize = item.HeaderSize - NFileHeader::kRecord2Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(ReadBytes(_block + 2, 4, processedSize));
|
||||
if (processedSize != 4)
|
||||
return S_FALSE;
|
||||
|
||||
bool magicOK =
|
||||
memcmp(_block, NFileHeader::NMagic::kMagic1, 6) == 0 ||
|
||||
memcmp(_block, NFileHeader::NMagic::kMagic2, 6) == 0;
|
||||
_blockPos = 6;
|
||||
if (magicOK)
|
||||
{
|
||||
RINOK(ReadBytes(_block + 6, NFileHeader::kRecordSize - 6, processedSize));
|
||||
if (processedSize != NFileHeader::kRecordSize - 6)
|
||||
return S_FALSE;
|
||||
item.Align = 4;
|
||||
|
||||
GetFromHex(item.inode);
|
||||
GetFromHex(item.Mode);
|
||||
GetFromHex(item.UID);
|
||||
GetFromHex(item.GID);
|
||||
GetFromHex(item.NumLinks);
|
||||
UInt32 mTime;
|
||||
GetFromHex(mTime);
|
||||
item.MTime = mTime;
|
||||
GetFromHex(item.Size);
|
||||
GetFromHex(item.DevMajor);
|
||||
GetFromHex(item.DevMinor);
|
||||
GetFromHex(item.RDevMajor);
|
||||
GetFromHex(item.RDevMinor);
|
||||
GetFromHex(nameSize);
|
||||
GetFromHex(item.ChkSum);
|
||||
item.HeaderSize = GetAlignedSize(
|
||||
nameSize + NFileHeader::kRecordSize, item.Align);
|
||||
nameSize = item.HeaderSize - NFileHeader::kRecordSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!memcmp(_block, NFileHeader::NMagic::kMagic3, 6) == 0)
|
||||
return S_FALSE;
|
||||
RINOK(ReadBytes(_block + 6, NFileHeader::kOctRecordSize - 6, processedSize));
|
||||
if (processedSize != NFileHeader::kOctRecordSize - 6)
|
||||
return S_FALSE;
|
||||
item.Align = 1;
|
||||
item.DevMajor = 0;
|
||||
GetFromOct6(item.DevMinor);
|
||||
GetFromOct6(item.inode);
|
||||
GetFromOct6(item.Mode);
|
||||
GetFromOct6(item.UID);
|
||||
GetFromOct6(item.GID);
|
||||
GetFromOct6(item.NumLinks);
|
||||
item.RDevMajor = 0;
|
||||
GetFromOct6(item.RDevMinor);
|
||||
UInt32 mTime;
|
||||
GetFromOct11(mTime);
|
||||
item.MTime = mTime;
|
||||
GetFromOct6(nameSize);
|
||||
GetFromOct11(item.Size); // ?????
|
||||
item.HeaderSize = GetAlignedSize(
|
||||
nameSize + NFileHeader::kOctRecordSize, item.Align);
|
||||
nameSize = item.HeaderSize - NFileHeader::kOctRecordSize;
|
||||
}
|
||||
}
|
||||
if (nameSize == 0 || nameSize >= (1 << 27))
|
||||
return E_FAIL;
|
||||
RINOK(ReadBytes(item.Name.GetBuffer(nameSize), nameSize, processedSize));
|
||||
if (processedSize != nameSize)
|
||||
return E_FAIL;
|
||||
item.Name.ReleaseBuffer();
|
||||
if (strcmp(item.Name, NFileHeader::NMagic::kEndName) == 0)
|
||||
return S_OK;
|
||||
filled = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::Skip(UInt64 numBytes)
|
||||
{
|
||||
UInt64 newPostion;
|
||||
RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
|
||||
m_Position += numBytes;
|
||||
if (m_Position != newPostion)
|
||||
return E_FAIL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::SkipDataRecords(UInt64 dataSize, UInt32 align)
|
||||
{
|
||||
while ((dataSize & (align - 1)) != 0)
|
||||
dataSize++;
|
||||
return Skip(dataSize);
|
||||
}
|
||||
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CObjectVector<CItemEx> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
||||
INTERFACE_IInArchive(;)
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
};
|
||||
|
||||
/*
|
||||
enum
|
||||
{
|
||||
kpidinode = kpidUserDefined,
|
||||
kpidiChkSum
|
||||
};
|
||||
*/
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidMTime, VT_FILETIME},
|
||||
{ NULL, kpidPosixAttrib, VT_UI4},
|
||||
// { L"inode", kpidinode, VT_UI4}
|
||||
// { L"CheckSum", kpidiChkSum, VT_UI4}
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
// try
|
||||
{
|
||||
CInArchive archive;
|
||||
|
||||
UInt64 endPos = 0;
|
||||
bool needSetTotal = true;
|
||||
|
||||
if (callback != NULL)
|
||||
{
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
|
||||
RINOK(archive.Open(stream));
|
||||
|
||||
_items.Clear();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
CItemEx item;
|
||||
bool filled;
|
||||
HRESULT result = archive.GetNextItem(filled, item);
|
||||
if (result == S_FALSE)
|
||||
return S_FALSE;
|
||||
if (result != S_OK)
|
||||
return S_FALSE;
|
||||
if (!filled)
|
||||
break;
|
||||
_items.Add(item);
|
||||
archive.SkipDataRecords(item.Size, item.Align);
|
||||
if (callback != NULL)
|
||||
{
|
||||
if (needSetTotal)
|
||||
{
|
||||
RINOK(callback->SetTotal(NULL, &endPos));
|
||||
needSetTotal = false;
|
||||
}
|
||||
if (_items.Size() % 100 == 0)
|
||||
{
|
||||
UInt64 numFiles = _items.Size();
|
||||
UInt64 numBytes = item.HeaderPosition;
|
||||
RINOK(callback->SetCompleted(&numFiles, &numBytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_items.Size() == 0)
|
||||
return S_FALSE;
|
||||
|
||||
_stream = stream;
|
||||
}
|
||||
/*
|
||||
catch(...)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
*/
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_items.Clear();
|
||||
_stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
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 CItemEx &item = _items[index];
|
||||
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break;
|
||||
case kpidIsDir: prop = item.IsDir(); break;
|
||||
case kpidSize:
|
||||
case kpidPackSize:
|
||||
prop = (UInt64)item.Size;
|
||||
break;
|
||||
case kpidMTime:
|
||||
{
|
||||
if (item.MTime != 0)
|
||||
{
|
||||
FILETIME utc;
|
||||
NWindows::NTime::UnixTimeToFileTime(item.MTime, utc);
|
||||
prop = utc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kpidPosixAttrib: prop = item.Mode; break;
|
||||
/*
|
||||
case kpidinode: prop = item.inode; break;
|
||||
case kpidiChkSum: prop = item.ChkSum; break;
|
||||
*/
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool testMode = (_aTestMode != 0);
|
||||
bool allFilesMode = (numItems == UInt32(-1));
|
||||
if (allFilesMode)
|
||||
numItems = _items.Size();
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
UInt64 totalSize = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < numItems; i++)
|
||||
totalSize += _items[allFilesMode ? i : indices[i]].Size;
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
UInt64 currentTotalSize = 0;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(_stream);
|
||||
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
lps->InSize = lps->OutSize = currentTotalSize;
|
||||
RINOK(lps->SetCur());
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
Int32 askMode = testMode ?
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
const CItemEx &item = _items[index];
|
||||
RINOK(extractCallback->GetStream(index, &outStream, askMode));
|
||||
currentTotalSize += item.Size;
|
||||
if (item.IsDir())
|
||||
{
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
if (!testMode && !outStream)
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
if (testMode)
|
||||
{
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
RINOK(_stream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(item.Size);
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
outStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ?
|
||||
NArchive::NExtract::NOperationResult::kOK:
|
||||
NArchive::NExtract::NOperationResult::kDataError));
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
const CItemEx &item = _items[index];
|
||||
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
static IInArchive *CreateArc() { return new NArchive::NCpio::CHandler; }
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"Cpio", L"cpio", 0, 0xED, { 0 }, 0, false, CreateArc, 0 };
|
||||
|
||||
REGISTER_ARC(Cpio)
|
||||
|
||||
}}
|
||||
@@ -30,7 +30,7 @@ namespace NHeader
|
||||
{
|
||||
const int kSignatureLen = 8;
|
||||
|
||||
const char *kSignature = "!<arch>\n";
|
||||
const char *kSignature = "!<arch>\n";
|
||||
|
||||
const int kNameSize = 16;
|
||||
const int kTimeSize = 12;
|
||||
@@ -53,20 +53,15 @@ namespace NHeader
|
||||
const int kHeaderSize = kNameSize + kTimeSize + 6 + 6 + kModeSize + kSizeSize + 1 + 1;
|
||||
}
|
||||
|
||||
class CItem
|
||||
struct CItem
|
||||
{
|
||||
public:
|
||||
AString Name;
|
||||
UInt64 Size;
|
||||
UInt32 MTime;
|
||||
UInt32 Mode;
|
||||
};
|
||||
|
||||
class CItemEx: public CItem
|
||||
{
|
||||
public:
|
||||
UInt64 HeaderPosition;
|
||||
UInt64 GetDataPosition() const { return HeaderPosition + NHeader::kHeaderSize; };
|
||||
UInt64 HeaderPos;
|
||||
UInt64 GetDataPos() const { return HeaderPos + NHeader::kHeaderSize; };
|
||||
// UInt64 GetFullSize() const { return NFileHeader::kRecordSize + Size; };
|
||||
};
|
||||
|
||||
@@ -75,12 +70,11 @@ class CInArchive
|
||||
CMyComPtr<IInStream> m_Stream;
|
||||
UInt64 m_Position;
|
||||
|
||||
HRESULT GetNextItemReal(bool &filled, CItemEx &itemInfo);
|
||||
HRESULT Skeep(UInt64 numBytes);
|
||||
HRESULT GetNextItemReal(bool &filled, CItem &itemInfo);
|
||||
public:
|
||||
HRESULT Open(IInStream *inStream);
|
||||
HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
|
||||
HRESULT SkeepData(UInt64 dataSize);
|
||||
HRESULT GetNextItem(bool &filled, CItem &itemInfo);
|
||||
HRESULT SkipData(UInt64 dataSize);
|
||||
};
|
||||
|
||||
HRESULT CInArchive::Open(IInStream *inStream)
|
||||
@@ -151,7 +145,7 @@ static bool DecimalToNumber32(const char *s, int size, UInt32 &res)
|
||||
#define RIF(x) { if (!(x)) return S_FALSE; }
|
||||
|
||||
|
||||
HRESULT CInArchive::GetNextItemReal(bool &filled, CItemEx &item)
|
||||
HRESULT CInArchive::GetNextItemReal(bool &filled, CItem &item)
|
||||
{
|
||||
filled = false;
|
||||
|
||||
@@ -159,7 +153,7 @@ HRESULT CInArchive::GetNextItemReal(bool &filled, CItemEx &item)
|
||||
const char *cur = header;
|
||||
|
||||
size_t processedSize = sizeof(header);
|
||||
item.HeaderPosition = m_Position;
|
||||
item.HeaderPos = m_Position;
|
||||
RINOK(ReadStream(m_Stream, header, &processedSize));
|
||||
m_Position += processedSize;
|
||||
if (processedSize != sizeof(header))
|
||||
@@ -191,7 +185,7 @@ HRESULT CInArchive::GetNextItemReal(bool &filled, CItemEx &item)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
|
||||
HRESULT CInArchive::GetNextItem(bool &filled, CItem &item)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
@@ -202,38 +196,26 @@ HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
|
||||
return S_OK;
|
||||
if (item.Size != 4)
|
||||
return S_OK;
|
||||
SkeepData(item.Size);
|
||||
SkipData(item.Size);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CInArchive::Skeep(UInt64 numBytes)
|
||||
HRESULT CInArchive::SkipData(UInt64 dataSize)
|
||||
{
|
||||
UInt64 newPostion;
|
||||
RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
|
||||
m_Position += numBytes;
|
||||
if (m_Position != newPostion)
|
||||
return E_FAIL;
|
||||
return S_OK;
|
||||
return m_Stream->Seek((dataSize + 1) & (~((UInt64)0x1)), STREAM_SEEK_CUR, &m_Position);
|
||||
}
|
||||
|
||||
HRESULT CInArchive::SkeepData(UInt64 dataSize)
|
||||
{
|
||||
return Skeep((dataSize + 1) & (~((UInt64)0x1)));
|
||||
}
|
||||
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CObjectVector<CItem> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IInArchive)
|
||||
|
||||
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
||||
INTERFACE_IInArchive(;)
|
||||
|
||||
private:
|
||||
CObjectVector<CItemEx> _items;
|
||||
CMyComPtr<IInStream> _inStream;
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
};
|
||||
|
||||
|
||||
@@ -241,7 +223,6 @@ STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidMTime, VT_FILETIME}
|
||||
};
|
||||
|
||||
@@ -268,7 +249,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
|
||||
for (;;)
|
||||
{
|
||||
CItemEx item;
|
||||
CItem item;
|
||||
bool filled;
|
||||
HRESULT result = archive.GetNextItem(filled, item);
|
||||
if (result == S_FALSE)
|
||||
@@ -278,14 +259,14 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
if (!filled)
|
||||
break;
|
||||
_items.Add(item);
|
||||
archive.SkeepData(item.Size);
|
||||
archive.SkipData(item.Size);
|
||||
if (openArchiveCallback != NULL)
|
||||
{
|
||||
UInt64 numFiles = _items.Size();
|
||||
RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL));
|
||||
}
|
||||
}
|
||||
_inStream = stream;
|
||||
_stream = stream;
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
@@ -293,7 +274,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_inStream.Release();
|
||||
_stream.Release();
|
||||
_items.Clear();
|
||||
return S_OK;
|
||||
}
|
||||
@@ -308,7 +289,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
const CItemEx &item = _items[index];
|
||||
const CItem &item = _items[index];
|
||||
|
||||
switch(propID)
|
||||
{
|
||||
@@ -350,7 +331,6 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
extractCallback->SetTotal(totalSize);
|
||||
|
||||
UInt64 currentTotalSize = 0;
|
||||
UInt64 currentItemSize;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
@@ -361,9 +341,9 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(_inStream);
|
||||
streamSpec->SetStream(_stream);
|
||||
|
||||
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
lps->InSize = lps->OutSize = currentTotalSize;
|
||||
RINOK(lps->SetCur());
|
||||
@@ -372,14 +352,9 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
const CItemEx &item = _items[index];
|
||||
const CItem &item = _items[index];
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
currentItemSize = item.Size;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
currentTotalSize += item.Size;
|
||||
|
||||
if (!testMode && (!realOutStream))
|
||||
continue;
|
||||
@@ -389,7 +364,7 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
RINOK(_inStream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
RINOK(_stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(item.Size);
|
||||
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
|
||||
realOutStream.Release();
|
||||
@@ -401,10 +376,18 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
const CItem &item = _items[index];
|
||||
return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
static IInArchive *CreateArc() { return new NArchive::NDeb::CHandler; }
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"Deb", L"deb", 0, 0xEC, { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' }, 8, false, CreateArc, 0 };
|
||||
{ L"Deb", L"deb", 0, 0xEC, { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' }, 8, false, CreateArc, 0 };
|
||||
|
||||
REGISTER_ARC(Deb)
|
||||
|
||||
|
||||
@@ -7,10 +7,7 @@
|
||||
#include "../../Common/Types.h"
|
||||
#include "../../Windows/PropVariant.h"
|
||||
#if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
|
||||
extern "C"
|
||||
{
|
||||
#include "../../../C/Alloc.h"
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "IArchive.h"
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
|
||||
#include "../Compress/CopyCoder.h"
|
||||
|
||||
#include "Common/DummyOutStream.h"
|
||||
|
||||
static UInt16 Get16(const Byte *p, int be) { if (be) return GetBe16(p); return GetUi16(p); }
|
||||
static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); }
|
||||
static UInt64 Get64(const Byte *p, int be) { if (be) return GetBe64(p); return GetUi64(p); }
|
||||
@@ -28,11 +26,11 @@ using namespace NWindows;
|
||||
namespace NArchive {
|
||||
namespace NElf {
|
||||
|
||||
#define ELF_CLASS_32 1
|
||||
#define ELF_CLASS_64 2
|
||||
#define ELF_CLASS_32 1
|
||||
#define ELF_CLASS_64 2
|
||||
|
||||
#define ELF_DATA_2LSB 1
|
||||
#define ELF_DATA_2MSB 2
|
||||
#define ELF_DATA_2LSB 1
|
||||
#define ELF_DATA_2MSB 2
|
||||
|
||||
#define NUM_SCAN_SECTIONS_MAX (1 << 6)
|
||||
|
||||
@@ -321,7 +319,7 @@ public:
|
||||
INTERFACE_IInArchive(;)
|
||||
};
|
||||
|
||||
#define ELF_PT_PHDR 6
|
||||
#define ELF_PT_PHDR 6
|
||||
|
||||
bool CHandler::Parse(const Byte *buf, UInt32 size)
|
||||
{
|
||||
@@ -498,9 +496,6 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(_inStream);
|
||||
|
||||
CDummyOutStream *outStreamSpec = new CDummyOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
|
||||
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
|
||||
{
|
||||
lps->InSize = lps->OutSize = currentTotalSize;
|
||||
@@ -511,20 +506,17 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
UInt32 index = allFilesMode ? i : indices[i];
|
||||
const CSegment &item = _sections[index];
|
||||
currentItemSize = item.PSize;
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
if (!testMode && (!realOutStream))
|
||||
continue;
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
outStreamSpec->Init();
|
||||
}
|
||||
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
RINOK(extractCallback->GetStream(index, &outStream, askMode));
|
||||
if (!testMode && !outStream)
|
||||
continue;
|
||||
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(_inStream->Seek(item.Offset, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(currentItemSize);
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
outStreamSpec->ReleaseStream();
|
||||
outStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ?
|
||||
NArchive::NExtract::NOperationResult::kOK:
|
||||
NArchive::NExtract::NOperationResult::kDataError));
|
||||
|
||||
Executable
+983
@@ -0,0 +1,983 @@
|
||||
// FatHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #include <stdio.h>
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "Common/Buffer.h"
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/IntToString.h"
|
||||
#include "Common/MyCom.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/StreamUtils.h"
|
||||
|
||||
#include "../Compress/CopyCoder.h"
|
||||
|
||||
#include "Common/DummyOutStream.h"
|
||||
|
||||
#define Get16(p) GetUi16(p)
|
||||
#define Get32(p) GetUi32(p)
|
||||
|
||||
#define PRF(x) /* x */
|
||||
|
||||
namespace NArchive {
|
||||
namespace NFat {
|
||||
|
||||
static const UInt32 kFatItemUsedByDirMask = (UInt32)1 << 31;
|
||||
|
||||
struct CHeader
|
||||
{
|
||||
UInt32 NumSectors;
|
||||
UInt16 NumReservedSectors;
|
||||
Byte NumFats;
|
||||
UInt32 NumFatSectors;
|
||||
UInt32 RootDirSector;
|
||||
UInt32 NumRootDirSectors;
|
||||
UInt32 DataSector;
|
||||
|
||||
UInt32 FatSize;
|
||||
UInt32 BadCluster;
|
||||
|
||||
Byte NumFatBits;
|
||||
Byte SectorSizeLog;
|
||||
Byte SectorsPerClusterLog;
|
||||
Byte ClusterSizeLog;
|
||||
|
||||
UInt16 SectorsPerTrack;
|
||||
UInt16 NumHeads;
|
||||
UInt32 NumHiddenSectors;
|
||||
|
||||
bool VolFieldsDefined;
|
||||
|
||||
UInt32 VolId;
|
||||
// Byte VolName[11];
|
||||
// Byte FileSys[8];
|
||||
|
||||
// Byte OemName[5];
|
||||
Byte MediaType;
|
||||
|
||||
// 32-bit FAT
|
||||
UInt16 Flags;
|
||||
UInt16 FsInfoSector;
|
||||
UInt32 RootCluster;
|
||||
|
||||
bool IsFat32() const { return NumFatBits == 32; }
|
||||
UInt64 GetPhySize() const { return (UInt64)NumSectors << SectorSizeLog; }
|
||||
UInt32 SectorSize() const { return (UInt32)1 << SectorSizeLog; }
|
||||
UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; }
|
||||
UInt32 ClusterToSector(UInt32 c) const { return DataSector + ((c - 2) << SectorsPerClusterLog); }
|
||||
UInt32 IsEoc(UInt32 c) const { return c > BadCluster; }
|
||||
UInt32 IsEocAndUnused(UInt32 c) const { return c > BadCluster && (c & kFatItemUsedByDirMask) == 0; }
|
||||
UInt32 IsValidCluster(UInt32 c) const { return c >= 2 && c < FatSize; }
|
||||
UInt32 SizeToSectors(UInt32 size) const { return (size + SectorSize() - 1) >> SectorSizeLog; }
|
||||
UInt32 CalcFatSizeInSectors() const { return SizeToSectors((FatSize * (NumFatBits / 4) + 1) / 2); }
|
||||
|
||||
UInt32 GetFatSector() const
|
||||
{
|
||||
UInt32 index = (IsFat32() && (Flags & 0x80) != 0) ? (Flags & 0xF) : 0;
|
||||
if (index > NumFats)
|
||||
index = 0;
|
||||
return NumReservedSectors + index * NumFatSectors;
|
||||
}
|
||||
|
||||
UInt64 GetFilePackSize(UInt32 unpackSize) const
|
||||
{
|
||||
UInt64 mask = ClusterSize() - 1;
|
||||
return (unpackSize + mask) & ~mask;
|
||||
}
|
||||
|
||||
UInt32 GetNumClusters(UInt32 size) const
|
||||
{ return (UInt32)(((UInt64)size + ClusterSize() - 1) >> ClusterSizeLog); }
|
||||
|
||||
bool Parse(const Byte *p);
|
||||
};
|
||||
|
||||
static int GetLog(UInt32 num)
|
||||
{
|
||||
for (int i = 0; i < 31; i++)
|
||||
if (((UInt32)1 << i) == num)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CHeader::Parse(const Byte *p)
|
||||
{
|
||||
if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
|
||||
return false;
|
||||
|
||||
int codeOffset = 0;
|
||||
switch (p[0])
|
||||
{
|
||||
case 0xE9: codeOffset = 3 + (Int16)Get16(p + 1); break;
|
||||
case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (signed char)p[1]; break;
|
||||
default: return false;
|
||||
}
|
||||
{
|
||||
int s = GetLog(Get16(p + 11));
|
||||
if (s < 9 || s > 12)
|
||||
return false;
|
||||
SectorSizeLog = (Byte)s;
|
||||
s = GetLog(p[13]);
|
||||
if (s < 0)
|
||||
return false;
|
||||
SectorsPerClusterLog = (Byte)s;
|
||||
ClusterSizeLog = SectorSizeLog + SectorsPerClusterLog;
|
||||
}
|
||||
|
||||
NumReservedSectors = Get16(p + 14);
|
||||
if (NumReservedSectors == 0)
|
||||
return false;
|
||||
|
||||
NumFats = p[16];
|
||||
if (NumFats < 1 || NumFats > 4)
|
||||
return false;
|
||||
|
||||
UInt16 numRootDirEntries = Get16(p + 17);
|
||||
if (numRootDirEntries == 0)
|
||||
{
|
||||
if (codeOffset < 90)
|
||||
return false;
|
||||
NumFatBits = 32;
|
||||
NumRootDirSectors = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (codeOffset < 62)
|
||||
return false;
|
||||
NumFatBits = 0;
|
||||
UInt32 mask = (1 << (SectorSizeLog - 5)) - 1;
|
||||
if ((numRootDirEntries & mask) != 0)
|
||||
return false;
|
||||
NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5);
|
||||
}
|
||||
|
||||
NumSectors = Get16(p + 19);
|
||||
if (NumSectors == 0)
|
||||
NumSectors = Get32(p + 32);
|
||||
else if (IsFat32())
|
||||
return false;
|
||||
|
||||
MediaType = p[21];
|
||||
NumFatSectors = Get16(p + 22);
|
||||
SectorsPerTrack = Get16(p + 24);
|
||||
NumHeads = Get16(p + 26);
|
||||
NumHiddenSectors = Get32(p + 28);
|
||||
|
||||
// memcpy(OemName, p + 3, 5);
|
||||
|
||||
p += 36;
|
||||
if (IsFat32())
|
||||
{
|
||||
if (NumFatSectors != 0)
|
||||
return false;
|
||||
NumFatSectors = Get32(p);
|
||||
if (NumFatSectors >= (1 << 24))
|
||||
return false;
|
||||
|
||||
Flags = Get16(p + 4);
|
||||
if (Get16(p + 6) != 0)
|
||||
return false;
|
||||
RootCluster = Get32(p + 8);
|
||||
FsInfoSector = Get16(p + 12);
|
||||
for (int i = 16; i < 28; i++)
|
||||
if (p[i] != 0)
|
||||
return false;
|
||||
p += 28;
|
||||
}
|
||||
|
||||
// DriveNumber = p[0];
|
||||
VolFieldsDefined = (p[2] == 0x29); // ExtendedBootSig
|
||||
VolId = Get32(p + 3);
|
||||
// memcpy(VolName, p + 7, 11);
|
||||
// memcpy(FileSys, p + 18, 8);
|
||||
|
||||
if (NumFatSectors == 0)
|
||||
return false;
|
||||
RootDirSector = NumReservedSectors + NumFatSectors * NumFats;
|
||||
DataSector = RootDirSector + NumRootDirSectors;
|
||||
if (NumSectors < DataSector)
|
||||
return false;
|
||||
UInt32 numDataSectors = NumSectors - DataSector;
|
||||
UInt32 numClusters = numDataSectors >> SectorsPerClusterLog;
|
||||
|
||||
BadCluster = 0x0FFFFFF7;
|
||||
if (numClusters < 0xFFF5)
|
||||
{
|
||||
if (NumFatBits == 32)
|
||||
return false;
|
||||
NumFatBits = (numClusters < 0xFF5) ? 12: 16;
|
||||
BadCluster &= ((1 << NumFatBits) - 1);
|
||||
}
|
||||
else if (NumFatBits != 32)
|
||||
return false;
|
||||
|
||||
FatSize = numClusters + 2;
|
||||
if (FatSize > BadCluster || CalcFatSizeInSectors() > NumFatSectors)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct CItem
|
||||
{
|
||||
UString UName;
|
||||
char DosName[11];
|
||||
Byte CTime2;
|
||||
UInt32 CTime;
|
||||
UInt32 MTime;
|
||||
UInt16 ADate;
|
||||
Byte Attrib;
|
||||
Byte Flags;
|
||||
UInt32 Size;
|
||||
UInt32 Cluster;
|
||||
Int32 Parent;
|
||||
|
||||
// NT uses Flags to store Low Case status
|
||||
bool NameIsLow() const { return (Flags & 0x8) != 0; }
|
||||
bool ExtIsLow() const { return (Flags & 0x10) != 0; }
|
||||
bool IsDir() const { return (Attrib & 0x10) != 0; }
|
||||
UString GetShortName() const;
|
||||
UString GetName() const;
|
||||
UString GetVolName() const;
|
||||
};
|
||||
|
||||
static int CopyAndTrim(char *dest, const char *src, int size, bool toLower)
|
||||
{
|
||||
int i;
|
||||
memcpy(dest, src, size);
|
||||
if (toLower)
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
char c = dest[i];
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
dest[i] = c + 0x20;
|
||||
}
|
||||
for (i = size - 1; i >= 0 && dest[i] == ' '; i--);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static UString FatStringToUnicode(const char *s)
|
||||
{
|
||||
return MultiByteToUnicodeString(s, CP_OEMCP);
|
||||
}
|
||||
|
||||
UString CItem::GetShortName() const
|
||||
{
|
||||
char s[16];
|
||||
int i = CopyAndTrim(s, DosName, 8, NameIsLow());
|
||||
s[i++] = '.';
|
||||
int j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow());
|
||||
if (j == 0)
|
||||
j--;
|
||||
s[i + j] = 0;
|
||||
return FatStringToUnicode(s);
|
||||
}
|
||||
|
||||
UString CItem::GetName() const
|
||||
{
|
||||
if (!UName.IsEmpty())
|
||||
return UName;
|
||||
return GetShortName();
|
||||
}
|
||||
|
||||
UString CItem::GetVolName() const
|
||||
{
|
||||
if (!UName.IsEmpty())
|
||||
return UName;
|
||||
char s[12];
|
||||
int i = CopyAndTrim(s, DosName, 11, false);
|
||||
s[i] = 0;
|
||||
return FatStringToUnicode(s);
|
||||
}
|
||||
|
||||
struct CDatabase
|
||||
{
|
||||
CHeader Header;
|
||||
CObjectVector<CItem> Items;
|
||||
UInt32 *Fat;
|
||||
CMyComPtr<IInStream> InStream;
|
||||
IArchiveOpenCallback *OpenCallback;
|
||||
|
||||
UInt32 NumFreeClusters;
|
||||
bool VolItemDefined;
|
||||
CItem VolItem;
|
||||
UInt32 NumDirClusters;
|
||||
CByteBuffer ByteBuf;
|
||||
UInt64 NumCurUsedBytes;
|
||||
|
||||
CDatabase(): Fat(0) {}
|
||||
~CDatabase() { ClearAndClose(); }
|
||||
|
||||
void Clear();
|
||||
void ClearAndClose();
|
||||
HRESULT OpenProgressFat(bool changeTotal = true);
|
||||
HRESULT OpenProgress();
|
||||
|
||||
UString GetItemPath(Int32 index) const;
|
||||
HRESULT Open();
|
||||
HRESULT ReadDir(Int32 parent, UInt32 cluster, int level);
|
||||
|
||||
UInt64 GetHeadersSize() const
|
||||
{
|
||||
return (UInt64)(Header.DataSector + (NumDirClusters << Header.SectorsPerClusterLog)) << Header.SectorSizeLog;
|
||||
}
|
||||
HRESULT SeekToSector(UInt32 sector);
|
||||
HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); }
|
||||
};
|
||||
|
||||
HRESULT CDatabase::SeekToSector(UInt32 sector)
|
||||
{
|
||||
return InStream->Seek((UInt64)sector << Header.SectorSizeLog, STREAM_SEEK_SET, NULL);
|
||||
}
|
||||
|
||||
void CDatabase::Clear()
|
||||
{
|
||||
VolItemDefined = false;
|
||||
NumDirClusters = 0;
|
||||
NumCurUsedBytes = 0;
|
||||
|
||||
Items.Clear();
|
||||
delete []Fat;
|
||||
Fat = 0;
|
||||
}
|
||||
|
||||
void CDatabase::ClearAndClose()
|
||||
{
|
||||
Clear();
|
||||
InStream.Release();
|
||||
}
|
||||
|
||||
HRESULT CDatabase::OpenProgressFat(bool changeTotal)
|
||||
{
|
||||
if (!OpenCallback)
|
||||
return S_OK;
|
||||
if (changeTotal)
|
||||
{
|
||||
UInt64 numTotalBytes = (Header.CalcFatSizeInSectors() << Header.SectorSizeLog) +
|
||||
((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog);
|
||||
RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes));
|
||||
}
|
||||
return OpenCallback->SetCompleted(NULL, &NumCurUsedBytes);
|
||||
}
|
||||
|
||||
HRESULT CDatabase::OpenProgress()
|
||||
{
|
||||
if (!OpenCallback)
|
||||
return S_OK;
|
||||
UInt64 numItems = Items.Size();
|
||||
return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes);
|
||||
}
|
||||
|
||||
UString CDatabase::GetItemPath(Int32 index) const
|
||||
{
|
||||
const CItem *item = &Items[index];
|
||||
UString name = item->GetName();
|
||||
for (;;)
|
||||
{
|
||||
index = item->Parent;
|
||||
if (index < 0)
|
||||
return name;
|
||||
item = &Items[index];
|
||||
name = item->GetName() + WCHAR_PATH_SEPARATOR + name;
|
||||
}
|
||||
}
|
||||
|
||||
static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, int numChars)
|
||||
{
|
||||
for (int i = 0; i < numChars; i++)
|
||||
{
|
||||
wchar_t c = Get16(p + i * 2);
|
||||
if (c != 0 && c != 0xFFFF)
|
||||
*dest++ = c;
|
||||
}
|
||||
*dest = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level)
|
||||
{
|
||||
int startIndex = Items.Size();
|
||||
if (startIndex >= (1 << 30) || level > 256)
|
||||
return S_FALSE;
|
||||
|
||||
UInt32 sectorIndex = 0;
|
||||
UInt32 blockSize = Header.ClusterSize();
|
||||
bool clusterMode = (Header.IsFat32() || parent >= 0);
|
||||
if (!clusterMode)
|
||||
{
|
||||
blockSize = Header.SectorSize();
|
||||
RINOK(SeekToSector(Header.RootDirSector));
|
||||
}
|
||||
|
||||
ByteBuf.SetCapacity(blockSize);
|
||||
UString curName;
|
||||
int checkSum = -1;
|
||||
int numLongRecords = -1;
|
||||
for (UInt32 pos = blockSize;; pos += 32)
|
||||
{
|
||||
if (pos == blockSize)
|
||||
{
|
||||
pos = 0;
|
||||
|
||||
if ((NumDirClusters & 0xFF) == 0)
|
||||
{
|
||||
RINOK(OpenProgress());
|
||||
}
|
||||
|
||||
if (clusterMode)
|
||||
{
|
||||
if (Header.IsEoc(cluster))
|
||||
break;
|
||||
if (!Header.IsValidCluster(cluster))
|
||||
return S_FALSE;
|
||||
PRF(printf("\nCluster = %4X", cluster));
|
||||
RINOK(SeekToCluster(cluster));
|
||||
UInt32 newCluster = Fat[cluster];
|
||||
if ((newCluster & kFatItemUsedByDirMask) != 0)
|
||||
return S_FALSE;
|
||||
Fat[cluster] |= kFatItemUsedByDirMask;
|
||||
cluster = newCluster;
|
||||
NumDirClusters++;
|
||||
NumCurUsedBytes += Header.ClusterSize();
|
||||
}
|
||||
else if (sectorIndex++ >= Header.NumRootDirSectors)
|
||||
break;
|
||||
|
||||
RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize));
|
||||
}
|
||||
const Byte *p = ByteBuf + pos;
|
||||
if (p[0] == 0)
|
||||
{
|
||||
if (clusterMode && !Header.IsEoc(cluster))
|
||||
return S_FALSE;
|
||||
break;
|
||||
}
|
||||
if (p[0] == 0xE5)
|
||||
{
|
||||
if (numLongRecords > 0)
|
||||
return S_FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
Byte attrib = p[11];
|
||||
if ((attrib & 0x3F) == 0xF)
|
||||
{
|
||||
if (p[0] > 0x7F || Get16(p + 26) != 0)
|
||||
return S_FALSE;
|
||||
int longIndex = p[0] & 0x3F;
|
||||
if (longIndex == 0)
|
||||
return S_FALSE;
|
||||
bool isLast = (p[0] & 0x40) != 0;
|
||||
if (numLongRecords < 0)
|
||||
{
|
||||
if (!isLast)
|
||||
return S_FALSE;
|
||||
numLongRecords = longIndex;
|
||||
}
|
||||
else if (isLast || numLongRecords != longIndex)
|
||||
return S_FALSE;
|
||||
|
||||
numLongRecords--;
|
||||
|
||||
if (p[12] == 0)
|
||||
{
|
||||
wchar_t nameBuf[14];
|
||||
wchar_t *dest;
|
||||
|
||||
dest = AddSubStringToName(nameBuf, p + 1, 5);
|
||||
dest = AddSubStringToName(dest, p + 14, 6);
|
||||
AddSubStringToName(dest, p + 28, 2);
|
||||
curName = nameBuf + curName;
|
||||
if (isLast)
|
||||
checkSum = p[13];
|
||||
if (checkSum != p[13])
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numLongRecords > 0)
|
||||
return S_FALSE;
|
||||
CItem item;
|
||||
memcpy(item.DosName, p, 11);
|
||||
|
||||
if (checkSum >= 0)
|
||||
{
|
||||
Byte sum = 0;
|
||||
for (int i = 0; i < 11; i++)
|
||||
sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i];
|
||||
if (sum == checkSum)
|
||||
item.UName = curName;
|
||||
}
|
||||
|
||||
if (item.DosName[0] == 5)
|
||||
item.DosName[0] = (char)(Byte)0xE5;
|
||||
item.Attrib = attrib;
|
||||
item.Flags = p[12];
|
||||
item.Size = Get32(p + 28);
|
||||
item.Cluster = Get16(p + 26) | ((UInt32)Get16(p + 20) << 16);
|
||||
item.CTime = Get32(p + 14);
|
||||
item.CTime2 = p[13];
|
||||
item.ADate = Get16(p + 18);
|
||||
item.MTime = Get32(p + 22);
|
||||
item.Parent = parent;
|
||||
|
||||
if (attrib == 8)
|
||||
{
|
||||
VolItem = item;
|
||||
VolItemDefined = true;
|
||||
}
|
||||
else
|
||||
if (memcmp(item.DosName, ". ", 11) != 0 &&
|
||||
memcmp(item.DosName, ".. ", 11) != 0)
|
||||
{
|
||||
if (!item.IsDir())
|
||||
NumCurUsedBytes += Header.GetFilePackSize(item.Size);
|
||||
Items.Add(item);
|
||||
PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1)));
|
||||
}
|
||||
numLongRecords = -1;
|
||||
curName.Empty();
|
||||
checkSum = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int finishIndex = Items.Size();
|
||||
for (int i = startIndex; i < finishIndex; i++)
|
||||
{
|
||||
const CItem &item = Items[i];
|
||||
if (item.IsDir())
|
||||
{
|
||||
PRF(printf("\n%S", GetItemPath(i)));
|
||||
RINOK(CDatabase::ReadDir(i, item.Cluster, level + 1));
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CDatabase::Open()
|
||||
{
|
||||
Clear();
|
||||
bool numFreeClustersDefined = false;
|
||||
{
|
||||
static const UInt32 kHeaderSize = 512;
|
||||
Byte buf[kHeaderSize];
|
||||
RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize));
|
||||
if (!Header.Parse(buf))
|
||||
return S_FALSE;
|
||||
UInt64 fileSize;
|
||||
RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize));
|
||||
if (fileSize < Header.GetPhySize())
|
||||
return S_FALSE;
|
||||
|
||||
if (Header.IsFat32())
|
||||
{
|
||||
SeekToSector(Header.FsInfoSector);
|
||||
RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize));
|
||||
if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
|
||||
return S_FALSE;
|
||||
if (Get32(buf) == 0x41615252 && Get32(buf + 484) == 0x61417272)
|
||||
{
|
||||
NumFreeClusters = Get32(buf + 488);
|
||||
numFreeClustersDefined = (NumFreeClusters <= Header.FatSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// numFreeClustersDefined = false; // to recalculate NumFreeClusters
|
||||
if (!numFreeClustersDefined)
|
||||
NumFreeClusters = 0;
|
||||
|
||||
CByteBuffer byteBuf;
|
||||
Fat = new UInt32[Header.FatSize];
|
||||
|
||||
RINOK(OpenProgressFat());
|
||||
RINOK(SeekToSector(Header.GetFatSector()));
|
||||
if (Header.NumFatBits == 32)
|
||||
{
|
||||
const UInt32 kBufSize = (1 << 15);
|
||||
byteBuf.SetCapacity(kBufSize);
|
||||
for (UInt32 i = 0; i < Header.FatSize;)
|
||||
{
|
||||
UInt32 size = Header.FatSize - i;
|
||||
const UInt32 kBufSize32 = kBufSize / 4;
|
||||
if (size > kBufSize32)
|
||||
size = kBufSize32;
|
||||
UInt32 readSize = Header.SizeToSectors(size * 4) << Header.SectorSizeLog;
|
||||
RINOK(ReadStream_FALSE(InStream, byteBuf, readSize));
|
||||
NumCurUsedBytes += readSize;
|
||||
|
||||
const UInt32 *src = (const UInt32 *)(const Byte *)byteBuf;
|
||||
UInt32 *dest = Fat + i;
|
||||
if (numFreeClustersDefined)
|
||||
for (UInt32 j = 0; j < size; j++)
|
||||
dest[j] = Get32(src + j) & 0x0FFFFFFF;
|
||||
else
|
||||
{
|
||||
UInt32 numFreeClusters = 0;
|
||||
for (UInt32 j = 0; j < size; j++)
|
||||
{
|
||||
UInt32 v = Get32(src + j) & 0x0FFFFFFF;
|
||||
numFreeClusters += (UInt32)(v - 1) >> 31;
|
||||
dest[j] = v;
|
||||
}
|
||||
NumFreeClusters += numFreeClusters;
|
||||
}
|
||||
i += size;
|
||||
if ((i & 0xFFFFF) == 0)
|
||||
{
|
||||
RINOK(OpenProgressFat(!numFreeClustersDefined));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const UInt32 kBufSize = (UInt32)Header.CalcFatSizeInSectors() << Header.SectorSizeLog;
|
||||
NumCurUsedBytes += kBufSize;
|
||||
byteBuf.SetCapacity(kBufSize);
|
||||
Byte *p = byteBuf;
|
||||
RINOK(ReadStream_FALSE(InStream, p, kBufSize));
|
||||
UInt32 fatSize = Header.FatSize;
|
||||
UInt32 *fat = &Fat[0];
|
||||
if (Header.NumFatBits == 16)
|
||||
for (UInt32 j = 0; j < fatSize; j++)
|
||||
fat[j] = Get16(p + j * 2);
|
||||
else
|
||||
for (UInt32 j = 0; j < fatSize; j++)
|
||||
fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF;
|
||||
|
||||
if (!numFreeClustersDefined)
|
||||
{
|
||||
UInt32 numFreeClusters = 0;
|
||||
for (UInt32 i = 0; i < fatSize; i++)
|
||||
numFreeClusters += (UInt32)(fat[i] - 1) >> 31;
|
||||
NumFreeClusters = numFreeClusters;
|
||||
}
|
||||
}
|
||||
|
||||
RINOK(OpenProgressFat());
|
||||
|
||||
if ((Fat[0] & 0xFF) != Header.MediaType)
|
||||
return S_FALSE;
|
||||
|
||||
return ReadDir(-1, Header.RootCluster, 0);
|
||||
}
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp,
|
||||
CDatabase
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
||||
INTERFACE_IInArchive(;)
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
};
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
*stream = 0;
|
||||
const CItem &item = Items[index];
|
||||
CClusterInStream *streamSpec = new CClusterInStream;
|
||||
CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
|
||||
streamSpec->Stream = InStream;
|
||||
streamSpec->StartOffset = Header.DataSector << Header.SectorSizeLog;
|
||||
streamSpec->BlockSizeLog = Header.ClusterSizeLog;
|
||||
streamSpec->Size = item.Size;
|
||||
|
||||
UInt32 numClusters = Header.GetNumClusters(item.Size);
|
||||
streamSpec->Vector.Reserve(numClusters);
|
||||
UInt32 cluster = item.Cluster;
|
||||
UInt32 size = item.Size;
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
if (cluster != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 clusterSize = Header.ClusterSize();
|
||||
for (;; size -= clusterSize)
|
||||
{
|
||||
if (!Header.IsValidCluster(cluster))
|
||||
return S_FALSE;
|
||||
streamSpec->Vector.Add(cluster - 2);
|
||||
cluster = Fat[cluster];
|
||||
if (size <= clusterSize)
|
||||
break;
|
||||
}
|
||||
if (!Header.IsEocAndUnused(cluster))
|
||||
return S_FALSE;
|
||||
}
|
||||
RINOK(streamSpec->InitAndSeek());
|
||||
*stream = streamTemp.Detach();
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidMTime, VT_FILETIME},
|
||||
{ NULL, kpidCTime, VT_FILETIME},
|
||||
{ NULL, kpidATime, VT_FILETIME},
|
||||
{ NULL, kpidAttrib, VT_UI8},
|
||||
{ NULL, kpidShortName, VT_BSTR}
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kpidNumFats = kpidUserDefined
|
||||
// kpidOemName,
|
||||
// kpidVolName,
|
||||
// kpidFileSysType
|
||||
};
|
||||
|
||||
STATPROPSTG kArcProps[] =
|
||||
{
|
||||
{ NULL, kpidFileSystem, VT_BSTR},
|
||||
{ NULL, kpidClusterSize, VT_UI4},
|
||||
{ NULL, kpidPhySize, VT_UI8},
|
||||
{ NULL, kpidFreeSpace, VT_UI8},
|
||||
{ NULL, kpidHeadersSize, VT_UI8},
|
||||
{ NULL, kpidMTime, VT_FILETIME},
|
||||
{ NULL, kpidVolumeName, VT_BSTR},
|
||||
|
||||
{ L"FATs", kpidNumFats, VT_UI4},
|
||||
{ NULL, kpidSectorSize, VT_UI4},
|
||||
{ NULL, kpidId, VT_UI4},
|
||||
// { L"OEM Name", kpidOemName, VT_BSTR},
|
||||
// { L"Volume Name", kpidVolName, VT_BSTR},
|
||||
// { L"File System Type", kpidFileSysType, VT_BSTR}
|
||||
// { NULL, kpidSectorsPerTrack, VT_UI4},
|
||||
// { NULL, kpidNumHeads, VT_UI4},
|
||||
// { NULL, kpidHiddenSectors, VT_UI4}
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_WITH_NAME
|
||||
|
||||
static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop)
|
||||
{
|
||||
FILETIME localFileTime, utc;
|
||||
if (NWindows::NTime::DosTimeToFileTime(dosTime, localFileTime))
|
||||
if (LocalFileTimeToFileTime(&localFileTime, &utc))
|
||||
{
|
||||
UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime;
|
||||
t64 += ms10 * 100000;
|
||||
utc.dwLowDateTime = (DWORD)t64;
|
||||
utc.dwHighDateTime = (DWORD)(t64 >> 32);
|
||||
prop = utc;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static void StringToProp(const Byte *src, int size, NWindows::NCOM::CPropVariant &prop)
|
||||
{
|
||||
char dest[32];
|
||||
memcpy(dest, src, size);
|
||||
dest[size] = 0;
|
||||
prop = FatStringToUnicode(dest);
|
||||
}
|
||||
|
||||
#define STRING_TO_PROP(s, p) StringToProp(s, sizeof(s), prop)
|
||||
*/
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
switch(propID)
|
||||
{
|
||||
case kpidFileSystem:
|
||||
{
|
||||
wchar_t s[32] = { L'F', L'A', L'T' };
|
||||
ConvertUInt32ToString(Header.NumFatBits, s + 3);
|
||||
prop = s;
|
||||
break;
|
||||
}
|
||||
case kpidClusterSize: prop = Header.ClusterSize(); break;
|
||||
case kpidPhySize: prop = Header.GetPhySize(); break;
|
||||
case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break;
|
||||
case kpidHeadersSize: prop = GetHeadersSize(); break;
|
||||
case kpidMTime: if (VolItemDefined) FatTimeToProp(VolItem.MTime, 0, prop); break;
|
||||
case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break;
|
||||
case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break;
|
||||
case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break;
|
||||
// case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break;
|
||||
// case kpidNumHeads: prop = Header.NumHeads; break;
|
||||
// case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break;
|
||||
case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break;
|
||||
// case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break;
|
||||
// case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break;
|
||||
// case kpidHiddenSectors: prop = Header.NumHiddenSectors; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
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 = GetItemPath(index); break;
|
||||
case kpidShortName: prop = item.GetShortName(); break;
|
||||
case kpidIsDir: prop = item.IsDir(); break;
|
||||
case kpidMTime: FatTimeToProp(item.MTime, 0, prop); break;
|
||||
case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break;
|
||||
case kpidATime: FatTimeToProp(((UInt32)item.ADate << 16), 0, prop); break;
|
||||
case kpidAttrib: prop = (UInt32)item.Attrib; break;
|
||||
case kpidSize: if (!item.IsDir()) prop = item.Size; break;
|
||||
case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
{
|
||||
OpenCallback = callback;
|
||||
InStream = stream;
|
||||
HRESULT res;
|
||||
try
|
||||
{
|
||||
res = CDatabase::Open();
|
||||
if (res == S_OK)
|
||||
return S_OK;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Close();
|
||||
throw;
|
||||
}
|
||||
Close();
|
||||
return res;
|
||||
}
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
ClearAndClose();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool testMode = (_aTestMode != 0);
|
||||
bool allFilesMode = (numItems == UInt32(-1));
|
||||
if (allFilesMode)
|
||||
numItems = Items.Size();
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
UInt32 i;
|
||||
UInt64 totalSize = 0;
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
const CItem &item = Items[allFilesMode ? i : indices[i]];
|
||||
if (!item.IsDir())
|
||||
totalSize += item.Size;
|
||||
}
|
||||
RINOK(extractCallback->SetTotal(totalSize));
|
||||
|
||||
UInt64 totalPackSize;
|
||||
totalSize = totalPackSize = 0;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
CDummyOutStream *outStreamSpec = new CDummyOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
lps->InSize = totalPackSize;
|
||||
lps->OutSize = totalSize;
|
||||
RINOK(lps->SetCur());
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode = testMode ?
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
const CItem &item = Items[index];
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
|
||||
if (item.IsDir())
|
||||
{
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
|
||||
totalPackSize += Header.GetFilePackSize(item.Size);
|
||||
totalSize += item.Size;
|
||||
|
||||
if (!testMode && (!realOutStream))
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
realOutStream.Release();
|
||||
outStreamSpec->Init();
|
||||
|
||||
int res = NArchive::NExtract::NOperationResult::kDataError;
|
||||
CMyComPtr<ISequentialInStream> inStream;
|
||||
HRESULT hres = GetStream(index, &inStream);
|
||||
if (hres != S_FALSE)
|
||||
{
|
||||
RINOK(hres);
|
||||
if (inStream)
|
||||
{
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
if (copyCoderSpec->TotalSize == item.Size)
|
||||
res = NArchive::NExtract::NOperationResult::kOK;
|
||||
}
|
||||
}
|
||||
outStreamSpec->ReleaseStream();
|
||||
RINOK(extractCallback->SetOperationResult(res));
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = Items.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static IInArchive *CreateArc() { return new CHandler; }
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"FAT", L"fat img", 0, 0xDA, { 0x55, 0xAA }, 2, false, CreateArc, 0 };
|
||||
|
||||
REGISTER_ARC(Fat)
|
||||
|
||||
}}
|
||||
@@ -1,284 +0,0 @@
|
||||
// GZipHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "GZipHandler.h"
|
||||
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/ComTry.h"
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/Time.h"
|
||||
|
||||
#include "../../ICoder.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "../Common/OutStreamWithCRC.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGZip {
|
||||
|
||||
static const CMethodId kMethodId_Deflate = 0x040108;
|
||||
|
||||
const wchar_t *kHostOS[] =
|
||||
{
|
||||
L"FAT",
|
||||
L"AMIGA",
|
||||
L"VMS",
|
||||
L"Unix",
|
||||
L"VM_CMS",
|
||||
L"Atari", // what if it's a minix filesystem? [cjh]
|
||||
L"HPFS", // filesystem used by OS/2 (and NT 3.x)
|
||||
L"Mac",
|
||||
L"Z_System",
|
||||
L"CPM",
|
||||
L"TOPS20", // pkzip 2.50 NTFS
|
||||
L"NTFS", // filesystem used by Windows NT
|
||||
L"QDOS ", // SMS/QDOS
|
||||
L"Acorn", // Archimedes Acorn RISC OS
|
||||
L"VFAT", // filesystem used by Windows 95, NT
|
||||
L"MVS",
|
||||
L"BeOS", // hybrid POSIX/database filesystem
|
||||
// BeBOX or PowerMac
|
||||
L"Tandem",
|
||||
L"THEOS"
|
||||
};
|
||||
|
||||
static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
|
||||
|
||||
static const wchar_t *kUnknownOS = L"Unknown";
|
||||
|
||||
/*
|
||||
enum // PropID
|
||||
{
|
||||
kpidExtraIsPresent = kpidUserDefined,
|
||||
kpidExtraFlags,
|
||||
kpidIsText
|
||||
};
|
||||
*/
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidMTime, VT_FILETIME},
|
||||
// { NULL, kpidMethod, VT_UI1},
|
||||
{ NULL, kpidHostOS, VT_BSTR},
|
||||
{ NULL, kpidCRC, VT_UI4}
|
||||
// { L"Extra", kpidExtraIsPresent, VT_BOOL}
|
||||
// { L"Extra flags", kpidExtraFlags, VT_UI1},
|
||||
// { L"Is Text", kpidIsText, VT_BOOL},
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = 1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath:
|
||||
if (m_Item.NameIsPresent())
|
||||
prop = MultiByteToUnicodeString(m_Item.Name, CP_ACP);
|
||||
break;
|
||||
case kpidMTime:
|
||||
{
|
||||
FILETIME utcTime;
|
||||
if (m_Item.Time != 0)
|
||||
{
|
||||
NTime::UnixTimeToFileTime((UInt32)m_Item.Time, utcTime);
|
||||
prop = utcTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// utcTime.dwLowDateTime = utcTime.dwHighDateTime = 0;
|
||||
// prop = utcTime;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kpidSize: prop = UInt64(m_Item.UnPackSize32); break;
|
||||
case kpidPackSize: prop = m_PackSize; break;
|
||||
case kpidCommented: prop = m_Item.CommentIsPresent(); break;
|
||||
case kpidHostOS:
|
||||
prop = (m_Item.HostOS < kNumHostOSes) ?
|
||||
kHostOS[m_Item.HostOS] : kUnknownOS;
|
||||
break;
|
||||
case kpidMethod: prop = m_Item.CompressionMethod; break;
|
||||
case kpidCRC: prop = m_Item.FileCRC; break;
|
||||
/*
|
||||
case kpidExtraFlags: prop = m_Item.ExtraFlags; break;
|
||||
case kpidIsText: prop = m_Item.IsText(); break;
|
||||
case kpidExtraIsPresent: prop = m_Item.ExtraFieldIsPresent(); break;
|
||||
*/
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
const UInt64 * /* maxCheckStartPosition */,
|
||||
IArchiveOpenCallback * /* openArchiveCallback */)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
try
|
||||
{
|
||||
CInArchive archive;
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition));
|
||||
RINOK(archive.ReadHeader(inStream, m_Item));
|
||||
m_DataOffset = archive.GetOffset();
|
||||
UInt64 newPosition;
|
||||
RINOK(inStream->Seek(-8, STREAM_SEEK_END, &newPosition));
|
||||
m_PackSize = newPosition - (m_StreamStartPosition + m_DataOffset);
|
||||
if (archive.ReadPostHeader(inStream, m_Item) != S_OK)
|
||||
return S_FALSE;
|
||||
m_Stream = inStream;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
m_Stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == UInt32(-1));
|
||||
if (!allFilesMode)
|
||||
{
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
if (numItems != 1)
|
||||
return E_INVALIDARG;
|
||||
if (indices[0] != 0)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
bool testMode = (_aTestMode != 0);
|
||||
|
||||
extractCallback->SetTotal(m_PackSize);
|
||||
|
||||
UInt64 currentTotalPacked = 0;
|
||||
|
||||
RINOK(extractCallback->SetCompleted(¤tTotalPacked));
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode;
|
||||
askMode = testMode ? NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
|
||||
RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
|
||||
|
||||
if(!testMode && !realOutStream)
|
||||
return S_OK;
|
||||
|
||||
extractCallback->PrepareOperation(askMode);
|
||||
|
||||
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
outStreamSpec->Init();
|
||||
realOutStream.Release();
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, true);
|
||||
|
||||
CMyComPtr<ICompressCoder> deflateDecoder;
|
||||
bool firstItem = true;
|
||||
RINOK(m_Stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL));
|
||||
Int32 opRes;
|
||||
for (;;)
|
||||
{
|
||||
lps->InSize = currentTotalPacked;
|
||||
lps->OutSize = outStreamSpec->GetSize();
|
||||
|
||||
CInArchive archive;
|
||||
CItem item;
|
||||
HRESULT result = archive.ReadHeader(m_Stream, item);
|
||||
if (result != S_OK)
|
||||
{
|
||||
if (firstItem)
|
||||
return E_FAIL;
|
||||
opRes = NArchive::NExtract::NOperationResult::kOK;
|
||||
break;
|
||||
}
|
||||
firstItem = false;
|
||||
|
||||
UInt64 dataStartPos;
|
||||
RINOK(m_Stream->Seek(0, STREAM_SEEK_CUR, &dataStartPos));
|
||||
|
||||
outStreamSpec->InitCRC();
|
||||
|
||||
if (item.CompressionMethod != NFileHeader::NCompressionMethod::kDeflate)
|
||||
{
|
||||
opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!deflateDecoder)
|
||||
{
|
||||
RINOK(CreateCoder(
|
||||
EXTERNAL_CODECS_VARS
|
||||
kMethodId_Deflate, deflateDecoder, false));
|
||||
if (!deflateDecoder)
|
||||
{
|
||||
opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = deflateDecoder->Code(m_Stream, outStream, NULL, NULL, progress);
|
||||
if (result != S_OK)
|
||||
{
|
||||
if (result != S_FALSE)
|
||||
return result;
|
||||
opRes = NArchive::NExtract::NOperationResult::kDataError;
|
||||
break;
|
||||
}
|
||||
|
||||
CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize;
|
||||
RINOK(deflateDecoder.QueryInterface(IID_ICompressGetInStreamProcessedSize,
|
||||
&getInStreamProcessedSize));
|
||||
UInt64 packSize;
|
||||
RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&packSize));
|
||||
UInt64 pos;
|
||||
RINOK(m_Stream->Seek(dataStartPos + packSize, STREAM_SEEK_SET, &pos));
|
||||
|
||||
currentTotalPacked = pos - m_StreamStartPosition;
|
||||
|
||||
CItem postItem;
|
||||
if (archive.ReadPostHeader(m_Stream, postItem) != S_OK)
|
||||
return E_FAIL;
|
||||
if((outStreamSpec->GetCRC() != postItem.FileCRC))
|
||||
{
|
||||
opRes = NArchive::NExtract::NOperationResult::kCRCError;
|
||||
break;
|
||||
}
|
||||
}
|
||||
outStream.Release();
|
||||
return extractCallback->SetOperationResult(opRes);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
IMPL_ISetCompressCodecsInfo
|
||||
|
||||
}}
|
||||
@@ -1,63 +0,0 @@
|
||||
// GZip/Handler.h
|
||||
|
||||
#ifndef __GZIP_HANDLER_H
|
||||
#define __GZIP_HANDLER_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
#include "GZipIn.h"
|
||||
#include "GZipUpdate.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGZip {
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IOutArchive,
|
||||
public ISetProperties,
|
||||
PUBLIC_ISetCompressCodecsInfo
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_QUERYINTERFACE_BEGIN2(IInArchive)
|
||||
MY_QUERYINTERFACE_ENTRY(IOutArchive)
|
||||
MY_QUERYINTERFACE_ENTRY(ISetProperties)
|
||||
QUERY_ENTRY_ISetCompressCodecsInfo
|
||||
MY_QUERYINTERFACE_END
|
||||
MY_ADDREF_RELEASE
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
INTERFACE_IOutArchive(;)
|
||||
|
||||
STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties);
|
||||
|
||||
DECL_ISetCompressCodecsInfo
|
||||
|
||||
CHandler() { InitMethodProperties(); }
|
||||
|
||||
private:
|
||||
NArchive::NGZip::CItem m_Item;
|
||||
UInt64 m_StreamStartPosition;
|
||||
UInt64 m_DataOffset;
|
||||
UInt64 m_PackSize;
|
||||
CMyComPtr<IInStream> m_Stream;
|
||||
CCompressionMethodMode m_Method;
|
||||
UInt32 m_Level;
|
||||
|
||||
DECL_EXTERNAL_CODECS_VARS
|
||||
|
||||
void InitMethodProperties()
|
||||
{
|
||||
m_Method.NumMatchFinderCyclesDefined = false;
|
||||
m_Level = m_Method.NumPasses = m_Method.NumFastBytes =
|
||||
m_Method.NumMatchFinderCycles = m_Method.Algo = 0xFFFFFFFF;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,202 +0,0 @@
|
||||
// GZipHandlerOut.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/StringToInt.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/Time.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
#include "../Common/ParseProperties.h"
|
||||
|
||||
#include "GZipHandler.h"
|
||||
#include "GZipUpdate.h"
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NTime;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGZip {
|
||||
|
||||
static const UInt32 kAlgoX1 = 0;
|
||||
static const UInt32 kAlgoX5 = 1;
|
||||
|
||||
static const UInt32 kNumPassesX1 = 1;
|
||||
static const UInt32 kNumPassesX7 = 3;
|
||||
static const UInt32 kNumPassesX9 = 10;
|
||||
|
||||
static const UInt32 kNumFastBytesX1 = 32;
|
||||
static const UInt32 kNumFastBytesX7 = 64;
|
||||
static const UInt32 kNumFastBytesX9 = 128;
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
|
||||
{
|
||||
*timeType = NFileTimeType::kUnix;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT CopyStreams(ISequentialInStream *inStream, ISequentialOutStream *outStream)
|
||||
{
|
||||
CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
|
||||
return copyCoder->Code(inStream, outStream, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
if (numItems != 1)
|
||||
return E_INVALIDARG;
|
||||
|
||||
UInt64 size;
|
||||
Int32 newData;
|
||||
Int32 newProperties;
|
||||
UInt32 indexInArchive;
|
||||
UInt32 itemIndex = 0;
|
||||
if (!updateCallback)
|
||||
return E_FAIL;
|
||||
RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProperties, &indexInArchive));
|
||||
|
||||
CItem newItem = m_Item;
|
||||
newItem.ExtraFlags = 0;
|
||||
newItem.Flags = 0;
|
||||
if (IntToBool(newProperties))
|
||||
{
|
||||
FILETIME utcTime;
|
||||
UString name;
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(itemIndex, kpidMTime, &prop));
|
||||
if (prop.vt != VT_FILETIME)
|
||||
return E_INVALIDARG;
|
||||
utcTime = prop.filetime;
|
||||
}
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(itemIndex, kpidPath, &prop));
|
||||
if (prop.vt == VT_EMPTY)
|
||||
name.Empty();
|
||||
else if (prop.vt != VT_BSTR)
|
||||
return E_INVALIDARG;
|
||||
else
|
||||
name = prop.bstrVal;
|
||||
}
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(itemIndex, kpidIsDir, &prop));
|
||||
if (prop.vt == VT_BOOL)
|
||||
{
|
||||
if (prop.boolVal != VARIANT_FALSE)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if(!FileTimeToUnixTime(utcTime, newItem.Time))
|
||||
return E_INVALIDARG;
|
||||
newItem.Name = UnicodeStringToMultiByte(name, CP_ACP);
|
||||
int dirDelimiterPos = newItem.Name.ReverseFind(CHAR_PATH_SEPARATOR);
|
||||
if (dirDelimiterPos >= 0)
|
||||
newItem.Name = newItem.Name.Mid(dirDelimiterPos + 1);
|
||||
|
||||
newItem.SetNameIsPresentFlag(!newItem.Name.IsEmpty());
|
||||
}
|
||||
|
||||
if (IntToBool(newData))
|
||||
{
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(itemIndex, kpidSize, &prop));
|
||||
if (prop.vt != VT_UI8)
|
||||
return E_INVALIDARG;
|
||||
size = prop.uhVal.QuadPart;
|
||||
}
|
||||
newItem.UnPackSize32 = (UInt32)size;
|
||||
|
||||
UInt32 level = m_Level;
|
||||
if (level == 0xFFFFFFFF)
|
||||
level = 5;
|
||||
if (m_Method.NumPasses == 0xFFFFFFFF)
|
||||
m_Method.NumPasses = (level >= 9 ? kNumPassesX9 :
|
||||
(level >= 7 ? kNumPassesX7 :
|
||||
kNumPassesX1));
|
||||
if (m_Method.NumFastBytes == 0xFFFFFFFF)
|
||||
m_Method.NumFastBytes = (level >= 9 ? kNumFastBytesX9 :
|
||||
(level >= 7 ? kNumFastBytesX7 :
|
||||
kNumFastBytesX1));
|
||||
if (m_Method.Algo == 0xFFFFFFFF)
|
||||
m_Method.Algo =
|
||||
(level >= 5 ? kAlgoX5 :
|
||||
kAlgoX1);
|
||||
|
||||
return UpdateArchive(
|
||||
EXTERNAL_CODECS_VARS
|
||||
m_Stream, size, outStream, newItem, m_Method, itemIndex, updateCallback);
|
||||
}
|
||||
|
||||
if (indexInArchive != 0)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (IntToBool(newProperties))
|
||||
{
|
||||
COutArchive outArchive;
|
||||
outArchive.Create(outStream);
|
||||
outArchive.WriteHeader(newItem);
|
||||
RINOK(m_Stream->Seek(m_StreamStartPosition + m_DataOffset, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(m_Stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
return CopyStreams(m_Stream, outStream);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
|
||||
{
|
||||
InitMethodProperties();
|
||||
for (int i = 0; i < numProperties; i++)
|
||||
{
|
||||
UString name = names[i];
|
||||
name.MakeUpper();
|
||||
const PROPVARIANT &prop = values[i];
|
||||
if (name[0] == L'X')
|
||||
{
|
||||
UInt32 level = 9;
|
||||
RINOK(ParsePropValue(name.Mid(1), prop, level));
|
||||
m_Level = level;
|
||||
}
|
||||
else if (name.Left(4) == L"PASS")
|
||||
{
|
||||
UInt32 num = kNumPassesX9;
|
||||
RINOK(ParsePropValue(name.Mid(4), prop, num));
|
||||
m_Method.NumPasses = num;
|
||||
}
|
||||
else if (name.Left(2) == L"FB")
|
||||
{
|
||||
UInt32 num = kNumFastBytesX9;
|
||||
RINOK(ParsePropValue(name.Mid(2), prop, num));
|
||||
m_Method.NumFastBytes = num;
|
||||
}
|
||||
else if (name.Left(2) == L"MC")
|
||||
{
|
||||
UInt32 num = 0xFFFFFFFF;
|
||||
RINOK(ParsePropValue(name.Mid(2), prop, num));
|
||||
m_Method.NumMatchFinderCycles = num;
|
||||
m_Method.NumMatchFinderCyclesDefined = true;
|
||||
}
|
||||
else if (name.Left(1) == L"A")
|
||||
{
|
||||
UInt32 num = kAlgoX5;
|
||||
RINOK(ParsePropValue(name.Mid(1), prop, num));
|
||||
m_Method.Algo = num;
|
||||
}
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Archive/GZip/Header.h
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "GZipHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGZip {
|
||||
|
||||
extern UInt16 kSignature = 0x8B1F + 1;
|
||||
|
||||
static class CMarkersInitializer
|
||||
{
|
||||
public:
|
||||
CMarkersInitializer()
|
||||
{ kSignature--; }
|
||||
} g_MarkerInitializer;
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
// Archive/GZip/Header.h
|
||||
|
||||
#ifndef __ARCHIVE_GZIP_HEADER_H
|
||||
#define __ARCHIVE_GZIP_HEADER_H
|
||||
|
||||
#include "Common/Types.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGZip {
|
||||
|
||||
extern UInt16 kSignature;
|
||||
static const UInt32 kSignatureSize = 2;
|
||||
|
||||
namespace NFileHeader
|
||||
{
|
||||
/*
|
||||
struct CBlock
|
||||
{
|
||||
UInt16 Id;
|
||||
Byte CompressionMethod;
|
||||
Byte Flags;
|
||||
UInt32 Time;
|
||||
Byte ExtraFlags;
|
||||
Byte HostOS;
|
||||
};
|
||||
*/
|
||||
|
||||
namespace NFlags
|
||||
{
|
||||
const int kDataIsText = 1 << 0;
|
||||
const int kHeaderCRCIsPresent = 1 << 1;
|
||||
const int kExtraIsPresent = 1 << 2;
|
||||
const int kNameIsPresent = 1 << 3;
|
||||
const int kComentIsPresent = 1 << 4;
|
||||
}
|
||||
|
||||
namespace NExtraFlags
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kMaximum = 2,
|
||||
kFastest = 4
|
||||
};
|
||||
}
|
||||
|
||||
namespace NCompressionMethod
|
||||
{
|
||||
const Byte kDeflate = 8;
|
||||
}
|
||||
|
||||
namespace NHostOS
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kFAT = 0, // filesystem used by MS-DOS, OS/2, Win32
|
||||
// pkzip 2.50 (FAT / VFAT / FAT32 file systems)
|
||||
kAMIGA = 1,
|
||||
kVMS = 2, // VAX/VMS
|
||||
kUnix = 3,
|
||||
kVM_CMS = 4,
|
||||
kAtari = 5, // what if it's a minix filesystem? [cjh]
|
||||
kHPFS = 6, // filesystem used by OS/2 (and NT 3.x)
|
||||
kMac = 7,
|
||||
kZ_System = 8,
|
||||
kCPM = 9,
|
||||
kTOPS20 = 10, // pkzip 2.50 NTFS
|
||||
kNTFS = 11, // filesystem used by Windows NT
|
||||
kQDOS = 12, // SMS/QDOS
|
||||
kAcorn = 13, // Archimedes Acorn RISC OS
|
||||
kVFAT = 14, // filesystem used by Windows 95, NT
|
||||
kMVS = 15,
|
||||
kBeOS = 16, // hybrid POSIX/database filesystem
|
||||
// BeBOX or PowerMac
|
||||
kTandem = 17,
|
||||
kTHEOS = 18,
|
||||
|
||||
kUnknown = 255
|
||||
};
|
||||
const int kNumHostSystems = 19;
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,119 +0,0 @@
|
||||
// Archive/GZipIn.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "GZipIn.h"
|
||||
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/MyCom.h"
|
||||
#include "Windows/Defs.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../../../../C/7zCrc.h"
|
||||
}
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGZip {
|
||||
|
||||
HRESULT CInArchive::ReadBytes(ISequentialInStream *inStream, void *data, UInt32 size)
|
||||
{
|
||||
RINOK(ReadStream_FALSE(inStream, data, size));
|
||||
m_Position += size;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::ReadByte(ISequentialInStream *inStream, Byte &value, UInt32 &crc)
|
||||
{
|
||||
RINOK(ReadBytes(inStream, &value, 1));
|
||||
crc = CRC_UPDATE_BYTE(crc, value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::ReadUInt16(ISequentialInStream *inStream, UInt16 &value, UInt32 &crc)
|
||||
{
|
||||
value = 0;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Byte b;
|
||||
RINOK(ReadByte(inStream, b, crc));
|
||||
value |= (UInt16(b) << (8 * i));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::ReadUInt32(ISequentialInStream *inStream, UInt32 &value, UInt32 &crc)
|
||||
{
|
||||
value = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Byte b;
|
||||
RINOK(ReadByte(inStream, b, crc));
|
||||
value |= (UInt32(b) << (8 * i));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::ReadZeroTerminatedString(ISequentialInStream *inStream, AString &resString, UInt32 &crc)
|
||||
{
|
||||
resString.Empty();
|
||||
for (;;)
|
||||
{
|
||||
Byte c;
|
||||
RINOK(ReadByte(inStream, c, crc));
|
||||
if (c == 0)
|
||||
return S_OK;
|
||||
resString += char(c);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CInArchive::ReadHeader(ISequentialInStream *inStream, CItem &item)
|
||||
{
|
||||
item.Clear();
|
||||
m_Position = 0;
|
||||
|
||||
UInt16 signature;
|
||||
UInt32 crc = CRC_INIT_VAL;;
|
||||
RINOK(ReadUInt16(inStream, signature, crc));
|
||||
if (signature != kSignature)
|
||||
return S_FALSE;
|
||||
|
||||
RINOK(ReadByte(inStream, item.CompressionMethod, crc));
|
||||
RINOK(ReadByte(inStream, item.Flags, crc));
|
||||
RINOK(ReadUInt32(inStream, item.Time, crc));
|
||||
RINOK(ReadByte(inStream, item.ExtraFlags, crc));
|
||||
RINOK(ReadByte(inStream, item.HostOS, crc));
|
||||
|
||||
if (item.ExtraFieldIsPresent())
|
||||
{
|
||||
UInt16 extraSize;
|
||||
RINOK(ReadUInt16(inStream, extraSize, crc));
|
||||
item.Extra.SetCapacity(extraSize);
|
||||
RINOK(ReadBytes(inStream, item.Extra, extraSize));
|
||||
crc = CrcUpdate(crc, item.Extra, extraSize);
|
||||
}
|
||||
if (item.NameIsPresent())
|
||||
RINOK(ReadZeroTerminatedString(inStream, item.Name, crc));
|
||||
if (item.CommentIsPresent())
|
||||
RINOK(ReadZeroTerminatedString(inStream, item.Comment, crc));
|
||||
if (item.HeaderCRCIsPresent())
|
||||
{
|
||||
UInt16 headerCRC;
|
||||
UInt32 dummy = 0;
|
||||
RINOK(ReadUInt16(inStream, headerCRC, dummy));
|
||||
if ((UInt16)CRC_GET_DIGEST(crc) != headerCRC)
|
||||
return S_FALSE;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::ReadPostHeader(ISequentialInStream *inStream, CItem &item)
|
||||
{
|
||||
UInt32 dummy = 0;
|
||||
RINOK(ReadUInt32(inStream, item.FileCRC, dummy));
|
||||
return ReadUInt32(inStream, item.UnPackSize32, dummy);
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Archive/GZipIn.h
|
||||
|
||||
#ifndef __ARCHIVE_GZIP_IN_H
|
||||
#define __ARCHIVE_GZIP_IN_H
|
||||
|
||||
#include "GZipHeader.h"
|
||||
#include "GZipItem.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGZip {
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
UInt64 m_Position;
|
||||
|
||||
HRESULT ReadBytes(ISequentialInStream *inStream, void *data, UInt32 size);
|
||||
HRESULT ReadZeroTerminatedString(ISequentialInStream *inStream, AString &resString, UInt32 &crc);
|
||||
HRESULT ReadByte(ISequentialInStream *inStream, Byte &value, UInt32 &crc);
|
||||
HRESULT ReadUInt16(ISequentialInStream *inStream, UInt16 &value, UInt32 &crc);
|
||||
HRESULT ReadUInt32(ISequentialInStream *inStream, UInt32 &value, UInt32 &crc);
|
||||
public:
|
||||
HRESULT ReadHeader(ISequentialInStream *inStream, CItem &item);
|
||||
HRESULT ReadPostHeader(ISequentialInStream *inStream, CItem &item);
|
||||
UInt64 GetOffset() const { return m_Position; }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,59 +0,0 @@
|
||||
// Archive/GZipItem.h
|
||||
|
||||
#ifndef __ARCHIVE_GZIP_ITEM_H
|
||||
#define __ARCHIVE_GZIP_ITEM_H
|
||||
|
||||
#include "Common/Types.h"
|
||||
#include "Common/MyString.h"
|
||||
#include "Common/Buffer.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGZip {
|
||||
|
||||
class CItem
|
||||
{
|
||||
private:
|
||||
bool TestFlag(Byte flag) const { return ((Flags & flag) != 0); }
|
||||
public:
|
||||
Byte CompressionMethod;
|
||||
Byte Flags;
|
||||
UInt32 Time;
|
||||
Byte ExtraFlags;
|
||||
Byte HostOS;
|
||||
UInt32 FileCRC;
|
||||
UInt32 UnPackSize32;
|
||||
|
||||
AString Name;
|
||||
AString Comment;
|
||||
CByteBuffer Extra;
|
||||
|
||||
bool IsText() const
|
||||
{ return TestFlag(NFileHeader::NFlags::kDataIsText); }
|
||||
bool HeaderCRCIsPresent() const
|
||||
{ return TestFlag(NFileHeader::NFlags::kHeaderCRCIsPresent); }
|
||||
bool ExtraFieldIsPresent() const
|
||||
{ return TestFlag(NFileHeader::NFlags::kExtraIsPresent); }
|
||||
bool NameIsPresent() const
|
||||
{ return TestFlag(NFileHeader::NFlags::kNameIsPresent); }
|
||||
bool CommentIsPresent() const
|
||||
{ return TestFlag(NFileHeader::NFlags::kComentIsPresent); }
|
||||
|
||||
void SetNameIsPresentFlag(bool nameIsPresent)
|
||||
{
|
||||
if (nameIsPresent)
|
||||
Flags |= NFileHeader::NFlags::kNameIsPresent;
|
||||
else
|
||||
Flags &= (~NFileHeader::NFlags::kNameIsPresent);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
Name.Empty();
|
||||
Comment.Empty();;
|
||||
Extra.SetCapacity(0);
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,65 +0,0 @@
|
||||
// Archive/GZipOut.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "GZipOut.h"
|
||||
|
||||
#include "Windows/Defs.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGZip {
|
||||
|
||||
HRESULT COutArchive::WriteBytes(const void *buffer, UInt32 size)
|
||||
{
|
||||
return WriteStream(m_Stream, buffer, size);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteByte(Byte value)
|
||||
{
|
||||
return WriteBytes(&value, 1);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteUInt16(UInt16 value)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
RINOK(WriteByte((Byte)value));
|
||||
value >>= 8;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteUInt32(UInt32 value)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
RINOK(WriteByte((Byte)value));
|
||||
value >>= 8;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteHeader(const CItem &item)
|
||||
{
|
||||
RINOK(WriteUInt16(kSignature));
|
||||
RINOK(WriteByte(item.CompressionMethod));
|
||||
RINOK(WriteByte((Byte)(item.Flags & NFileHeader::NFlags::kNameIsPresent)));
|
||||
RINOK(WriteUInt32(item.Time));
|
||||
RINOK(WriteByte(item.ExtraFlags));
|
||||
RINOK(WriteByte(item.HostOS));
|
||||
if (item.NameIsPresent())
|
||||
{
|
||||
RINOK(WriteBytes((const char *)item.Name, item.Name.Length()));
|
||||
RINOK(WriteByte(0));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WritePostHeader(const CItem &item)
|
||||
{
|
||||
RINOK(WriteUInt32(item.FileCRC));
|
||||
return WriteUInt32(item.UnPackSize32);
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Archive/GZipOut.h
|
||||
|
||||
#ifndef __ARCHIVE_GZIP_OUT_H
|
||||
#define __ARCHIVE_GZIP_OUT_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "GZipHeader.h"
|
||||
#include "GZipItem.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGZip {
|
||||
|
||||
class COutArchive
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> m_Stream;
|
||||
HRESULT WriteBytes(const void *buffer, UInt32 size);
|
||||
HRESULT WriteByte(Byte value);
|
||||
HRESULT WriteUInt16(UInt16 value);
|
||||
HRESULT WriteUInt32(UInt32 value);
|
||||
public:
|
||||
void Create(ISequentialOutStream *outStream) { m_Stream = outStream; }
|
||||
HRESULT WriteHeader(const CItem &item);
|
||||
HRESULT WritePostHeader(const CItem &item);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,18 +0,0 @@
|
||||
// GZipRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "GZipHandler.h"
|
||||
static IInArchive *CreateArc() { return new NArchive::NGZip::CHandler; }
|
||||
#ifndef EXTRACT_ONLY
|
||||
static IOutArchive *CreateArcOut() { return new NArchive::NGZip::CHandler; }
|
||||
#else
|
||||
#define CreateArcOut 0
|
||||
#endif
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"GZip", L"gz gzip tgz tpz", L"* * .tar .tar", 0xEF, { 0x1F, 0x8B, 8 }, 3, true, CreateArc, CreateArcOut };
|
||||
|
||||
REGISTER_ARC(GZip)
|
||||
@@ -1,112 +0,0 @@
|
||||
// GZipUpdate.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/StringConvert.h"
|
||||
|
||||
#include "Windows/Defs.h"
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
#include "../../ICoder.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
#include "../Common/InStreamWithCRC.h"
|
||||
|
||||
#include "GZipUpdate.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGZip {
|
||||
|
||||
static const CMethodId kMethodId_Deflate = 0x040108;
|
||||
|
||||
static const Byte kHostOS =
|
||||
#ifdef _WIN32
|
||||
NFileHeader::NHostOS::kFAT;
|
||||
#else
|
||||
NFileHeader::NHostOS::kUnix;
|
||||
#endif
|
||||
|
||||
HRESULT UpdateArchive(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
IInStream * /* inStream */,
|
||||
UInt64 unpackSize,
|
||||
ISequentialOutStream *outStream,
|
||||
const CItem &newItem,
|
||||
const CCompressionMethodMode &compressionMethod,
|
||||
int indexInClient,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
UInt64 complexity = unpackSize;
|
||||
|
||||
RINOK(updateCallback->SetTotal(complexity));
|
||||
|
||||
CMyComPtr<ICompressCoder> deflateEncoder;
|
||||
|
||||
complexity = 0;
|
||||
RINOK(updateCallback->SetCompleted(&complexity));
|
||||
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
|
||||
RINOK(updateCallback->GetStream(indexInClient, &fileInStream));
|
||||
|
||||
CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC;
|
||||
CMyComPtr<ISequentialInStream> crcStream(inStreamSpec);
|
||||
inStreamSpec->SetStream(fileInStream);
|
||||
inStreamSpec->Init();
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(updateCallback, true);
|
||||
|
||||
COutArchive outArchive;
|
||||
outArchive.Create(outStream);
|
||||
|
||||
CItem item = newItem;
|
||||
item.CompressionMethod = NFileHeader::NCompressionMethod::kDeflate;
|
||||
item.ExtraFlags = 0;
|
||||
item.HostOS = kHostOS;
|
||||
|
||||
RINOK(outArchive.WriteHeader(item));
|
||||
|
||||
{
|
||||
RINOK(CreateCoder(
|
||||
EXTERNAL_CODECS_LOC_VARS
|
||||
kMethodId_Deflate, deflateEncoder, true));
|
||||
if (!deflateEncoder)
|
||||
return E_NOTIMPL;
|
||||
|
||||
NWindows::NCOM::CPropVariant properties[] =
|
||||
{
|
||||
compressionMethod.Algo,
|
||||
compressionMethod.NumPasses,
|
||||
compressionMethod.NumFastBytes,
|
||||
compressionMethod.NumMatchFinderCycles
|
||||
};
|
||||
PROPID propIDs[] =
|
||||
{
|
||||
NCoderPropID::kAlgorithm,
|
||||
NCoderPropID::kNumPasses,
|
||||
NCoderPropID::kNumFastBytes,
|
||||
NCoderPropID::kMatchFinderCycles
|
||||
};
|
||||
int numProps = sizeof(propIDs) / sizeof(propIDs[0]);
|
||||
if (!compressionMethod.NumMatchFinderCyclesDefined)
|
||||
numProps--;
|
||||
CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
|
||||
RINOK(deflateEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties));
|
||||
RINOK(setCoderProperties->SetCoderProperties(propIDs, properties, numProps));
|
||||
}
|
||||
RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress));
|
||||
|
||||
item.FileCRC = inStreamSpec->GetCRC();
|
||||
item.UnPackSize32 = (UInt32)inStreamSpec->GetSize();
|
||||
RINOK(outArchive.WritePostHeader(item));
|
||||
return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,37 +0,0 @@
|
||||
// GZip/Update.h
|
||||
|
||||
#ifndef __GZIP_UPDATE_H
|
||||
#define __GZIP_UPDATE_H
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
#include "GZipOut.h"
|
||||
#include "GZipItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGZip {
|
||||
|
||||
struct CCompressionMethodMode
|
||||
{
|
||||
UInt32 NumPasses;
|
||||
UInt32 NumFastBytes;
|
||||
UInt32 Algo;
|
||||
bool NumMatchFinderCyclesDefined;
|
||||
UInt32 NumMatchFinderCycles;
|
||||
};
|
||||
|
||||
HRESULT UpdateArchive(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
IInStream *inStream,
|
||||
UInt64 unpackSize,
|
||||
ISequentialOutStream *outStream,
|
||||
const CItem &newItem,
|
||||
const CCompressionMethodMode &compressionMethod,
|
||||
int indexInClient,
|
||||
IArchiveUpdateCallback *updateCallback);
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,8 +0,0 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/MyWindows.h"
|
||||
|
||||
#endif
|
||||
Executable
+820
@@ -0,0 +1,820 @@
|
||||
// GzHandler.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/ProgressUtils.h"
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "../Compress/CopyCoder.h"
|
||||
#include "../Compress/DeflateDecoder.h"
|
||||
#include "../Compress/DeflateEncoder.h"
|
||||
|
||||
#include "Common/InStreamWithCRC.h"
|
||||
#include "Common/OutStreamWithCRC.h"
|
||||
#include "Common/ParseProperties.h"
|
||||
|
||||
#define Get32(p) GetUi32(p)
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NGz {
|
||||
|
||||
static const UInt16 kSignature = 0x8B1F;
|
||||
|
||||
namespace NHeader
|
||||
{
|
||||
namespace NFlags
|
||||
{
|
||||
const Byte kIsText = 1 << 0;
|
||||
const Byte kCrc = 1 << 1;
|
||||
const Byte kExtra = 1 << 2;
|
||||
const Byte kName = 1 << 3;
|
||||
const Byte kComment = 1 << 4;
|
||||
}
|
||||
|
||||
namespace NExtraFlags
|
||||
{
|
||||
const Byte kMaximum = 2;
|
||||
const Byte kFastest = 4;
|
||||
}
|
||||
|
||||
namespace NCompressionMethod
|
||||
{
|
||||
const Byte kDeflate = 8;
|
||||
}
|
||||
|
||||
namespace NHostOS
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kFAT = 0,
|
||||
kAMIGA,
|
||||
kVMS,
|
||||
kUnix,
|
||||
kVM_CMS,
|
||||
kAtari,
|
||||
kHPFS,
|
||||
kMac,
|
||||
kZ_System,
|
||||
kCPM,
|
||||
kTOPS20,
|
||||
kNTFS,
|
||||
kQDOS,
|
||||
kAcorn,
|
||||
kVFAT,
|
||||
kMVS,
|
||||
kBeOS,
|
||||
kTandem,
|
||||
|
||||
kUnknown = 255
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static const char *kHostOSes[] =
|
||||
{
|
||||
"FAT",
|
||||
"AMIGA",
|
||||
"VMS",
|
||||
"Unix",
|
||||
"VM/CMS",
|
||||
"Atari",
|
||||
"HPFS",
|
||||
"Macintosh",
|
||||
"Z-System",
|
||||
"CP/M",
|
||||
"TOPS-20",
|
||||
"NTFS",
|
||||
"SMS/QDOS",
|
||||
"Acorn",
|
||||
"VFAT",
|
||||
"MVS",
|
||||
"BeOS",
|
||||
"Tandem",
|
||||
"OS/400",
|
||||
"OS/X"
|
||||
};
|
||||
|
||||
static const char *kUnknownOS = "Unknown";
|
||||
|
||||
class CItem
|
||||
{
|
||||
bool TestFlag(Byte flag) const { return (Flags & flag) != 0; }
|
||||
public:
|
||||
Byte Method;
|
||||
Byte Flags;
|
||||
Byte ExtraFlags;
|
||||
Byte HostOS;
|
||||
UInt32 Time;
|
||||
UInt32 Crc;
|
||||
UInt32 Size32;
|
||||
|
||||
AString Name;
|
||||
AString Comment;
|
||||
// CByteBuffer Extra;
|
||||
|
||||
// bool IsText() const { return TestFlag(NHeader::NFlags::kIsText); }
|
||||
bool HeaderCrcIsPresent() const { return TestFlag(NHeader::NFlags::kCrc); }
|
||||
bool ExtraFieldIsPresent() const { return TestFlag(NHeader::NFlags::kExtra); }
|
||||
bool NameIsPresent() const { return TestFlag(NHeader::NFlags::kName); }
|
||||
bool CommentIsPresent() const { return TestFlag(NHeader::NFlags::kComment); }
|
||||
|
||||
void Clear()
|
||||
{
|
||||
Name.Empty();
|
||||
Comment.Empty();
|
||||
// Extra.SetCapacity(0);
|
||||
}
|
||||
|
||||
HRESULT ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream);
|
||||
HRESULT ReadFooter1(NCompress::NDeflate::NDecoder::CCOMCoder *stream);
|
||||
HRESULT ReadFooter2(ISequentialInStream *stream);
|
||||
|
||||
HRESULT WriteHeader(ISequentialOutStream *stream);
|
||||
HRESULT WriteFooter(ISequentialOutStream *stream);
|
||||
};
|
||||
|
||||
static HRESULT ReadBytes(NCompress::NDeflate::NDecoder::CCOMCoder *stream, Byte *data, UInt32 size)
|
||||
{
|
||||
for (UInt32 i = 0; i < size; i++)
|
||||
data[i] = stream->ReadByte();
|
||||
return stream->InputEofError() ? S_FALSE : S_OK;
|
||||
}
|
||||
|
||||
static HRESULT SkipBytes(NCompress::NDeflate::NDecoder::CCOMCoder *stream, UInt32 size)
|
||||
{
|
||||
for (UInt32 i = 0; i < size; i++)
|
||||
stream->ReadByte();
|
||||
return stream->InputEofError() ? S_FALSE : S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ReadUInt16(NCompress::NDeflate::NDecoder::CCOMCoder *stream, UInt16 &value /* , UInt32 &crc */)
|
||||
{
|
||||
value = 0;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Byte b = stream->ReadByte();
|
||||
if (stream->InputEofError())
|
||||
return S_FALSE;
|
||||
// crc = CRC_UPDATE_BYTE(crc, b);
|
||||
value |= (UInt16(b) << (8 * i));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ReadString(NCompress::NDeflate::NDecoder::CCOMCoder *stream, AString &s, UInt32 limit /* , UInt32 &crc */)
|
||||
{
|
||||
s.Empty();
|
||||
for (UInt32 i = 0; i < limit; i++)
|
||||
{
|
||||
Byte b = stream->ReadByte();
|
||||
if (stream->InputEofError())
|
||||
return S_FALSE;
|
||||
// crc = CRC_UPDATE_BYTE(crc, b);
|
||||
if (b == 0)
|
||||
return S_OK;
|
||||
s += (char)b;
|
||||
}
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT CItem::ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream)
|
||||
{
|
||||
Clear();
|
||||
|
||||
// Header-CRC field had another meaning in old version of gzip!
|
||||
// UInt32 crc = CRC_INIT_VAL;
|
||||
Byte buf[10];
|
||||
|
||||
RINOK(ReadBytes(stream, buf, 10));
|
||||
|
||||
if (GetUi16(buf) != kSignature)
|
||||
return S_FALSE;
|
||||
|
||||
Method = buf[2];
|
||||
|
||||
if (Method != NHeader::NCompressionMethod::kDeflate)
|
||||
return S_FALSE;
|
||||
|
||||
Flags = buf[3];
|
||||
Time = Get32(buf + 4);
|
||||
ExtraFlags = buf[8];
|
||||
HostOS = buf[9];
|
||||
|
||||
// crc = CrcUpdate(crc, buf, 10);
|
||||
|
||||
if (ExtraFieldIsPresent())
|
||||
{
|
||||
UInt16 extraSize;
|
||||
RINOK(ReadUInt16(stream, extraSize /* , crc */));
|
||||
RINOK(SkipBytes(stream, extraSize));
|
||||
// Extra.SetCapacity(extraSize);
|
||||
// RINOK(ReadStream_FALSE(stream, Extra, extraSize));
|
||||
// crc = CrcUpdate(crc, Extra, extraSize);
|
||||
}
|
||||
if (NameIsPresent())
|
||||
RINOK(ReadString(stream, Name, (1 << 10) /* , crc */));
|
||||
if (CommentIsPresent())
|
||||
RINOK(ReadString(stream, Comment, (1 << 16) /* , crc */));
|
||||
|
||||
if (HeaderCrcIsPresent())
|
||||
{
|
||||
UInt16 headerCRC;
|
||||
// UInt32 dummy = 0;
|
||||
RINOK(ReadUInt16(stream, headerCRC /* , dummy */));
|
||||
/*
|
||||
if ((UInt16)CRC_GET_DIGEST(crc) != headerCRC)
|
||||
return S_FALSE;
|
||||
*/
|
||||
}
|
||||
return stream->InputEofError() ? S_FALSE : S_OK;
|
||||
}
|
||||
|
||||
HRESULT CItem::ReadFooter1(NCompress::NDeflate::NDecoder::CCOMCoder *stream)
|
||||
{
|
||||
Byte buf[8];
|
||||
RINOK(ReadBytes(stream, buf, 8));
|
||||
Crc = Get32(buf);
|
||||
Size32 = Get32(buf + 4);
|
||||
return stream->InputEofError() ? S_FALSE : S_OK;
|
||||
}
|
||||
|
||||
HRESULT CItem::ReadFooter2(ISequentialInStream *stream)
|
||||
{
|
||||
Byte buf[8];
|
||||
RINOK(ReadStream_FALSE(stream, buf, 8));
|
||||
Crc = Get32(buf);
|
||||
Size32 = Get32(buf + 4);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CItem::WriteHeader(ISequentialOutStream *stream)
|
||||
{
|
||||
Byte buf[10];
|
||||
SetUi16(buf, kSignature);
|
||||
buf[2] = Method;
|
||||
buf[3] = Flags & NHeader::NFlags::kName;
|
||||
// buf[3] |= NHeader::NFlags::kCrc;
|
||||
SetUi32(buf + 4, Time);
|
||||
buf[8] = ExtraFlags;
|
||||
buf[9] = HostOS;
|
||||
RINOK(WriteStream(stream, buf, 10));
|
||||
// crc = CrcUpdate(CRC_INIT_VAL, buf, 10);
|
||||
if (NameIsPresent())
|
||||
{
|
||||
// crc = CrcUpdate(crc, (const char *)Name, Name.Length() + 1);
|
||||
RINOK(WriteStream(stream, (const char *)Name, Name.Length() + 1));
|
||||
}
|
||||
// SetUi16(buf, (UInt16)CRC_GET_DIGEST(crc));
|
||||
// RINOK(WriteStream(stream, buf, 2));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CItem::WriteFooter(ISequentialOutStream *stream)
|
||||
{
|
||||
Byte buf[8];
|
||||
SetUi32(buf, Crc);
|
||||
SetUi32(buf + 4, Size32);
|
||||
return WriteStream(stream, buf, 8);
|
||||
}
|
||||
|
||||
static const UInt32 kAlgoX1 = 0;
|
||||
static const UInt32 kAlgoX5 = 1;
|
||||
|
||||
static const UInt32 kNumPassesX1 = 1;
|
||||
static const UInt32 kNumPassesX7 = 3;
|
||||
static const UInt32 kNumPassesX9 = 10;
|
||||
|
||||
static const UInt32 kNumFastBytesX1 = 32;
|
||||
static const UInt32 kNumFastBytesX7 = 64;
|
||||
static const UInt32 kNumFastBytesX9 = 128;
|
||||
|
||||
struct CCompressMode
|
||||
{
|
||||
UInt32 NumPasses;
|
||||
UInt32 NumFastBytes;
|
||||
UInt32 Algo;
|
||||
UInt32 Mc;
|
||||
bool McDefined;
|
||||
|
||||
bool IsMaximum() const { return Algo > 0; }
|
||||
|
||||
void Init()
|
||||
{
|
||||
NumPasses = NumFastBytes = Mc = Algo = 0xFFFFFFFF;
|
||||
McDefined = false;
|
||||
}
|
||||
|
||||
void Normalize(UInt32 level)
|
||||
{
|
||||
if (level == 0xFFFFFFFF)
|
||||
level = 5;
|
||||
if (NumPasses == 0xFFFFFFFF)
|
||||
NumPasses =
|
||||
(level >= 9 ? kNumPassesX9 :
|
||||
(level >= 7 ? kNumPassesX7 :
|
||||
kNumPassesX1));
|
||||
if (NumFastBytes == 0xFFFFFFFF)
|
||||
NumFastBytes =
|
||||
(level >= 9 ? kNumFastBytesX9 :
|
||||
(level >= 7 ? kNumFastBytesX7 :
|
||||
kNumFastBytesX1));
|
||||
if (Algo == 0xFFFFFFFF)
|
||||
Algo = (level >= 5 ?
|
||||
kAlgoX5 :
|
||||
kAlgoX1);
|
||||
}
|
||||
};
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IArchiveOpenSeq,
|
||||
public IOutArchive,
|
||||
public ISetProperties,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CItem _item;
|
||||
UInt64 _startPosition;
|
||||
UInt64 _headerSize;
|
||||
UInt64 _packSize;
|
||||
bool _packSizeDefined;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CMyComPtr<ICompressCoder> _decoder;
|
||||
NCompress::NDeflate::NDecoder::CCOMCoder *_decoderSpec;
|
||||
|
||||
CCompressMode _method;
|
||||
UInt32 _level;
|
||||
|
||||
void InitMethodProperties()
|
||||
{
|
||||
_level = 0xFFFFFFFF;
|
||||
_method.Init();
|
||||
}
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties)
|
||||
INTERFACE_IInArchive(;)
|
||||
INTERFACE_IOutArchive(;)
|
||||
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
|
||||
STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps);
|
||||
|
||||
CHandler()
|
||||
{
|
||||
InitMethodProperties();
|
||||
_decoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
|
||||
_decoder = _decoderSpec;
|
||||
}
|
||||
};
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidMTime, VT_FILETIME},
|
||||
{ NULL, kpidHostOS, VT_BSTR},
|
||||
{ NULL, kpidCRC, VT_UI4}
|
||||
// { NULL, kpidComment, VT_BSTR}
|
||||
}
|
||||
;
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO_Table
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPhySize: if (_packSizeDefined) prop = _packSize; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = 1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath:
|
||||
if (_item.NameIsPresent())
|
||||
prop = MultiByteToUnicodeString(_item.Name, CP_ACP);
|
||||
break;
|
||||
// case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break;
|
||||
case kpidMTime:
|
||||
{
|
||||
if (_item.Time != 0)
|
||||
{
|
||||
FILETIME utc;
|
||||
NTime::UnixTimeToFileTime(_item.Time, utc);
|
||||
prop = utc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kpidSize: if (_stream) prop = (UInt64)_item.Size32; break;
|
||||
case kpidPackSize: if (_packSizeDefined) prop = _packSize; break;
|
||||
case kpidHostOS: prop = (_item.HostOS < sizeof(kHostOSes) / sizeof(kHostOSes[0])) ?
|
||||
kHostOSes[_item.HostOS] : kUnknownOS; break;
|
||||
case kpidCRC: if (_stream) prop = _item.Crc; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
HRESULT res;
|
||||
try
|
||||
{
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPosition));
|
||||
res = OpenSeq(stream);
|
||||
if (res == S_OK)
|
||||
{
|
||||
UInt64 endPos;
|
||||
res = stream->Seek(-8, STREAM_SEEK_END, &endPos);
|
||||
_packSize = endPos + 8 - _startPosition;
|
||||
_packSizeDefined = true;
|
||||
if (res == S_OK)
|
||||
{
|
||||
res = _item.ReadFooter2(stream);
|
||||
_stream = stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...) { res = S_FALSE; }
|
||||
if (res != S_OK)
|
||||
Close();
|
||||
return res;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
HRESULT res;
|
||||
try
|
||||
{
|
||||
Close();
|
||||
_decoderSpec->SetInStream(stream);
|
||||
_decoderSpec->InitInStream(true);
|
||||
res = _item.ReadHeader(_decoderSpec);
|
||||
_headerSize = _decoderSpec->GetInputProcessedSize();
|
||||
}
|
||||
catch(...) { res = S_FALSE; }
|
||||
if (res != S_OK)
|
||||
Close();
|
||||
return res;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_packSizeDefined = false;
|
||||
_stream.Release();
|
||||
_decoderSpec->ReleaseInStream();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == (UInt32)-1);
|
||||
if (!allFilesMode)
|
||||
{
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
if (numItems != 1 || indices[0] != 0)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
bool testMode = (_aTestMode != 0);
|
||||
if (_stream)
|
||||
extractCallback->SetTotal(_packSize);
|
||||
UInt64 currentTotalPacked = 0;
|
||||
RINOK(extractCallback->SetCompleted(¤tTotalPacked));
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode = testMode ?
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
|
||||
if (!testMode && !realOutStream)
|
||||
return S_OK;
|
||||
|
||||
extractCallback->PrepareOperation(askMode);
|
||||
|
||||
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
outStreamSpec->Init();
|
||||
realOutStream.Release();
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, true);
|
||||
|
||||
if (_stream)
|
||||
{
|
||||
RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL));
|
||||
_decoderSpec->InitInStream(true);
|
||||
}
|
||||
bool firstItem = true;
|
||||
Int32 opRes;
|
||||
for (;;)
|
||||
{
|
||||
lps->InSize = _packSize = _decoderSpec->GetInputProcessedSize();
|
||||
_packSizeDefined = true;
|
||||
lps->OutSize = outStreamSpec->GetSize();
|
||||
RINOK(lps->SetCur());
|
||||
|
||||
CItem item;
|
||||
if (!firstItem || _stream)
|
||||
{
|
||||
HRESULT result = item.ReadHeader(_decoderSpec);
|
||||
if (result != S_OK)
|
||||
{
|
||||
if (result != S_FALSE)
|
||||
return result;
|
||||
opRes = firstItem ?
|
||||
NArchive::NExtract::NOperationResult::kDataError :
|
||||
NArchive::NExtract::NOperationResult::kOK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
firstItem = false;
|
||||
|
||||
UInt64 startOffset = outStreamSpec->GetSize();
|
||||
outStreamSpec->InitCRC();
|
||||
|
||||
HRESULT result = _decoderSpec->CodeResume(outStream, NULL, progress);
|
||||
if (result != S_OK)
|
||||
{
|
||||
if (result != S_FALSE)
|
||||
return result;
|
||||
opRes = NArchive::NExtract::NOperationResult::kDataError;
|
||||
break;
|
||||
}
|
||||
|
||||
_decoderSpec->AlignToByte();
|
||||
if (item.ReadFooter1(_decoderSpec) != S_OK)
|
||||
{
|
||||
opRes = NArchive::NExtract::NOperationResult::kDataError;
|
||||
break;
|
||||
}
|
||||
if (item.Crc != outStreamSpec->GetCRC() ||
|
||||
item.Size32 != (UInt32)(outStreamSpec->GetSize() - startOffset))
|
||||
{
|
||||
opRes = NArchive::NExtract::NOperationResult::kCRCError;
|
||||
break;
|
||||
}
|
||||
}
|
||||
outStream.Release();
|
||||
return extractCallback->SetOperationResult(opRes);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
static const Byte kHostOS =
|
||||
#ifdef _WIN32
|
||||
NHeader::NHostOS::kFAT;
|
||||
#else
|
||||
NHeader::NHostOS::kUnix;
|
||||
#endif
|
||||
|
||||
static HRESULT UpdateArchive(
|
||||
ISequentialOutStream *outStream,
|
||||
UInt64 unpackSize,
|
||||
const CItem &newItem,
|
||||
const CCompressMode &compressionMode,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
UInt64 complexity = 0;
|
||||
RINOK(updateCallback->SetTotal(unpackSize));
|
||||
RINOK(updateCallback->SetCompleted(&complexity));
|
||||
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
|
||||
RINOK(updateCallback->GetStream(0, &fileInStream));
|
||||
|
||||
CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC;
|
||||
CMyComPtr<ISequentialInStream> crcStream(inStreamSpec);
|
||||
inStreamSpec->SetStream(fileInStream);
|
||||
inStreamSpec->Init();
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(updateCallback, true);
|
||||
|
||||
CItem item = newItem;
|
||||
item.Method = NHeader::NCompressionMethod::kDeflate;
|
||||
item.ExtraFlags = compressionMode.IsMaximum() ?
|
||||
NHeader::NExtraFlags::kMaximum :
|
||||
NHeader::NExtraFlags::kFastest;
|
||||
|
||||
item.HostOS = kHostOS;
|
||||
|
||||
RINOK(item.WriteHeader(outStream));
|
||||
|
||||
NCompress::NDeflate::NEncoder::CCOMCoder *deflateEncoderSpec = new NCompress::NDeflate::NEncoder::CCOMCoder;
|
||||
CMyComPtr<ICompressCoder> deflateEncoder = deflateEncoderSpec;
|
||||
{
|
||||
NWindows::NCOM::CPropVariant props[] =
|
||||
{
|
||||
compressionMode.Algo,
|
||||
compressionMode.NumPasses,
|
||||
compressionMode.NumFastBytes,
|
||||
compressionMode.Mc
|
||||
};
|
||||
PROPID propIDs[] =
|
||||
{
|
||||
NCoderPropID::kAlgorithm,
|
||||
NCoderPropID::kNumPasses,
|
||||
NCoderPropID::kNumFastBytes,
|
||||
NCoderPropID::kMatchFinderCycles
|
||||
};
|
||||
int numProps = sizeof(propIDs) / sizeof(propIDs[0]);
|
||||
if (!compressionMode.McDefined)
|
||||
numProps--;
|
||||
RINOK(deflateEncoderSpec->SetCoderProperties(propIDs, props, numProps));
|
||||
}
|
||||
RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress));
|
||||
|
||||
item.Crc = inStreamSpec->GetCRC();
|
||||
item.Size32 = (UInt32)inStreamSpec->GetSize();
|
||||
RINOK(item.WriteFooter(outStream));
|
||||
return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
|
||||
{
|
||||
*timeType = NFileTimeType::kUnix;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
if (numItems != 1)
|
||||
return E_INVALIDARG;
|
||||
|
||||
Int32 newData, newProps;
|
||||
UInt32 indexInArchive;
|
||||
if (!updateCallback)
|
||||
return E_FAIL;
|
||||
RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
|
||||
|
||||
CItem newItem = _item;
|
||||
newItem.ExtraFlags = 0;
|
||||
newItem.Flags = 0;
|
||||
if (IntToBool(newProps))
|
||||
{
|
||||
{
|
||||
FILETIME utcTime;
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(0, kpidMTime, &prop));
|
||||
if (prop.vt != VT_FILETIME)
|
||||
return E_INVALIDARG;
|
||||
utcTime = prop.filetime;
|
||||
if (!NTime::FileTimeToUnixTime(utcTime, newItem.Time))
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(0, kpidPath, &prop));
|
||||
if (prop.vt == VT_BSTR)
|
||||
{
|
||||
UString name = prop.bstrVal;
|
||||
int dirDelimiterPos = name.ReverseFind(CHAR_PATH_SEPARATOR);
|
||||
if (dirDelimiterPos >= 0)
|
||||
name = name.Mid(dirDelimiterPos + 1);
|
||||
newItem.Name = UnicodeStringToMultiByte(name, CP_ACP);
|
||||
if (!newItem.Name.IsEmpty())
|
||||
newItem.Flags |= NHeader::NFlags::kName;
|
||||
}
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
|
||||
if (prop.vt == VT_BOOL)
|
||||
{
|
||||
if (prop.boolVal != VARIANT_FALSE)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
if (IntToBool(newData))
|
||||
{
|
||||
UInt64 size;
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
|
||||
if (prop.vt != VT_UI8)
|
||||
return E_INVALIDARG;
|
||||
size = prop.uhVal.QuadPart;
|
||||
}
|
||||
|
||||
_method.Normalize(_level);
|
||||
return UpdateArchive(outStream, size, newItem, _method, updateCallback);
|
||||
}
|
||||
|
||||
if (indexInArchive != 0)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!_stream)
|
||||
return E_NOTIMPL;
|
||||
|
||||
UInt64 offset = _startPosition;
|
||||
if (IntToBool(newProps))
|
||||
{
|
||||
newItem.WriteHeader(outStream);
|
||||
offset += _headerSize;
|
||||
}
|
||||
RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL));
|
||||
return NCompress::CopyStream(_stream, outStream, NULL);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps)
|
||||
{
|
||||
InitMethodProperties();
|
||||
for (int i = 0; i < numProps; i++)
|
||||
{
|
||||
UString name = names[i];
|
||||
name.MakeUpper();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
const PROPVARIANT &prop = values[i];
|
||||
if (name[0] == L'X')
|
||||
{
|
||||
UInt32 level = 9;
|
||||
RINOK(ParsePropValue(name.Mid(1), prop, level));
|
||||
_level = level;
|
||||
}
|
||||
else if (name.Left(4) == L"PASS")
|
||||
{
|
||||
UInt32 num = kNumPassesX9;
|
||||
RINOK(ParsePropValue(name.Mid(4), prop, num));
|
||||
_method.NumPasses = num;
|
||||
}
|
||||
else if (name.Left(2) == L"FB")
|
||||
{
|
||||
UInt32 num = kNumFastBytesX9;
|
||||
RINOK(ParsePropValue(name.Mid(2), prop, num));
|
||||
_method.NumFastBytes = num;
|
||||
}
|
||||
else if (name.Left(2) == L"MC")
|
||||
{
|
||||
UInt32 num = 0xFFFFFFFF;
|
||||
RINOK(ParsePropValue(name.Mid(2), prop, num));
|
||||
_method.Mc = num;
|
||||
_method.McDefined = true;
|
||||
}
|
||||
else if (name.Left(1) == L"A")
|
||||
{
|
||||
UInt32 num = kAlgoX5;
|
||||
RINOK(ParsePropValue(name.Mid(1), prop, num));
|
||||
_method.Algo = num;
|
||||
}
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static IInArchive *CreateArc() { return new CHandler; }
|
||||
#ifndef EXTRACT_ONLY
|
||||
static IOutArchive *CreateArcOut() { return new CHandler; }
|
||||
#else
|
||||
#define CreateArcOut 0
|
||||
#endif
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"GZip", L"gz gzip tgz tpz", L"* * .tar .tar", 0xEF, { 0x1F, 0x8B, 8 }, 3, true, CreateArc, CreateArcOut };
|
||||
|
||||
REGISTER_ARC(GZip)
|
||||
|
||||
}}
|
||||
@@ -3,8 +3,8 @@
|
||||
#ifndef __IARCHIVE_H
|
||||
#define __IARCHIVE_H
|
||||
|
||||
#include "../IStream.h"
|
||||
#include "../IProgress.h"
|
||||
#include "../IStream.h"
|
||||
#include "../PropID.h"
|
||||
|
||||
#define ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 6, x)
|
||||
@@ -82,7 +82,6 @@ ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10)
|
||||
|
||||
#define INTERFACE_IArchiveExtractCallback(x) \
|
||||
INTERFACE_IProgress(x) \
|
||||
/* GetStream OUT: S_OK - OK, S_FALSE - skeep this file */ \
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \
|
||||
STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \
|
||||
STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) x; \
|
||||
@@ -139,6 +138,10 @@ ARCHIVE_INTERFACE(IInArchive, 0x60)
|
||||
INTERFACE_IInArchive(PURE)
|
||||
};
|
||||
|
||||
ARCHIVE_INTERFACE(IArchiveOpenSeq, 0x61)
|
||||
{
|
||||
STDMETHOD(OpenSeq)(ISequentialInStream *stream) PURE;
|
||||
};
|
||||
|
||||
#define INTERFACE_IArchiveUpdateCallback(x) \
|
||||
INTERFACE_IProgress(x); \
|
||||
@@ -217,11 +220,14 @@ ARCHIVE_INTERFACE(ISetProperties, 0x03)
|
||||
{ *numProperties = sizeof(kArcProps) / sizeof(kArcProps[0]); return S_OK; } \
|
||||
STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kArcProps)
|
||||
|
||||
#define IMP_IInArchive_ArcProps_NO \
|
||||
#define IMP_IInArchive_ArcProps_NO_Table \
|
||||
STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) \
|
||||
{ *numProperties = 0; return S_OK; } \
|
||||
STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *) \
|
||||
{ return E_NOTIMPL; } \
|
||||
|
||||
#define IMP_IInArchive_ArcProps_NO \
|
||||
IMP_IInArchive_ArcProps_NO_Table \
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value) \
|
||||
{ value->vt = VT_EMPTY; return S_OK; }
|
||||
|
||||
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
@@ -46,9 +46,9 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
Close();
|
||||
// try
|
||||
{
|
||||
if(_archive.Open(stream) != S_OK)
|
||||
if (_archive.Open(stream) != S_OK)
|
||||
return S_FALSE;
|
||||
_inStream = stream;
|
||||
_stream = stream;
|
||||
}
|
||||
// catch(...) { return S_FALSE; }
|
||||
return S_OK;
|
||||
@@ -58,7 +58,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_archive.Clear();
|
||||
_inStream.Release();
|
||||
_stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
bool allFilesMode = (numItems == UInt32(-1));
|
||||
if (allFilesMode)
|
||||
numItems = _archive.Refs.Size();
|
||||
if(numItems == 0)
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
UInt64 totalSize = 0;
|
||||
UInt32 i;
|
||||
@@ -192,7 +192,10 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
|
||||
CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(_inStream);
|
||||
streamSpec->SetStream(_stream);
|
||||
|
||||
CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
|
||||
for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
|
||||
{
|
||||
@@ -211,7 +214,7 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
{
|
||||
const CRef &ref = _archive.Refs[index];
|
||||
const CDir &item = ref.Dir->_subItems[ref.Index];
|
||||
if(item.IsDir())
|
||||
if (item.IsDir())
|
||||
{
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
@@ -231,16 +234,14 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
if (!testMode && (!realOutStream))
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
if (testMode)
|
||||
{
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
RINOK(_inStream->Seek(blockIndex * _archive.BlockSize, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(currentItemSize);
|
||||
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
realOutStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == currentItemSize) ?
|
||||
outStreamSpec->Init(currentItemSize);
|
||||
RINOK(_stream->Seek(blockIndex * _archive.BlockSize, STREAM_SEEK_SET, NULL));
|
||||
streamSpec->Init(currentItemSize);
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
outStreamSpec->ReleaseStream();
|
||||
RINOK(extractCallback->SetOperationResult(outStreamSpec->IsFinishedOK() ?
|
||||
NArchive::NExtract::NOperationResult::kOK:
|
||||
NArchive::NExtract::NOperationResult::kDataError));
|
||||
}
|
||||
@@ -248,4 +249,30 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
*stream = 0;
|
||||
UInt64 blockIndex;
|
||||
UInt64 currentItemSize;
|
||||
if (index < (UInt32)_archive.Refs.Size())
|
||||
{
|
||||
const CRef &ref = _archive.Refs[index];
|
||||
const CDir &item = ref.Dir->_subItems[ref.Index];
|
||||
if (item.IsDir())
|
||||
return S_FALSE;
|
||||
currentItemSize = item.DataLength;
|
||||
blockIndex = item.ExtentLocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
int bootIndex = index - _archive.Refs.Size();
|
||||
const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
|
||||
currentItemSize = _archive.GetBootItemSize(bootIndex);
|
||||
blockIndex = be.LoadRBA;
|
||||
}
|
||||
return CreateLimitedInStream(_stream, blockIndex * _archive.BlockSize, currentItemSize, stream);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Iso/Handler.h
|
||||
// IsoHandler.h
|
||||
|
||||
#ifndef __ISO_HANDLER_H
|
||||
#define __ISO_HANDLER_H
|
||||
@@ -6,26 +6,23 @@
|
||||
#include "Common/MyCom.h"
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "IsoItem.h"
|
||||
#include "IsoIn.h"
|
||||
#include "IsoItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NIso {
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IInArchiveGetStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(
|
||||
IInArchive
|
||||
)
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
|
||||
private:
|
||||
CMyComPtr<IInStream> _inStream;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CInArchive _archive;
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
|
||||
INTERFACE_IInArchive(;)
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "IsoIn.h"
|
||||
#include "IsoHeader.h"
|
||||
|
||||
#include "Windows/Defs.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
@@ -35,13 +32,13 @@ void CInArchive::ReadBytes(Byte *data, UInt32 size)
|
||||
data[i] = ReadByte();
|
||||
}
|
||||
|
||||
void CInArchive::Skeep(size_t size)
|
||||
void CInArchive::Skip(size_t size)
|
||||
{
|
||||
while (size-- != 0)
|
||||
ReadByte();
|
||||
}
|
||||
|
||||
void CInArchive::SkeepZeros(size_t size)
|
||||
void CInArchive::SkipZeros(size_t size)
|
||||
{
|
||||
while (size-- != 0)
|
||||
{
|
||||
@@ -174,8 +171,8 @@ void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len)
|
||||
ReadBytes((Byte *)r.FileId, idLen);
|
||||
int padSize = 1 - (idLen & 1);
|
||||
|
||||
// SkeepZeros(1 - (idLen & 1));
|
||||
Skeep(1 - (idLen & 1)); // it's bug in some cd's. Must be zeros
|
||||
// SkipZeros(1 - (idLen & 1));
|
||||
Skip(1 - (idLen & 1)); // it's bug in some cd's. Must be zeros
|
||||
|
||||
int curPos = 33 + idLen + padSize;
|
||||
if (curPos > len)
|
||||
@@ -199,7 +196,7 @@ void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d)
|
||||
d.VolFlags = ReadByte();
|
||||
ReadBytes(d.SystemId, sizeof(d.SystemId));
|
||||
ReadBytes(d.VolumeId, sizeof(d.VolumeId));
|
||||
SkeepZeros(8);
|
||||
SkipZeros(8);
|
||||
d.VolumeSpaceSize = ReadUInt32();
|
||||
ReadBytes(d.EscapeSequence, sizeof(d.EscapeSequence));
|
||||
d.VolumeSetSize = ReadUInt16();
|
||||
@@ -223,9 +220,9 @@ void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d)
|
||||
ReadDateTime(d.ExpirationTime);
|
||||
ReadDateTime(d.EffectiveTime);
|
||||
d.FileStructureVersion = ReadByte(); // = 1
|
||||
SkeepZeros(1);
|
||||
SkipZeros(1);
|
||||
ReadBytes(d.ApplicationUse, sizeof(d.ApplicationUse));
|
||||
SkeepZeros(653);
|
||||
SkipZeros(653);
|
||||
}
|
||||
|
||||
static const Byte kSig_CD001[5] = { 'C', 'D', '0', '0', '1' };
|
||||
@@ -371,7 +368,7 @@ HRESULT CInArchive::Open2()
|
||||
}
|
||||
else
|
||||
break;
|
||||
SkeepZeros(0x800 - 7);
|
||||
SkipZeros(0x800 - 7);
|
||||
continue;
|
||||
*/
|
||||
}
|
||||
@@ -382,7 +379,7 @@ HRESULT CInArchive::Open2()
|
||||
if (sig[0] == NVolDescType::kTerminator)
|
||||
{
|
||||
break;
|
||||
// Skeep(0x800 - 7);
|
||||
// Skip(0x800 - 7);
|
||||
// continue;
|
||||
}
|
||||
switch(sig[0])
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
#ifndef __ARCHIVE_ISO_IN_H
|
||||
#define __ARCHIVE_ISO_IN_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "Common/IntToString.h"
|
||||
#include "Common/MyCom.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "IsoItem.h"
|
||||
#include "IsoHeader.h"
|
||||
#include "IsoItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NIso {
|
||||
@@ -159,8 +159,8 @@ struct CBootInitialEntry
|
||||
s += L"_";
|
||||
if (BootMediaType >= kNumBootMediaTypes)
|
||||
{
|
||||
wchar_t name[32];
|
||||
ConvertUInt64ToString(BootMediaType, name);
|
||||
wchar_t name[16];
|
||||
ConvertUInt32ToString(BootMediaType, name);
|
||||
s += name;
|
||||
}
|
||||
else
|
||||
@@ -232,8 +232,8 @@ class CInArchive
|
||||
bool _bootIsDefined;
|
||||
CBootRecordDescriptor _bootDesc;
|
||||
|
||||
void Skeep(size_t size);
|
||||
void SkeepZeros(size_t size);
|
||||
void Skip(size_t size);
|
||||
void SkipZeros(size_t size);
|
||||
Byte ReadByte();
|
||||
void ReadBytes(Byte *data, UInt32 size);
|
||||
UInt16 ReadUInt16Spec();
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
// LzhCRC.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "LzhCRC.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzh {
|
||||
|
||||
static const UInt16 kCRCPoly = 0xA001;
|
||||
|
||||
UInt16 CCRC::Table[256];
|
||||
|
||||
void CCRC::InitTable()
|
||||
{
|
||||
for (UInt32 i = 0; i < 256; i++)
|
||||
{
|
||||
UInt32 r = i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
if (r & 1)
|
||||
r = (r >> 1) ^ kCRCPoly;
|
||||
else
|
||||
r >>= 1;
|
||||
CCRC::Table[i] = (UInt16)r;
|
||||
}
|
||||
}
|
||||
|
||||
class CCRCTableInit
|
||||
{
|
||||
public:
|
||||
CCRCTableInit() { CCRC::InitTable(); }
|
||||
} g_CRCTableInit;
|
||||
|
||||
void CCRC::Update(const void *data, size_t size)
|
||||
{
|
||||
UInt16 v = _value;
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0; size--, p++)
|
||||
v = (UInt16)(Table[((Byte)(v)) ^ *p] ^ (v >> 8));
|
||||
_value = v;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,27 +0,0 @@
|
||||
// LzhCRC.h
|
||||
|
||||
#ifndef __LZH_CRC_H
|
||||
#define __LZH_CRC_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "Common/Types.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzh {
|
||||
|
||||
class CCRC
|
||||
{
|
||||
UInt16 _value;
|
||||
public:
|
||||
static UInt16 Table[256];
|
||||
static void InitTable();
|
||||
|
||||
CCRC(): _value(0){};
|
||||
void Init() { _value = 0; }
|
||||
void Update(const void *data, size_t size);
|
||||
UInt16 GetDigest() const { return _value; }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,387 +0,0 @@
|
||||
// LzhHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/StringConvert.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/Time.h"
|
||||
|
||||
#include "LzhHandler.h"
|
||||
#include "LzhOutStreamWithCRC.h"
|
||||
|
||||
#include "../../ICoder.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
#include "../../Compress/LzhDecoder.h"
|
||||
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NTime;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzh{
|
||||
|
||||
struct COsPair
|
||||
{
|
||||
Byte Id;
|
||||
const wchar_t *Name;
|
||||
};
|
||||
|
||||
COsPair g_OsPairs[] =
|
||||
{
|
||||
{ 'M', L"MS-DOS" },
|
||||
{ '2', L"OS/2" },
|
||||
{ '9', L"OS9" },
|
||||
{ 'K', L"OS/68K" },
|
||||
{ '3', L"OS/386" },
|
||||
{ 'H', L"HUMAN" },
|
||||
{ 'U', L"UNIX" },
|
||||
{ 'C', L"CP/M" },
|
||||
{ 'F', L"FLEX" },
|
||||
{ 'm', L"Mac" },
|
||||
{ 'R', L"Runser" },
|
||||
{ 'T', L"TownsOS" },
|
||||
{ 'X', L"XOSK" },
|
||||
{ 'w', L"Windows95" },
|
||||
{ 'W', L"WindowsNT" },
|
||||
{ 0, L"MS-DOS" },
|
||||
{ 'J', L"Java VM" }
|
||||
};
|
||||
|
||||
const wchar_t *kUnknownOS = L"Unknown";
|
||||
|
||||
const int kNumHostOSes = sizeof(g_OsPairs) / sizeof(g_OsPairs[0]);
|
||||
|
||||
static const wchar_t *GetOS(Byte osId)
|
||||
{
|
||||
for (int i = 0; i < kNumHostOSes; i++)
|
||||
if (g_OsPairs[i].Id == osId)
|
||||
return g_OsPairs[i].Name;
|
||||
return kUnknownOS;
|
||||
};
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidMTime, VT_FILETIME},
|
||||
{ NULL, kpidAttrib, VT_UI4},
|
||||
|
||||
// { NULL, kpidCommented, VT_BOOL},
|
||||
|
||||
{ NULL, kpidCRC, VT_UI4},
|
||||
|
||||
{ NULL, kpidMethod, VT_UI1},
|
||||
{ NULL, kpidHostOS, VT_BSTR}
|
||||
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO
|
||||
|
||||
CHandler::CHandler() {}
|
||||
|
||||
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 CItemEx &item = _items[index];
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath:
|
||||
{
|
||||
UString s = NItemName::WinNameToOSName(MultiByteToUnicodeString(item.GetName(), CP_OEMCP));
|
||||
if (!s.IsEmpty())
|
||||
{
|
||||
if (s[s.Length() - 1] == WCHAR_PATH_SEPARATOR)
|
||||
s.Delete(s.Length() - 1);
|
||||
prop = s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kpidIsDir: prop = item.IsDir(); break;
|
||||
case kpidSize: prop = item.Size; break;
|
||||
case kpidPackSize: prop = item.PackSize; break;
|
||||
case kpidCRC: prop = (UInt32)item.CRC; break;
|
||||
case kpidHostOS: prop = GetOS(item.OsId); break;
|
||||
case kpidMTime:
|
||||
{
|
||||
FILETIME utcFileTime;
|
||||
UInt32 unixTime;
|
||||
if (item.GetUnixTime(unixTime))
|
||||
NTime::UnixTimeToFileTime(unixTime, utcFileTime);
|
||||
else
|
||||
{
|
||||
FILETIME localFileTime;
|
||||
if (DosTimeToFileTime(item.ModifiedTime, localFileTime))
|
||||
{
|
||||
if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
|
||||
utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
|
||||
}
|
||||
else
|
||||
utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
|
||||
}
|
||||
prop = utcFileTime;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case kpidAttrib: prop = (UInt32)item.Attributes; break;
|
||||
case kpidCommented: prop = item.IsCommented(); break;
|
||||
*/
|
||||
case kpidMethod:
|
||||
{
|
||||
wchar_t method2[kMethodIdSize + 1];
|
||||
method2[kMethodIdSize] = 0;
|
||||
for (int i = 0; i < kMethodIdSize; i++)
|
||||
method2[i] = item.Method[i];
|
||||
prop = method2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
/*
|
||||
class CProgressImp: public CProgressVirt
|
||||
{
|
||||
public:
|
||||
CMyComPtr<IArchiveOpenCallback> Callback;
|
||||
STDMETHOD(SetCompleted)(const UInt64 *numFiles);
|
||||
};
|
||||
|
||||
STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles)
|
||||
{
|
||||
if (Callback)
|
||||
return Callback->SetCompleted(numFiles, NULL);
|
||||
return S_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
try
|
||||
{
|
||||
_items.Clear();
|
||||
CInArchive archive;
|
||||
|
||||
UInt64 endPos = 0;
|
||||
bool needSetTotal = true;
|
||||
|
||||
if (callback != NULL)
|
||||
{
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
|
||||
RINOK(archive.Open(stream));
|
||||
for (;;)
|
||||
{
|
||||
CItemEx item;
|
||||
bool filled;
|
||||
HRESULT result = archive.GetNextItem(filled, item);
|
||||
if (result == S_FALSE)
|
||||
return S_FALSE;
|
||||
if (result != S_OK)
|
||||
return S_FALSE;
|
||||
if (!filled)
|
||||
break;
|
||||
_items.Add(item);
|
||||
archive.Skeep(item.PackSize);
|
||||
if (callback != NULL)
|
||||
{
|
||||
if (needSetTotal)
|
||||
{
|
||||
RINOK(callback->SetTotal(NULL, &endPos));
|
||||
needSetTotal = false;
|
||||
}
|
||||
if (_items.Size() % 100 == 0)
|
||||
{
|
||||
UInt64 numFiles = _items.Size();
|
||||
UInt64 numBytes = item.DataPosition;
|
||||
RINOK(callback->SetCompleted(&numFiles, &numBytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_items.IsEmpty())
|
||||
return S_FALSE;
|
||||
|
||||
_stream = stream;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
COM_TRY_END
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_items.Clear();
|
||||
_stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
// CHandler::DecompressItems
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool testMode = (testModeSpec != 0);
|
||||
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 CItemEx &item = _items[allFilesMode ? i : indices[i]];
|
||||
totalUnPacked += item.Size;
|
||||
totalPacked += item.PackSize;
|
||||
}
|
||||
extractCallback->SetTotal(totalUnPacked);
|
||||
|
||||
UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
|
||||
UInt64 currentItemUnPacked, currentItemPacked;
|
||||
|
||||
NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = 0;
|
||||
CMyComPtr<ICompressCoder> lzhDecoder;
|
||||
CMyComPtr<ICompressCoder> lzh1Decoder;
|
||||
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 *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(_stream);
|
||||
|
||||
for(i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,
|
||||
currentTotalPacked += currentItemPacked)
|
||||
{
|
||||
currentItemUnPacked = 0;
|
||||
currentItemPacked = 0;
|
||||
|
||||
lps->InSize = currentTotalPacked;
|
||||
lps->OutSize = currentTotalUnPacked;
|
||||
RINOK(lps->SetCur());
|
||||
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode;
|
||||
askMode = testMode ? NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
const CItemEx &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));
|
||||
currentItemUnPacked = item.Size;
|
||||
currentItemPacked = item.PackSize;
|
||||
|
||||
{
|
||||
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
outStreamSpec->Init(realOutStream);
|
||||
realOutStream.Release();
|
||||
|
||||
UInt64 pos;
|
||||
_stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos);
|
||||
|
||||
streamSpec->Init(item.PackSize);
|
||||
|
||||
HRESULT result = S_OK;
|
||||
Int32 opRes = NExtract::NOperationResult::kOK;
|
||||
|
||||
if (item.IsCopyMethod())
|
||||
{
|
||||
result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
|
||||
if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)
|
||||
result = S_FALSE;
|
||||
}
|
||||
else if (item.IsLh4GroupMethod())
|
||||
{
|
||||
if (!lzhDecoder)
|
||||
{
|
||||
lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
|
||||
lzhDecoder = lzhDecoderSpec;
|
||||
}
|
||||
lzhDecoderSpec->SetDictionary(item.GetNumDictBits());
|
||||
result = lzhDecoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress);
|
||||
}
|
||||
/*
|
||||
else if (item.IsLh1GroupMethod())
|
||||
{
|
||||
if (!lzh1Decoder)
|
||||
{
|
||||
lzh1DecoderSpec = new NCompress::NLzh1::NDecoder::CCoder;
|
||||
lzh1Decoder = lzh1DecoderSpec;
|
||||
}
|
||||
lzh1DecoderSpec->SetDictionary(item.GetNumDictBits());
|
||||
result = lzh1Decoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress);
|
||||
}
|
||||
*/
|
||||
else
|
||||
opRes = NExtract::NOperationResult::kUnSupportedMethod;
|
||||
|
||||
if (opRes == NExtract::NOperationResult::kOK)
|
||||
{
|
||||
if (result == S_FALSE)
|
||||
opRes = NExtract::NOperationResult::kDataError;
|
||||
else
|
||||
{
|
||||
RINOK(result);
|
||||
if (outStreamSpec->GetCRC() != item.CRC)
|
||||
opRes = NExtract::NOperationResult::kCRCError;
|
||||
}
|
||||
}
|
||||
outStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(opRes));
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,30 +0,0 @@
|
||||
// LzhHandler.h
|
||||
|
||||
#ifndef __LZH_HANDLER_H
|
||||
#define __LZH_HANDLER_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "../IArchive.h"
|
||||
#include "LzhIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzh {
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IInArchive)
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
|
||||
CHandler();
|
||||
private:
|
||||
CObjectVector<CItemEx> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,19 +0,0 @@
|
||||
// Archive/Lzh/Header.h
|
||||
|
||||
#ifndef __ARCHIVE_LZH_HEADER_H
|
||||
#define __ARCHIVE_LZH_HEADER_H
|
||||
|
||||
#include "Common/Types.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzh {
|
||||
|
||||
const int kMethodIdSize = 5;
|
||||
|
||||
const Byte kExtIdFileName = 0x01;
|
||||
const Byte kExtIdDirName = 0x02;
|
||||
const Byte kExtIdUnixTime = 0x54;
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,172 +0,0 @@
|
||||
// Archive/LzhIn.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/Buffer.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "LzhIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzh {
|
||||
|
||||
HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
|
||||
{
|
||||
size_t realProcessedSize = size;
|
||||
RINOK(ReadStream(m_Stream, data, &realProcessedSize));
|
||||
processedSize = (UInt32)realProcessedSize;
|
||||
m_Position += processedSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::CheckReadBytes(void *data, UInt32 size)
|
||||
{
|
||||
UInt32 processedSize;
|
||||
RINOK(ReadBytes(data, size, processedSize));
|
||||
return (processedSize == size) ? S_OK: S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::Open(IInStream *inStream)
|
||||
{
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
|
||||
m_Stream = inStream;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const Byte *ReadUInt32(const Byte *p, UInt32 &v)
|
||||
{
|
||||
v = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
v |= ((UInt32)(*p++) << (i * 8));
|
||||
return p;
|
||||
}
|
||||
|
||||
static const Byte *ReadUInt16(const Byte *p, UInt16 &v)
|
||||
{
|
||||
v = 0;
|
||||
for (int i = 0; i < 2; i++)
|
||||
v |= ((UInt16)(*p++) << (i * 8));
|
||||
return p;
|
||||
}
|
||||
|
||||
static const Byte *ReadString(const Byte *p, size_t size, AString &s)
|
||||
{
|
||||
s.Empty();
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
char c = p[i];
|
||||
if (c == 0)
|
||||
break;
|
||||
s += c;
|
||||
}
|
||||
return p + size;
|
||||
}
|
||||
|
||||
static Byte CalcSum(const Byte *data, size_t size)
|
||||
{
|
||||
Byte sum = 0;
|
||||
for (size_t i = 0; i < size; i++)
|
||||
sum = (Byte)(sum + data[i]);
|
||||
return sum;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
|
||||
{
|
||||
filled = false;
|
||||
|
||||
UInt32 processedSize;
|
||||
Byte startHeader[2];
|
||||
RINOK(ReadBytes(startHeader, 2, processedSize))
|
||||
if (processedSize == 0)
|
||||
return S_OK;
|
||||
if (processedSize == 1)
|
||||
return (startHeader[0] == 0) ? S_OK: S_FALSE;
|
||||
if (startHeader[0] == 0 && startHeader[1] == 0)
|
||||
return S_OK;
|
||||
|
||||
Byte header[256];
|
||||
const UInt32 kBasicPartSize = 22;
|
||||
RINOK(ReadBytes(header, kBasicPartSize, processedSize));
|
||||
if (processedSize != kBasicPartSize)
|
||||
return (startHeader[0] == 0) ? S_OK: S_FALSE;
|
||||
|
||||
const Byte *p = header;
|
||||
memmove(item.Method, p, kMethodIdSize);
|
||||
if (!item.IsValidMethod())
|
||||
return S_OK;
|
||||
p += kMethodIdSize;
|
||||
p = ReadUInt32(p, item.PackSize);
|
||||
p = ReadUInt32(p, item.Size);
|
||||
p = ReadUInt32(p, item.ModifiedTime);
|
||||
item.Attributes = *p++;
|
||||
item.Level = *p++;
|
||||
if (item.Level > 2)
|
||||
return S_FALSE;
|
||||
UInt32 headerSize;
|
||||
if (item.Level < 2)
|
||||
{
|
||||
headerSize = startHeader[0];
|
||||
if (headerSize < kBasicPartSize)
|
||||
return S_FALSE;
|
||||
UInt32 remain = headerSize - kBasicPartSize;
|
||||
RINOK(CheckReadBytes(header + kBasicPartSize, remain));
|
||||
if (startHeader[1] != CalcSum(header, headerSize))
|
||||
return S_FALSE;
|
||||
size_t nameLength = *p++;
|
||||
if ((p - header) + nameLength + 2 > headerSize)
|
||||
return S_FALSE;
|
||||
p = ReadString(p, nameLength, item.Name);
|
||||
}
|
||||
else
|
||||
headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8);
|
||||
p = ReadUInt16(p, item.CRC);
|
||||
if (item.Level != 0)
|
||||
{
|
||||
if (item.Level == 2)
|
||||
{
|
||||
RINOK(CheckReadBytes(header + kBasicPartSize, 2));
|
||||
}
|
||||
if ((size_t)(p - header) + 3 > headerSize)
|
||||
return S_FALSE;
|
||||
item.OsId = *p++;
|
||||
UInt16 nextSize;
|
||||
p = ReadUInt16(p, nextSize);
|
||||
while (nextSize != 0)
|
||||
{
|
||||
if (nextSize < 3)
|
||||
return S_FALSE;
|
||||
if (item.Level == 1)
|
||||
{
|
||||
if (item.PackSize < nextSize)
|
||||
return S_FALSE;
|
||||
item.PackSize -= nextSize;
|
||||
}
|
||||
CExtension ext;
|
||||
RINOK(CheckReadBytes(&ext.Type, 1))
|
||||
nextSize -= 3;
|
||||
ext.Data.SetCapacity(nextSize);
|
||||
RINOK(CheckReadBytes((Byte *)ext.Data, nextSize))
|
||||
item.Extensions.Add(ext);
|
||||
Byte hdr2[2];
|
||||
RINOK(CheckReadBytes(hdr2, 2));
|
||||
ReadUInt16(hdr2, nextSize);
|
||||
}
|
||||
}
|
||||
item.DataPosition = m_Position;
|
||||
filled = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::Skeep(UInt64 numBytes)
|
||||
{
|
||||
UInt64 newPostion;
|
||||
RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
|
||||
m_Position += numBytes;
|
||||
if (m_Position != newPostion)
|
||||
return E_FAIL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Archive/LzhIn.h
|
||||
|
||||
#ifndef __ARCHIVE_LZHIN_H
|
||||
#define __ARCHIVE_LZHIN_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "LzhItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzh {
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
CMyComPtr<IInStream> m_Stream;
|
||||
UInt64 m_Position;
|
||||
|
||||
HRESULT ReadBytes(void *data, UInt32 size, UInt32 &processedSize);
|
||||
HRESULT CheckReadBytes(void *data, UInt32 size);
|
||||
public:
|
||||
HRESULT Open(IInStream *inStream);
|
||||
HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
|
||||
HRESULT Skeep(UInt64 numBytes);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,172 +0,0 @@
|
||||
// Archive/LzhItem.h
|
||||
|
||||
#ifndef __ARCHIVE_LZH_ITEM_H
|
||||
#define __ARCHIVE_LZH_ITEM_H
|
||||
|
||||
#include "Common/Types.h"
|
||||
#include "Common/MyString.h"
|
||||
#include "Common/Buffer.h"
|
||||
#include "LzhHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzh {
|
||||
|
||||
struct CExtension
|
||||
{
|
||||
Byte Type;
|
||||
CByteBuffer Data;
|
||||
AString GetString() const
|
||||
{
|
||||
AString s;
|
||||
for (size_t i = 0; i < Data.GetCapacity(); i++)
|
||||
{
|
||||
char c = (char)Data[i];
|
||||
if (c == 0)
|
||||
break;
|
||||
s += c;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
struct CItem
|
||||
{
|
||||
public:
|
||||
AString Name;
|
||||
Byte Method[kMethodIdSize];
|
||||
UInt32 PackSize;
|
||||
UInt32 Size;
|
||||
UInt32 ModifiedTime;
|
||||
Byte Attributes;
|
||||
Byte Level;
|
||||
UInt16 CRC;
|
||||
Byte OsId;
|
||||
CObjectVector<CExtension> Extensions;
|
||||
|
||||
bool IsValidMethod() const { return (Method[0] == '-' && Method[1] == 'l' && Method[4] == '-'); }
|
||||
bool IsLhMethod() const {return (IsValidMethod() && Method[2] == 'h'); }
|
||||
bool IsDir() const {return (IsLhMethod() && Method[3] == 'd'); }
|
||||
|
||||
bool IsCopyMethod() const
|
||||
{
|
||||
return (IsLhMethod() && Method[3] == '0') ||
|
||||
(IsValidMethod() && Method[2] == 'z' && Method[3] == '4');
|
||||
}
|
||||
|
||||
bool IsLh1GroupMethod() const
|
||||
{
|
||||
if (!IsLhMethod())
|
||||
return false;
|
||||
switch(Method[3])
|
||||
{
|
||||
case '1':
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsLh4GroupMethod() const
|
||||
{
|
||||
if (!IsLhMethod())
|
||||
return false;
|
||||
switch(Method[3])
|
||||
{
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int GetNumDictBits() const
|
||||
{
|
||||
if (!IsLhMethod())
|
||||
return 0;
|
||||
switch(Method[3])
|
||||
{
|
||||
case '1':
|
||||
return 12;
|
||||
case '2':
|
||||
return 13;
|
||||
case '3':
|
||||
return 13;
|
||||
case '4':
|
||||
return 12;
|
||||
case '5':
|
||||
return 13;
|
||||
case '6':
|
||||
return 15;
|
||||
case '7':
|
||||
return 16;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FindExt(Byte type) const
|
||||
{
|
||||
for (int i = 0; i < Extensions.Size(); i++)
|
||||
if (Extensions[i].Type == type)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
bool GetUnixTime(UInt32 &value) const
|
||||
{
|
||||
int index = FindExt(kExtIdUnixTime);
|
||||
if (index < 0)
|
||||
{
|
||||
if (Level == 2)
|
||||
{
|
||||
value = ModifiedTime;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const Byte *data = (const Byte *)(Extensions[index].Data);
|
||||
value = data[0] |
|
||||
((UInt32)data[1] << 8) |
|
||||
((UInt32)data[2] << 16) |
|
||||
((UInt32)data[3] << 24);
|
||||
return true;
|
||||
}
|
||||
|
||||
AString GetDirName() const
|
||||
{
|
||||
int index = FindExt(kExtIdDirName);
|
||||
if (index < 0)
|
||||
return AString();
|
||||
return Extensions[index].GetString();
|
||||
}
|
||||
|
||||
AString GetFileName() const
|
||||
{
|
||||
int index = FindExt(kExtIdFileName);
|
||||
if (index < 0)
|
||||
return Name;
|
||||
return Extensions[index].GetString();
|
||||
}
|
||||
|
||||
AString GetName() const
|
||||
{
|
||||
AString dirName = GetDirName();
|
||||
dirName.Replace((char)(unsigned char)0xFF, '\\');
|
||||
if (!dirName.IsEmpty())
|
||||
{
|
||||
char c = dirName[dirName.Length() - 1];
|
||||
if (c != '\\')
|
||||
dirName += '\\';
|
||||
}
|
||||
return dirName + GetFileName();
|
||||
}
|
||||
};
|
||||
|
||||
class CItemEx: public CItem
|
||||
{
|
||||
public:
|
||||
UInt64 DataPosition;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,27 +0,0 @@
|
||||
// LzhOutStreamWithCRC.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "LzhOutStreamWithCRC.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzh {
|
||||
|
||||
STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessedSize;
|
||||
HRESULT result;
|
||||
if(!_stream)
|
||||
{
|
||||
realProcessedSize = size;
|
||||
result = S_OK;
|
||||
}
|
||||
else
|
||||
result = _stream->Write(data, size, &realProcessedSize);
|
||||
_crc.Update(data, realProcessedSize);
|
||||
if(processedSize != NULL)
|
||||
*processedSize = realProcessedSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,38 +0,0 @@
|
||||
// LzhOutStreamWithCRC.h
|
||||
|
||||
#ifndef __LZHOUTSTREAMWITHCRC_H
|
||||
#define __LZHOUTSTREAMWITHCRC_H
|
||||
|
||||
#include "LzhCRC.h"
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzh {
|
||||
|
||||
class COutStreamWithCRC:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
private:
|
||||
CCRC _crc;
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
public:
|
||||
void Init(ISequentialOutStream *stream)
|
||||
{
|
||||
_stream = stream;
|
||||
_crc.Init();
|
||||
}
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
UInt32 GetCRC() const { return _crc.GetDigest(); }
|
||||
void InitCRC() { _crc.Init(); }
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,13 +0,0 @@
|
||||
// LzhRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "LzhHandler.h"
|
||||
static IInArchive *CreateArc() { return new NArchive::NLzh::CHandler; }
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"Lzh", L"lzh lha", 0, 6, { '-', 'l' }, 2, false, CreateArc, 0 };
|
||||
|
||||
REGISTER_ARC(Lzh)
|
||||
@@ -1,8 +0,0 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/MyWindows.h"
|
||||
|
||||
#endif
|
||||
Executable
+783
@@ -0,0 +1,783 @@
|
||||
// LzhHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "Common/Buffer.h"
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/StringConvert.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/Time.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/LimitedStreams.h"
|
||||
#include "../Common/ProgressUtils.h"
|
||||
#include "../Common/RegisterArc.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "../Compress/CopyCoder.h"
|
||||
#include "../Compress/LzhDecoder.h"
|
||||
|
||||
#include "IArchive.h"
|
||||
|
||||
#include "Common/ItemNameUtils.h"
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NTime;
|
||||
|
||||
#define Get16(p) GetUi16(p)
|
||||
#define Get32(p) GetUi32(p)
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzh{
|
||||
|
||||
const int kMethodIdSize = 5;
|
||||
|
||||
const Byte kExtIdFileName = 0x01;
|
||||
const Byte kExtIdDirName = 0x02;
|
||||
const Byte kExtIdUnixTime = 0x54;
|
||||
|
||||
struct CExtension
|
||||
{
|
||||
Byte Type;
|
||||
CByteBuffer Data;
|
||||
AString GetString() const
|
||||
{
|
||||
AString s;
|
||||
for (size_t i = 0; i < Data.GetCapacity(); i++)
|
||||
{
|
||||
char c = (char)Data[i];
|
||||
if (c == 0)
|
||||
break;
|
||||
s += c;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
struct CItem
|
||||
{
|
||||
AString Name;
|
||||
Byte Method[kMethodIdSize];
|
||||
Byte Attributes;
|
||||
Byte Level;
|
||||
Byte OsId;
|
||||
UInt32 PackSize;
|
||||
UInt32 Size;
|
||||
UInt32 ModifiedTime;
|
||||
UInt16 CRC;
|
||||
CObjectVector<CExtension> Extensions;
|
||||
|
||||
bool IsValidMethod() const { return (Method[0] == '-' && Method[1] == 'l' && Method[4] == '-'); }
|
||||
bool IsLhMethod() const {return (IsValidMethod() && Method[2] == 'h'); }
|
||||
bool IsDir() const {return (IsLhMethod() && Method[3] == 'd'); }
|
||||
|
||||
bool IsCopyMethod() const
|
||||
{
|
||||
return (IsLhMethod() && Method[3] == '0') ||
|
||||
(IsValidMethod() && Method[2] == 'z' && Method[3] == '4');
|
||||
}
|
||||
|
||||
bool IsLh1GroupMethod() const
|
||||
{
|
||||
if (!IsLhMethod())
|
||||
return false;
|
||||
switch(Method[3])
|
||||
{
|
||||
case '1':
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsLh4GroupMethod() const
|
||||
{
|
||||
if (!IsLhMethod())
|
||||
return false;
|
||||
switch(Method[3])
|
||||
{
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int GetNumDictBits() const
|
||||
{
|
||||
if (!IsLhMethod())
|
||||
return 0;
|
||||
switch(Method[3])
|
||||
{
|
||||
case '1': return 12;
|
||||
case '2': return 13;
|
||||
case '3': return 13;
|
||||
case '4': return 12;
|
||||
case '5': return 13;
|
||||
case '6': return 15;
|
||||
case '7': return 16;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FindExt(Byte type) const
|
||||
{
|
||||
for (int i = 0; i < Extensions.Size(); i++)
|
||||
if (Extensions[i].Type == type)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
bool GetUnixTime(UInt32 &value) const
|
||||
{
|
||||
int index = FindExt(kExtIdUnixTime);
|
||||
if (index < 0)
|
||||
{
|
||||
if (Level == 2)
|
||||
{
|
||||
value = ModifiedTime;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const Byte *data = (const Byte *)(Extensions[index].Data);
|
||||
value = GetUi32(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
AString GetDirName() const
|
||||
{
|
||||
int index = FindExt(kExtIdDirName);
|
||||
if (index < 0)
|
||||
return AString();
|
||||
return Extensions[index].GetString();
|
||||
}
|
||||
|
||||
AString GetFileName() const
|
||||
{
|
||||
int index = FindExt(kExtIdFileName);
|
||||
if (index < 0)
|
||||
return Name;
|
||||
return Extensions[index].GetString();
|
||||
}
|
||||
|
||||
AString GetName() const
|
||||
{
|
||||
AString dirName = GetDirName();
|
||||
dirName.Replace((char)(unsigned char)0xFF, '\\');
|
||||
if (!dirName.IsEmpty())
|
||||
{
|
||||
char c = dirName[dirName.Length() - 1];
|
||||
if (c != '\\')
|
||||
dirName += '\\';
|
||||
}
|
||||
return dirName + GetFileName();
|
||||
}
|
||||
};
|
||||
|
||||
struct CItemEx: public CItem
|
||||
{
|
||||
UInt64 DataPosition;
|
||||
};
|
||||
|
||||
class CInArchive
|
||||
{
|
||||
CMyComPtr<IInStream> m_Stream;
|
||||
UInt64 m_Position;
|
||||
|
||||
HRESULT ReadBytes(void *data, UInt32 size, UInt32 &processedSize);
|
||||
HRESULT CheckReadBytes(void *data, UInt32 size);
|
||||
public:
|
||||
HRESULT Open(IInStream *inStream);
|
||||
HRESULT GetNextItem(bool &filled, CItemEx &itemInfo);
|
||||
HRESULT Skip(UInt64 numBytes);
|
||||
};
|
||||
|
||||
HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
|
||||
{
|
||||
size_t realProcessedSize = size;
|
||||
RINOK(ReadStream(m_Stream, data, &realProcessedSize));
|
||||
processedSize = (UInt32)realProcessedSize;
|
||||
m_Position += processedSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::CheckReadBytes(void *data, UInt32 size)
|
||||
{
|
||||
UInt32 processedSize;
|
||||
RINOK(ReadBytes(data, size, processedSize));
|
||||
return (processedSize == size) ? S_OK: S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::Open(IInStream *inStream)
|
||||
{
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position));
|
||||
m_Stream = inStream;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const Byte *ReadUInt16(const Byte *p, UInt16 &v)
|
||||
{
|
||||
v = Get16(p);
|
||||
return p + 2;
|
||||
}
|
||||
|
||||
static const Byte *ReadString(const Byte *p, size_t size, AString &s)
|
||||
{
|
||||
s.Empty();
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
char c = p[i];
|
||||
if (c == 0)
|
||||
break;
|
||||
s += c;
|
||||
}
|
||||
return p + size;
|
||||
}
|
||||
|
||||
static Byte CalcSum(const Byte *data, size_t size)
|
||||
{
|
||||
Byte sum = 0;
|
||||
for (size_t i = 0; i < size; i++)
|
||||
sum = (Byte)(sum + data[i]);
|
||||
return sum;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item)
|
||||
{
|
||||
filled = false;
|
||||
|
||||
UInt32 processedSize;
|
||||
Byte startHeader[2];
|
||||
RINOK(ReadBytes(startHeader, 2, processedSize))
|
||||
if (processedSize == 0)
|
||||
return S_OK;
|
||||
if (processedSize == 1)
|
||||
return (startHeader[0] == 0) ? S_OK: S_FALSE;
|
||||
if (startHeader[0] == 0 && startHeader[1] == 0)
|
||||
return S_OK;
|
||||
|
||||
Byte header[256];
|
||||
const UInt32 kBasicPartSize = 22;
|
||||
RINOK(ReadBytes(header, kBasicPartSize, processedSize));
|
||||
if (processedSize != kBasicPartSize)
|
||||
return (startHeader[0] == 0) ? S_OK: S_FALSE;
|
||||
|
||||
const Byte *p = header;
|
||||
memmove(item.Method, p, kMethodIdSize);
|
||||
if (!item.IsValidMethod())
|
||||
return S_OK;
|
||||
p += kMethodIdSize;
|
||||
item.PackSize = Get32(p);
|
||||
item.Size = Get32(p + 4);
|
||||
item.ModifiedTime = Get32(p + 8);
|
||||
item.Attributes = p[12];
|
||||
item.Level = p[13];
|
||||
p += 14;
|
||||
if (item.Level > 2)
|
||||
return S_FALSE;
|
||||
UInt32 headerSize;
|
||||
if (item.Level < 2)
|
||||
{
|
||||
headerSize = startHeader[0];
|
||||
if (headerSize < kBasicPartSize)
|
||||
return S_FALSE;
|
||||
UInt32 remain = headerSize - kBasicPartSize;
|
||||
RINOK(CheckReadBytes(header + kBasicPartSize, remain));
|
||||
if (startHeader[1] != CalcSum(header, headerSize))
|
||||
return S_FALSE;
|
||||
size_t nameLength = *p++;
|
||||
if ((p - header) + nameLength + 2 > headerSize)
|
||||
return S_FALSE;
|
||||
p = ReadString(p, nameLength, item.Name);
|
||||
}
|
||||
else
|
||||
headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8);
|
||||
p = ReadUInt16(p, item.CRC);
|
||||
if (item.Level != 0)
|
||||
{
|
||||
if (item.Level == 2)
|
||||
{
|
||||
RINOK(CheckReadBytes(header + kBasicPartSize, 2));
|
||||
}
|
||||
if ((size_t)(p - header) + 3 > headerSize)
|
||||
return S_FALSE;
|
||||
item.OsId = *p++;
|
||||
UInt16 nextSize;
|
||||
p = ReadUInt16(p, nextSize);
|
||||
while (nextSize != 0)
|
||||
{
|
||||
if (nextSize < 3)
|
||||
return S_FALSE;
|
||||
if (item.Level == 1)
|
||||
{
|
||||
if (item.PackSize < nextSize)
|
||||
return S_FALSE;
|
||||
item.PackSize -= nextSize;
|
||||
}
|
||||
CExtension ext;
|
||||
RINOK(CheckReadBytes(&ext.Type, 1))
|
||||
nextSize -= 3;
|
||||
ext.Data.SetCapacity(nextSize);
|
||||
RINOK(CheckReadBytes((Byte *)ext.Data, nextSize))
|
||||
item.Extensions.Add(ext);
|
||||
Byte hdr2[2];
|
||||
RINOK(CheckReadBytes(hdr2, 2));
|
||||
ReadUInt16(hdr2, nextSize);
|
||||
}
|
||||
}
|
||||
item.DataPosition = m_Position;
|
||||
filled = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CInArchive::Skip(UInt64 numBytes)
|
||||
{
|
||||
UInt64 newPostion;
|
||||
RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion));
|
||||
m_Position += numBytes;
|
||||
if (m_Position != newPostion)
|
||||
return E_FAIL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
struct COsPair
|
||||
{
|
||||
Byte Id;
|
||||
const char *Name;
|
||||
};
|
||||
|
||||
static COsPair g_OsPairs[] =
|
||||
{
|
||||
{ 0, "MS-DOS" },
|
||||
{ 'M', "MS-DOS" },
|
||||
{ '2', "OS/2" },
|
||||
{ '9', "OS9" },
|
||||
{ 'K', "OS/68K" },
|
||||
{ '3', "OS/386" },
|
||||
{ 'H', "HUMAN" },
|
||||
{ 'U', "UNIX" },
|
||||
{ 'C', "CP/M" },
|
||||
{ 'F', "FLEX" },
|
||||
{ 'm', "Mac" },
|
||||
{ 'R', "Runser" },
|
||||
{ 'T', "TownsOS" },
|
||||
{ 'X', "XOSK" },
|
||||
{ 'w', "Windows 95" },
|
||||
{ 'W', "Windows NT" },
|
||||
{ 'J', "Java VM" }
|
||||
};
|
||||
|
||||
static const char *kUnknownOS = "Unknown";
|
||||
|
||||
static const char *GetOS(Byte osId)
|
||||
{
|
||||
for (int i = 0; i < sizeof(g_OsPairs) / sizeof(g_OsPairs[0]); i++)
|
||||
if (g_OsPairs[i].Id == osId)
|
||||
return g_OsPairs[i].Name;
|
||||
return kUnknownOS;
|
||||
};
|
||||
|
||||
static STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidMTime, VT_FILETIME},
|
||||
// { NULL, kpidAttrib, VT_UI4},
|
||||
{ NULL, kpidCRC, VT_UI4},
|
||||
{ NULL, kpidMethod, VT_BSTR},
|
||||
{ NULL, kpidHostOS, VT_BSTR}
|
||||
};
|
||||
|
||||
class CCRC
|
||||
{
|
||||
UInt16 _value;
|
||||
public:
|
||||
static UInt16 Table[256];
|
||||
static void InitTable();
|
||||
|
||||
CCRC(): _value(0){};
|
||||
void Init() { _value = 0; }
|
||||
void Update(const void *data, size_t size);
|
||||
UInt16 GetDigest() const { return _value; }
|
||||
};
|
||||
|
||||
static const UInt16 kCRCPoly = 0xA001;
|
||||
|
||||
UInt16 CCRC::Table[256];
|
||||
|
||||
void CCRC::InitTable()
|
||||
{
|
||||
for (UInt32 i = 0; i < 256; i++)
|
||||
{
|
||||
UInt32 r = i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
if (r & 1)
|
||||
r = (r >> 1) ^ kCRCPoly;
|
||||
else
|
||||
r >>= 1;
|
||||
CCRC::Table[i] = (UInt16)r;
|
||||
}
|
||||
}
|
||||
|
||||
class CCRCTableInit
|
||||
{
|
||||
public:
|
||||
CCRCTableInit() { CCRC::InitTable(); }
|
||||
} g_CRCTableInit;
|
||||
|
||||
void CCRC::Update(const void *data, size_t size)
|
||||
{
|
||||
UInt16 v = _value;
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0; size--, p++)
|
||||
v = (UInt16)(Table[((Byte)(v)) ^ *p] ^ (v >> 8));
|
||||
_value = v;
|
||||
}
|
||||
|
||||
|
||||
class COutStreamWithCRC:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
private:
|
||||
CCRC _crc;
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
public:
|
||||
void Init(ISequentialOutStream *stream)
|
||||
{
|
||||
_stream = stream;
|
||||
_crc.Init();
|
||||
}
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
UInt32 GetCRC() const { return _crc.GetDigest(); }
|
||||
void InitCRC() { _crc.Init(); }
|
||||
|
||||
};
|
||||
|
||||
STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessedSize;
|
||||
HRESULT result;
|
||||
if(!_stream)
|
||||
{
|
||||
realProcessedSize = size;
|
||||
result = S_OK;
|
||||
}
|
||||
else
|
||||
result = _stream->Write(data, size, &realProcessedSize);
|
||||
_crc.Update(data, realProcessedSize);
|
||||
if(processedSize != NULL)
|
||||
*processedSize = realProcessedSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CObjectVector<CItemEx> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IInArchive)
|
||||
INTERFACE_IInArchive(;)
|
||||
CHandler();
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO
|
||||
|
||||
CHandler::CHandler() {}
|
||||
|
||||
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 CItemEx &item = _items[index];
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath:
|
||||
{
|
||||
UString s = NItemName::WinNameToOSName(MultiByteToUnicodeString(item.GetName(), CP_OEMCP));
|
||||
if (!s.IsEmpty())
|
||||
{
|
||||
if (s[s.Length() - 1] == WCHAR_PATH_SEPARATOR)
|
||||
s.Delete(s.Length() - 1);
|
||||
prop = s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kpidIsDir: prop = item.IsDir(); break;
|
||||
case kpidSize: prop = item.Size; break;
|
||||
case kpidPackSize: prop = item.PackSize; break;
|
||||
case kpidCRC: prop = (UInt32)item.CRC; break;
|
||||
case kpidHostOS: prop = GetOS(item.OsId); break;
|
||||
case kpidMTime:
|
||||
{
|
||||
FILETIME utc;
|
||||
UInt32 unixTime;
|
||||
if (item.GetUnixTime(unixTime))
|
||||
NTime::UnixTimeToFileTime(unixTime, utc);
|
||||
else
|
||||
{
|
||||
FILETIME localFileTime;
|
||||
if (DosTimeToFileTime(item.ModifiedTime, localFileTime))
|
||||
{
|
||||
if (!LocalFileTimeToFileTime(&localFileTime, &utc))
|
||||
utc.dwHighDateTime = utc.dwLowDateTime = 0;
|
||||
}
|
||||
else
|
||||
utc.dwHighDateTime = utc.dwLowDateTime = 0;
|
||||
}
|
||||
prop = utc;
|
||||
break;
|
||||
}
|
||||
// case kpidAttrib: prop = (UInt32)item.Attributes; break;
|
||||
case kpidMethod:
|
||||
{
|
||||
char method2[kMethodIdSize + 1];
|
||||
method2[kMethodIdSize] = 0;
|
||||
memcpy(method2, item.Method, kMethodIdSize);
|
||||
prop = method2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *stream,
|
||||
const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
try
|
||||
{
|
||||
_items.Clear();
|
||||
CInArchive archive;
|
||||
|
||||
UInt64 endPos = 0;
|
||||
bool needSetTotal = true;
|
||||
|
||||
if (callback != NULL)
|
||||
{
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
|
||||
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
|
||||
RINOK(archive.Open(stream));
|
||||
for (;;)
|
||||
{
|
||||
CItemEx item;
|
||||
bool filled;
|
||||
HRESULT result = archive.GetNextItem(filled, item);
|
||||
if (result == S_FALSE)
|
||||
return S_FALSE;
|
||||
if (result != S_OK)
|
||||
return S_FALSE;
|
||||
if (!filled)
|
||||
break;
|
||||
_items.Add(item);
|
||||
archive.Skip(item.PackSize);
|
||||
if (callback != NULL)
|
||||
{
|
||||
if (needSetTotal)
|
||||
{
|
||||
RINOK(callback->SetTotal(NULL, &endPos));
|
||||
needSetTotal = false;
|
||||
}
|
||||
if (_items.Size() % 100 == 0)
|
||||
{
|
||||
UInt64 numFiles = _items.Size();
|
||||
UInt64 numBytes = item.DataPosition;
|
||||
RINOK(callback->SetCompleted(&numFiles, &numBytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_items.IsEmpty())
|
||||
return S_FALSE;
|
||||
|
||||
_stream = stream;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
COM_TRY_END
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_items.Clear();
|
||||
_stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
// CHandler::DecompressItems
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
Int32 testModeSpec, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool testMode = (testModeSpec != 0);
|
||||
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 CItemEx &item = _items[allFilesMode ? i : indices[i]];
|
||||
totalUnPacked += item.Size;
|
||||
totalPacked += item.PackSize;
|
||||
}
|
||||
extractCallback->SetTotal(totalUnPacked);
|
||||
|
||||
UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
|
||||
UInt64 currentItemUnPacked, currentItemPacked;
|
||||
|
||||
NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = 0;
|
||||
CMyComPtr<ICompressCoder> lzhDecoder;
|
||||
CMyComPtr<ICompressCoder> lzh1Decoder;
|
||||
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 *streamSpec = new CLimitedSequentialInStream;
|
||||
CMyComPtr<ISequentialInStream> inStream(streamSpec);
|
||||
streamSpec->SetStream(_stream);
|
||||
|
||||
for(i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,
|
||||
currentTotalPacked += currentItemPacked)
|
||||
{
|
||||
currentItemUnPacked = 0;
|
||||
currentItemPacked = 0;
|
||||
|
||||
lps->InSize = currentTotalPacked;
|
||||
lps->OutSize = currentTotalUnPacked;
|
||||
RINOK(lps->SetCur());
|
||||
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode;
|
||||
askMode = testMode ? NExtract::NAskMode::kTest :
|
||||
NExtract::NAskMode::kExtract;
|
||||
Int32 index = allFilesMode ? i : indices[i];
|
||||
const CItemEx &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));
|
||||
currentItemUnPacked = item.Size;
|
||||
currentItemPacked = item.PackSize;
|
||||
|
||||
{
|
||||
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
outStreamSpec->Init(realOutStream);
|
||||
realOutStream.Release();
|
||||
|
||||
UInt64 pos;
|
||||
_stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos);
|
||||
|
||||
streamSpec->Init(item.PackSize);
|
||||
|
||||
HRESULT result = S_OK;
|
||||
Int32 opRes = NExtract::NOperationResult::kOK;
|
||||
|
||||
if (item.IsCopyMethod())
|
||||
{
|
||||
result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
|
||||
if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)
|
||||
result = S_FALSE;
|
||||
}
|
||||
else if (item.IsLh4GroupMethod())
|
||||
{
|
||||
if (!lzhDecoder)
|
||||
{
|
||||
lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
|
||||
lzhDecoder = lzhDecoderSpec;
|
||||
}
|
||||
lzhDecoderSpec->SetDictionary(item.GetNumDictBits());
|
||||
result = lzhDecoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress);
|
||||
}
|
||||
/*
|
||||
else if (item.IsLh1GroupMethod())
|
||||
{
|
||||
if (!lzh1Decoder)
|
||||
{
|
||||
lzh1DecoderSpec = new NCompress::NLzh1::NDecoder::CCoder;
|
||||
lzh1Decoder = lzh1DecoderSpec;
|
||||
}
|
||||
lzh1DecoderSpec->SetDictionary(item.GetNumDictBits());
|
||||
result = lzh1Decoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress);
|
||||
}
|
||||
*/
|
||||
else
|
||||
opRes = NExtract::NOperationResult::kUnSupportedMethod;
|
||||
|
||||
if (opRes == NExtract::NOperationResult::kOK)
|
||||
{
|
||||
if (result == S_FALSE)
|
||||
opRes = NExtract::NOperationResult::kDataError;
|
||||
else
|
||||
{
|
||||
RINOK(result);
|
||||
if (outStreamSpec->GetCRC() != item.CRC)
|
||||
opRes = 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"Lzh", L"lzh lha", 0, 6, { '-', 'l' }, 2, false, CreateArc, 0 };
|
||||
|
||||
REGISTER_ARC(Lzh)
|
||||
|
||||
}}
|
||||
@@ -1,14 +0,0 @@
|
||||
// LzmaArcRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "LzmaHandler.h"
|
||||
|
||||
static IInArchive *CreateArc() { return new NArchive::NLzma::CHandler; }
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"Lzma", L"lzma lzma86", 0, 0xA, {0 }, 0, true, CreateArc, NULL };
|
||||
|
||||
REGISTER_ARC(Lzma)
|
||||
@@ -1,86 +0,0 @@
|
||||
// LzmaFiltersDecode.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "LzmaFiltersDecode.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzma {
|
||||
|
||||
static const UInt64 k_LZMA = 0x030101;
|
||||
static const UInt64 k_BCJ = 0x03030103;
|
||||
|
||||
HRESULT CDecoder::Code(
|
||||
DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
const CHeader &block,
|
||||
ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
UInt64 *inProcessedSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
*inProcessedSize = (UInt64)(Int64)-1;
|
||||
|
||||
if (block.FilterMethod > 1)
|
||||
return E_NOTIMPL;
|
||||
|
||||
if (!_lzmaDecoder)
|
||||
{
|
||||
RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS k_LZMA, _lzmaDecoder, false));
|
||||
if (_lzmaDecoder == 0)
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
{
|
||||
CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
|
||||
_lzmaDecoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties);
|
||||
if (!setDecoderProperties)
|
||||
return E_NOTIMPL;
|
||||
RINOK(setDecoderProperties->SetDecoderProperties2(block.LzmaProps, 5));
|
||||
}
|
||||
|
||||
bool filteredMode = (block.FilterMethod == 1);
|
||||
|
||||
CMyComPtr<ICompressSetOutStream> setOutStream;
|
||||
|
||||
if (filteredMode)
|
||||
{
|
||||
if (!_bcjStream)
|
||||
{
|
||||
CMyComPtr<ICompressCoder> coder;
|
||||
RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS k_BCJ, coder, false));
|
||||
if (!coder)
|
||||
return E_NOTIMPL;
|
||||
coder.QueryInterface(IID_ISequentialOutStream, &_bcjStream);
|
||||
if (!_bcjStream)
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
_bcjStream.QueryInterface(IID_ICompressSetOutStream, &setOutStream);
|
||||
if (!setOutStream)
|
||||
return E_NOTIMPL;
|
||||
RINOK(setOutStream->SetOutStream(outStream));
|
||||
outStream = _bcjStream;
|
||||
}
|
||||
|
||||
const UInt64 *unpackSize = block.HasUnpackSize() ? &block.UnpackSize : NULL;
|
||||
RINOK(_lzmaDecoder->Code(inStream, outStream, NULL, unpackSize, progress));
|
||||
|
||||
if (filteredMode)
|
||||
{
|
||||
CMyComPtr<IOutStreamFlush> flush;
|
||||
_bcjStream.QueryInterface(IID_IOutStreamFlush, &flush);
|
||||
if (flush)
|
||||
{
|
||||
RINOK(flush->Flush());
|
||||
}
|
||||
RINOK(setOutStream->ReleaseOutStream());
|
||||
}
|
||||
|
||||
CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize;
|
||||
_lzmaDecoder.QueryInterface(IID_ICompressGetInStreamProcessedSize, &getInStreamProcessedSize);
|
||||
if (getInStreamProcessedSize)
|
||||
{
|
||||
RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(inProcessedSize));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,26 +0,0 @@
|
||||
// LzmaFiltersDecode.h
|
||||
|
||||
#ifndef __LZMA_FILTERS_DECODE_H
|
||||
#define __LZMA_FILTERS_DECODE_H
|
||||
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
#include "LzmaItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzma {
|
||||
|
||||
class CDecoder
|
||||
{
|
||||
CMyComPtr<ICompressCoder> _lzmaDecoder;
|
||||
CMyComPtr<ISequentialOutStream> _bcjStream;
|
||||
public:
|
||||
HRESULT Code(DECL_EXTERNAL_CODECS_LOC_VARS
|
||||
const CHeader &block,
|
||||
ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
UInt64 *inProcessedSize, ICompressProgressInfo *progress);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,243 +0,0 @@
|
||||
// LzmaHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "LzmaHandler.h"
|
||||
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/IntToString.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
#include "../Common/DummyOutStream.h"
|
||||
|
||||
#include "LzmaFiltersDecode.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzma {
|
||||
|
||||
STATPROPSTG kProps[] =
|
||||
{
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidMethod, VT_UI1}
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
IMP_IInArchive_ArcProps_NO
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = 1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void ConvertUInt32ToString(UInt32 value, wchar_t *s)
|
||||
{
|
||||
ConvertUInt64ToString(value, s + MyStringLen(s));
|
||||
}
|
||||
|
||||
static void DictSizeToString(UInt32 value, wchar_t *s)
|
||||
{
|
||||
for (int i = 0; i <= 31; i++)
|
||||
if ((UInt32(1) << i) == value)
|
||||
{
|
||||
ConvertUInt32ToString(i, s);
|
||||
return;
|
||||
}
|
||||
wchar_t c = L'b';
|
||||
if ((value & ((1 << 20) - 1)) == 0)
|
||||
{
|
||||
value >>= 20;
|
||||
c = L'm';
|
||||
}
|
||||
else if ((value & ((1 << 10) - 1)) == 0)
|
||||
{
|
||||
value >>= 10;
|
||||
c = L'k';
|
||||
}
|
||||
ConvertUInt32ToString(value, s);
|
||||
int p = MyStringLen(s);
|
||||
s[p++] = c;
|
||||
s[p++] = L'\0';
|
||||
}
|
||||
|
||||
static void MyStrCat(wchar_t *d, const wchar_t *s)
|
||||
{
|
||||
MyStringCopy(d + MyStringLen(d), s);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
if (index != 0)
|
||||
return E_INVALIDARG;
|
||||
NWindows::NCOM::CPropVariant propVariant;
|
||||
switch(propID)
|
||||
{
|
||||
case kpidSize:
|
||||
if (m_StreamInfo.HasUnpackSize())
|
||||
propVariant = (UInt64)m_StreamInfo.UnpackSize;
|
||||
break;
|
||||
case kpidPackSize:
|
||||
propVariant = (UInt64)m_PackSize;
|
||||
break;
|
||||
case kpidMethod:
|
||||
{
|
||||
wchar_t s[64];
|
||||
s[0] = '\0';
|
||||
if (m_StreamInfo.IsThereFilter)
|
||||
{
|
||||
const wchar_t *f;
|
||||
if (m_StreamInfo.FilterMethod == 0)
|
||||
f = L"Copy";
|
||||
else if (m_StreamInfo.FilterMethod == 1)
|
||||
f = L"BCJ";
|
||||
else
|
||||
f = L"Unknown";
|
||||
MyStrCat(s, f);
|
||||
MyStrCat(s, L" ");
|
||||
}
|
||||
MyStrCat(s, L"LZMA:");
|
||||
DictSizeToString(m_StreamInfo.GetDicSize(), s);
|
||||
propVariant = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
const UInt64 * /* maxCheckStartPosition */,
|
||||
IArchiveOpenCallback * /* openArchiveCallback */)
|
||||
{
|
||||
{
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition));
|
||||
|
||||
HRESULT res = ReadStreamHeader(inStream, m_StreamInfo);
|
||||
if (res != S_OK)
|
||||
return S_FALSE;
|
||||
|
||||
Byte b;
|
||||
RINOK(ReadStream_FALSE(inStream, &b, 1));
|
||||
if (b != 0)
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 endPos;
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos));
|
||||
m_PackSize = endPos - m_StreamStartPosition - m_StreamInfo.GetHeaderSize();
|
||||
|
||||
m_Stream = inStream;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
m_Stream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == UInt32(-1));
|
||||
if (!allFilesMode)
|
||||
{
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
if (numItems != 1)
|
||||
return E_INVALIDARG;
|
||||
if (indices[0] != 0)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
bool testMode = (_aTestMode != 0);
|
||||
|
||||
RINOK(extractCallback->SetTotal(m_PackSize));
|
||||
|
||||
UInt64 currentTotalPacked = 0;
|
||||
|
||||
CDummyOutStream *outStreamSpec = new CDummyOutStream;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
Int32 askMode = testMode ?
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
|
||||
RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
|
||||
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
outStreamSpec->Init();
|
||||
if(!testMode && !realOutStream)
|
||||
return S_OK;
|
||||
extractCallback->PrepareOperation(askMode);
|
||||
}
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, true);
|
||||
|
||||
CDecoder decoder;
|
||||
RINOK(m_Stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL));
|
||||
UInt64 streamPos = m_StreamStartPosition;
|
||||
Int32 opRes = NArchive::NExtract::NOperationResult::kOK;
|
||||
bool firstItem = true;
|
||||
for (;;)
|
||||
{
|
||||
CHeader st;
|
||||
HRESULT result = ReadStreamHeader(m_Stream, st);
|
||||
if (result != S_OK)
|
||||
{
|
||||
if (firstItem)
|
||||
return E_FAIL;
|
||||
break;
|
||||
}
|
||||
firstItem = false;
|
||||
|
||||
lps->OutSize = outStreamSpec->GetSize();
|
||||
lps->InSize = currentTotalPacked;
|
||||
RINOK(lps->SetCur());
|
||||
|
||||
streamPos += st.GetHeaderSize();
|
||||
UInt64 packProcessed;
|
||||
|
||||
{
|
||||
result = decoder.Code(
|
||||
EXTERNAL_CODECS_VARS
|
||||
st, m_Stream, outStream, &packProcessed, progress);
|
||||
if (result == E_NOTIMPL)
|
||||
{
|
||||
opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod;
|
||||
break;
|
||||
}
|
||||
if (result == S_FALSE)
|
||||
{
|
||||
opRes = NArchive::NExtract::NOperationResult::kDataError;
|
||||
break;
|
||||
}
|
||||
RINOK(result);
|
||||
}
|
||||
|
||||
if (packProcessed == (UInt64)(Int64)-1)
|
||||
break;
|
||||
RINOK(m_Stream->Seek(streamPos + packProcessed, STREAM_SEEK_SET, NULL));
|
||||
currentTotalPacked += packProcessed;
|
||||
streamPos += packProcessed;
|
||||
}
|
||||
outStream.Release();
|
||||
return extractCallback->SetOperationResult(opRes);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
IMPL_ISetCompressCodecsInfo
|
||||
|
||||
}}
|
||||
@@ -1,69 +0,0 @@
|
||||
// Lzma/Handler.h
|
||||
|
||||
#ifndef __GZIP_HANDLER_H
|
||||
#define __GZIP_HANDLER_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
|
||||
#include "../IArchive.h"
|
||||
#include "../../Common/CreateCoder.h"
|
||||
|
||||
#include "LzmaIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzma {
|
||||
|
||||
// const UInt64 k_LZMA = 0x030101;
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
PUBLIC_ISetCompressCodecsInfo
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_QUERYINTERFACE_BEGIN
|
||||
MY_QUERYINTERFACE_ENTRY(IInArchive)
|
||||
QUERY_ENTRY_ISetCompressCodecsInfo
|
||||
MY_QUERYINTERFACE_END
|
||||
MY_ADDREF_RELEASE
|
||||
|
||||
STDMETHOD(Open)(IInStream *inStream,
|
||||
const UInt64 *maxCheckStartPosition,
|
||||
IArchiveOpenCallback *openArchiveCallback);
|
||||
STDMETHOD(Close)();
|
||||
|
||||
STDMETHOD(GetNumberOfItems)(UInt32 *numItems);
|
||||
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
|
||||
STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback);
|
||||
|
||||
STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value);
|
||||
|
||||
STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties);
|
||||
STDMETHOD(GetPropertyInfo)(UInt32 index,
|
||||
BSTR *name, PROPID *propID, VARTYPE *varType);
|
||||
|
||||
STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProperties);
|
||||
STDMETHOD(GetArchivePropertyInfo)(UInt32 index,
|
||||
BSTR *name, PROPID *propID, VARTYPE *varType);
|
||||
|
||||
UString GetMethodString();
|
||||
public:
|
||||
CHandler() { }
|
||||
|
||||
private:
|
||||
CHeader m_StreamInfo;
|
||||
UInt64 m_StreamStartPosition;
|
||||
UInt64 m_PackSize;
|
||||
|
||||
CMyComPtr<IInStream> m_Stream;
|
||||
|
||||
DECL_EXTERNAL_CODECS_VARS
|
||||
|
||||
DECL_ISetCompressCodecsInfo
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
// Archive/LzmaIn.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "LzmaIn.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzma {
|
||||
|
||||
static bool CheckDictSize(const Byte *p)
|
||||
{
|
||||
UInt32 dicSize = GetUi32(p);
|
||||
int i;
|
||||
for (i = 1; i <= 30; i++)
|
||||
if (dicSize == ((UInt32)2 << i) || dicSize == ((UInt32)3 << i))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT ReadStreamHeader(ISequentialInStream *inStream, CHeader &block)
|
||||
{
|
||||
Byte sig[5 + 9];
|
||||
RINOK(ReadStream_FALSE(inStream, sig, 5 + 8));
|
||||
|
||||
const Byte kMaxProp0Val = 5 * 5 * 9 - 1;
|
||||
if (sig[0] > kMaxProp0Val)
|
||||
return S_FALSE;
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
block.LzmaProps[i] = sig[i];
|
||||
|
||||
block.IsThereFilter = false;
|
||||
block.FilterMethod = 0;
|
||||
|
||||
if (!CheckDictSize(sig + 1))
|
||||
{
|
||||
if (sig[0] > 1 || sig[1] > kMaxProp0Val)
|
||||
return S_FALSE;
|
||||
block.IsThereFilter = true;
|
||||
block.FilterMethod = sig[0];
|
||||
for (int i = 0; i < 5; i++)
|
||||
block.LzmaProps[i] = sig[i + 1];
|
||||
if (!CheckDictSize(block.LzmaProps + 1))
|
||||
return S_FALSE;
|
||||
RINOK(ReadStream_FALSE(inStream, sig + 5 + 8, 1));
|
||||
}
|
||||
UInt32 unpOffset = 5 + (block.IsThereFilter ? 1 : 0);
|
||||
block.UnpackSize = GetUi64(sig + unpOffset);
|
||||
if (block.HasUnpackSize() && block.UnpackSize >= ((UInt64)1 << 56))
|
||||
return S_FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Archive/LzmaIn.h
|
||||
|
||||
#ifndef __ARCHIVE_LZMA_IN_H
|
||||
#define __ARCHIVE_LZMA_IN_H
|
||||
|
||||
#include "LzmaItem.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NLzma {
|
||||
|
||||
HRESULT ReadStreamHeader(ISequentialInStream *inStream, CHeader &st);
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user