// 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 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 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)); 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; } }}