blob: c404b9cb5af26c2fb201e8789a3c0e0583e7df1b [file] [log] [blame]
// 7zHandler.cpp
#include "StdAfx.h"
#include "../../../../C/CpuArch.h"
#include "../../../Common/ComTry.h"
#include "../../../Common/IntToString.h"
#ifndef __7Z_SET_PROPERTIES
#include "../../../Windows/System.h"
#endif
#include "../Common/ItemNameUtils.h"
#include "7zHandler.h"
#include "7zProperties.h"
#ifdef __7Z_SET_PROPERTIES
#ifdef EXTRACT_ONLY
#include "../Common/ParseProperties.h"
#endif
#endif
using namespace NWindows;
extern UString ConvertMethodIdToString(UInt64 id);
namespace NArchive {
namespace N7z {
CHandler::CHandler()
{
_crcSize = 4;
#ifndef _NO_CRYPTO
_passwordIsDefined = false;
#endif
#ifdef EXTRACT_ONLY
#ifdef __7Z_SET_PROPERTIES
_numThreads = NSystem::GetNumberOfProcessors();
#endif
#else
Init();
#endif
}
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
{
*numItems = _db.Files.Size();
return S_OK;
}
#ifdef _SFX
IMP_IInArchive_ArcProps_NO
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */)
{
return E_NOTIMPL;
}
STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
{
return E_NOTIMPL;
}
#else
STATPROPSTG kArcProps[] =
{
{ NULL, kpidMethod, VT_BSTR},
{ NULL, kpidSolid, VT_BOOL},
{ NULL, kpidNumBlocks, VT_UI4},
{ NULL, kpidPhySize, VT_UI8},
{ NULL, kpidHeadersSize, VT_UI8},
{ NULL, kpidOffset, VT_UI8}
};
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
switch(propID)
{
case kpidMethod:
{
UString resString;
CRecordVector<UInt64> ids;
int i;
for (i = 0; i < _db.Folders.Size(); i++)
{
const CFolder &f = _db.Folders[i];
for (int j = f.Coders.Size() - 1; j >= 0; j--)
ids.AddToUniqueSorted(f.Coders[j].MethodID);
}
for (i = 0; i < ids.Size(); i++)
{
UInt64 id = ids[i];
UString methodName;
/* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName);
if (methodName.IsEmpty())
methodName = ConvertMethodIdToString(id);
if (!resString.IsEmpty())
resString += L' ';
resString += methodName;
}
prop = resString;
break;
}
case kpidSolid: prop = _db.IsSolid(); break;
case kpidNumBlocks: prop = (UInt32)_db.Folders.Size(); break;
case kpidHeadersSize: prop = _db.HeadersSize; break;
case kpidPhySize: prop = _db.PhySize; break;
case kpidOffset: if (_db.ArchiveInfo.StartPosition != 0) prop = _db.ArchiveInfo.StartPosition; break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
IMP_IInArchive_ArcProps
#endif
static void SetPropFromUInt64Def(CUInt64DefVector &v, int index, NCOM::CPropVariant &prop)
{
UInt64 value;
if (v.GetItem(index, value))
{
FILETIME ft;
ft.dwLowDateTime = (DWORD)value;
ft.dwHighDateTime = (DWORD)(value >> 32);
prop = ft;
}
}
#ifndef _SFX
static UString ConvertUInt32ToString(UInt32 value)
{
wchar_t buffer[32];
ConvertUInt64ToString(value, buffer);
return buffer;
}
static UString GetStringForSizeValue(UInt32 value)
{
for (int i = 31; i >= 0; i--)
if ((UInt32(1) << i) == value)
return ConvertUInt32ToString(i);
UString result;
if (value % (1 << 20) == 0)
{
result += ConvertUInt32ToString(value >> 20);
result += L"m";
}
else if (value % (1 << 10) == 0)
{
result += ConvertUInt32ToString(value >> 10);
result += L"k";
}
else
{
result += ConvertUInt32ToString(value);
result += L"b";
}
return result;
}
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;
static wchar_t GetHex(Byte value)
{
return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10)));
}
static inline void AddHexToString(UString &res, Byte value)
{
res += GetHex((Byte)(value >> 4));
res += GetHex((Byte)(value & 0xF));
}
#endif
bool CHandler::IsEncrypted(UInt32 index2) const
{
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
if (folderIndex != kNumNoIndex)
return _db.Folders[folderIndex].IsEncrypted();
return false;
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
/*
const CRef2 &ref2 = _refs[index];
if (ref2.Refs.IsEmpty())
return E_FAIL;
const CRef &ref = ref2.Refs.Front();
*/
const CFileItem &item = _db.Files[index];
UInt32 index2 = index;
switch(propID)
{
case kpidPath:
if (!item.Name.IsEmpty())
prop = NItemName::GetOSName(item.Name);
break;
case kpidIsDir: prop = item.IsDir; break;
case kpidSize:
{
prop = item.Size;
// prop = ref2.Size;
break;
}
case kpidPackSize:
{
// prop = ref2.PackSize;
{
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
if (folderIndex != kNumNoIndex)
{
if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2)
prop = _db.GetFolderFullPackSize(folderIndex);
/*
else
prop = (UInt64)0;
*/
}
else
prop = (UInt64)0;
}
break;
}
case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) prop = v; break; }
case kpidCTime: SetPropFromUInt64Def(_db.CTime, index2, prop); break;
case kpidATime: SetPropFromUInt64Def(_db.ATime, index2, prop); break;
case kpidMTime: SetPropFromUInt64Def(_db.MTime, index2, prop); break;
case kpidAttrib: if (item.AttribDefined) prop = item.Attrib; break;
case kpidCRC: if (item.CrcDefined) prop = item.Crc; break;
case kpidEncrypted: prop = IsEncrypted(index2); break;
case kpidIsAnti: prop = _db.IsItemAnti(index2); break;
#ifndef _SFX
case kpidMethod:
{
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
if (folderIndex != kNumNoIndex)
{
const CFolder &folderInfo = _db.Folders[folderIndex];
UString methodsString;
for (int i = folderInfo.Coders.Size() - 1; i >= 0; 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
{
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)
{
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;
propsString = L'o';
propsString += ConvertUInt32ToString(order);
propsString += 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)
{
UInt32 saltSize = (firstByte >> 7) & 1;
UInt32 ivSize = (firstByte >> 6) & 1;
if (coder.Props.GetCapacity() >= 2)
{
Byte secondByte = *data++;
saltSize += (secondByte >> 4);
ivSize += (secondByte & 0x0F);
}
}
*/
}
}
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())
{
methodsString += L"..";
break;
}
else
AddHexToString(methodsString, coder.Props[bi]);
}
methodsString += L']';
}
}
prop = methodsString;
}
}
break;
case kpidBlock:
{
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
if (folderIndex != kNumNoIndex)
prop = (UInt32)folderIndex;
}
break;
case kpidPackedSize0:
case kpidPackedSize1:
case kpidPackedSize2:
case kpidPackedSize3:
case kpidPackedSize4:
{
CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
if (folderIndex != kNumNoIndex)
{
const CFolder &folderInfo = _db.Folders[folderIndex];
if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0))
{
prop = _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0);
}
else
prop = (UInt64)0;
}
else
prop = (UInt64)0;
}
break;
#endif
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::Open(IInStream *stream,
const UInt64 *maxCheckStartPosition,
IArchiveOpenCallback *openArchiveCallback)
{
COM_TRY_BEGIN
Close();
#ifndef _SFX
_fileInfoPopIDs.Clear();
#endif
try
{
CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
#ifndef _NO_CRYPTO
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
if (openArchiveCallback)
{
openArchiveCallbackTemp.QueryInterface(
IID_ICryptoGetTextPassword, &getTextPassword);
}
#endif
CInArchive archive;
RINOK(archive.Open(stream, maxCheckStartPosition));
#ifndef _NO_CRYPTO
_passwordIsDefined = false;
UString password;
#endif
HRESULT result = archive.ReadDatabase(
EXTERNAL_CODECS_VARS
_db
#ifndef _NO_CRYPTO
, getTextPassword, _passwordIsDefined
#endif
);
RINOK(result);
_db.Fill();
_inStream = stream;
}
catch(...)
{
Close();
return S_FALSE;
}
// _inStream = stream;
#ifndef _SFX
FillPopIDs();
#endif
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::Close()
{
COM_TRY_BEGIN
_inStream.Release();
_db.Clear();
return S_OK;
COM_TRY_END
}
#ifdef __7Z_SET_PROPERTIES
#ifdef EXTRACT_ONLY
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
{
COM_TRY_BEGIN
const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
_numThreads = numProcessors;
for (int i = 0; i < numProperties; i++)
{
UString name = names[i];
name.MakeUpper();
if (name.IsEmpty())
return E_INVALIDARG;
const PROPVARIANT &value = values[i];
UInt32 number;
int index = ParseStringToUInt32(name, number);
if (index == 0)
{
if(name.Left(2).CompareNoCase(L"MT") == 0)
{
RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
continue;
}
else
return E_INVALIDARG;
}
}
return S_OK;
COM_TRY_END
}
#endif
#endif
IMPL_ISetCompressCodecsInfo
}}