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.
466 lines
12 KiB
466 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ticketSchema.cpp
|
|
|
|
Abstract:
|
|
|
|
Implementation of ticket schema lookup
|
|
|
|
Usage:
|
|
|
|
Author:
|
|
|
|
Wei Jiang(weijiang) 15-Jan-2001
|
|
|
|
Revision History:
|
|
15-Jan-2001 weijiang Created.
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include "ticketschema.h"
|
|
#include "BstrDebug.h"
|
|
#include <winsock2.h> // u_short, u_long, ntohs, ntohl
|
|
#include <crtdbg.h>
|
|
#include <pmerrorcodes.h>
|
|
#include <time.h>
|
|
// #include <pmalerts.h>
|
|
|
|
CTicketSchema::CTicketSchema()
|
|
: m_isOk(FALSE), m_szReason(L"Uninitialized"),
|
|
m_numAtts(0), m_attsDef(NULL), m_version(0)
|
|
{
|
|
}
|
|
|
|
CTicketSchema::~CTicketSchema()
|
|
{
|
|
if (m_attsDef != NULL)
|
|
delete[] m_attsDef;
|
|
}
|
|
|
|
BOOL CTicketSchema::ReadSchema(MSXML::IXMLElementPtr &root)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
LPTSTR r=NULL; // The current error, if it happens
|
|
int cAtts = 0;
|
|
MSXML::IXMLElementCollectionPtr atts;
|
|
MSXML::IXMLElementPtr pElt;
|
|
VARIANT iAtts;
|
|
|
|
// Type identifiers
|
|
|
|
try
|
|
{
|
|
// Ok, now iterate over attributes
|
|
atts = root->children;
|
|
cAtts = atts->length;
|
|
|
|
if (cAtts <= 0)
|
|
{
|
|
_com_issue_error(E_FAIL);
|
|
}
|
|
|
|
if (m_attsDef)
|
|
{
|
|
delete[] m_attsDef;
|
|
|
|
//
|
|
// Paranoid
|
|
//
|
|
|
|
m_attsDef = NULL;
|
|
}
|
|
|
|
m_attsDef = new TicketFieldDef[cAtts];
|
|
if (NULL == m_attsDef)
|
|
{
|
|
m_isOk = FALSE;
|
|
bResult = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// get name and version info
|
|
m_name = root->getAttribute(ATTRNAME_NAME);
|
|
_bstr_t aVersion = root->getAttribute(ATTRNAME_VERSION);
|
|
|
|
if(aVersion.length() != 0)
|
|
m_version = (short)_wtol(aVersion);
|
|
else
|
|
m_version = 0; // invalid
|
|
|
|
VariantInit(&iAtts);
|
|
iAtts.vt = VT_I4;
|
|
|
|
for (iAtts.lVal = 0; iAtts.lVal < cAtts; iAtts.lVal++)
|
|
{
|
|
pElt = atts->item(iAtts);
|
|
m_attsDef[iAtts.lVal].name = pElt->getAttribute(ATTRNAME_NAME);
|
|
_bstr_t aType = pElt->getAttribute(ATTRNAME_TYPE);
|
|
_bstr_t aFlags = pElt->getAttribute(ATTRNAME_FLAGS);
|
|
|
|
// find out the type information
|
|
m_attsDef[iAtts.lVal].type = tInvalid;
|
|
if(aType.length() != 0)
|
|
{
|
|
for(int i = 0; i < (sizeof(TicketTypeNameMap) / sizeof(CTicketTypeNameMap)); ++i)
|
|
{
|
|
if(_wcsicmp(aType, TicketTypeNameMap[i].name) == 0)
|
|
{
|
|
m_attsDef[iAtts.lVal].type = TicketTypeNameMap[i].type;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// flags
|
|
if(aFlags.length() != 0)
|
|
m_attsDef[iAtts.lVal].flags = _wtol(aFlags);
|
|
else
|
|
m_attsDef[iAtts.lVal].flags = 0;
|
|
}
|
|
|
|
m_numAtts = iAtts.lVal;
|
|
bResult = m_isOk = TRUE;
|
|
|
|
}
|
|
catch (_com_error &e)
|
|
{
|
|
if (m_attsDef)
|
|
{
|
|
delete[] m_attsDef;
|
|
|
|
//
|
|
// Paranoid
|
|
//
|
|
|
|
m_attsDef = NULL;
|
|
}
|
|
bResult = m_isOk = FALSE;
|
|
}
|
|
Cleanup:
|
|
return bResult;
|
|
}
|
|
|
|
|
|
HRESULT CTicketSchema::parseTicket(LPCSTR raw, UINT size, CTicketPropertyBag& bag)
|
|
{
|
|
DWORD cParsed = 0;
|
|
HRESULT hr = S_OK;
|
|
LPBYTE dataToParse = (LPBYTE)raw;
|
|
UINT cDataToParse = size;
|
|
|
|
//
|
|
// Make sure the data passed in is good.
|
|
// maskF.Parse doesn't validate the parameter.
|
|
//
|
|
|
|
if (IsBadReadPtr(raw, size)) return E_INVALIDARG;
|
|
|
|
// then the schema version #
|
|
if(cDataToParse > 2) // enough for version
|
|
{
|
|
unsigned short * p = (unsigned short *)(dataToParse);
|
|
|
|
if (m_version < VALID_SCHEMA_VERSION_MIN || m_version > VALID_SCHEMA_VERSION_MAX)
|
|
return S_FALSE; // not able to process with this version of ppm
|
|
|
|
dataToParse += 2;
|
|
cDataToParse -= 2;
|
|
}
|
|
|
|
// then the maskK
|
|
CTicketFieldMasks maskF;
|
|
hr = maskF.Parse(dataToParse, cDataToParse, &cParsed);
|
|
|
|
if(hr != S_OK)
|
|
return hr;
|
|
|
|
// pointer advances
|
|
dataToParse += cParsed;
|
|
cDataToParse -= cParsed;
|
|
|
|
USHORT* pIndexes = maskF.GetIndexes();
|
|
DWORD type = 0;
|
|
DWORD flags = 0;
|
|
DWORD fSize = 0;
|
|
variant_t value;
|
|
u_short slen;
|
|
u_long llen;
|
|
|
|
USHORT index = MASK_INDEX_INVALID;
|
|
// then the data
|
|
// get items that enabled by the schema
|
|
while((index = *pIndexes) != MASK_INDEX_INVALID && cDataToParse > 0)
|
|
{
|
|
TicketProperty prop;
|
|
// if index is out of schema range
|
|
if (index >= m_numAtts) break;
|
|
|
|
// fill-in the offset of the property
|
|
prop.offset = dataToParse - (LPBYTE)raw;
|
|
|
|
// type
|
|
type = m_attsDef[index].type;
|
|
|
|
fSize = TicketTypeSizes[type];
|
|
switch (type)
|
|
{
|
|
case tText:
|
|
{
|
|
//
|
|
// due to IA64 alignment faults this memcpy needs to be performed
|
|
//
|
|
memcpy((PBYTE)&slen, dataToParse, sizeof(slen));
|
|
slen = ntohs(slen);
|
|
value.vt = VT_BSTR;
|
|
if (slen == 0)
|
|
{
|
|
value.bstrVal = ALLOC_AND_GIVEAWAY_BSTR_LEN(L"", 0);
|
|
}
|
|
else
|
|
{
|
|
int wlen = MultiByteToWideChar(CP_UTF8, 0,
|
|
(LPCSTR)dataToParse+sizeof(u_short),
|
|
slen, NULL, 0);
|
|
if (!wlen) {
|
|
|
|
//
|
|
// BUGBUG:
|
|
// What should we do here? free all the previously allocated memory?
|
|
// The original code was not doing that. See case default below. Keep
|
|
// the data parsed so far? That seems the original logic. This needs to
|
|
// further looked at.
|
|
//
|
|
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
|
|
}
|
|
value.bstrVal = ALLOC_AND_GIVEAWAY_BSTR_LEN(NULL, wlen);
|
|
if (!MultiByteToWideChar(
|
|
CP_UTF8,
|
|
0,
|
|
(LPCSTR)dataToParse+sizeof(u_short),
|
|
slen,
|
|
value.bstrVal,
|
|
wlen))
|
|
{
|
|
FREE_BSTR(value.bstrVal);
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
value.bstrVal[wlen] = L'\0';
|
|
}
|
|
|
|
dataToParse += slen + sizeof(u_short);
|
|
cDataToParse -= slen + sizeof(u_short);
|
|
}
|
|
break;
|
|
|
|
case tChar:
|
|
_ASSERTE(0); // NEED MORE THOUGHT -- IF unicode makes more sense
|
|
/*
|
|
{
|
|
int wlen = MultiByteToWideChar(CP_UTF8, 0,
|
|
raw+m_pos[index],
|
|
m_schema->GetByteSize(index), NULL, 0);
|
|
pVal->vt = VT_BSTR;
|
|
pVal->bstrVal = ALLOC_AND_GIVEAWAY_BSTR_LEN(NULL, wlen);
|
|
MultiByteToWideChar(CP_UTF8, 0,
|
|
raw+m_pos[index],
|
|
m_schema->GetByteSize(index), pVal->bstrVal, wlen);
|
|
pVal->bstrVal[wlen] = L'\0';
|
|
}
|
|
*/
|
|
break;
|
|
case tByte:
|
|
value.vt = VT_I2;
|
|
value.iVal = *(BYTE*)(dataToParse);
|
|
break;
|
|
case tWord:
|
|
value.vt = VT_I2;
|
|
//
|
|
// due to IA64 alignment faults this memcpy needs to be performed
|
|
//
|
|
memcpy((PBYTE)slen, dataToParse, sizeof(slen));
|
|
value.iVal = ntohs(slen);
|
|
break;
|
|
case tLong:
|
|
value.vt = VT_I4;
|
|
//
|
|
// due to IA64 alignment faults this memcpy needs to be performed
|
|
//
|
|
memcpy((PBYTE)&llen, dataToParse, sizeof(llen));
|
|
value.lVal = ntohl(llen);
|
|
break;
|
|
case tDate:
|
|
value.vt = VT_DATE;
|
|
//
|
|
// due to IA64 alignment faults this memcpy needs to be performed
|
|
//
|
|
memcpy((PBYTE)&llen, dataToParse, sizeof(llen));
|
|
llen = ntohl(llen);
|
|
VarDateFromI4(llen, &(value.date));
|
|
break;
|
|
default:
|
|
return PP_E_BAD_DATA_FORMAT;
|
|
}
|
|
|
|
// now with name, flags, value, type, we can put it into property bag
|
|
// name, flags, value
|
|
prop.flags = m_attsDef[index].flags;
|
|
prop.type = type;
|
|
prop.value.Attach(value.Detach());
|
|
bag.PutProperty(m_attsDef[index].name, prop);
|
|
|
|
|
|
// for text data, the pointer was already adjusted
|
|
if (fSize != SIZE_TEXT)
|
|
{
|
|
dataToParse += fSize;
|
|
cDataToParse -= fSize;
|
|
}
|
|
|
|
++pIndexes;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
//
|
|
// Ticket property bag
|
|
//
|
|
CTicketPropertyBag::CTicketPropertyBag()
|
|
{
|
|
|
|
}
|
|
|
|
CTicketPropertyBag::~CTicketPropertyBag()
|
|
{
|
|
}
|
|
|
|
HRESULT CTicketPropertyBag::GetProperty(LPCWSTR name, TicketProperty& prop)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(!name || (!*name))
|
|
return E_INVALIDARG;
|
|
|
|
TicketPropertyMap::iterator i;
|
|
|
|
i = m_props.find(name);
|
|
|
|
if(i!= m_props.end())
|
|
prop = i->second;
|
|
else
|
|
hr = S_FALSE;
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CTicketPropertyBag::PutProperty(LPCWSTR name, const TicketProperty& prop)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(!name || (!*name))
|
|
return E_INVALIDARG;
|
|
try{
|
|
m_props[name] = prop;
|
|
}
|
|
catch (...)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
//
|
|
// class CTicketFieldMasks
|
|
//
|
|
inline HRESULT CTicketFieldMasks::Parse(PBYTE masks, ULONG size, ULONG* pcParsed) throw()
|
|
{
|
|
_ASSERT(pcParsed && masks);
|
|
// 16 bits as a unit of masks
|
|
|
|
*pcParsed = 0;
|
|
if (!masks || size < 2) return E_INVALIDARG;
|
|
// validate the masks
|
|
PBYTE p = masks;
|
|
ULONG totalMasks = 15;
|
|
BOOL fContinue = FALSE;
|
|
u_short mask;
|
|
*pcParsed += 2;
|
|
|
|
// find out size
|
|
//
|
|
// due to IA64 alignment faults this memcpy needs to be performed
|
|
//
|
|
memcpy((PBYTE)&mask, p, sizeof(u_short));
|
|
p += 2;
|
|
fContinue = MORE_MASKUNIT(ntohs(mask));
|
|
while(fContinue) //the folling short is mask unit
|
|
{
|
|
totalMasks += 15;
|
|
// insufficient data in buffer
|
|
if (*pcParsed + 2 > size) return E_INVALIDARG;
|
|
|
|
*pcParsed += 2;
|
|
|
|
//
|
|
// due to IA64 alignment faults this memcpy needs to be performed
|
|
//
|
|
memcpy((PBYTE)&mask, p, sizeof(u_short));
|
|
p += 2;
|
|
fContinue = MORE_MASKUNIT(ntohs(mask));
|
|
}
|
|
|
|
if(m_fieldIndexes) delete[] m_fieldIndexes;
|
|
m_fieldIndexes = new unsigned short[totalMasks]; // max number of mask bits
|
|
if (NULL == m_fieldIndexes)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
for ( unsigned int i = 0; i < totalMasks; ++i)
|
|
{
|
|
m_fieldIndexes[i] = MASK_INDEX_INVALID;
|
|
}
|
|
|
|
p = masks;
|
|
unsigned short index = 0;
|
|
totalMasks = 0;
|
|
// fill in the mask
|
|
do
|
|
{
|
|
//
|
|
// due to IA64 alignment faults this memcpy needs to be performed
|
|
//
|
|
memcpy((PBYTE)&mask, p, sizeof(u_short));
|
|
p += 2;
|
|
mask = ntohs(mask);
|
|
//// find the bits
|
|
if (mask & 0x7fff) // any 1s
|
|
{
|
|
unsigned short j = 0x0001;
|
|
while( j != 0x8000 )
|
|
{
|
|
if(j & mask)
|
|
m_fieldIndexes[totalMasks++] = index;
|
|
++index;
|
|
j <<= 1;
|
|
}
|
|
}
|
|
else
|
|
index += 15;
|
|
} while(MORE_MASKUNIT(mask)); //the folling short is mask unit
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|