578 lines
12 KiB
C++
578 lines
12 KiB
C++
|
/* ----------------------------------------------------------------------
|
||
|
|
||
|
Module: ULS.DLL (Service Provider)
|
||
|
File: spanyatt.cpp
|
||
|
Content: This file contains the arbitrary-attribute object.
|
||
|
History:
|
||
|
10/15/96 Chu, Lon-Chan [lonchanc]
|
||
|
Created.
|
||
|
|
||
|
Copyright (c) Microsoft Corporation 1996-1997
|
||
|
|
||
|
---------------------------------------------------------------------- */
|
||
|
|
||
|
#include "ulsp.h"
|
||
|
#include "spinc.h"
|
||
|
|
||
|
|
||
|
/* ---------- public methods ----------- */
|
||
|
|
||
|
|
||
|
UlsLdap_CAnyAttrs::UlsLdap_CAnyAttrs ( VOID )
|
||
|
{
|
||
|
m_cAttrs = 0;
|
||
|
m_AttrList = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
UlsLdap_CAnyAttrs::~UlsLdap_CAnyAttrs ( VOID )
|
||
|
{
|
||
|
FreeAttrList (m_AttrList);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ---------- protected methods ----------- */
|
||
|
|
||
|
|
||
|
HRESULT UlsLdap_CAnyAttrs::SetAnyAttrs (
|
||
|
ULONG *puRespID,
|
||
|
ULONG *puMsgID,
|
||
|
ULONG uNotifyMsg,
|
||
|
ULONG cAttrs,
|
||
|
TCHAR *pszAttrs,
|
||
|
ULONG cPrefix,
|
||
|
TCHAR *pszPrefix,
|
||
|
LONG ModOp,
|
||
|
SERVER_INFO *pServerInfo,
|
||
|
TCHAR *pszDN )
|
||
|
{
|
||
|
MyAssert (puRespID != NULL || puMsgID != NULL);
|
||
|
MyAssert (cAttrs != 0);
|
||
|
MyAssert (pszAttrs != NULL);
|
||
|
MyAssert (cPrefix != 0);
|
||
|
MyAssert (pszPrefix != NULL);
|
||
|
MyAssert (pServerInfo != NULL);
|
||
|
MyAssert (pszDN != NULL);
|
||
|
MyAssert (ModOp == LDAP_MOD_REPLACE || ModOp == LDAP_MOD_ADD);
|
||
|
|
||
|
// create a prefix for each attr name in the following pair
|
||
|
pszAttrs = PrefixNameValueArray (TRUE, cAttrs, pszAttrs);
|
||
|
if (pszAttrs == NULL)
|
||
|
return ULS_E_MEMORY;
|
||
|
|
||
|
// build modify array for ldap_modify()
|
||
|
LDAPMod **ppMod = NULL;
|
||
|
HRESULT hr = SetAttrsAux (cAttrs, pszAttrs, cPrefix, pszPrefix, ModOp, &ppMod);
|
||
|
if (hr != S_OK)
|
||
|
{
|
||
|
MemFree (pszAttrs);
|
||
|
return hr;
|
||
|
}
|
||
|
MyAssert (ppMod != NULL);
|
||
|
|
||
|
// so far, we are done with local preparation
|
||
|
|
||
|
// get the connection object
|
||
|
UlsLdap_CSession *pSession = NULL;
|
||
|
hr = g_pSessionContainer->GetSession (&pSession, pServerInfo);
|
||
|
if (hr != S_OK)
|
||
|
{
|
||
|
MemFree (pszAttrs);
|
||
|
MemFree (ppMod);
|
||
|
return hr;
|
||
|
}
|
||
|
MyAssert (pSession != NULL);
|
||
|
|
||
|
// get the ldap session
|
||
|
LDAP *ld = pSession->GetLd ();
|
||
|
MyAssert (ld != NULL);
|
||
|
|
||
|
// send the data over the wire
|
||
|
ULONG uMsgID = ldap_modify (ld, pszDN, ppMod);
|
||
|
MemFree (pszAttrs);
|
||
|
MemFree (ppMod);
|
||
|
if (uMsgID == -1)
|
||
|
{
|
||
|
hr = ::LdapError2Hresult (ld->ld_errno);
|
||
|
pSession->Disconnect ();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// if the caller does not ask for notify id
|
||
|
// then do not queue a pending info
|
||
|
if (puRespID != NULL)
|
||
|
{
|
||
|
PENDING_INFO PendingInfo;
|
||
|
::FillDefPendingInfo (&PendingInfo, ld, uMsgID, INVALID_MSG_ID);
|
||
|
PendingInfo.uLdapResType = LDAP_RES_MODIFY;
|
||
|
PendingInfo.uNotifyMsg = uNotifyMsg;
|
||
|
|
||
|
// queue it
|
||
|
hr = g_pPendingQueue->EnterRequest (pSession, &PendingInfo);
|
||
|
if (hr != S_OK)
|
||
|
{
|
||
|
ldap_abandon (ld, uMsgID);
|
||
|
pSession->Disconnect ();
|
||
|
MyAssert (FALSE);
|
||
|
}
|
||
|
|
||
|
*puRespID = PendingInfo.uRespID;
|
||
|
}
|
||
|
|
||
|
if (puMsgID)
|
||
|
*puMsgID = uMsgID;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT UlsLdap_CAnyAttrs::RemoveAllAnyAttrs (
|
||
|
ULONG *puMsgID,
|
||
|
ULONG cPrefix,
|
||
|
TCHAR *pszPrefix,
|
||
|
SERVER_INFO *pServerInfo,
|
||
|
TCHAR *pszDN )
|
||
|
{
|
||
|
ULONG cbAttrs = 0;
|
||
|
ULONG cAttrs = 0;
|
||
|
|
||
|
for (ANY_ATTR *p = m_AttrList; p != NULL; p = p->next)
|
||
|
{
|
||
|
cAttrs++;
|
||
|
if (p->pszAttrName != NULL)
|
||
|
cbAttrs += (lstrlen (p->pszAttrName) + 1) * sizeof (TCHAR);
|
||
|
}
|
||
|
|
||
|
MyAssert (cAttrs == m_cAttrs);
|
||
|
|
||
|
TCHAR *pszAttrs = (TCHAR *) MemAlloc (cbAttrs);
|
||
|
if (pszAttrs == NULL)
|
||
|
return ULS_E_MEMORY;
|
||
|
|
||
|
TCHAR *psz = pszAttrs;
|
||
|
for (p = m_AttrList; p != NULL; p = p->next)
|
||
|
{
|
||
|
if (p->pszAttrName != NULL)
|
||
|
{
|
||
|
lstrcpy (psz, p->pszAttrName);
|
||
|
psz += lstrlen (psz) + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT hr = RemoveAnyAttrsEx ( NULL,
|
||
|
puMsgID,
|
||
|
0,
|
||
|
cAttrs,
|
||
|
pszAttrs,
|
||
|
cPrefix,
|
||
|
pszPrefix,
|
||
|
pServerInfo,
|
||
|
pszDN);
|
||
|
MemFree (pszAttrs);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT UlsLdap_CAnyAttrs::RemoveAnyAttrs (
|
||
|
ULONG *puRespID,
|
||
|
ULONG *puMsgID,
|
||
|
ULONG uNotifyMsg,
|
||
|
ULONG cAttrs,
|
||
|
TCHAR *pszAttrs,
|
||
|
ULONG cPrefix,
|
||
|
TCHAR *pszPrefix,
|
||
|
SERVER_INFO *pServerInfo,
|
||
|
TCHAR *pszDN)
|
||
|
{
|
||
|
MyAssert (puRespID != NULL || puMsgID != NULL);
|
||
|
MyAssert (cAttrs != 0);
|
||
|
MyAssert (pszAttrs != NULL);
|
||
|
MyAssert (cPrefix != 0);
|
||
|
MyAssert (pszPrefix != NULL);
|
||
|
MyAssert (pServerInfo != NULL);
|
||
|
MyAssert (pszDN != NULL);
|
||
|
|
||
|
pszAttrs = PrefixNameValueArray (FALSE, cAttrs, pszAttrs);
|
||
|
if (pszAttrs == NULL)
|
||
|
return ULS_E_MEMORY;
|
||
|
|
||
|
HRESULT hr = RemoveAnyAttrsEx ( puRespID,
|
||
|
puMsgID,
|
||
|
uNotifyMsg,
|
||
|
cAttrs,
|
||
|
pszAttrs,
|
||
|
cPrefix,
|
||
|
pszPrefix,
|
||
|
pServerInfo,
|
||
|
pszDN);
|
||
|
MemFree (pszAttrs);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT UlsLdap_CAnyAttrs::RemoveAnyAttrsEx (
|
||
|
ULONG *puRespID,
|
||
|
ULONG *puMsgID,
|
||
|
ULONG uNotifyMsg,
|
||
|
ULONG cAttrs,
|
||
|
TCHAR *pszAttrs,
|
||
|
ULONG cPrefix,
|
||
|
TCHAR *pszPrefix,
|
||
|
SERVER_INFO *pServerInfo,
|
||
|
TCHAR *pszDN)
|
||
|
{
|
||
|
MyAssert (puRespID != NULL || puMsgID != NULL);
|
||
|
MyAssert (cAttrs != 0);
|
||
|
MyAssert (pszAttrs != NULL);
|
||
|
MyAssert (cPrefix != 0);
|
||
|
MyAssert (pszPrefix != NULL);
|
||
|
MyAssert (pServerInfo != NULL);
|
||
|
MyAssert (pszDN != NULL);
|
||
|
|
||
|
// build modify array for ldap_modify()
|
||
|
LDAPMod **ppMod = NULL;
|
||
|
HRESULT hr = RemoveAttrsAux (cAttrs, pszAttrs, cPrefix, pszPrefix, &ppMod);
|
||
|
if (hr != S_OK)
|
||
|
return hr;
|
||
|
MyAssert (ppMod != NULL);
|
||
|
|
||
|
// so far, we are done with local preparation
|
||
|
|
||
|
// get the connection object
|
||
|
UlsLdap_CSession *pSession = NULL;
|
||
|
hr = g_pSessionContainer->GetSession (&pSession, pServerInfo);
|
||
|
if (hr != S_OK)
|
||
|
{
|
||
|
MemFree (ppMod);
|
||
|
return hr;
|
||
|
}
|
||
|
MyAssert (pSession != NULL);
|
||
|
|
||
|
// get the ldap session
|
||
|
LDAP *ld = pSession->GetLd ();
|
||
|
MyAssert (ld != NULL);
|
||
|
|
||
|
// send the data over the wire
|
||
|
ULONG uMsgID = ldap_modify (ld, pszDN, ppMod);
|
||
|
MemFree (ppMod);
|
||
|
if (uMsgID == -1)
|
||
|
{
|
||
|
hr = ::LdapError2Hresult (ld->ld_errno);
|
||
|
pSession->Disconnect ();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// if the caller does not ask for notify id
|
||
|
// then do not queue a pending info
|
||
|
if (puRespID != NULL)
|
||
|
{
|
||
|
PENDING_INFO PendingInfo;
|
||
|
::FillDefPendingInfo (&PendingInfo, ld, uMsgID, INVALID_MSG_ID);
|
||
|
PendingInfo.uLdapResType = LDAP_RES_MODIFY;
|
||
|
PendingInfo.uNotifyMsg = uNotifyMsg;
|
||
|
|
||
|
hr = g_pPendingQueue->EnterRequest (pSession, &PendingInfo);
|
||
|
if (hr != S_OK)
|
||
|
{
|
||
|
ldap_abandon (ld, uMsgID);
|
||
|
pSession->Disconnect ();
|
||
|
MyAssert (FALSE);
|
||
|
}
|
||
|
|
||
|
*puRespID = PendingInfo.uRespID;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (puMsgID != NULL)
|
||
|
*puMsgID = uMsgID;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ---------- private methods ----------- */
|
||
|
|
||
|
|
||
|
HRESULT UlsLdap_CAnyAttrs::SetAttrsAux (
|
||
|
ULONG cAttrs,
|
||
|
TCHAR *pszAttrs,
|
||
|
ULONG cPrefix,
|
||
|
TCHAR *pszPrefix,
|
||
|
LONG ModOp,
|
||
|
LDAPMod ***pppMod )
|
||
|
{
|
||
|
MyAssert (cAttrs != 0);
|
||
|
MyAssert (pszAttrs != NULL);
|
||
|
MyAssert (cPrefix != 0);
|
||
|
MyAssert (pszPrefix != NULL);
|
||
|
MyAssert (ModOp == LDAP_MOD_REPLACE || ModOp == LDAP_MOD_ADD);
|
||
|
MyAssert (pppMod != NULL);
|
||
|
|
||
|
// create modify list
|
||
|
ULONG cTotal = cPrefix + cAttrs;
|
||
|
ULONG cbMod = ::IlsCalcModifyListSize (cTotal);
|
||
|
*pppMod = (LDAPMod **) MemAlloc (cbMod);
|
||
|
if (*pppMod == NULL)
|
||
|
{
|
||
|
return ULS_E_MEMORY;
|
||
|
}
|
||
|
|
||
|
LDAPMod *pMod;
|
||
|
for (ULONG i = 0; i < cTotal; i++)
|
||
|
{
|
||
|
pMod = ::IlsGetModifyListMod (pppMod, cTotal, i);
|
||
|
(*pppMod)[i] = pMod;
|
||
|
pMod->mod_values = (TCHAR **) (pMod + 1);
|
||
|
|
||
|
if (i < cPrefix)
|
||
|
{
|
||
|
pMod->mod_op = LDAP_MOD_REPLACE;
|
||
|
pMod->mod_type = pszPrefix;
|
||
|
pszPrefix += lstrlen (pszPrefix) + 1;
|
||
|
*(pMod->mod_values) = pszPrefix;
|
||
|
pszPrefix += lstrlen (pszPrefix) + 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pMod->mod_op = ModOp;
|
||
|
if (LocateAttr (pszAttrs) == NULL)
|
||
|
{
|
||
|
pMod->mod_op = LDAP_MOD_ADD;
|
||
|
m_cAttrs++;
|
||
|
}
|
||
|
if (pMod->mod_op == LDAP_MOD_ADD)
|
||
|
{
|
||
|
ULONG cbAttrSize = sizeof (ANY_ATTR) + sizeof (TCHAR) *
|
||
|
(lstrlen (pszAttrs) + 1);
|
||
|
ANY_ATTR *pNew = (ANY_ATTR *) MemAlloc (cbAttrSize);
|
||
|
if (pNew == NULL)
|
||
|
{
|
||
|
return ULS_E_MEMORY;
|
||
|
}
|
||
|
// fill in attr name
|
||
|
pNew->pszAttrName = (TCHAR *) (pNew + 1);
|
||
|
lstrcpy (pNew->pszAttrName, pszAttrs);
|
||
|
// link to the list
|
||
|
pNew->prev = NULL;
|
||
|
pNew->next = m_AttrList;
|
||
|
m_AttrList = pNew;
|
||
|
}
|
||
|
pMod->mod_type = pszAttrs;
|
||
|
pszAttrs += lstrlen (pszAttrs) + 1;
|
||
|
*(pMod->mod_values) = pszAttrs;
|
||
|
pszAttrs += lstrlen (pszAttrs) + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
(*pppMod)[cTotal] = NULL;
|
||
|
::IlsFixUpModOp ((*pppMod)[0], ModOp, ISBU_MODOP_MODIFY_APP);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT UlsLdap_CAnyAttrs::RemoveAttrsAux (
|
||
|
ULONG cAttrs,
|
||
|
TCHAR *pszAttrs,
|
||
|
ULONG cPrefix,
|
||
|
TCHAR *pszPrefix,
|
||
|
LDAPMod ***pppMod )
|
||
|
{
|
||
|
MyAssert (cAttrs != 0);
|
||
|
MyAssert (pszAttrs != NULL);
|
||
|
MyAssert (cPrefix != 0);
|
||
|
MyAssert (pszPrefix != NULL);
|
||
|
MyAssert (pppMod != NULL);
|
||
|
|
||
|
// create modify list
|
||
|
ULONG cTotal = cPrefix + cAttrs;
|
||
|
ULONG cbMod = ::IlsCalcModifyListSize (cTotal);
|
||
|
*pppMod = (LDAPMod **) MemAlloc (cbMod);
|
||
|
if (*pppMod == NULL)
|
||
|
{
|
||
|
return ULS_E_MEMORY;
|
||
|
}
|
||
|
|
||
|
LDAPMod *pMod;
|
||
|
for (ULONG i = 0; i < cTotal; i++)
|
||
|
{
|
||
|
pMod = ::IlsGetModifyListMod (pppMod, cTotal, i);
|
||
|
(*pppMod)[i] = pMod;
|
||
|
|
||
|
if (i < cPrefix)
|
||
|
{
|
||
|
pMod->mod_op = LDAP_MOD_REPLACE;
|
||
|
pMod->mod_type = pszPrefix;
|
||
|
pszPrefix += lstrlen (pszPrefix) + 1;
|
||
|
pMod->mod_values = (TCHAR **) (pMod + 1);
|
||
|
*(pMod->mod_values) = pszPrefix;
|
||
|
pszPrefix += lstrlen (pszPrefix) + 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pMod->mod_op = LDAP_MOD_DELETE;
|
||
|
RemoveAttrFromList (pszAttrs);
|
||
|
pMod->mod_type = pszAttrs;
|
||
|
pszAttrs += lstrlen (pszAttrs) + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
(*pppMod)[cTotal] = NULL;
|
||
|
::IlsFixUpModOp ((*pppMod)[0], LDAP_MOD_REPLACE, ISBU_MODOP_MODIFY_APP);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID UlsLdap_CAnyAttrs::RemoveAttrFromList ( TCHAR *pszAttrName )
|
||
|
{
|
||
|
ANY_ATTR *pOld = LocateAttr (pszAttrName);
|
||
|
if (pOld != NULL)
|
||
|
{
|
||
|
// remove it
|
||
|
if (pOld->prev != NULL)
|
||
|
{
|
||
|
pOld->prev->next = pOld->next;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_AttrList = pOld->next;
|
||
|
}
|
||
|
if (pOld->next != NULL)
|
||
|
{
|
||
|
pOld->next->prev = pOld->prev;
|
||
|
}
|
||
|
|
||
|
MyAssert (m_cAttrs != 0);
|
||
|
m_cAttrs--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID UlsLdap_CAnyAttrs::FreeAttrList ( ANY_ATTR *AttrList )
|
||
|
{
|
||
|
ANY_ATTR *pCurr, *pNext;
|
||
|
for (pCurr = AttrList; pCurr != NULL; pCurr = pNext)
|
||
|
{
|
||
|
pNext = pCurr->next;
|
||
|
MemFree (pCurr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
ANY_ATTR *UlsLdap_CAnyAttrs::LocateAttr ( TCHAR *pszAttrName )
|
||
|
{
|
||
|
ANY_ATTR *pAttr;
|
||
|
for (pAttr = m_AttrList; pAttr != NULL; pAttr = pAttr->next)
|
||
|
{
|
||
|
if (! My_lstrcmpi (pszAttrName, pAttr->pszAttrName))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return pAttr;
|
||
|
}
|
||
|
|
||
|
// const TCHAR c_szAnyAttrPrefix[] = TEXT ("ulsaan_");
|
||
|
const TCHAR c_szAnyAttrPrefix[] = TEXT ("ILSA");
|
||
|
#define SIZE_ANY_ATTR_PREFIX (sizeof (c_szAnyAttrPrefix) / sizeof (TCHAR))
|
||
|
|
||
|
const TCHAR *SkipAnyAttrNamePrefix ( const TCHAR *pszAttrName )
|
||
|
{
|
||
|
MyAssert (pszAttrName != NULL);
|
||
|
|
||
|
const TCHAR *psz = IsAnyAttrName (pszAttrName);
|
||
|
if (psz == NULL)
|
||
|
{
|
||
|
MyAssert (FALSE);
|
||
|
psz = pszAttrName;
|
||
|
}
|
||
|
|
||
|
return psz;
|
||
|
}
|
||
|
|
||
|
const TCHAR *IsAnyAttrName ( const TCHAR *pszAttrName )
|
||
|
{
|
||
|
BOOL fRet = FALSE;
|
||
|
TCHAR *psz = (TCHAR *) pszAttrName;
|
||
|
|
||
|
if (pszAttrName != NULL)
|
||
|
{
|
||
|
if (lstrlen (pszAttrName) > SIZE_ANY_ATTR_PREFIX)
|
||
|
{
|
||
|
TCHAR c = pszAttrName[SIZE_ANY_ATTR_PREFIX-1];
|
||
|
psz[SIZE_ANY_ATTR_PREFIX-1] = TEXT ('\0');
|
||
|
fRet = (My_lstrcmpi (pszAttrName, &c_szAnyAttrPrefix[0]) == 0);
|
||
|
psz[SIZE_ANY_ATTR_PREFIX-1] = c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (fRet ? &pszAttrName[SIZE_ANY_ATTR_PREFIX-1] : NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
TCHAR *PrefixNameValueArray ( BOOL fPair, ULONG cAttrs, const TCHAR *pszAttrs )
|
||
|
{
|
||
|
if (cAttrs == 0 || pszAttrs == NULL)
|
||
|
{
|
||
|
MyAssert (FALSE);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// compute the total size required
|
||
|
ULONG cbTotalSize = 0;
|
||
|
ULONG cbThisSize;
|
||
|
TCHAR *pszSrc = (TCHAR *) pszAttrs;
|
||
|
for (ULONG i = 0; i < cAttrs; i++)
|
||
|
{
|
||
|
// get name size
|
||
|
cbThisSize = lstrlen (pszSrc) + 1;
|
||
|
pszSrc += lstrlen (pszSrc) + 1;
|
||
|
|
||
|
// get value size as needed
|
||
|
if (fPair)
|
||
|
{
|
||
|
cbThisSize += lstrlen (pszSrc) + 1;
|
||
|
pszSrc += lstrlen (pszSrc) + 1;
|
||
|
}
|
||
|
|
||
|
// adjust the size
|
||
|
cbThisSize += SIZE_ANY_ATTR_PREFIX;
|
||
|
cbThisSize *= sizeof (TCHAR);
|
||
|
|
||
|
// accumulate it
|
||
|
cbTotalSize += cbThisSize;
|
||
|
}
|
||
|
|
||
|
// allocate the new buffer
|
||
|
TCHAR *pszPrefixAttrs = (TCHAR *) MemAlloc (cbTotalSize);
|
||
|
if (pszPrefixAttrs == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
// copy the strings over to the new buffer
|
||
|
pszSrc = (TCHAR *) pszAttrs;
|
||
|
TCHAR *pszDst = pszPrefixAttrs;
|
||
|
for (i = 0; i < cAttrs; i++)
|
||
|
{
|
||
|
// copy prefix
|
||
|
lstrcpy (pszDst, &c_szAnyAttrPrefix[0]);
|
||
|
pszDst += lstrlen (pszDst); // no plus 1
|
||
|
|
||
|
// copy name
|
||
|
lstrcpy (pszDst, pszSrc);
|
||
|
pszDst += lstrlen (pszDst) + 1;
|
||
|
pszSrc += lstrlen (pszSrc) + 1;
|
||
|
|
||
|
// copy value as needed
|
||
|
if (fPair)
|
||
|
{
|
||
|
lstrcpy (pszDst, pszSrc);
|
||
|
pszDst += lstrlen (pszDst) + 1;
|
||
|
pszSrc += lstrlen (pszSrc) + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pszPrefixAttrs;
|
||
|
}
|
||
|
|
||
|
|