mame/3rdparty/lzma/CPP/7zip/UI/Client7z/Client7z.cpp
2023-12-06 07:58:49 +11:00

1123 lines
26 KiB
C++

// Client7z.cpp
#include "StdAfx.h"
#include <stdio.h>
#include "../../../Common/MyWindows.h"
#include "../../../Common/MyInitGuid.h"
#include "../../../Common/Defs.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/StringConvert.h"
#include "../../../Windows/DLL.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileFind.h"
#include "../../../Windows/FileName.h"
#include "../../../Windows/NtCheck.h"
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/PropVariantConv.h"
#include "../../Common/FileStreams.h"
#include "../../Archive/IArchive.h"
#include "../../IPassword.h"
#include "../../../../C/7zVersion.h"
#ifdef _WIN32
extern
HINSTANCE g_hInstance;
HINSTANCE g_hInstance = NULL;
#endif
// You can find full list of all GUIDs supported by 7-Zip in Guid.txt file.
// 7z format GUID: {23170F69-40C1-278A-1000-000110070000}
#define DEFINE_GUID_ARC(name, id) Z7_DEFINE_GUID(name, \
0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, id, 0x00, 0x00);
enum
{
kId_Zip = 1,
kId_BZip2 = 2,
kId_7z = 7,
kId_Xz = 0xC,
kId_Tar = 0xEE,
kId_GZip = 0xEF
};
// use another id, if you want to support other formats (zip, Xz, ...).
// DEFINE_GUID_ARC (CLSID_Format, kId_Zip)
// DEFINE_GUID_ARC (CLSID_Format, kId_BZip2)
// DEFINE_GUID_ARC (CLSID_Format, kId_Xz)
// DEFINE_GUID_ARC (CLSID_Format, kId_Tar)
// DEFINE_GUID_ARC (CLSID_Format, kId_GZip)
DEFINE_GUID_ARC (CLSID_Format, kId_7z)
using namespace NWindows;
using namespace NFile;
using namespace NDir;
#ifdef _WIN32
#define kDllName "7z.dll"
#else
#define kDllName "7z.so"
#endif
static const char * const kCopyrightString =
"\n"
"7-Zip"
" (" kDllName " client)"
" " MY_VERSION
" : " MY_COPYRIGHT_DATE
"\n";
static const char * const kHelpString =
"Usage: 7zcl.exe [a | l | x] archive.7z [fileName ...]\n"
"Examples:\n"
" 7zcl.exe a archive.7z f1.txt f2.txt : compress two files to archive.7z\n"
" 7zcl.exe l archive.7z : List contents of archive.7z\n"
" 7zcl.exe x archive.7z : eXtract files from archive.7z\n";
static void Convert_UString_to_AString(const UString &s, AString &temp)
{
int codePage = CP_OEMCP;
/*
int g_CodePage = -1;
int codePage = g_CodePage;
if (codePage == -1)
codePage = CP_OEMCP;
if (codePage == CP_UTF8)
ConvertUnicodeToUTF8(s, temp);
else
*/
UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
}
static FString CmdStringToFString(const char *s)
{
return us2fs(GetUnicodeString(s));
}
static void Print(const char *s)
{
fputs(s, stdout);
}
static void Print(const AString &s)
{
Print(s.Ptr());
}
static void Print(const UString &s)
{
AString as;
Convert_UString_to_AString(s, as);
Print(as);
}
static void Print(const wchar_t *s)
{
Print(UString(s));
}
static void PrintNewLine()
{
Print("\n");
}
static void PrintStringLn(const char *s)
{
Print(s);
PrintNewLine();
}
static void PrintError(const char *message)
{
Print("Error: ");
PrintNewLine();
Print(message);
PrintNewLine();
}
static void PrintError(const char *message, const FString &name)
{
PrintError(message);
Print(name);
}
static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
{
NCOM::CPropVariant prop;
RINOK(archive->GetProperty(index, propID, &prop))
if (prop.vt == VT_BOOL)
result = VARIANT_BOOLToBool(prop.boolVal);
else if (prop.vt == VT_EMPTY)
result = false;
else
return E_FAIL;
return S_OK;
}
static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
{
return IsArchiveItemProp(archive, index, kpidIsDir, result);
}
static const wchar_t * const kEmptyFileAlias = L"[Content]";
//////////////////////////////////////////////////////////////
// Archive Open callback class
class CArchiveOpenCallback Z7_final:
public IArchiveOpenCallback,
public ICryptoGetTextPassword,
public CMyUnknownImp
{
Z7_IFACES_IMP_UNK_2(IArchiveOpenCallback, ICryptoGetTextPassword)
public:
bool PasswordIsDefined;
UString Password;
CArchiveOpenCallback() : PasswordIsDefined(false) {}
};
Z7_COM7F_IMF(CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */))
{
return S_OK;
}
Z7_COM7F_IMF(CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */))
{
return S_OK;
}
Z7_COM7F_IMF(CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password))
{
if (!PasswordIsDefined)
{
// You can ask real password here from user
// Password = GetPassword(OutStream);
// PasswordIsDefined = true;
PrintError("Password is not defined");
return E_ABORT;
}
return StringToBstr(Password, password);
}
static const char * const kIncorrectCommand = "incorrect command";
//////////////////////////////////////////////////////////////
// Archive Extracting callback class
static const char * const kTestingString = "Testing ";
static const char * const kExtractingString = "Extracting ";
static const char * const kSkippingString = "Skipping ";
static const char * const kReadingString = "Reading ";
static const char * const kUnsupportedMethod = "Unsupported Method";
static const char * const kCRCFailed = "CRC Failed";
static const char * const kDataError = "Data Error";
static const char * const kUnavailableData = "Unavailable data";
static const char * const kUnexpectedEnd = "Unexpected end of data";
static const char * const kDataAfterEnd = "There are some data after the end of the payload data";
static const char * const kIsNotArc = "Is not archive";
static const char * const kHeadersError = "Headers Error";
struct CArcTime
{
FILETIME FT;
UInt16 Prec;
Byte Ns100;
bool Def;
CArcTime()
{
Clear();
}
void Clear()
{
FT.dwHighDateTime = FT.dwLowDateTime = 0;
Prec = 0;
Ns100 = 0;
Def = false;
}
bool IsZero() const
{
return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0;
}
int GetNumDigits() const
{
if (Prec == k_PropVar_TimePrec_Unix ||
Prec == k_PropVar_TimePrec_DOS)
return 0;
if (Prec == k_PropVar_TimePrec_HighPrec)
return 9;
if (Prec == k_PropVar_TimePrec_0)
return 7;
int digits = (int)Prec - (int)k_PropVar_TimePrec_Base;
if (digits < 0)
digits = 0;
return digits;
}
void Write_To_FiTime(CFiTime &dest) const
{
#ifdef _WIN32
dest = FT;
#else
if (FILETIME_To_timespec(FT, dest))
if ((Prec == k_PropVar_TimePrec_Base + 8 ||
Prec == k_PropVar_TimePrec_Base + 9)
&& Ns100 != 0)
{
dest.tv_nsec += Ns100;
}
#endif
}
void Set_From_Prop(const PROPVARIANT &prop)
{
FT = prop.filetime;
unsigned prec = 0;
unsigned ns100 = 0;
const unsigned prec_Temp = prop.wReserved1;
if (prec_Temp != 0
&& prec_Temp <= k_PropVar_TimePrec_1ns
&& prop.wReserved3 == 0)
{
const unsigned ns100_Temp = prop.wReserved2;
if (ns100_Temp < 100)
{
ns100 = ns100_Temp;
prec = prec_Temp;
}
}
Prec = (UInt16)prec;
Ns100 = (Byte)ns100;
Def = true;
}
};
class CArchiveExtractCallback Z7_final:
public IArchiveExtractCallback,
public ICryptoGetTextPassword,
public CMyUnknownImp
{
Z7_IFACES_IMP_UNK_2(IArchiveExtractCallback, ICryptoGetTextPassword)
Z7_IFACE_COM7_IMP(IProgress)
CMyComPtr<IInArchive> _archiveHandler;
FString _directoryPath; // Output directory
UString _filePath; // name inside arcvhive
FString _diskFilePath; // full path to file on disk
bool _extractMode;
struct CProcessedFileInfo
{
CArcTime MTime;
UInt32 Attrib;
bool isDir;
bool Attrib_Defined;
} _processedFileInfo;
COutFileStream *_outFileStreamSpec;
CMyComPtr<ISequentialOutStream> _outFileStream;
public:
void Init(IInArchive *archiveHandler, const FString &directoryPath);
UInt64 NumErrors;
bool PasswordIsDefined;
UString Password;
CArchiveExtractCallback() : PasswordIsDefined(false) {}
};
void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const FString &directoryPath)
{
NumErrors = 0;
_archiveHandler = archiveHandler;
_directoryPath = directoryPath;
NName::NormalizeDirPathPrefix(_directoryPath);
}
Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 /* size */))
{
return S_OK;
}
Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */))
{
return S_OK;
}
Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index,
ISequentialOutStream **outStream, Int32 askExtractMode))
{
*outStream = NULL;
_outFileStream.Release();
{
// Get Name
NCOM::CPropVariant prop;
RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop))
UString fullPath;
if (prop.vt == VT_EMPTY)
fullPath = kEmptyFileAlias;
else
{
if (prop.vt != VT_BSTR)
return E_FAIL;
fullPath = prop.bstrVal;
}
_filePath = fullPath;
}
if (askExtractMode != NArchive::NExtract::NAskMode::kExtract)
return S_OK;
{
// Get Attrib
NCOM::CPropVariant prop;
RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop))
if (prop.vt == VT_EMPTY)
{
_processedFileInfo.Attrib = 0;
_processedFileInfo.Attrib_Defined = false;
}
else
{
if (prop.vt != VT_UI4)
return E_FAIL;
_processedFileInfo.Attrib = prop.ulVal;
_processedFileInfo.Attrib_Defined = true;
}
}
RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir))
{
_processedFileInfo.MTime.Clear();
// Get Modified Time
NCOM::CPropVariant prop;
RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop))
switch (prop.vt)
{
case VT_EMPTY:
// _processedFileInfo.MTime = _utcMTimeDefault;
break;
case VT_FILETIME:
_processedFileInfo.MTime.Set_From_Prop(prop);
break;
default:
return E_FAIL;
}
}
{
// Get Size
NCOM::CPropVariant prop;
RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop))
UInt64 newFileSize;
/* bool newFileSizeDefined = */ ConvertPropVariantToUInt64(prop, newFileSize);
}
{
// Create folders for file
int slashPos = _filePath.ReverseFind_PathSepar();
if (slashPos >= 0)
CreateComplexDir(_directoryPath + us2fs(_filePath.Left(slashPos)));
}
FString fullProcessedPath = _directoryPath + us2fs(_filePath);
_diskFilePath = fullProcessedPath;
if (_processedFileInfo.isDir)
{
CreateComplexDir(fullProcessedPath);
}
else
{
NFind::CFileInfo fi;
if (fi.Find(fullProcessedPath))
{
if (!DeleteFileAlways(fullProcessedPath))
{
PrintError("Cannot delete output file", fullProcessedPath);
return E_ABORT;
}
}
_outFileStreamSpec = new COutFileStream;
CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
if (!_outFileStreamSpec->Open(fullProcessedPath, CREATE_ALWAYS))
{
PrintError("Cannot open output file", fullProcessedPath);
return E_ABORT;
}
_outFileStream = outStreamLoc;
*outStream = outStreamLoc.Detach();
}
return S_OK;
}
Z7_COM7F_IMF(CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode))
{
_extractMode = false;
switch (askExtractMode)
{
case NArchive::NExtract::NAskMode::kExtract: _extractMode = true; break;
}
switch (askExtractMode)
{
case NArchive::NExtract::NAskMode::kExtract: Print(kExtractingString); break;
case NArchive::NExtract::NAskMode::kTest: Print(kTestingString); break;
case NArchive::NExtract::NAskMode::kSkip: Print(kSkippingString); break;
case NArchive::NExtract::NAskMode::kReadExternal: Print(kReadingString); break;
default:
Print("??? "); break;
}
Print(_filePath);
return S_OK;
}
Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 operationResult))
{
switch (operationResult)
{
case NArchive::NExtract::NOperationResult::kOK:
break;
default:
{
NumErrors++;
Print(" : ");
const char *s = NULL;
switch (operationResult)
{
case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
s = kUnsupportedMethod;
break;
case NArchive::NExtract::NOperationResult::kCRCError:
s = kCRCFailed;
break;
case NArchive::NExtract::NOperationResult::kDataError:
s = kDataError;
break;
case NArchive::NExtract::NOperationResult::kUnavailable:
s = kUnavailableData;
break;
case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
s = kUnexpectedEnd;
break;
case NArchive::NExtract::NOperationResult::kDataAfterEnd:
s = kDataAfterEnd;
break;
case NArchive::NExtract::NOperationResult::kIsNotArc:
s = kIsNotArc;
break;
case NArchive::NExtract::NOperationResult::kHeadersError:
s = kHeadersError;
break;
}
if (s)
{
Print("Error : ");
Print(s);
}
else
{
char temp[16];
ConvertUInt32ToString((UInt32)operationResult, temp);
Print("Error #");
Print(temp);
}
}
}
if (_outFileStream)
{
if (_processedFileInfo.MTime.Def)
{
CFiTime ft;
_processedFileInfo.MTime.Write_To_FiTime(ft);
_outFileStreamSpec->SetMTime(&ft);
}
RINOK(_outFileStreamSpec->Close())
}
_outFileStream.Release();
if (_extractMode && _processedFileInfo.Attrib_Defined)
SetFileAttrib_PosixHighDetect(_diskFilePath, _processedFileInfo.Attrib);
PrintNewLine();
return S_OK;
}
Z7_COM7F_IMF(CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password))
{
if (!PasswordIsDefined)
{
// You can ask real password here from user
// Password = GetPassword(OutStream);
// PasswordIsDefined = true;
PrintError("Password is not defined");
return E_ABORT;
}
return StringToBstr(Password, password);
}
//////////////////////////////////////////////////////////////
// Archive Creating callback class
struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase
{
UString Path_For_Handler;
FString FullPath; // for filesystem
CDirItem(const NWindows::NFile::NFind::CFileInfo &fi):
CFileInfoBase(fi)
{}
};
class CArchiveUpdateCallback Z7_final:
public IArchiveUpdateCallback2,
public ICryptoGetTextPassword2,
public CMyUnknownImp
{
Z7_IFACES_IMP_UNK_2(IArchiveUpdateCallback2, ICryptoGetTextPassword2)
Z7_IFACE_COM7_IMP(IProgress)
Z7_IFACE_COM7_IMP(IArchiveUpdateCallback)
public:
CRecordVector<UInt64> VolumesSizes;
UString VolName;
UString VolExt;
FString DirPrefix;
const CObjectVector<CDirItem> *DirItems;
bool PasswordIsDefined;
UString Password;
bool AskPassword;
bool m_NeedBeClosed;
FStringVector FailedFiles;
CRecordVector<HRESULT> FailedCodes;
CArchiveUpdateCallback():
DirItems(NULL),
PasswordIsDefined(false),
AskPassword(false)
{}
~CArchiveUpdateCallback() { Finilize(); }
HRESULT Finilize();
void Init(const CObjectVector<CDirItem> *dirItems)
{
DirItems = dirItems;
m_NeedBeClosed = false;
FailedFiles.Clear();
FailedCodes.Clear();
}
};
Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal(UInt64 /* size */))
{
return S_OK;
}
Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */))
{
return S_OK;
}
Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */,
Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive))
{
if (newData)
*newData = BoolToInt(true);
if (newProperties)
*newProperties = BoolToInt(true);
if (indexInArchive)
*indexInArchive = (UInt32)(Int32)-1;
return S_OK;
}
Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
{
NCOM::CPropVariant prop;
if (propID == kpidIsAnti)
{
prop = false;
prop.Detach(value);
return S_OK;
}
{
const CDirItem &di = (*DirItems)[index];
switch (propID)
{
case kpidPath: prop = di.Path_For_Handler; break;
case kpidIsDir: prop = di.IsDir(); break;
case kpidSize: prop = di.Size; break;
case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break;
case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break;
case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break;
case kpidAttrib: prop = (UInt32)di.GetWinAttrib(); break;
case kpidPosixAttrib: prop = (UInt32)di.GetPosixAttrib(); break;
}
}
prop.Detach(value);
return S_OK;
}
HRESULT CArchiveUpdateCallback::Finilize()
{
if (m_NeedBeClosed)
{
PrintNewLine();
m_NeedBeClosed = false;
}
return S_OK;
}
static void GetStream2(const wchar_t *name)
{
Print("Compressing ");
if (name[0] == 0)
name = kEmptyFileAlias;
Print(name);
}
Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream))
{
RINOK(Finilize())
const CDirItem &dirItem = (*DirItems)[index];
GetStream2(dirItem.Path_For_Handler);
if (dirItem.IsDir())
return S_OK;
{
CInFileStream *inStreamSpec = new CInFileStream;
CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
FString path = DirPrefix + dirItem.FullPath;
if (!inStreamSpec->Open(path))
{
const DWORD sysError = ::GetLastError();
FailedCodes.Add(HRESULT_FROM_WIN32(sysError));
FailedFiles.Add(path);
// if (systemError == ERROR_SHARING_VIOLATION)
{
PrintNewLine();
PrintError("WARNING: can't open file");
// Print(NError::MyFormatMessageW(systemError));
return S_FALSE;
}
// return sysError;
}
*inStream = inStreamLoc.Detach();
}
return S_OK;
}
Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */))
{
m_NeedBeClosed = true;
return S_OK;
}
Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size))
{
if (VolumesSizes.Size() == 0)
return S_FALSE;
if (index >= (UInt32)VolumesSizes.Size())
index = VolumesSizes.Size() - 1;
*size = VolumesSizes[index];
return S_OK;
}
Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream))
{
wchar_t temp[16];
ConvertUInt32ToString(index + 1, temp);
UString res = temp;
while (res.Len() < 2)
res.InsertAtFront(L'0');
UString fileName = VolName;
fileName.Add_Dot();
fileName += res;
fileName += VolExt;
COutFileStream *streamSpec = new COutFileStream;
CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
if (!streamSpec->Create(us2fs(fileName), false))
return GetLastError_noZero_HRESULT();
*volumeStream = streamLoc.Detach();
return S_OK;
}
Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password))
{
if (!PasswordIsDefined)
{
if (AskPassword)
{
// You can ask real password here from user
// Password = GetPassword(OutStream);
// PasswordIsDefined = true;
PrintError("Password is not defined");
return E_ABORT;
}
}
*passwordIsDefined = BoolToInt(PasswordIsDefined);
return StringToBstr(Password, password);
}
// Main function
#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1;
#endif
int Z7_CDECL main(int numArgs, const char *args[])
{
NT_CHECK
#ifdef ENV_HAVE_LOCALE
MY_SetLocale();
#endif
PrintStringLn(kCopyrightString);
if (numArgs < 2)
{
PrintStringLn(kHelpString);
return 0;
}
FString dllPrefix;
#ifdef _WIN32
dllPrefix = NDLL::GetModuleDirPrefix();
#else
{
AString s (args[0]);
int sep = s.ReverseFind_PathSepar();
s.DeleteFrom(sep + 1);
dllPrefix = s;
}
#endif
NDLL::CLibrary lib;
if (!lib.Load(dllPrefix + FTEXT(kDllName)))
{
PrintError("Cannot load 7-zip library");
return 1;
}
Func_CreateObject
f_CreateObject = Z7_GET_PROC_ADDRESS(
Func_CreateObject, lib.Get_HMODULE(),
"CreateObject");
if (!f_CreateObject)
{
PrintError("Cannot get CreateObject");
return 1;
}
char c = 0;
UString password;
bool passwordIsDefined = false;
CObjectVector<FString> params;
for (int curCmd = 1; curCmd < numArgs; curCmd++)
{
AString a(args[curCmd]);
if (!a.IsEmpty())
{
if (a[0] == '-')
{
if (!passwordIsDefined && a[1] == 'p')
{
password = GetUnicodeString(a.Ptr(2));
passwordIsDefined = true;
continue;
}
}
else
{
if (c)
{
params.Add(CmdStringToFString(a));
continue;
}
if (a.Len() == 1)
{
c = (char)MyCharLower_Ascii(a[0]);
continue;
}
}
}
{
PrintError(kIncorrectCommand);
return 1;
}
}
if (!c || params.Size() < 1)
{
PrintError(kIncorrectCommand);
return 1;
}
const FString &archiveName = params[0];
if (c == 'a')
{
// create archive command
if (params.Size() < 2)
{
PrintError(kIncorrectCommand);
return 1;
}
CObjectVector<CDirItem> dirItems;
{
unsigned i;
for (i = 1; i < params.Size(); i++)
{
const FString &name = params[i];
NFind::CFileInfo fi;
if (!fi.Find(name))
{
PrintError("Can't find file", name);
return 1;
}
CDirItem di(fi);
di.Path_For_Handler = fs2us(name);
di.FullPath = name;
dirItems.Add(di);
}
}
COutFileStream *outFileStreamSpec = new COutFileStream;
CMyComPtr<IOutStream> outFileStream = outFileStreamSpec;
if (!outFileStreamSpec->Create(archiveName, false))
{
PrintError("can't create archive file");
return 1;
}
CMyComPtr<IOutArchive> outArchive;
if (f_CreateObject(&CLSID_Format, &IID_IOutArchive, (void **)&outArchive) != S_OK)
{
PrintError("Cannot get class object");
return 1;
}
CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
CMyComPtr<IArchiveUpdateCallback2> updateCallback(updateCallbackSpec);
updateCallbackSpec->Init(&dirItems);
updateCallbackSpec->PasswordIsDefined = passwordIsDefined;
updateCallbackSpec->Password = password;
/*
{
const wchar_t *names[] =
{
L"m",
L"s",
L"x"
};
const unsigned kNumProps = Z7_ARRAY_SIZE(names);
NCOM::CPropVariant values[kNumProps] =
{
L"lzma",
false, // solid mode OFF
(UInt32)9 // compression level = 9 - ultra
};
CMyComPtr<ISetProperties> setProperties;
outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties);
if (!setProperties)
{
PrintError("ISetProperties unsupported");
return 1;
}
if (setProperties->SetProperties(names, values, kNumProps) != S_OK)
{
PrintError("SetProperties() error");
return 1;
}
}
*/
HRESULT result = outArchive->UpdateItems(outFileStream, dirItems.Size(), updateCallback);
updateCallbackSpec->Finilize();
if (result != S_OK)
{
PrintError("Update Error");
return 1;
}
FOR_VECTOR (i, updateCallbackSpec->FailedFiles)
{
PrintNewLine();
PrintError("Error for file", updateCallbackSpec->FailedFiles[i]);
}
if (updateCallbackSpec->FailedFiles.Size() != 0)
return 1;
}
else
{
if (params.Size() != 1)
{
PrintError(kIncorrectCommand);
return 1;
}
bool listCommand;
if (c == 'l')
listCommand = true;
else if (c == 'x')
listCommand = false;
else
{
PrintError(kIncorrectCommand);
return 1;
}
CMyComPtr<IInArchive> archive;
if (f_CreateObject(&CLSID_Format, &IID_IInArchive, (void **)&archive) != S_OK)
{
PrintError("Cannot get class object");
return 1;
}
CInFileStream *fileSpec = new CInFileStream;
CMyComPtr<IInStream> file = fileSpec;
if (!fileSpec->Open(archiveName))
{
PrintError("Cannot open archive file", archiveName);
return 1;
}
{
CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;
CMyComPtr<IArchiveOpenCallback> openCallback(openCallbackSpec);
openCallbackSpec->PasswordIsDefined = passwordIsDefined;
openCallbackSpec->Password = password;
const UInt64 scanSize = 1 << 23;
if (archive->Open(file, &scanSize, openCallback) != S_OK)
{
PrintError("Cannot open file as archive", archiveName);
return 1;
}
}
if (listCommand)
{
// List command
UInt32 numItems = 0;
archive->GetNumberOfItems(&numItems);
for (UInt32 i = 0; i < numItems; i++)
{
{
// Get uncompressed size of file
NCOM::CPropVariant prop;
archive->GetProperty(i, kpidSize, &prop);
char s[32];
ConvertPropVariantToShortString(prop, s);
Print(s);
Print(" ");
}
{
// Get name of file
NCOM::CPropVariant prop;
archive->GetProperty(i, kpidPath, &prop);
if (prop.vt == VT_BSTR)
Print(prop.bstrVal);
else if (prop.vt != VT_EMPTY)
Print("ERROR!");
}
PrintNewLine();
}
}
else
{
// Extract command
CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
extractCallbackSpec->Init(archive, FString()); // second parameter is output folder path
extractCallbackSpec->PasswordIsDefined = passwordIsDefined;
extractCallbackSpec->Password = password;
/*
const wchar_t *names[] =
{
L"mt",
L"mtf"
};
const unsigned kNumProps = sizeof(names) / sizeof(names[0]);
NCOM::CPropVariant values[kNumProps] =
{
(UInt32)1,
false
};
CMyComPtr<ISetProperties> setProperties;
archive->QueryInterface(IID_ISetProperties, (void **)&setProperties);
if (setProperties)
{
if (setProperties->SetProperties(names, values, kNumProps) != S_OK)
{
PrintError("SetProperties() error");
return 1;
}
}
*/
HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback);
if (result != S_OK)
{
PrintError("Extract Error");
return 1;
}
}
}
return 0;
}