mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 15:14:59 -06:00
203 lines
5.6 KiB
C++
Executable File
203 lines
5.6 KiB
C++
Executable File
// Archive/GZip/OutHandler.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "GZipHandler.h"
|
|
#include "GZipUpdate.h"
|
|
|
|
#include "Common/StringConvert.h"
|
|
#include "Common/StringToInt.h"
|
|
|
|
#include "Windows/Time.h"
|
|
#include "Windows/FileFind.h"
|
|
#include "Windows/PropVariant.h"
|
|
|
|
#include "../../Compress/Copy/CopyCoder.h"
|
|
#include "../Common/ParseProperties.h"
|
|
|
|
using namespace NWindows;
|
|
using namespace NTime;
|
|
|
|
namespace NArchive {
|
|
namespace NGZip {
|
|
|
|
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))
|
|
{
|
|
UInt32 attributes;
|
|
FILETIME utcTime;
|
|
UString name;
|
|
bool isDirectory;
|
|
{
|
|
NCOM::CPropVariant propVariant;
|
|
RINOK(updateCallback->GetProperty(itemIndex, kpidAttributes, &propVariant));
|
|
if (propVariant.vt == VT_EMPTY)
|
|
attributes = 0;
|
|
else if (propVariant.vt != VT_UI4)
|
|
return E_INVALIDARG;
|
|
else
|
|
attributes = propVariant.ulVal;
|
|
}
|
|
{
|
|
NCOM::CPropVariant propVariant;
|
|
RINOK(updateCallback->GetProperty(itemIndex, kpidLastWriteTime, &propVariant));
|
|
if (propVariant.vt != VT_FILETIME)
|
|
return E_INVALIDARG;
|
|
utcTime = propVariant.filetime;
|
|
}
|
|
{
|
|
NCOM::CPropVariant propVariant;
|
|
RINOK(updateCallback->GetProperty(itemIndex, kpidPath, &propVariant));
|
|
if (propVariant.vt == VT_EMPTY)
|
|
name.Empty();
|
|
else if (propVariant.vt != VT_BSTR)
|
|
return E_INVALIDARG;
|
|
else
|
|
name = propVariant.bstrVal;
|
|
}
|
|
{
|
|
NCOM::CPropVariant propVariant;
|
|
RINOK(updateCallback->GetProperty(itemIndex, kpidIsFolder, &propVariant));
|
|
if (propVariant.vt == VT_EMPTY)
|
|
isDirectory = false;
|
|
else if (propVariant.vt != VT_BOOL)
|
|
return E_INVALIDARG;
|
|
else
|
|
isDirectory = (propVariant.boolVal != VARIANT_FALSE);
|
|
}
|
|
if (isDirectory || NFile::NFind::NAttributes::IsDirectory(attributes))
|
|
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 propVariant;
|
|
RINOK(updateCallback->GetProperty(itemIndex, kpidSize, &propVariant));
|
|
if (propVariant.vt != VT_UI8)
|
|
return E_INVALIDARG;
|
|
size = propVariant.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));
|
|
|
|
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
|
|
return E_INVALIDARG;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
}}
|