mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-11 23:09:54 -06:00
9.34
This commit is contained in:
committed by
Kornel Lesiński
parent
83f8ddcc5b
commit
f08f4dcc3c
390
CPP/7zip/Archive/Tar/TarHandler.cpp
Executable file → Normal file
390
CPP/7zip/Archive/Tar/TarHandler.cpp
Executable file → Normal file
@@ -2,13 +2,15 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/StringConvert.h"
|
||||
#include "../../../Common/ComTry.h"
|
||||
#include "../../../Common/IntToString.h"
|
||||
#include "../../../Common/StringConvert.h"
|
||||
#include "../../../Common/UTFConvert.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/Time.h"
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/MethodProps.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamObjects.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
@@ -16,32 +18,34 @@
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
|
||||
#include "TarHandler.h"
|
||||
#include "TarIn.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
static const char *kUnexpectedEnd = "Unexpected end of archive";
|
||||
static const UINT k_DefaultCodePage = CP_OEMCP; // it uses it if UTF8 check in names shows error
|
||||
|
||||
static const STATPROPSTG kProps[] =
|
||||
|
||||
static const Byte 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},
|
||||
{ NULL, kpidUser, VT_BSTR},
|
||||
{ NULL, kpidGroup, VT_BSTR},
|
||||
{ NULL, kpidLink, VT_BSTR}
|
||||
kpidPath,
|
||||
kpidIsDir,
|
||||
kpidSize,
|
||||
kpidPackSize,
|
||||
kpidMTime,
|
||||
kpidPosixAttrib,
|
||||
kpidUser,
|
||||
kpidGroup,
|
||||
kpidSymLink,
|
||||
kpidHardLink,
|
||||
// kpidLinkType
|
||||
};
|
||||
|
||||
static const STATPROPSTG kArcProps[] =
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
{ NULL, kpidPhySize, VT_UI8},
|
||||
{ NULL, kpidHeadersSize, VT_UI8}
|
||||
kpidHeadersSize,
|
||||
kpidCodePage
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
@@ -50,11 +54,42 @@ IMP_IInArchive_ArcProps
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
switch(propID)
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPhySize: if (_phySizeDefined) prop = _phySize; break;
|
||||
case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break;
|
||||
case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
|
||||
case kpidErrorFlags:
|
||||
{
|
||||
UInt32 flags = 0;
|
||||
if (!_isArc)
|
||||
flags |= kpv_ErrorFlags_IsNotArc;
|
||||
else switch (_error)
|
||||
{
|
||||
case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break;
|
||||
case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break;
|
||||
}
|
||||
prop = flags;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidCodePage:
|
||||
{
|
||||
const char *name = NULL;
|
||||
switch (_openCodePage)
|
||||
{
|
||||
case CP_OEMCP: name = "OEM"; break;
|
||||
case CP_UTF8: name = "UTF-8"; break;
|
||||
}
|
||||
if (name != NULL)
|
||||
prop = name;
|
||||
else
|
||||
{
|
||||
char sz[16];
|
||||
ConvertUInt32ToString(_openCodePage, sz);
|
||||
prop = sz;
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
@@ -63,9 +98,16 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item)
|
||||
{
|
||||
item.HeaderPos = _phySize;
|
||||
RINOK(ReadItem(stream, filled, item, _errorMessage));
|
||||
if (filled && item.IsSparse())
|
||||
_isSparse = true;
|
||||
RINOK(ReadItem(stream, filled, item, _error));
|
||||
if (filled)
|
||||
{
|
||||
/*
|
||||
if (item.IsSparse())
|
||||
_isSparse = true;
|
||||
*/
|
||||
if (item.IsPaxExtendedHeader())
|
||||
_thereIsPaxExtendedHeader = true;
|
||||
}
|
||||
_phySize += item.HeaderSize;
|
||||
_headersSize += item.HeaderSize;
|
||||
return S_OK;
|
||||
@@ -80,6 +122,14 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
}
|
||||
|
||||
_phySizeDefined = true;
|
||||
|
||||
bool utf8_OK = true;
|
||||
if (!_forceCodePage)
|
||||
{
|
||||
if (!utf8_OK)
|
||||
_curCodePage = k_DefaultCodePage;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
CItemEx item;
|
||||
@@ -87,12 +137,22 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
RINOK(ReadItem2(stream, filled, item));
|
||||
if (!filled)
|
||||
break;
|
||||
|
||||
_isArc = true;
|
||||
_items.Add(item);
|
||||
|
||||
if (!_forceCodePage)
|
||||
{
|
||||
if (utf8_OK) utf8_OK = CheckUTF8(item.Name);
|
||||
if (utf8_OK) utf8_OK = CheckUTF8(item.User);
|
||||
if (utf8_OK) utf8_OK = CheckUTF8(item.Group);
|
||||
if (utf8_OK) utf8_OK = CheckUTF8(item.LinkName);
|
||||
}
|
||||
|
||||
RINOK(stream->Seek(item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize));
|
||||
if (_phySize > endPos)
|
||||
{
|
||||
_errorMessage = kUnexpectedEnd;
|
||||
_error = k_ErrorType_UnexpectedEnd;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
@@ -102,13 +162,13 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
break;
|
||||
}
|
||||
*/
|
||||
if (callback != NULL)
|
||||
if (callback)
|
||||
{
|
||||
if (_items.Size() == 1)
|
||||
{
|
||||
RINOK(callback->SetTotal(NULL, &endPos));
|
||||
}
|
||||
if (_items.Size() % 100 == 0)
|
||||
if ((_items.Size() & 0x3FF) == 0)
|
||||
{
|
||||
UInt64 numFiles = _items.Size();
|
||||
RINOK(callback->SetCompleted(&numFiles, &_phySize));
|
||||
@@ -116,8 +176,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
}
|
||||
}
|
||||
|
||||
if (!_forceCodePage)
|
||||
{
|
||||
if (!utf8_OK)
|
||||
_curCodePage = k_DefaultCodePage;
|
||||
}
|
||||
_openCodePage = _curCodePage;
|
||||
|
||||
if (_items.Size() == 0)
|
||||
{
|
||||
if (_error != k_ErrorType_OK)
|
||||
{
|
||||
_isArc = false;
|
||||
return S_FALSE;
|
||||
}
|
||||
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
|
||||
if (!callback)
|
||||
return S_FALSE;
|
||||
@@ -129,11 +201,12 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
return S_FALSE;
|
||||
if (prop.vt != VT_BSTR)
|
||||
return S_FALSE;
|
||||
UString baseName = prop.bstrVal;
|
||||
baseName = baseName.Right(4);
|
||||
if (baseName.CompareNoCase(L".tar") != 0)
|
||||
unsigned len = MyStringLen(prop.bstrVal);
|
||||
if (len < 4 || MyStringCompareNoCase(prop.bstrVal + len - 4, L".tar") != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
_isArc = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -158,13 +231,16 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_errorMessage.Empty();
|
||||
_isArc = false;
|
||||
_error = k_ErrorType_OK;
|
||||
|
||||
_phySizeDefined = false;
|
||||
_phySize = 0;
|
||||
_headersSize = 0;
|
||||
_curIndex = 0;
|
||||
_latestIsRead = false;
|
||||
_isSparse = false;
|
||||
// _isSparse = false;
|
||||
_thereIsPaxExtendedHeader = false;
|
||||
_items.Clear();
|
||||
_seqStream.Release();
|
||||
_stream.Release();
|
||||
@@ -181,6 +257,8 @@ CHandler::CHandler()
|
||||
{
|
||||
copyCoderSpec = new NCompress::CCopyCoder();
|
||||
copyCoder = copyCoderSpec;
|
||||
_openCodePage = CP_UTF8;
|
||||
Init();
|
||||
}
|
||||
|
||||
HRESULT CHandler::SkipTo(UInt32 index)
|
||||
@@ -194,7 +272,7 @@ HRESULT CHandler::SkipTo(UInt32 index)
|
||||
_phySize += copyCoderSpec->TotalSize;
|
||||
if (copyCoderSpec->TotalSize != packSize)
|
||||
{
|
||||
_errorMessage = kUnexpectedEnd;
|
||||
_error = k_ErrorType_UnexpectedEnd;
|
||||
return S_FALSE;
|
||||
}
|
||||
_latestIsRead = false;
|
||||
@@ -215,15 +293,29 @@ HRESULT CHandler::SkipTo(UInt32 index)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static UString TarStringToUnicode(const AString &s)
|
||||
void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs) const
|
||||
{
|
||||
return MultiByteToUnicodeString(s, CP_OEMCP);
|
||||
UString dest;
|
||||
if (_curCodePage == CP_UTF8)
|
||||
{
|
||||
if (!ConvertUTF8ToUnicode(s, dest))
|
||||
{
|
||||
prop = "[ERROR-NAME]";
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
dest = MultiByteToUnicodeString(s, _curCodePage);
|
||||
if (toOs)
|
||||
prop = NItemName::GetOSName2(dest);
|
||||
else
|
||||
prop = dest;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
NCOM::CPropVariant prop;
|
||||
|
||||
const CItemEx *item;
|
||||
if (_stream)
|
||||
@@ -239,9 +331,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
}
|
||||
}
|
||||
|
||||
switch(propID)
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break;
|
||||
case kpidPath: TarStringToUnicode(item->Name, prop, true); break;
|
||||
case kpidIsDir: prop = item->IsDir(); break;
|
||||
case kpidSize: prop = item->GetUnpackSize(); break;
|
||||
case kpidPackSize: prop = item->GetPackSizeAligned(); break;
|
||||
@@ -254,9 +346,11 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
}
|
||||
break;
|
||||
case kpidPosixAttrib: prop = item->Mode; break;
|
||||
case kpidUser: prop = TarStringToUnicode(item->User); break;
|
||||
case kpidGroup: prop = TarStringToUnicode(item->Group); break;
|
||||
case kpidLink: prop = TarStringToUnicode(item->LinkName); break;
|
||||
case kpidUser: TarStringToUnicode(item->User, prop); break;
|
||||
case kpidGroup: TarStringToUnicode(item->Group, prop); break;
|
||||
case kpidSymLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kSymLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break;
|
||||
case kpidHardLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kHardLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break;
|
||||
// case kpidLinkType: prop = (int)item->LinkFlag; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
@@ -272,7 +366,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
if (!seqMode)
|
||||
stream = _stream;
|
||||
|
||||
bool allFilesMode = (numItems == (UInt32)-1);
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
if (allFilesMode)
|
||||
numItems = _items.Size();
|
||||
if (_stream && numItems == 0)
|
||||
@@ -333,7 +427,18 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
if (!testMode && !realOutStream)
|
||||
{
|
||||
if (!seqMode)
|
||||
{
|
||||
/*
|
||||
// probably we must show extracting info it callback handler instead
|
||||
if (item->IsHardLink() ||
|
||||
item->IsSymLink())
|
||||
{
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
||||
}
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
skipMode = true;
|
||||
askMode = NExtract::NAskMode::kSkip;
|
||||
}
|
||||
@@ -344,13 +449,20 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
|
||||
|
||||
Int32 opRes = NExtract::NOperationResult::kOK;
|
||||
if (item->IsSparse())
|
||||
opRes = NExtract::NOperationResult::kUnSupportedMethod;
|
||||
CMyComPtr<ISequentialInStream> inStream2;
|
||||
if (!item->IsSparse())
|
||||
inStream2 = inStream;
|
||||
else
|
||||
{
|
||||
if (item->IsLink())
|
||||
GetStream(index, &inStream2);
|
||||
if (!inStream2)
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
{
|
||||
if (item->IsSymLink())
|
||||
{
|
||||
RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length()));
|
||||
RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -359,7 +471,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
streamSpec->Init(item->GetPackSizeAligned());
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress));
|
||||
}
|
||||
if (outStreamSpec->GetRem() != 0)
|
||||
opRes = NExtract::NOperationResult::kDataError;
|
||||
@@ -376,22 +488,198 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
class CSparseStream:
|
||||
public IInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
UInt64 _phyPos;
|
||||
UInt64 _virtPos;
|
||||
bool _needStartSeek;
|
||||
|
||||
public:
|
||||
CHandler *Handler;
|
||||
CMyComPtr<IUnknown> HandlerRef;
|
||||
unsigned ItemIndex;
|
||||
CRecordVector<UInt64> PhyOffsets;
|
||||
|
||||
MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
|
||||
|
||||
void Init()
|
||||
{
|
||||
_virtPos = 0;
|
||||
_phyPos = 0;
|
||||
_needStartSeek = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
if (size == 0)
|
||||
return S_OK;
|
||||
const CItemEx &item = Handler->_items[ItemIndex];
|
||||
if (_virtPos >= item.Size)
|
||||
return S_OK;
|
||||
{
|
||||
UInt64 rem = item.Size - _virtPos;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
}
|
||||
|
||||
HRESULT res = S_OK;
|
||||
|
||||
if (item.SparseBlocks.IsEmpty())
|
||||
memset(data, 0, size);
|
||||
else
|
||||
{
|
||||
unsigned left = 0, right = item.SparseBlocks.Size();
|
||||
for (;;)
|
||||
{
|
||||
unsigned mid = (left + right) / 2;
|
||||
if (mid == left)
|
||||
break;
|
||||
if (_virtPos < item.SparseBlocks[mid].Offset)
|
||||
right = mid;
|
||||
else
|
||||
left = mid;
|
||||
}
|
||||
|
||||
const CSparseBlock &sb = item.SparseBlocks[left];
|
||||
UInt64 relat = _virtPos - sb.Offset;
|
||||
|
||||
if (_virtPos >= sb.Offset && relat < sb.Size)
|
||||
{
|
||||
UInt64 rem = sb.Size - relat;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
UInt64 phyPos = PhyOffsets[left] + relat;
|
||||
if (_needStartSeek || _phyPos != phyPos)
|
||||
{
|
||||
RINOK(Handler->_stream->Seek(item.GetDataPosition() + phyPos, STREAM_SEEK_SET, NULL));
|
||||
_needStartSeek = false;
|
||||
_phyPos = phyPos;
|
||||
}
|
||||
res = Handler->_stream->Read(data, size, &size);
|
||||
_phyPos += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt64 next = item.Size;
|
||||
if (_virtPos < sb.Offset)
|
||||
next = sb.Offset;
|
||||
else if (left + 1 < item.SparseBlocks.Size())
|
||||
next = item.SparseBlocks[left + 1].Offset;
|
||||
UInt64 rem = next - _virtPos;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
memset(data, 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
_virtPos += size;
|
||||
if (processedSize)
|
||||
*processedSize = size;
|
||||
return res;
|
||||
}
|
||||
|
||||
STDMETHODIMP CSparseStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
|
||||
{
|
||||
switch (seekOrigin)
|
||||
{
|
||||
case STREAM_SEEK_SET: break;
|
||||
case STREAM_SEEK_CUR: offset += _virtPos; break;
|
||||
case STREAM_SEEK_END: offset += Handler->_items[ItemIndex].Size; break;
|
||||
default: return STG_E_INVALIDFUNCTION;
|
||||
}
|
||||
if (offset < 0)
|
||||
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
|
||||
_virtPos = offset;
|
||||
if (newPosition)
|
||||
*newPosition = _virtPos;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
const CItemEx &item = _items[index];
|
||||
|
||||
if (item.IsSparse())
|
||||
return E_NOTIMPL;
|
||||
if (item.IsLink())
|
||||
{
|
||||
CBufInStream *streamSpec = new CBufInStream;
|
||||
CSparseStream *streamSpec = new CSparseStream;
|
||||
CMyComPtr<IInStream> streamTemp = streamSpec;
|
||||
streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Length(), (IInArchive *)this);
|
||||
streamSpec->Init();
|
||||
streamSpec->Handler = this;
|
||||
streamSpec->HandlerRef = (IInArchive *)this;
|
||||
streamSpec->ItemIndex = index;
|
||||
streamSpec->PhyOffsets.Reserve(item.SparseBlocks.Size());
|
||||
UInt64 offs = 0;
|
||||
FOR_VECTOR(i, item.SparseBlocks)
|
||||
{
|
||||
const CSparseBlock &sb = item.SparseBlocks[i];
|
||||
streamSpec->PhyOffsets.AddInReserved(offs);
|
||||
offs += sb.Size;
|
||||
}
|
||||
*stream = streamTemp.Detach();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (item.IsSymLink())
|
||||
{
|
||||
CBufInStream *streamSpec = new CBufInStream;
|
||||
CMyComPtr<IInStream> streamTemp = streamSpec;
|
||||
streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this);
|
||||
*stream = streamTemp.Detach();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream);
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
void CHandler::Init()
|
||||
{
|
||||
_forceCodePage = false;
|
||||
// _codePage = CP_OEMCP;
|
||||
_curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
|
||||
{
|
||||
Init();
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
UString name = names[i];
|
||||
name.MakeLower_Ascii();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
|
||||
const PROPVARIANT &prop = values[i];
|
||||
|
||||
if (name[0] == L'x')
|
||||
{
|
||||
// some clients write 'x' property. So we support it
|
||||
UInt32 level = 0;
|
||||
RINOK(ParsePropToUInt32(name.Ptr(1), prop, level));
|
||||
}
|
||||
else if (name.IsEqualTo("cp"))
|
||||
{
|
||||
UInt32 cp = CP_OEMCP;
|
||||
RINOK(ParsePropToUInt32(L"", prop, cp));
|
||||
_forceCodePage = true;
|
||||
_curCodePage = _specifiedCodePage = cp;
|
||||
}
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user