Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

664 lines
16 KiB

/*===================================================================
Microsoft Denali
Microsoft Confidential.
Copyright 1996 Microsoft Corporation. All Rights Reserved.
Component: StringList object
File: strlist.cpp
Owner: DGottner
This file contains the code for the implementation of the String List object.
===================================================================*/
#include "denpre.h"
#pragma hdrstop
#include "strlist.h"
#include "MemChk.h"
#pragma warning (disable: 4355) // ignore: "'this' used in base member init
/*===================================================================
CStringListElem::CStringListElem
Constructor
===================================================================*/
CStringListElem::CStringListElem()
:
m_fBufferInUse(FALSE),
m_fAllocated(FALSE),
m_pNext(NULL),
m_szPointer(NULL)
{
}
/*===================================================================
CStringListElem::~CStringListElem
Destructor
===================================================================*/
CStringListElem::~CStringListElem()
{
if (m_fAllocated)
delete [] m_szPointer;
if (m_pNext)
delete m_pNext;
}
/*===================================================================
CStringListElem::Init
Init CStringListElem
Parameters
szValue the string
fMakeCopy if FALSE - just store the pointer
lCodePage codepage to use to convert to UNICODE
===================================================================*/
HRESULT CStringListElem::Init(
char *szValue,
BOOL fMakeCopy,
UINT lCodePage)
{
// for now, always make a copy of the string. This is to ensure
// that any string lists placed in session state via a dictionary
// object do not have their elements freed from under them when
// the request completes.
if (1 /*fMakeCopy*/) {
CMBCSToWChar convStr;
HRESULT hr = S_OK;
if (FAILED(hr = convStr.Init(szValue, lCodePage))) {
return hr;
}
// now we will move the string into the elements memory. If the
// converted string is bigger than the internal buffer, then
// set the element's pointer to an allocated copy of the converted
// string.
if ((convStr.GetStringLen() + 1) > (sizeof(m_szBuffer)/sizeof(WCHAR))) {
m_szPointer = convStr.GetString(TRUE);
if (!m_szPointer)
return E_OUTOFMEMORY;
m_fBufferInUse = FALSE;
m_fAllocated = TRUE;
}
else {
// if it fits, simply copy it into the internal buffer.
wcscpy(m_szBuffer, convStr.GetString());
m_fBufferInUse = TRUE;
m_fAllocated = FALSE;
}
}
#if 0
else {
m_szPointer = szValue;
m_fBufferInUse = FALSE;
m_fAllocated = FALSE;
}
#endif
m_pNext = NULL;
return S_OK;
}
/*===================================================================
CStringListElem::Init
Init CStringListElem
Parameters
szValue the string
fMakeCopy if FALSE - just store the pointer
===================================================================*/
HRESULT CStringListElem::Init(
WCHAR *wszValue,
BOOL fMakeCopy)
{
// for now, always make a copy of the string. This is to ensure
// that any string lists placed in session state via a dictionary
// object do not have their elements freed from under them when
// the request completes.
if (1 /*fMakeCopy*/) {
// now we will move the string into the elements memory. If the
// converted string is bigger than the internal buffer, then
// set the element's pointer to an allocated copy
if ((wcslen(wszValue) + 1) > (sizeof(m_szBuffer)/sizeof(WCHAR))) {
m_szPointer = StringDupW(wszValue);
if (!m_szPointer)
return E_OUTOFMEMORY;
m_fBufferInUse = FALSE;
m_fAllocated = TRUE;
}
else {
// if it fits, simply copy it into the internal buffer.
wcscpy(m_szBuffer, wszValue);
m_fBufferInUse = TRUE;
m_fAllocated = FALSE;
}
}
#if 0
else {
m_szPointer = szValue;
m_fBufferInUse = FALSE;
m_fAllocated = FALSE;
}
#endif
m_pNext = NULL;
return S_OK;
}
/*===================================================================
CStringList::CStringList
Constructor
===================================================================*/
CStringList::CStringList(IUnknown *pUnkOuter, PFNDESTROYED pfnDestroy)
: m_ISupportErrImp(this, pUnkOuter, IID_IStringList)
{
m_pBegin = m_pEnd = NULL;
m_cValues = 0;
m_cRefs = 1;
m_pfnDestroy = pfnDestroy;
CDispatch::Init(IID_IStringList);
m_lCodePage = GetACP();
}
/*===================================================================
CStringList::~CStringList
Destructor
===================================================================*/
CStringList::~CStringList()
{
if (m_pBegin)
delete m_pBegin;
}
/*===================================================================
CStringList::AddValue
Parameters:
szValue - value to add to the string list
lCodePage - the CodePage used when construct return value
===================================================================*/
HRESULT CStringList::AddValue(char *szValue, BOOL fDuplicate, UINT lCodePage)
{
CStringListElem *pElem = new CStringListElem;
if (!pElem)
return E_OUTOFMEMORY;
m_lCodePage = lCodePage;
HRESULT hr = pElem->Init(szValue, fDuplicate, lCodePage);
if (FAILED(hr)) {
delete pElem;
return hr;
}
if (m_pBegin == NULL)
{
m_pBegin = m_pEnd = pElem;
}
else
{
m_pEnd->SetNext(pElem);
m_pEnd = pElem;
}
++m_cValues;
return S_OK;
}
/*===================================================================
CStringList::AddValue
Parameters:
szValue - value to add to the string list
lCodePage - the CodePage used when construct return value
===================================================================*/
HRESULT CStringList::AddValue(WCHAR *szValue, BOOL fDuplicate)
{
CStringListElem *pElem = new CStringListElem;
if (!pElem)
return E_OUTOFMEMORY;
HRESULT hr = pElem->Init(szValue, fDuplicate);
if (FAILED(hr)) {
delete pElem;
return hr;
}
if (m_pBegin == NULL)
{
m_pBegin = m_pEnd = pElem;
}
else
{
m_pEnd->SetNext(pElem);
m_pEnd = pElem;
}
++m_cValues;
return S_OK;
}
/*===================================================================
CStringList::QueryInterface
CStringList::AddRef
CStringList::Release
IUnknown members for CStringList object.
===================================================================*/
STDMETHODIMP CStringList::QueryInterface(const IID &iid, void **ppvObj)
{
*ppvObj = NULL;
if (iid == IID_IUnknown || iid == IID_IDispatch ||
iid == IID_IStringList || iid == IID_IDenaliIntrinsic)
{
*ppvObj = this;
}
if (iid == IID_ISupportErrorInfo)
*ppvObj = &m_ISupportErrImp;
if (*ppvObj != NULL)
{
static_cast<IUnknown *>(*ppvObj)->AddRef();
return S_OK;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CStringList::AddRef()
{
return ++m_cRefs;
}
STDMETHODIMP_(ULONG) CStringList::Release()
{
if (--m_cRefs != 0)
return m_cRefs;
if (m_pfnDestroy != NULL)
(*m_pfnDestroy)();
delete this;
return 0;
}
/*===================================================================
CStringList::get_Count
Parameters:
pcValues - count is stored in *pcValues
===================================================================*/
STDMETHODIMP CStringList::get_Count(int *pcValues)
{
*pcValues = m_cValues;
return S_OK;
}
/*===================================================================
CStringList::ConstructDefaultReturn
Return comma-separated list for the case where the CStringList
is not indexed.
===================================================================*/
HRESULT CStringList::ConstructDefaultReturn(VARIANT *pvarOut) {
VariantClear(pvarOut);
//
// NEW SEMANTIC: we now return Empty (and not "") if nothing is in the collection
//
if (m_cValues == 0)
return S_OK; // VariantClear set pvarOut to Empty
STACK_BUFFER( tempValues, 1024 );
register CStringListElem *pElem;
int cBytes = 0;
for (pElem = m_pBegin; pElem != NULL; pElem = pElem->QueryNext())
cBytes += (wcslen(pElem->QueryValue()) * sizeof(WCHAR));
// need to account for the ", " and NULL Termination
cBytes += sizeof(WCHAR) + ((2*(m_cValues - 1)) * sizeof(WCHAR));
if (!tempValues.Resize(cBytes)) {
ExceptionId(IID_IStringList, IDE_REQUEST, IDE_OOM);
return E_FAIL;
}
WCHAR *szReturn = (WCHAR *)tempValues.QueryPtr();
szReturn[0] = L'\0';
WCHAR *szNext = szReturn;
for (pElem = m_pBegin; pElem != NULL; pElem = pElem->QueryNext()) {
szNext = strcpyExW(szNext, pElem->QueryValue());
if (pElem->QueryNext() != NULL)
szNext = strcpyExW(szNext, L", ");
}
BSTR bstrT;
if ((bstrT = SysAllocString(szReturn)) == NULL) {
ExceptionId(IID_IStringList, IDE_REQUEST, IDE_OOM);
return E_FAIL;
}
V_VT(pvarOut) = VT_BSTR;
V_BSTR(pvarOut) = bstrT;
return S_OK;
}
/*===================================================================
CStringList::get_Item
===================================================================*/
STDMETHODIMP CStringList::get_Item(VARIANT varIndex, VARIANT *pvarOut)
{
long i;
VariantInit(pvarOut);
if (V_VT(&varIndex) == VT_ERROR) {
return ConstructDefaultReturn(pvarOut);
}
// BUG 937: VBScript passes VT_VARIANT|VT_BYREF when passing variants
// Loop through while we have a VT_BYREF until we get the real variant.
//
// and changed again...
//
// BUG 1609 the prior code was only checking for VT_I4 and jscript passed in a
// VT_R8 and it failed so now we use the VariantChangeType call to solve the
// problem
VARIANT var;
VariantInit(&var);
HRESULT hr = S_OK;
if((hr = VariantChangeType(&var, &varIndex ,0,VT_I4)) != S_OK) {
ExceptionId(IID_IStringList, IDE_REQUEST, IDE_EXPECTING_INT);
return E_FAIL;
}
i = V_I4(&var);
VariantClear(&var);
// END bug 1609
if (i <= 0 || i > m_cValues) {
ExceptionId(IID_IStringList, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
return E_FAIL;
}
register CStringListElem *pElem = m_pBegin;
while (--i > 0)
pElem = pElem->QueryNext();
BSTR bstrT;
if ((bstrT = SysAllocString(pElem->QueryValue())) == NULL ) {
ExceptionId(IID_IStringList, IDE_REQUEST, IDE_OOM);
return E_FAIL;
}
V_VT(pvarOut) = VT_BSTR;
V_BSTR(pvarOut) = bstrT;
return S_OK;
}
/*===================================================================
CStringList::get__NewEnum
===================================================================*/
STDMETHODIMP CStringList::get__NewEnum(IUnknown **ppEnumReturn)
{
*ppEnumReturn = new CStrListIterator(this);
if (*ppEnumReturn == NULL)
{
ExceptionId(IID_IStringList, IDE_REQUEST, IDE_OOM);
return E_OUTOFMEMORY;
}
return S_OK;
}
/*------------------------------------------------------------------
* C S t r L i s t I t e r a t o r
*/
/*===================================================================
CStrListIterator::CStrListIterator
Constructor
NOTE: CRequest is (currently) not refcounted. AddRef/Release
added to protect against future changes.
===================================================================*/
CStrListIterator::CStrListIterator(CStringList *pStrings)
{
Assert (pStrings != NULL);
m_pStringList = pStrings;
m_pCurrent = m_pStringList->m_pBegin;
m_cRefs = 1;
m_pStringList->AddRef();
}
/*===================================================================
CStrListIterator::CStrListIterator
Destructor
===================================================================*/
CStrListIterator::~CStrListIterator()
{
m_pStringList->Release();
}
/*===================================================================
CStrListIterator::QueryInterface
CStrListIterator::AddRef
CStrListIterator::Release
IUnknown members for CServVarsIterator object.
===================================================================*/
STDMETHODIMP CStrListIterator::QueryInterface(REFIID iid, void **ppvObj)
{
if (iid == IID_IUnknown || iid == IID_IEnumVARIANT)
{
AddRef();
*ppvObj = this;
return S_OK;
}
*ppvObj = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CStrListIterator::AddRef()
{
return ++m_cRefs;
}
STDMETHODIMP_(ULONG) CStrListIterator::Release()
{
if (--m_cRefs > 0)
return m_cRefs;
delete this;
return 0;
}
/*===================================================================
CStrListIterator::Clone
Clone this iterator (standard method)
===================================================================*/
STDMETHODIMP CStrListIterator::Clone(IEnumVARIANT **ppEnumReturn)
{
CStrListIterator *pNewIterator = new CStrListIterator(m_pStringList);
if (pNewIterator == NULL)
return E_OUTOFMEMORY;
// new iterator should point to same location as this.
pNewIterator->m_pCurrent = m_pCurrent;
*ppEnumReturn = pNewIterator;
return S_OK;
}
/*===================================================================
CStrListIterator::Next
Get next value (standard method)
To rehash standard OLE semantics:
We get the next "cElements" from the collection and store them
in "rgVariant" which holds at least "cElements" items. On
return "*pcElementsFetched" contains the actual number of elements
stored. Returns S_FALSE if less than "cElements" were stored, S_OK
otherwise.
===================================================================*/
STDMETHODIMP CStrListIterator::Next(unsigned long cElementsRequested, VARIANT *rgVariant, unsigned long *pcElementsFetched)
{
// give a valid pointer value to 'pcElementsFetched'
//
unsigned long cElementsFetched;
if (pcElementsFetched == NULL)
pcElementsFetched = &cElementsFetched;
// Loop through the collection until either we reach the end or
// cElements becomes zero
//
unsigned long cElements = cElementsRequested;
*pcElementsFetched = 0;
while (cElements > 0 && m_pCurrent != NULL)
{
BSTR bstrT = SysAllocString(m_pCurrent->QueryValue());
if (bstrT == NULL)
return E_OUTOFMEMORY;
V_VT(rgVariant) = VT_BSTR;
V_BSTR(rgVariant) = bstrT;
++rgVariant;
--cElements;
++*pcElementsFetched;
m_pCurrent = m_pCurrent->QueryNext();
}
// initialize the remaining variants
//
while (cElements-- > 0)
VariantInit(rgVariant++);
return (*pcElementsFetched == cElementsRequested)? S_OK : S_FALSE;
}
/*===================================================================
CStrListIterator::Skip
Skip items (standard method)
To rehash standard OLE semantics:
We skip over the next "cElements" from the collection.
Returns S_FALSE if less than "cElements" were skipped, S_OK
otherwise.
===================================================================*/
STDMETHODIMP CStrListIterator::Skip(unsigned long cElements)
{
/* Loop through the collection until either we reach the end or
* cElements becomes zero
*/
while (cElements > 0 && m_pCurrent != NULL)
{
--cElements;
m_pCurrent = m_pCurrent->QueryNext();
}
return (cElements == 0)? S_OK : S_FALSE;
}
/*===================================================================
CStrListIterator::Reset
Reset the iterator (standard method)
===================================================================*/
STDMETHODIMP CStrListIterator::Reset()
{
m_pCurrent = m_pStringList->m_pBegin;
return S_OK;
}