blob: aff580936c4fdfba9be7cfbeeb6f66feefae63ef [file] [log] [blame]
// 7zHandlerOut.cpp
#include "StdAfx.h"
#include "../../../Common/ComTry.h"
#include "../../../Common/StringToInt.h"
#include "../../../Common/Wildcard.h"
#include "../Common/ItemNameUtils.h"
#include "../Common/ParseProperties.h"
#include "7zHandler.h"
#include "7zOut.h"
#include "7zUpdate.h"
using namespace NWindows;
namespace NArchive {
namespace N7z {
static const wchar_t *k_LZMA_Name = L"LZMA";
static const wchar_t *kDefaultMethodName = L"LZMA2";
static const wchar_t *k_Copy_Name = L"Copy";
static const wchar_t *k_MatchFinder_ForHeaders = L"BT2";
static const UInt32 k_NumFastBytes_ForHeaders = 273;
static const UInt32 k_Level_ForHeaders = 5;
static const UInt32 k_Dictionary_ForHeaders =
#ifdef UNDER_CE
1 << 18;
#else
1 << 20;
#endif
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
{
*type = NFileTimeType::kWindows;
return S_OK;
}
HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m)
{
if (!FindMethod(
EXTERNAL_CODECS_VARS
m.MethodName, dest.Id, dest.NumInStreams, dest.NumOutStreams))
return E_INVALIDARG;
(CProps &)dest = (CProps &)m;
return S_OK;
}
HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod)
{
if (!_compressHeaders)
return S_OK;
COneMethodInfo m;
m.MethodName = k_LZMA_Name;
m.AddPropString(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders);
m.AddProp32(NCoderPropID::kLevel, k_Level_ForHeaders);
m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders);
m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders);
m.AddNumThreadsProp(1);
CMethodFull methodFull;
RINOK(PropsMethod_To_FullMethod(methodFull, m));
headerMethod.Methods.Add(methodFull);
return S_OK;
}
void CHandler::AddDefaultMethod()
{
FOR_VECTOR (i, _methods)
{
UString &methodName = _methods[i].MethodName;
if (methodName.IsEmpty())
methodName = kDefaultMethodName;
}
if (_methods.IsEmpty())
{
COneMethodInfo m;
m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName);
_methods.Add(m);
}
}
HRESULT CHandler::SetMainMethod(
CCompressionMethodMode &methodMode,
CObjectVector<COneMethodInfo> &methods
#ifndef _7ZIP_ST
, UInt32 numThreads
#endif
)
{
AddDefaultMethod();
const UInt64 kSolidBytes_Min = (1 << 24);
const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1;
bool needSolid = false;
FOR_VECTOR (i, methods)
{
COneMethodInfo &oneMethodInfo = methods[i];
SetGlobalLevelAndThreads(oneMethodInfo
#ifndef _7ZIP_ST
, numThreads
#endif
);
CMethodFull methodFull;
RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo));
methodMode.Methods.Add(methodFull);
if (methodFull.Id != k_Copy)
needSolid = true;
if (_numSolidBytesDefined)
continue;
UInt32 dicSize;
switch (methodFull.Id)
{
case k_LZMA:
case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break;
case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break;
case k_Deflate: dicSize = (UInt32)1 << 15; break;
case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break;
default: continue;
}
_numSolidBytes = (UInt64)dicSize << 7;
if (_numSolidBytes < kSolidBytes_Min) _numSolidBytes = kSolidBytes_Min;
if (_numSolidBytes > kSolidBytes_Max) _numSolidBytes = kSolidBytes_Max;
_numSolidBytesDefined = true;
}
if (!_numSolidBytesDefined)
if (needSolid)
_numSolidBytes = kSolidBytes_Max;
else
_numSolidBytes = 0;
_numSolidBytesDefined = true;
return S_OK;
}
static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, UInt64 &ft, bool &ftDefined)
{
// ft = 0;
// ftDefined = false;
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(index, propID, &prop));
if (prop.vt == VT_FILETIME)
{
ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32);
ftDefined = true;
}
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
else
{
ft = 0;
ftDefined = false;
}
return S_OK;
}
/*
#ifdef _WIN32
static const wchar_t kDirDelimiter1 = L'\\';
#endif
static const wchar_t kDirDelimiter2 = L'/';
static inline bool IsCharDirLimiter(wchar_t c)
{
return (
#ifdef _WIN32
c == kDirDelimiter1 ||
#endif
c == kDirDelimiter2);
}
static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex)
{
CTreeFolder &tf = treeFolders[cur];
tf.SortIndex = curSortIndex++;
for (int i = 0; i < tf.SubFolders.Size(); i++)
curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex);
tf.SortIndexEnd = curSortIndex;
return curSortIndex;
}
static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos)
{
const CIntVector &subFolders = treeFolders[cur].SubFolders;
int left = 0, right = subFolders.Size();
insertPos = -1;
for (;;)
{
if (left == right)
{
insertPos = left;
return -1;
}
int mid = (left + right) / 2;
int midFolder = subFolders[mid];
int compare = CompareFileNames(name, treeFolders[midFolder].Name);
if (compare == 0)
return midFolder;
if (compare < 0)
right = mid;
else
left = mid + 1;
}
}
static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name)
{
int insertPos;
int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos);
if (folderIndex < 0)
{
folderIndex = treeFolders.Size();
CTreeFolder &newFolder = treeFolders.AddNew();
newFolder.Parent = cur;
newFolder.Name = name;
treeFolders[cur].SubFolders.Insert(insertPos, folderIndex);
}
// else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234;
return folderIndex;
}
*/
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
IArchiveUpdateCallback *updateCallback)
{
COM_TRY_BEGIN
const CDbEx *db = 0;
#ifdef _7Z_VOL
if (_volumes.Size() > 1)
return E_FAIL;
const CVolume *volume = 0;
if (_volumes.Size() == 1)
{
volume = &_volumes.Front();
db = &volume->Database;
}
#else
if (_inStream != 0)
db = &_db;
#endif
/*
CMyComPtr<IArchiveGetRawProps> getRawProps;
updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps);
CUniqBlocks secureBlocks;
secureBlocks.AddUniq(NULL, 0);
CObjectVector<CTreeFolder> treeFolders;
{
CTreeFolder folder;
folder.Parent = -1;
treeFolders.Add(folder);
}
*/
CObjectVector<CUpdateItem> updateItems;
bool need_CTime = (Write_CTime.Def && Write_CTime.Val);
bool need_ATime = (Write_ATime.Def && Write_ATime.Val);
bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def);
if (db)
{
if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
}
UString s;
for (UInt32 i = 0; i < numItems; i++)
{
Int32 newData, newProps;
UInt32 indexInArchive;
if (!updateCallback)
return E_FAIL;
RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
CUpdateItem ui;
ui.NewProps = IntToBool(newProps);
ui.NewData = IntToBool(newData);
ui.IndexInArchive = indexInArchive;
ui.IndexInClient = i;
ui.IsAnti = false;
ui.Size = 0;
UString name;
// bool isAltStream = false;
if (ui.IndexInArchive != -1)
{
if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size())
return E_INVALIDARG;
const CFileItem &fi = db->Files[ui.IndexInArchive];
if (!ui.NewProps)
{
_db.GetPath(ui.IndexInArchive, name);
}
ui.IsDir = fi.IsDir;
ui.Size = fi.Size;
// isAltStream = fi.IsAltStream;
ui.IsAnti = db->IsItemAnti(ui.IndexInArchive);
if (!ui.NewProps)
{
ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime);
ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime);
ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime);
}
}
if (ui.NewProps)
{
bool folderStatusIsDefined;
{
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop));
if (prop.vt == VT_EMPTY)
ui.AttribDefined = false;
else if (prop.vt != VT_UI4)
return E_INVALIDARG;
else
{
ui.Attrib = prop.ulVal;
ui.AttribDefined = true;
}
}
// we need MTime to sort files.
if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined));
if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined));
if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined));
/*
if (getRawProps)
{
const void *data;
UInt32 dataSize;
UInt32 propType;
getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType);
if (dataSize != 0 && propType != NPropDataType::kRaw)
return E_FAIL;
ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize);
}
*/
{
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(i, kpidPath, &prop));
if (prop.vt == VT_EMPTY)
{
}
else if (prop.vt != VT_BSTR)
return E_INVALIDARG;
else
{
name = NItemName::MakeLegalName(prop.bstrVal);
}
}
{
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop));
if (prop.vt == VT_EMPTY)
folderStatusIsDefined = false;
else if (prop.vt != VT_BOOL)
return E_INVALIDARG;
else
{
ui.IsDir = (prop.boolVal != VARIANT_FALSE);
folderStatusIsDefined = true;
}
}
{
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop));
if (prop.vt == VT_EMPTY)
ui.IsAnti = false;
else if (prop.vt != VT_BOOL)
return E_INVALIDARG;
else
ui.IsAnti = (prop.boolVal != VARIANT_FALSE);
}
/*
{
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop));
if (prop.vt == VT_EMPTY)
isAltStream = false;
else if (prop.vt != VT_BOOL)
return E_INVALIDARG;
else
isAltStream = (prop.boolVal != VARIANT_FALSE);
}
*/
if (ui.IsAnti)
{
ui.AttribDefined = false;
ui.CTimeDefined = false;
ui.ATimeDefined = false;
ui.MTimeDefined = false;
ui.Size = 0;
}
if (!folderStatusIsDefined && ui.AttribDefined)
ui.SetDirStatusFromAttrib();
}
else
{
/*
if (_db.SecureIDs.IsEmpty())
ui.SecureIndex = secureBlocks.AddUniq(NULL, 0);
else
{
int id = _db.SecureIDs[ui.IndexInArchive];
size_t offs = _db.SecureOffsets[id];
size_t size = _db.SecureOffsets[id + 1] - offs;
ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size);
}
*/
}
/*
{
int folderIndex = 0;
if (_useParents)
{
int j;
s.Empty();
for (j = 0; j < name.Len(); j++)
{
wchar_t c = name[j];
if (IsCharDirLimiter(c))
{
folderIndex = AddFolder(treeFolders, folderIndex, s);
s.Empty();
continue;
}
s += c;
}
if (isAltStream)
{
int colonPos = s.Find(':');
if (colonPos < 0)
{
// isAltStream = false;
return E_INVALIDARG;
}
UString mainName = s.Left(colonPos);
int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName);
if (treeFolders[newFolderIndex].UpdateItemIndex < 0)
{
for (int j = updateItems.Size() - 1; j >= 0; j--)
{
CUpdateItem &ui2 = updateItems[j];
if (ui2.ParentFolderIndex == folderIndex
&& ui2.Name == mainName)
{
ui2.TreeFolderIndex = newFolderIndex;
treeFolders[newFolderIndex].UpdateItemIndex = j;
}
}
}
folderIndex = newFolderIndex;
s.Delete(0, colonPos + 1);
}
ui.Name = s;
}
else
ui.Name = name;
ui.IsAltStream = isAltStream;
ui.ParentFolderIndex = folderIndex;
ui.TreeFolderIndex = -1;
if (ui.IsDir && !s.IsEmpty())
{
ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s);
treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size();
}
}
*/
ui.Name = name;
if (ui.NewData)
{
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(i, kpidSize, &prop));
if (prop.vt != VT_UI8)
return E_INVALIDARG;
ui.Size = (UInt64)prop.uhVal.QuadPart;
if (ui.Size != 0 && ui.IsAnti)
return E_INVALIDARG;
}
updateItems.Add(ui);
}
/*
FillSortIndex(treeFolders, 0, 0);
for (i = 0; i < (UInt32)updateItems.Size(); i++)
{
CUpdateItem &ui = updateItems[i];
ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex;
ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd;
}
*/
CCompressionMethodMode methodMode, headerMethod;
HRESULT res = SetMainMethod(methodMode, _methods
#ifndef _7ZIP_ST
, _numThreads
#endif
);
RINOK(res);
methodMode.Binds = _binds;
RINOK(SetHeaderMethod(headerMethod));
#ifndef _7ZIP_ST
methodMode.NumThreads = _numThreads;
headerMethod.NumThreads = 1;
#endif
CMyComPtr<ICryptoGetTextPassword2> getPassword2;
updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2);
methodMode.PasswordIsDefined = false;
methodMode.Password.Empty();
if (getPassword2)
{
CMyComBSTR password;
Int32 passwordIsDefined;
RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password));
methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
if (methodMode.PasswordIsDefined && (BSTR)password)
methodMode.Password = password;
}
bool compressMainHeader = _compressHeaders; // check it
bool encryptHeaders = false;
if (methodMode.PasswordIsDefined)
{
if (_encryptHeadersSpecified)
encryptHeaders = _encryptHeaders;
#ifndef _NO_CRYPTO
else
encryptHeaders = _passwordIsDefined;
#endif
compressMainHeader = true;
if (encryptHeaders)
{
headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;
headerMethod.Password = methodMode.Password;
}
}
if (numItems < 2)
compressMainHeader = false;
CUpdateOptions options;
options.Method = &methodMode;
options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : 0;
int level = GetLevel();
options.UseFilters = level != 0 && _autoFilter;
options.MaxFilter = level >= 8;
options.HeaderOptions.CompressMainHeader = compressMainHeader;
/*
options.HeaderOptions.WriteCTime = Write_CTime;
options.HeaderOptions.WriteATime = Write_ATime;
options.HeaderOptions.WriteMTime = Write_MTime;
*/
options.NumSolidFiles = _numSolidFiles;
options.NumSolidBytes = _numSolidBytes;
options.SolidExtension = _solidExtension;
options.RemoveSfxBlock = _removeSfxBlock;
options.VolumeMode = _volumeMode;
COutArchive archive;
CArchiveDatabaseOut newDatabase;
CMyComPtr<ICryptoGetTextPassword> getPassword;
updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword);
/*
if (secureBlocks.Sorted.Size() > 1)
{
secureBlocks.GetReverseMap();
for (int i = 0; i < updateItems.Size(); i++)
{
int &secureIndex = updateItems[i].SecureIndex;
secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex];
}
}
*/
res = Update(
EXTERNAL_CODECS_VARS
#ifdef _7Z_VOL
volume ? volume->Stream: 0,
volume ? db : 0,
#else
_inStream,
db,
#endif
updateItems,
// treeFolders,
// secureBlocks,
archive, newDatabase, outStream, updateCallback, options
#ifndef _NO_CRYPTO
, getPassword
#endif
);
RINOK(res);
updateItems.ClearAndFree();
return archive.WriteDatabase(EXTERNAL_CODECS_VARS
newDatabase, options.HeaderMethod, options.HeaderOptions);
COM_TRY_END
}
static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream)
{
stream = 0;
int index = ParseStringToUInt32(srcString, coder);
if (index == 0)
return E_INVALIDARG;
srcString.Delete(0, index);
if (srcString[0] == 's')
{
srcString.Delete(0);
int index = ParseStringToUInt32(srcString, stream);
if (index == 0)
return E_INVALIDARG;
srcString.Delete(0, index);
}
return S_OK;
}
void COutHandler::InitProps()
{
CMultiMethodProps::Init();
_removeSfxBlock = false;
_compressHeaders = true;
_encryptHeadersSpecified = false;
_encryptHeaders = false;
// _useParents = false;
Write_CTime.Init();
Write_ATime.Init();
Write_MTime.Init();
_volumeMode = false;
InitSolid();
}
HRESULT COutHandler::SetSolidFromString(const UString &s)
{
UString s2 = s;
s2.MakeLower_Ascii();
for (unsigned i = 0; i < s2.Len();)
{
const wchar_t *start = ((const wchar_t *)s2) + i;
const wchar_t *end;
UInt64 v = ConvertStringToUInt64(start, &end);
if (start == end)
{
if (s2[i++] != 'e')
return E_INVALIDARG;
_solidExtension = true;
continue;
}
i += (int)(end - start);
if (i == s2.Len())
return E_INVALIDARG;
wchar_t c = s2[i++];
if (c == 'f')
{
if (v < 1)
v = 1;
_numSolidFiles = v;
}
else
{
unsigned numBits;
switch (c)
{
case 'b': numBits = 0; break;
case 'k': numBits = 10; break;
case 'm': numBits = 20; break;
case 'g': numBits = 30; break;
case 't': numBits = 40; break;
default: return E_INVALIDARG;
}
_numSolidBytes = (v << numBits);
_numSolidBytesDefined = true;
}
}
return S_OK;
}
HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value)
{
bool isSolid;
switch (value.vt)
{
case VT_EMPTY: isSolid = true; break;
case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
case VT_BSTR:
if (StringToBool(value.bstrVal, isSolid))
break;
return SetSolidFromString(value.bstrVal);
default: return E_INVALIDARG;
}
if (isSolid)
InitSolid();
else
_numSolidFiles = 1;
return S_OK;
}
static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
{
RINOK(PROPVARIANT_to_bool(prop, dest.Val));
dest.Def = true;
return S_OK;
}
HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
{
UString name = nameSpec;
name.MakeLower_Ascii();
if (name.IsEmpty())
return E_INVALIDARG;
if (name[0] == L's')
{
name.Delete(0);
if (name.IsEmpty())
return SetSolidFromPROPVARIANT(value);
if (value.vt != VT_EMPTY)
return E_INVALIDARG;
return SetSolidFromString(name);
}
UInt32 number;
int index = ParseStringToUInt32(name, number);
UString realName = name.Ptr(index);
if (index == 0)
{
if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock);
if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders);
// if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents);
if (name.IsEqualTo("hcf"))
{
bool compressHeadersFull = true;
RINOK(PROPVARIANT_to_bool(value, compressHeadersFull));
return compressHeadersFull ? S_OK: E_INVALIDARG;
}
if (name.IsEqualTo("he"))
{
RINOK(PROPVARIANT_to_bool(value, _encryptHeaders));
_encryptHeadersSpecified = true;
return S_OK;
}
if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime);
if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime);
if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime);
if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode);
}
return CMultiMethodProps::SetProperty(name, value);
}
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
{
COM_TRY_BEGIN
_binds.Clear();
InitProps();
for (UInt32 i = 0; i < numProps; i++)
{
UString name = names[i];
name.MakeLower_Ascii();
if (name.IsEmpty())
return E_INVALIDARG;
const PROPVARIANT &value = values[i];
if (name[0] == 'b')
{
if (value.vt != VT_EMPTY)
return E_INVALIDARG;
name.Delete(0);
CBind bind;
RINOK(GetBindInfoPart(name, bind.OutCoder, bind.OutStream));
if (name[0] != ':')
return E_INVALIDARG;
name.Delete(0);
RINOK(GetBindInfoPart(name, bind.InCoder, bind.InStream));
if (!name.IsEmpty())
return E_INVALIDARG;
_binds.Add(bind);
continue;
}
RINOK(SetProperty(name, value));
}
unsigned numEmptyMethods = GetNumEmptyMethods();
if (numEmptyMethods > 0)
{
unsigned k;
for (k = 0; k < _binds.Size(); k++)
{
const CBind &bind = _binds[k];
if (bind.InCoder < (UInt32)numEmptyMethods ||
bind.OutCoder < (UInt32)numEmptyMethods)
return E_INVALIDARG;
}
for (k = 0; k < _binds.Size(); k++)
{
CBind &bind = _binds[k];
bind.InCoder -= (UInt32)numEmptyMethods;
bind.OutCoder -= (UInt32)numEmptyMethods;
}
_methods.DeleteFrontal(numEmptyMethods);
}
AddDefaultMethod();
if (!_filterMethod.MethodName.IsEmpty())
{
FOR_VECTOR (k, _binds)
{
CBind &bind = _binds[k];
bind.InCoder++;
bind.OutCoder++;
}
_methods.Insert(0, _filterMethod);
}
FOR_VECTOR (k, _binds)
{
const CBind &bind = _binds[k];
if (bind.InCoder >= (UInt32)_methods.Size() ||
bind.OutCoder >= (UInt32)_methods.Size())
return E_INVALIDARG;
}
return S_OK;
COM_TRY_END
}
}}