windows-nt/Source/XPSP1/NT/base/pnp/tools/devcon2/strings.cpp

624 lines
11 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// Strings.cpp : Implementation of CStrings
#include "stdafx.h"
#include "DevCon2.h"
#include "xStrings.h"
#include "StringsEnum.h"
#include "utils.h"
/////////////////////////////////////////////////////////////////////////////
// CStrings
CStrings::~CStrings()
{
DWORD c;
if(pMultiStrings) {
for(c=0;c<Count;c++) {
SysFreeString(pMultiStrings[c]);
}
delete [] pMultiStrings;
}
}
STDMETHODIMP CStrings::get_Count(long *pVal)
{
*pVal = (long)Count;
return S_OK;
}
STDMETHODIMP CStrings::Item(VARIANT Index, VARIANT *pVal)
{
HRESULT hr;
DWORD i;
BSTR ValueCopy = NULL;
if(!IsNoArg(&Index)) {
//
// get single value
//
hr = GetIndex(&Index,&i);
if(FAILED(hr)) {
return hr;
}
ValueCopy = SysAllocStringLen(pMultiStrings[i],SysStringLen(pMultiStrings[i]));
if(!ValueCopy) {
return E_OUTOFMEMORY;
}
VariantInit(pVal);
V_VT(pVal) = VT_BSTR;
V_BSTR(pVal) = ValueCopy;
return S_OK;
}
//
// return collection as an array of strings
//
#if 1
SAFEARRAY *pArray;
SAFEARRAYBOUND bounds[1];
LONG ind[1];
bounds[0].lLbound = 1;
bounds[0].cElements = Count;
VARIANT v;
pArray = SafeArrayCreate(VT_VARIANT,1,bounds);
if(!pArray) {
return E_OUTOFMEMORY;
}
DWORD c;
VariantInit(&v);
for(c=0;c<Count;c++) {
ind[0] = (LONG)(c+1);
V_VT(&v) = VT_BSTR;
V_BSTR(&v) = pMultiStrings[c];
hr = SafeArrayPutElement(pArray,ind,&v);
if(FAILED(hr)) {
SafeArrayDestroy(pArray);
return hr;
}
}
VariantInit(pVal);
V_VT(pVal) = VT_ARRAY | VT_VARIANT;
V_ARRAY(pVal) = pArray;
#else
SAFEARRAY *pArray;
SAFEARRAYBOUND bounds[1];
LONG ind[1];
bounds[0].lLbound = 1;
bounds[0].cElements = Count;
pArray = SafeArrayCreate(VT_BSTR,1,bounds);
if(!pArray) {
return E_OUTOFMEMORY;
}
DWORD c;
for(c=0;c<Count;c++) {
ind[0] = (LONG)(c+1);
hr = SafeArrayPutElement(pArray,ind,pMultiStrings[c]);
if(FAILED(hr)) {
SafeArrayDestroy(pArray);
return hr;
}
}
VariantInit(pVal);
V_VT(pVal) = VT_ARRAY | VT_BSTR;
V_ARRAY(pVal) = pArray;
#endif
return S_OK;
}
STDMETHODIMP CStrings::get__NewEnum(IUnknown **ppUnk)
{
*ppUnk = NULL;
HRESULT hr;
CComObject<CStringsEnum> *pEnum = NULL;
hr = CComObject<CStringsEnum>::CreateInstance(&pEnum);
if(FAILED(hr)) {
return hr;
}
if(!pEnum) {
return E_OUTOFMEMORY;
}
pEnum->AddRef();
if(!pEnum->CopyStrings(pMultiStrings,Count)) {
pEnum->Release();
return E_OUTOFMEMORY;
}
*ppUnk = pEnum;
return S_OK;
}
HRESULT CStrings::InternalAdd(LPCWSTR Value, UINT len)
{
if(len == (UINT)(-1)) {
len = wcslen(Value);
}
BSTR ValueCopy = NULL;
if(!IncreaseArraySize(1)) {
return E_OUTOFMEMORY;
}
ValueCopy = SysAllocStringLen(Value,len);
if(!ValueCopy) {
return E_OUTOFMEMORY;
}
pMultiStrings[Count++] = ValueCopy;
return S_OK;
}
STDMETHODIMP CStrings::Add(VARIANT Value)
{
return InternalInsert(Count,&Value);
}
BOOL CStrings::IncreaseArraySize(DWORD strings)
{
BSTR* pNewStrings;
DWORD Inc;
DWORD c;
if((ArraySize-Count)>=strings) {
return TRUE;
}
Inc = ArraySize + strings + 32;
pNewStrings = new BSTR[Inc];
if(!pNewStrings) {
return FALSE;
}
for(c=0;c<Count;c++) {
pNewStrings[c] = pMultiStrings[c];
}
delete [] pMultiStrings;
pMultiStrings = pNewStrings;
ArraySize = Inc;
return TRUE;
}
STDMETHODIMP CStrings::Insert(VARIANT Index, VARIANT Value)
{
HRESULT hr;
DWORD i;
hr = GetIndex(&Index,&i);
if(FAILED(hr)) {
return hr;
}
//
// allow i==Count
//
if(i>Count) {
return E_INVALIDARG;
}
return InternalInsert(i,&Value);
}
STDMETHODIMP CStrings::Remove(VARIANT Index)
{
HRESULT hr;
DWORD i;
hr = GetIndex(&Index,&i);
if(FAILED(hr)) {
return hr;
}
if(i>=Count) {
return E_INVALIDARG;
}
DWORD c;
SysFreeString(pMultiStrings[i]);
Count--;
for(c=i;c<Count;c++) {
pMultiStrings[c] = pMultiStrings[c+1];
}
return S_OK;
}
HRESULT CStrings::InternalInsert(DWORD Index, LPVARIANT pVal)
{
CComVariant v;
HRESULT hr;
SAFEARRAY *pArray;
VARTYPE vt;
CComPtr<IEnumVARIANT> pEnum;
if(IsArrayVariant(pVal,&pArray,&vt)) {
return InternalInsertArray(Index,vt,pArray);
}
if(IsCollectionVariant(pVal,&pEnum)) {
return InternalInsertCollection(Index,pEnum);
}
//
// now see if we can treat it as a string
//
hr = v.ChangeType(VT_BSTR,pVal);
if(SUCCEEDED(hr)) {
return InternalInsertString(Index,V_BSTR(&v));
}
return hr;
}
HRESULT CStrings::InternalInsertArray(DWORD Index, VARTYPE vt, SAFEARRAY *pArray)
{
HRESULT hr;
UINT dims = SafeArrayGetDim(pArray);
if(!dims) {
return S_FALSE;
}
long *pDims = new long[dims];
if(!pDims) {
return E_OUTOFMEMORY;
}
//
// write values into a temporary collection
//
CComObject<CStrings> *pStringTemp = NULL;
hr = CComObject<CStrings>::CreateInstance(&pStringTemp);
if(FAILED(hr)) {
delete [] pDims;
return hr;
}
pStringTemp->AddRef();
hr = InternalInsertArrayDim(pStringTemp,vt,pArray,pDims,0,dims);
delete [] pDims;
if(FAILED(hr)) {
pStringTemp->Release();
return hr;
}
//
// now quickly insert pStringTemp strings into this collection
//
DWORD Added = pStringTemp->Count;
if(!IncreaseArraySize(Added)) {
pStringTemp->Release();
return E_OUTOFMEMORY;
}
DWORD c;
for(c=Count;c>Index;c--) {
pMultiStrings[c-1+Added] = pMultiStrings[c-1];
}
for(c=0;c<Added;c++) {
pMultiStrings[Index+c] = pStringTemp->pMultiStrings[c];
}
Count += Added;
//
// throw strings in temp collection away without free'ing them
//
pStringTemp->Count = 0;
pStringTemp->Release();
return S_OK;
}
HRESULT CStrings::InternalInsertArrayDim(CComObject<CStrings> *pStringTemp, VARTYPE vt, SAFEARRAY *pArray,long *pDims,UINT dim,UINT dims)
{
long lower;
long upper;
long aIndex;
HRESULT hr;
UINT nextdim = dim+1;
hr = SafeArrayGetLBound(pArray,nextdim,&lower);
if(FAILED(hr)) {
return hr;
}
hr = SafeArrayGetUBound(pArray,nextdim,&upper);
if(FAILED(hr)) {
return hr;
}
if(nextdim<dims) {
for(aIndex=lower;aIndex<=upper;aIndex++) {
pDims[dim] = aIndex;
hr = InternalInsertArrayDim(pStringTemp,vt,pArray,pDims,nextdim,dims);
if(FAILED(hr)) {
return hr;
}
}
return S_OK;
}
if(upper-lower<0) {
return S_OK;
}
//
// write values for this vector
//
UINT elemsize = SafeArrayGetElemsize(pArray);
PBYTE buffer = new BYTE[elemsize];
if(!buffer) {
return E_OUTOFMEMORY;
}
for(aIndex=lower;aIndex<=upper;aIndex++) {
pDims[dim] = aIndex;
hr = SafeArrayGetElement(pArray,pDims,buffer);
if(FAILED(hr)) {
delete [] buffer;
return hr;
}
VARIANT v;
if(elemsize < sizeof(VARIANT)) {
VariantInit(&v);
V_VT(&v) = vt & ~(VT_ARRAY|VT_VECTOR|VT_BYREF);
memcpy(&V_BYREF(&v),buffer,elemsize);
} else {
memcpy(&v,buffer,sizeof(v));
}
if(V_VT(&v)!=VT_EMPTY) {
//
// only add non-empty items
//
hr = pStringTemp->Add(v);
}
VariantClear(&v);
if(FAILED(hr)) {
delete [] buffer;
return hr;
}
}
return S_OK;
}
HRESULT CStrings::InternalInsertCollection(DWORD Index, IEnumVARIANT *pEnum)
{
pEnum->Reset();
CComVariant ent;
//
// get first item - this allows us to do little work if
// source collection is empty
//
HRESULT hr = pEnum->Next(1,&ent,NULL);
if(FAILED(hr)) {
return hr;
}
if(hr != S_OK) {
//
// empty
//
return S_FALSE;
}
//
// create a temporary collection for working
//
CComObject<CStrings> *pStringTemp = NULL;
hr = CComObject<CStrings>::CreateInstance(&pStringTemp);
if(FAILED(hr)) {
return hr;
}
pStringTemp->AddRef();
do {
//
// this will recursively process an element of this collection
//
hr = pStringTemp->Add(ent);
if(FAILED(hr)) {
break;
}
//
// next
//
ent.Clear();
hr = pEnum->Next(1,&ent,NULL);
} while(hr == S_OK);
if(FAILED(hr)) {
pStringTemp->Release();
return hr;
}
//
// now quickly insert pStringTemp strings into this collection
//
DWORD Added = pStringTemp->Count;
if(!IncreaseArraySize(Added)) {
pStringTemp->Release();
return E_OUTOFMEMORY;
}
DWORD c;
for(c=Count;c>Index;c--) {
pMultiStrings[c-1+Added] = pMultiStrings[c-1];
}
for(c=0;c<Added;c++) {
pMultiStrings[Index+c] = pStringTemp->pMultiStrings[c];
}
Count += Added;
//
// throw strings in temp collection away without free'ing them
//
pStringTemp->Count = 0;
pStringTemp->Release();
return S_OK;
}
HRESULT CStrings::InternalInsertString(DWORD Index, BSTR pString)
{
DWORD c;
BSTR ValueCopy = NULL;
if(Index>Count) {
return E_INVALIDARG;
}
if(!IncreaseArraySize(1)) {
return E_OUTOFMEMORY;
}
ValueCopy = SysAllocStringLen(pString,SysStringLen(pString));
if(!ValueCopy) {
return E_OUTOFMEMORY;
}
for(c=Count;c>Index;c--) {
pMultiStrings[c] = pMultiStrings[c-1];
}
pMultiStrings[Index] = ValueCopy;
Count++;
return S_OK;
}
HRESULT CStrings::GetMultiSz(LPWSTR *pResult, DWORD *pSize)
{
//
// get a multi-sz buffer from this list of strings
//
DWORD c;
DWORD buflen = 1;
DWORD actlen = 0;
LPWSTR buffer = NULL;
for(c=0;c<Count;c++) {
//
// estimate buffer size
//
DWORD ellen = SysStringLen(pMultiStrings[c]);
if(ellen) {
buflen += ellen+1;
}
}
buffer = new WCHAR[buflen];
if(!buffer) {
return E_OUTOFMEMORY;
}
for(c=0;c<Count;c++) {
//
// first NULL of string might be inside string
// in such a case, terminate string there
//
DWORD ellen = wcslen(pMultiStrings[c]);
if(ellen == 0) {
continue;
}
memcpy(buffer+actlen,pMultiStrings[c],ellen*sizeof(WCHAR));
actlen += ellen;
buffer[actlen++] = 0;
}
buffer[actlen++] = 0;
*pResult = buffer;
*pSize = actlen;
return S_OK;
}
HRESULT CStrings::FromMultiSz(LPCWSTR pMultiSz)
{
//
// append to list from multi-sz
// usually used with a temporary/new CStrings
//
DWORD len = 0;
HRESULT hr;
for(;*pMultiSz;pMultiSz+=len+1) {
len = wcslen(pMultiSz);
hr = InternalAdd(pMultiSz,len);
if(FAILED(hr)) {
return hr;
}
}
return S_OK;
}
HRESULT CStrings::GetIndex(VARIANT *Index, DWORD *pAt)
{
CComVariant v;
HRESULT hr;
if(IsNumericVariant(Index)) {
hr = v.ChangeType(VT_I4,Index);
if(FAILED(hr)) {
return DISP_E_TYPEMISMATCH;
}
if(V_I4(&v)<1) {
return E_INVALIDARG;
}
*pAt = ((DWORD)V_I4(&v))-1;
return S_OK;
}
//
// user actually supplied instance id
//
hr = v.ChangeType(VT_BSTR,Index);
if(FAILED(hr)) {
return DISP_E_TYPEMISMATCH;
}
if(!Count) {
//
// cannot match anything
//
return E_INVALIDARG;
}
//
// find an existing device that matches this
//
DWORD c;
for(c=0;c<Count;c++) {
if(wcscmp(pMultiStrings[c],V_BSTR(&v))==0) {
*pAt = c;
return S_OK;
}
}
//
// none found, run through again ignoring case
//
if(!IsCaseSensative) {
for(c=0;c<Count;c++) {
if(_wcsicmp(pMultiStrings[c],V_BSTR(&v))==0) {
*pAt = c;
return S_OK;
}
}
}
//
// still none found
//
return E_INVALIDARG;
}
BOOL CStrings::InternalEnum(DWORD index,BSTR *pNext)
{
//
// note that pNext returned is not a unique string
//
if(index>=Count) {
return FALSE;
}
*pNext = pMultiStrings[index];
return TRUE;
}
STDMETHODIMP CStrings::Find(BSTR name, long *pFound)
{
//
// find an existing device that matches this
//
DWORD c;
for(c=0;c<Count;c++) {
if(wcscmp(pMultiStrings[c],name)==0) {
*pFound = (long)(c+1);
return S_OK;
}
}
//
// none found, run through again ignoring case
//
if(!IsCaseSensative) {
for(c=0;c<Count;c++) {
if(_wcsicmp(pMultiStrings[c],name)==0) {
*pFound = (long)(c+1);
return S_OK;
}
}
}
*pFound = 0;
return S_FALSE;
}
STDMETHODIMP CStrings::get_CaseSensative(VARIANT_BOOL *pVal)
{
*pVal = IsCaseSensative ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP CStrings::put_CaseSensative(VARIANT_BOOL newVal)
{
IsCaseSensative = newVal ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}