|
|
//--------------------------------------------------------------------------
// Query.cpp
//--------------------------------------------------------------------------
#include "pch.hxx"
#include "database.h"
#include "query.h"
#include "shlwapi.h"
#include "strconst.h"
//--------------------------------------------------------------------------
// OPERATORTYPE
//--------------------------------------------------------------------------
typedef enum tagOPERATORTYPE { OPERATOR_LEFTPAREN, OPERATOR_RIGHTPAREN, OPERATOR_EQUAL, OPERATOR_NOTEQUAL, OPERATOR_LESSTHANEQUAL, OPERATOR_LESSTHAN, OPERATOR_GREATERTHANEQUAL, OPERATOR_GREATERTHAN, OPERATOR_AND, OPERATOR_BITWISEAND, OPERATOR_OR, OPERATOR_BITWISEOR, OPERATOR_STRSTRI, OPERATOR_STRSTR, OPERATOR_LSTRCMPI, OPERATOR_LSTRCMP, OPERATOR_ADD, OPERATOR_SUBTRACT, OPERATOR_MULTIPLY, OPERATOR_DIVIDE, OPERATOR_MOD, OPERATOR_LAST } OPERATORTYPE;
//--------------------------------------------------------------------------
// TOKENTYPE
//--------------------------------------------------------------------------
typedef enum tagTOKENTYPE { TOKEN_INVALID, TOKEN_OPERATOR, TOKEN_OPERAND } TOKENTYPE;
//--------------------------------------------------------------------------
// OPERANDTYPE
//--------------------------------------------------------------------------
typedef enum tagOPERANDTYPE { OPERAND_INVALID, OPERAND_COLUMN, OPERAND_STRING, OPERAND_DWORD, OPERAND_METHOD, OPERAND_LAST } OPERANDTYPE;
//--------------------------------------------------------------------------
// OPERANDINFO
//--------------------------------------------------------------------------
typedef struct tagOPERANDINFO { OPERANDTYPE tyOperand; DWORD iSymbol; LPVOID pRelease; union { COLUMNORDINAL iColumn; // OPERAND_COLUMN
LPSTR pszString; // OPERAND_STRING
DWORD dwValue; // OPERAND_DWORD
METHODID idMethod; // OPERAND_METHOD
}; DWORD dwReserved; } OPERANDINFO, *LPOPERANDINFO;
//--------------------------------------------------------------------------
// QUERYTOKEN
//--------------------------------------------------------------------------
typedef struct tagQUERYTOKEN *LPQUERYTOKEN; typedef struct tagQUERYTOKEN { TOKENTYPE tyToken; DWORD cRefs; union { OPERATORTYPE tyOperator; // TOKEN_OPERATOR
OPERANDINFO Operand; // TOKEN_OPERAND
}; LPQUERYTOKEN pNext; LPQUERYTOKEN pPrevious; } QUERYTOKEN;
//--------------------------------------------------------------------------
// PFNCOMPAREOPERAND - Compares Two Operands of the same type
//--------------------------------------------------------------------------
typedef INT (APIENTRY *PFNCOMPAREOPERAND)(LPVOID pDataLeft, LPVOID pDataRight); #define PCOMPARE(_pfn) ((PFNCOMPAREOPERAND)_pfn)
//--------------------------------------------------------------------------
// CompareOperandString
//--------------------------------------------------------------------------
INT CompareOperandString(LPVOID pDataLeft, LPVOID pDataRight) { return(lstrcmpi((LPSTR)pDataLeft, (LPSTR)pDataRight)); }
//--------------------------------------------------------------------------
// CompareOperandDword
//--------------------------------------------------------------------------
INT CompareOperandDword(LPVOID pDataLeft, LPVOID pDataRight) { return (INT)(*((DWORD *)pDataLeft) - *((DWORD *)pDataRight)); }
//--------------------------------------------------------------------------
// g_rgpfnCompareOperand
//--------------------------------------------------------------------------
const static PFNCOMPAREOPERAND g_rgpfnCompareOperand[OPERAND_LAST] = { NULL, // OPERAND_INVALID
NULL, // OPERAND_COLUMN
PCOMPARE(CompareOperandString), // OPERAND_STRING
PCOMPARE(CompareOperandDword) // OPERAND_DWORD
};
//--------------------------------------------------------------------------
// CompareOperands
//--------------------------------------------------------------------------
#define CompareOperands(_tyOperand, _pDataLeft, _pDataRight) \
(*(g_rgpfnCompareOperand[_tyOperand]))(_pDataLeft, _pDataRight)
//--------------------------------------------------------------------------
// PFNEVALUATEOPERATOR - Compares data in two flat records.
//--------------------------------------------------------------------------
typedef DWORD (APIENTRY *PFNEVALUATEOPERATOR)(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); #define PEVAL(_pfn) ((PFNEVALUATEOPERATOR)_pfn)
//--------------------------------------------------------------------------
// Evaluate Operator Prototypes
//--------------------------------------------------------------------------
DWORD EvaluateEqual(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateNotEqual(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateLessThanEqual(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateLessThan(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateGreaterThanEqual(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateGreaterThan(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateAnd(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateBitwiseAnd(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateOr(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateBitwiseOr(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateStrStrI(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateStrStr(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateStrcmpi(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateStrcmp(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateAdd(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateSubtract(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateMultiply(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateDivide(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight); DWORD EvaluateModula(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight);
//--------------------------------------------------------------------------
// OPERATORINFO
//--------------------------------------------------------------------------
typedef struct tagOPERATORINFO { LPCSTR pszName; BYTE bISP; BYTE bICP; PFNEVALUATEOPERATOR pfnEvaluate; } OPERATORINFO, *LPOPERATORINFO;
//--------------------------------------------------------------------------
// Operator Precedence Table
//--------------------------------------------------------------------------
static const OPERATORINFO g_rgOperator[OPERATOR_LAST] = { // Name ISP ICP Function
{ "(", 6, 0, NULL }, // OPERATOR_LEFTPAREN
{ ")", 1, 1, NULL }, // OPERATOR_RIGHTPAREN
{ "==", 5, 5, PEVAL(EvaluateEqual) }, // OPERATOR_EQUAL
{ "!=", 5, 5, PEVAL(EvaluateNotEqual) }, // OPERATOR_NOTEQUAL
{ "<=", 5, 5, PEVAL(EvaluateLessThanEqual) }, // OPERATOR_LESSTHANEQUAL
{ "<", 5, 5, PEVAL(EvaluateLessThan) }, // OPERATOR_LESSTHAN
{ ">=", 5, 5, PEVAL(EvaluateGreaterThanEqual) }, // OPERATOR_GREATERTHANEQUAL
{ ">", 5, 5, PEVAL(EvaluateGreaterThan) }, // OPERATOR_GREATERTHAN
{ "&&", 4, 4, PEVAL(EvaluateAnd) }, // OPERATOR_AND
{ "&", 3, 3, PEVAL(EvaluateBitwiseAnd) }, // OPERATOR_BITWISEAND
{ "||", 4, 4, PEVAL(EvaluateOr) }, // OPERATOR_OR
{ "|", 3, 3, PEVAL(EvaluateBitwiseOr) }, // OPERATOR_BITWISEOR
{ "containsi", 5, 5, PEVAL(EvaluateStrStrI) }, // OPERATOR_STRSTRI
{ "contains", 5, 5, PEVAL(EvaluateStrStr) }, // OPERATOR_STRSTR
{ "comparei", 5, 5, PEVAL(EvaluateStrcmpi) }, // OPERATOR_LSTRCMPI
{ "compare", 5, 5, PEVAL(EvaluateStrcmp) }, // OPERATOR_LSTRCMP
{ "+", 4, 4, PEVAL(EvaluateAdd) }, // OPERATOR_ADD,
{ "-", 4, 4, PEVAL(EvaluateSubtract) }, // OPERATOR_SUBTRACT,
{ "*", 3, 3, PEVAL(EvaluateMultiply) }, // OPERATOR_MULTIPLY,
{ "/", 3, 3, PEVAL(EvaluateDivide) }, // OPERATOR_DIVIDE,
{ "%", 3, 3, PEVAL(EvaluateModula) }, // OPERATOR_MOD,
};
//--------------------------------------------------------------------------
// EvaluateOperator
//--------------------------------------------------------------------------
#define EvaluateOperator(_tyOperator, _tyOperand, _pDataLeft, _pDataRight) \
(*(g_rgOperator[_tyOperator].pfnEvaluate))(_tyOperand, _pDataLeft, _pDataRight)
//--------------------------------------------------------------------------
// MAPCOLUMNTYPE
//--------------------------------------------------------------------------
typedef void (APIENTRY *PFNMAPCOLUMNTYPE)(LPOPERANDINFO pOperand, LPCTABLECOLUMN pColumn, LPVOID pBinding, LPVOID *ppValue); #define PMAP(_pfn) ((PFNMAPCOLUMNTYPE)_pfn)
//--------------------------------------------------------------------------
// MapColumnString
//--------------------------------------------------------------------------
void MapColumnString(LPOPERANDINFO pOperand, LPCTABLECOLUMN pColumn, LPVOID pBinding, LPVOID *ppValue) { (*ppValue) = *((LPSTR *)((LPBYTE)pBinding + pColumn->ofBinding)); }
//--------------------------------------------------------------------------
// MapColumnByte
//--------------------------------------------------------------------------
void MapColumnByte(LPOPERANDINFO pOperand, LPCTABLECOLUMN pColumn, LPVOID pBinding, LPVOID *ppValue) { pOperand->dwReserved = *((BYTE *)((LPBYTE)pBinding + pColumn->ofBinding)); (*ppValue) = (LPVOID)&pOperand->dwReserved; }
//--------------------------------------------------------------------------
// MapColumnDword
//--------------------------------------------------------------------------
void MapColumnDword(LPOPERANDINFO pOperand, LPCTABLECOLUMN pColumn, LPVOID pBinding, LPVOID *ppValue) { pOperand->dwReserved = *((DWORD *)((LPBYTE)pBinding + pColumn->ofBinding)); (*ppValue) = (LPVOID)&pOperand->dwReserved; }
//--------------------------------------------------------------------------
// MapColumnWord
//--------------------------------------------------------------------------
void MapColumnWord(LPOPERANDINFO pOperand, LPCTABLECOLUMN pColumn, LPVOID pBinding, LPVOID *ppValue) { pOperand->dwReserved = *((WORD *)((LPBYTE)pBinding + pColumn->ofBinding)); (*ppValue) = (LPVOID)&pOperand->dwReserved; }
//--------------------------------------------------------------------------
// COLUMNTYPEINFO
//--------------------------------------------------------------------------
typedef struct tagCOLUMNTYPEINFO { OPERANDTYPE tyOperand; PFNMAPCOLUMNTYPE pfnMapColumnType; } COLUMNTYPEINFO, *LPCOLUMNTYPEINFO;
//--------------------------------------------------------------------------
// g_rgColumnTypeInfo
//--------------------------------------------------------------------------
static const COLUMNTYPEINFO g_rgColumnTypeInfo[CDT_LASTTYPE] = { { OPERAND_INVALID, NULL }, // CDT_FILETIME,
{ OPERAND_STRING, PMAP(MapColumnString) }, // CDT_FIXSTRA,
{ OPERAND_STRING, PMAP(MapColumnString) }, // CDT_VARSTRA,
{ OPERAND_DWORD, PMAP(MapColumnByte) }, // CDT_BYTE,
{ OPERAND_DWORD, PMAP(MapColumnDword) }, // CDT_DWORD,
{ OPERAND_DWORD, PMAP(MapColumnWord) }, // CDT_WORD,
{ OPERAND_DWORD, PMAP(MapColumnDword) }, // CDT_STREAM,
{ OPERAND_INVALID, NULL }, // CDT_VARBLOB,
{ OPERAND_INVALID, NULL }, // CDT_FIXBLOB,
{ OPERAND_DWORD, PMAP(MapColumnDword) }, // CDT_FLAGS,
{ OPERAND_DWORD, PMAP(MapColumnDword) }, // CDT_UNIQUE
};
//--------------------------------------------------------------------------
// MapColumnType
//--------------------------------------------------------------------------
#define MapColumnType(_tyColumn, _pOperand, _pColumn, _pBinding, _ppValue) \
(*(g_rgColumnTypeInfo[_tyColumn].pfnMapColumnType))(_pOperand, _pColumn, _pBinding, _ppValue)
//--------------------------------------------------------------------------
// Prototypes
//--------------------------------------------------------------------------
HRESULT GetNextQueryToken(LPSTR *ppszT, LPCTABLESCHEMA pSchema, LPQUERYTOKEN *ppToken, CDatabase *pDB); HRESULT LinkToken(LPQUERYTOKEN pToken, LPQUERYTOKEN *ppHead, LPQUERYTOKEN *ppTail); HRESULT ReleaseTokenList(BOOL fReverse, LPQUERYTOKEN *ppHead, CDatabase *pDB); HRESULT ReleaseToken(LPQUERYTOKEN *ppToken, CDatabase *pDB); HRESULT ParseStringLiteral(LPCSTR pszStart, LPOPERANDINFO pOperand, LPSTR *ppszEnd, CDatabase *pDB); HRESULT ParseNumeric(LPCSTR pszT, LPOPERANDINFO pOperand, LPSTR *ppszEnd); HRESULT ParseSymbol(LPCSTR pszT, LPCTABLESCHEMA pSchema, LPOPERANDINFO pOperand, LPSTR *ppszEnd, CDatabase *pDB); HRESULT PushStackToken(LPQUERYTOKEN pToken, LPQUERYTOKEN *ppStackTop); HRESULT PopStackToken(LPQUERYTOKEN *ppToken, LPQUERYTOKEN *ppStackTop); HRESULT EvaluateClause(OPERATORTYPE tyOperator, LPVOID pBinding, LPCTABLESCHEMA pSchema, LPQUERYTOKEN *ppStackTop, CDatabase *pDB, IDatabaseExtension *pExtension); IF_DEBUG(HRESULT DebugDumpExpression(LPCSTR pszQuery, LPCTABLESCHEMA pSchema, LPQUERYTOKEN pPostfixHead));
//--------------------------------------------------------------------------
// ISP inline
//--------------------------------------------------------------------------
inline BYTE ISP(LPQUERYTOKEN pToken) { // Validate
Assert(TOKEN_OPERATOR == pToken->tyToken && pToken->tyOperator < OPERATOR_LAST);
// Return ISP
return (g_rgOperator[pToken->tyOperator].bISP); }
//--------------------------------------------------------------------------
// ICP inline
//--------------------------------------------------------------------------
inline BYTE ICP(LPQUERYTOKEN pToken) { // Validate
Assert(TOKEN_OPERATOR == pToken->tyToken && pToken->tyOperator < OPERATOR_LAST);
// Return ISP
return (g_rgOperator[pToken->tyOperator].bICP); }
// --------------------------------------------------------------------------
// DBIsDigit
// --------------------------------------------------------------------------
int DBIsDigit(LPSTR psz) { WORD wType; if (IsDBCSLeadByte(*psz)) SideAssert(GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, psz, 2, &wType)); else SideAssert(GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, psz, 1, &wType)); return(wType & C1_DIGIT); }
//--------------------------------------------------------------------------
// EvaluateQuery
//--------------------------------------------------------------------------
HRESULT EvaluateQuery(HQUERY hQuery, LPVOID pBinding, LPCTABLESCHEMA pSchema, CDatabase *pDB, IDatabaseExtension *pExtension) { // Locals
HRESULT hr=S_OK; LPQUERYTOKEN pToken; LPQUERYTOKEN pResult=NULL; LPQUERYTOKEN pStackTop=NULL;
// Trace
TraceCall("EvaluateQuery");
// Assert
Assert(hQuery && pBinding && pSchema);
// Walk through the tokens
for (pToken=(LPQUERYTOKEN)hQuery; pToken!=NULL; pToken=pToken->pNext) { // If this is an operand, append to the stack
if (TOKEN_OPERAND == pToken->tyToken) { // LinkStackToken
PushStackToken(pToken, &pStackTop); }
// Otherwise, must be an operator
else { // Operator ?
Assert(TOKEN_OPERATOR == pToken->tyToken && g_rgOperator[pToken->tyOperator].pfnEvaluate != NULL);
// EvaluateOperator
IF_FAILEXIT(hr = EvaluateClause(pToken->tyOperator, pBinding, pSchema, &pStackTop, pDB, pExtension)); } }
// Pop the stack
PopStackToken(&pResult, &pStackTop);
// No Token and Stack should now be empty..
Assert(pResult && NULL == pStackTop && pResult->tyToken == TOKEN_OPERAND && pResult->Operand.tyOperand == OPERAND_DWORD);
// 0 or not zero
hr = (pResult->Operand.dwValue == 0) ? S_FALSE : S_OK;
exit: // Cleanup
ReleaseToken(&pResult, pDB); ReleaseTokenList(TRUE, &pStackTop, pDB);
// Done
return(SUCCEEDED(hr) ? hr : S_FALSE); }
//--------------------------------------------------------------------------
// ParseQuery
//--------------------------------------------------------------------------
HRESULT ParseQuery(LPCSTR pszQuery, LPCTABLESCHEMA pSchema, LPHQUERY phQuery, CDatabase *pDB) { // Locals
HRESULT hr=S_OK; LPSTR pszT=(LPSTR)pszQuery; LPQUERYTOKEN pCurrent; LPQUERYTOKEN pPrevious; LPQUERYTOKEN pToken=NULL; LPQUERYTOKEN pPostfixHead=NULL; LPQUERYTOKEN pPostfixTail=NULL; LPQUERYTOKEN pStackTop=NULL;
// Trace
TraceCall("ParseQuery");
// Invalid Args
if (NULL == pszQuery || NULL == pSchema || NULL == phQuery) return TraceResult(E_INVALIDARG);
// Initialize
(*phQuery) = NULL;
// Start the Parsing Loop
while(1) { // Parse next Token
IF_FAILEXIT(hr = GetNextQueryToken(&pszT, pSchema, &pToken, pDB));
// Done
if (S_FALSE == hr) break;
// If this was an operand, append to postfix expression
if (TOKEN_OPERAND == pToken->tyToken) { // LinkToken
LinkToken(pToken, &pPostfixHead, &pPostfixTail);
// Don't pToken
ReleaseToken(&pToken, pDB); }
// Otherwise, must be an operator
else { // Must be an operator
Assert(TOKEN_OPERATOR == pToken->tyToken); // If Right Paren
if (OPERATOR_RIGHTPAREN == pToken->tyOperator) { // Pop all the items from the stack and link into the postfix expression
while (pStackTop && OPERATOR_LEFTPAREN != pStackTop->tyOperator) { // Save pPrevious
pPrevious = pStackTop->pPrevious;
// Otherwise
LinkToken(pStackTop, &pPostfixHead, &pPostfixTail);
// Releae
ReleaseToken(&pStackTop, pDB);
// Goto Previuos
pStackTop = pPrevious; }
// If not a left parent was found, then we failed
if (OPERATOR_LEFTPAREN != pStackTop->tyOperator) { hr = TraceResult(DB_E_UNMATCHINGPARENS); goto exit; }
// Save pPrevious
pPrevious = pStackTop->pPrevious;
// Free pStackTop
ReleaseToken(&pStackTop, pDB);
// Reset pStackTop
pStackTop = pPrevious;
// Free pToken
ReleaseToken(&pToken, pDB); }
// Otherwise
else { // Pop all the items into the postfix expression according to a cool little priority rule
while (pStackTop && ISP(pStackTop) <= ICP(pToken)) { // Save pPrevious
pPrevious = pStackTop->pPrevious;
// Otherwise
LinkToken(pStackTop, &pPostfixHead, &pPostfixTail);
// Releae
ReleaseToken(&pStackTop, pDB);
// Goto Previuos
pStackTop = pPrevious; }
// Append pToken to the Stack
LinkToken(pToken, NULL, &pStackTop);
// Don't pToken
ReleaseToken(&pToken, pDB); } } }
// Pop all the items from the stack and link into the postfix expression
while (pStackTop) { // Save pPrevious
pPrevious = pStackTop->pPrevious;
// Append to Postfix Expression
LinkToken(pStackTop, &pPostfixHead, &pPostfixTail);
// Releae
ReleaseToken(&pStackTop, pDB);
// Goto Previuos
pStackTop = pPrevious; }
// lets write the postfix notation...
//IF_DEBUG(DebugDumpExpression(pszQuery, pSchema, pPostfixHead));
// Success
(*phQuery) = (HQUERY)pPostfixHead;
exit: // Cleanup On Failure
if (FAILED(hr)) { // Free pToken
ReleaseToken(&pToken, pDB);
// Free the Stack
ReleaseTokenList(TRUE, &pStackTop, pDB);
// Free the Postfix Expression
ReleaseTokenList(FALSE, &pPostfixHead, pDB); }
// Done
return(hr); }
//--------------------------------------------------------------------------
// DebugDumpExpression
//--------------------------------------------------------------------------
#ifdef DEBUG
HRESULT DebugDumpExpression(LPCSTR pszQuery, LPCTABLESCHEMA pSchema, LPQUERYTOKEN pPostfixHead) { // Locals
LPQUERYTOKEN pToken;
// Trace
TraceCall("DebugDumpExpression");
// Write Infix
DebugTrace("ParseQuery (Infix) : %s\n", pszQuery);
// Write Postfix header
DebugTrace("ParseQuery (Postfix) : ");
// Loop through the tokens
for (pToken=pPostfixHead; pToken!=NULL; pToken=pToken->pNext) { // Operator
if (TOKEN_OPERATOR == pToken->tyToken) { // Write the Operator
DebugTrace("%s", g_rgOperator[pToken->tyOperator].pszName); }
// Operand
else if (TOKEN_OPERAND == pToken->tyToken) { // Column Operand
if (OPERAND_COLUMN == pToken->Operand.tyOperand) { // Must have an iSymbol
Assert(0xffffffff != pToken->Operand.iSymbol);
// Write the Symbol
DebugTrace("Column: %d (%s)", pToken->Operand.dwValue, pSchema->pSymbols->rgSymbol[pToken->Operand.iSymbol].pszName); }
// String Operand
else if (OPERAND_STRING == pToken->Operand.tyOperand) { // Write the Symbol
DebugTrace("<%s>", pToken->Operand.pszString); }
// Dword Operand
else if (OPERAND_DWORD == pToken->Operand.tyOperand) { // Has a iSymbol
if (0xffffffff != pToken->Operand.iSymbol) { // Write the Symbol
DebugTrace("%d (%s)", pToken->Operand.dwValue, pSchema->pSymbols->rgSymbol[pToken->Operand.iSymbol].pszName); }
// Otherwise, just write the value
else { // Write the Symbol
DebugTrace("%d", pToken->Operand.dwValue); } }
// Method
else if (OPERAND_METHOD == pToken->Operand.tyOperand) { // Validate Symbol Type
Assert(SYMBOL_METHOD == pSchema->pSymbols->rgSymbol[pToken->Operand.iSymbol].tySymbol);
// Write the Method
DebugTrace("Method: %d (%s)", pToken->Operand.idMethod, pSchema->pSymbols->rgSymbol[pToken->Operand.iSymbol].pszName); } }
// Bad
else Assert(FALSE);
// Write Delimiter
DebugTrace(", "); }
// Wrap the line
DebugTrace("\n");
// Done
return(S_OK); } #endif // DEBUG
//--------------------------------------------------------------------------
// CompareSymbol
//--------------------------------------------------------------------------
HRESULT CompareSymbol(LPSTR pszT, LPCSTR pszName, LPSTR *ppszEnd) { // Locals
LPSTR pszName1; LPSTR pszName2;
// Trace
TraceCall("CompareSymbol");
// Set pszName
pszName1 = (LPSTR)pszName;
// Set pszName2
pszName2 = pszT;
// Compare pszTo to Operator pszName...
while ('\0' != *pszName2 && *pszName1 == *pszName2) { // Increment
pszName1++; pszName2++;
// Reached the End of pszName1, must be a match
if ('\0' == *pszName1) { // Set ppszEnd
*ppszEnd = pszName2;
// Done
return(S_OK); } }
// Done
return(S_FALSE); }
//--------------------------------------------------------------------------
// GetNextQueryToken
//--------------------------------------------------------------------------
HRESULT GetNextQueryToken(LPSTR *ppszT, LPCTABLESCHEMA pSchema, LPQUERYTOKEN *ppToken, CDatabase *pDB) { // Locals
HRESULT hr=S_FALSE; LPSTR pszT=(*ppszT); LPSTR pszEnd; DWORD i; LPQUERYTOKEN pToken=NULL;
// Trace
TraceCall("GetNextQueryToken");
// Allocate a Token
IF_NULLEXIT(pToken = (LPQUERYTOKEN)pDB->PHeapAllocate(HEAP_ZERO_MEMORY, sizeof(QUERYTOKEN)));
// Set Reference Count
pToken->cRefs = 1;
// No Token foundyet
pToken->tyToken = TOKEN_INVALID;
// Invalid Symbol Index
pToken->Operand.iSymbol = 0xffffffff;
// Skip White Space...
while(*pszT && (*pszT == ' ' || *pszT == '\t')) pszT++;
// Done
if ('\0' == *pszT) goto exit; // Check for the Start of an Operator...
for (i=0; i<OPERATOR_LAST; i++) { // Does pszT point to the start of an operator ?
if (S_OK == CompareSymbol(pszT, g_rgOperator[i].pszName, &pszEnd)) { // Update pszT
pszT = pszEnd;
// We found an operator
pToken->tyToken = TOKEN_OPERATOR;
// Set the operator type
pToken->tyOperator = (OPERATORTYPE)i;
// Done
break; } }
// No Token Yet ?
if (TOKEN_INVALID == pToken->tyToken) { // Start of a String Literal ?
if ('"' == *pszT) { // ParseStringLiteral
IF_FAILEXIT(hr = ParseStringLiteral(pszT, &pToken->Operand, &pszEnd, pDB)); }
// Otherwise, start of a number
else if (DBIsDigit(pszT)) { // ParseNumeric
IF_FAILEXIT(hr = ParseNumeric(pszT, &pToken->Operand, &pszEnd)); }
// Start of a Symbol
else { // ParseSymbol
IF_FAILEXIT(hr = ParseSymbol(pszT, pSchema, &pToken->Operand, &pszEnd, pDB)); }
// Must have been an operand
pToken->tyToken = TOKEN_OPERAND;
// Set pszT
pszT = pszEnd; }
// Set ppszT
*ppszT = pszT;
// Success
hr = S_OK;
// Return the Token
*ppToken = pToken;
// Don't Free the Token
pToken = NULL;
exit: // Cleanup
ReleaseToken(&pToken, pDB);
// Done
return(hr); }
//--------------------------------------------------------------------------
// ParseStringLiteral
//--------------------------------------------------------------------------
HRESULT ParseStringLiteral(LPCSTR pszStart, LPOPERANDINFO pOperand, LPSTR *ppszEnd, CDatabase *pDB) { // Locals
HRESULT hr=S_OK; LPSTR pszValue; DWORD cchString; LPSTR pszT=(LPSTR)pszStart; // Trace
TraceCall("ParseStringLiteral");
// Validate Args
Assert(*pszT == '"' && pOperand && ppszEnd);
// Increment over "
pszT++;
// Find the End of the Quoted String
while(*pszT) { // DBCS Lead Byte
if (IsDBCSLeadByte(*pszT) || '\\' == *pszT) { pszT+=2; continue; }
// If Escaped Quote..
if ('"' == *pszT) { // Set ppszEnd
*ppszEnd = pszT + 1;
// Done
break; }
// Increment pszT
pszT++; }
// Not Found
if ('\0' == *pszT) { hr = TraceResult(DB_E_UNMATCHINGQUOTES); goto exit; }
// Get Size
cchString = (DWORD)(pszT - (pszStart + 1));
// Duplicate the String
IF_NULLEXIT(pszValue = (LPSTR)pDB->PHeapAllocate(NOFLAGS, cchString + 1));
// Copy the String
CopyMemory(pszValue, pszStart + 1, cchString);
// Set the Null
pszValue[cchString] = '\0';
// Set Operand Type
pOperand->tyOperand = OPERAND_STRING;
// Release
pOperand->pRelease = (LPVOID)pszValue;
// Set Value
pOperand->pszString = pszValue;
exit: // Done
return(hr); }
//--------------------------------------------------------------------------
// ParseNumeric
//--------------------------------------------------------------------------
HRESULT ParseNumeric(LPCSTR pszStart, LPOPERANDINFO pOperand, LPSTR *ppszEnd) { // Locals
HRESULT hr=S_OK; DWORD dwValue; CHAR szNumber[255]; DWORD dwIncrement=0; LPSTR pszT=(LPSTR)pszStart; DWORD cchNumber; // Trace
TraceCall("ParseNumeric");
// Validate Args
Assert(DBIsDigit(pszT) && pOperand && ppszEnd);
// Is Hex: 0x
if ('0' == *pszT && '\0' != *(pszT + 1) && 'X' == TOUPPERA(*(pszT + 1))) { // IsHex
dwIncrement = 2;
// Set pszT
pszT += 2; }
// Find the End of the Number
while (*pszT && DBIsDigit(pszT)) { // Increment
pszT++; }
// Get Length
cchNumber = (DWORD)(pszT - (pszStart + dwIncrement));
// Too Frickin Big
if (cchNumber >= ARRAYSIZE(szNumber)) { hr = TraceResult(DB_E_NUMBERTOOBIG); goto exit; }
// Copy into szNumber
CopyMemory(szNumber, pszStart + dwIncrement, cchNumber);
// Set Null
szNumber[cchNumber] = '\0';
// If Is Hex, convert to integer
if (FALSE == StrToIntEx(szNumber, dwIncrement ? STIF_SUPPORT_HEX : STIF_DEFAULT, (INT *)&dwValue)) { hr = TraceResult(DB_E_BADNUMBER); goto exit; }
// Set Operand Type
pOperand->tyOperand = OPERAND_DWORD;
// Set Value
pOperand->dwValue = dwValue;
// Return ppszEnd
*ppszEnd = pszT;
exit: // Done
return(hr); }
//--------------------------------------------------------------------------
// ParseSymbol
//--------------------------------------------------------------------------
HRESULT ParseSymbol(LPCSTR pszT, LPCTABLESCHEMA pSchema, LPOPERANDINFO pOperand, LPSTR *ppszEnd, CDatabase *pDB) { // Locals
HRESULT hr=S_OK; DWORD i; LPSYMBOLINFO pSymbol; LPSTR pszEnd; // Trace
TraceCall("ParseSymbol");
// No Symbols
if (NULL == pSchema->pSymbols) { hr = TraceResult(DB_E_NOSYMBOLS); goto exit; }
// Check for the Start of an Operator...
for (i=0; i<pSchema->pSymbols->cSymbols; i++) { // Readability
pSymbol = (LPSYMBOLINFO)&pSchema->pSymbols->rgSymbol[i];
// Does pszT point to the start of an operator ?
if (S_OK == CompareSymbol((LPSTR)pszT, pSymbol->pszName, &pszEnd)) { // Update pszT
*ppszEnd = pszEnd;
// Save iSymbol
pOperand->iSymbol = i;
// Is Column Symbol
if (SYMBOL_COLUMN == pSymbol->tySymbol) { // Validate the Ordinal
if (pSymbol->dwValue > pSchema->cColumns) { hr = TraceResult(DB_E_INVALIDCOLUMN); goto exit; }
// Convert to OPERANDTYPE
pOperand->tyOperand = OPERAND_COLUMN;
// Save the Column
pOperand->iColumn = (COLUMNORDINAL)pSymbol->dwValue; }
// Otherwise, is a method ?
else if (SYMBOL_METHOD == pSymbol->tySymbol) { // Convert to OPERANDTYPE
pOperand->tyOperand = OPERAND_METHOD;
// Save the Column
pOperand->idMethod = pSymbol->dwValue; }
// Otherwise, just a dword value
else { // Dword
pOperand->tyOperand = OPERAND_DWORD;
// Set the operator type
pOperand->dwValue = pSymbol->dwValue; }
// Done
goto exit; } }
// Not Found
hr = TraceResult(DB_E_INVALIDSYMBOL);
exit: // Done
return(hr); }
//--------------------------------------------------------------------------
// CloseQuery
//--------------------------------------------------------------------------
HRESULT CloseQuery(LPHQUERY phQuery, CDatabase *pDB) { // Trace
TraceCall("CloseQuery");
// ReleaseTokenList
ReleaseTokenList(FALSE, (LPQUERYTOKEN *)phQuery, pDB);
// Done
return(S_OK); }
//--------------------------------------------------------------------------
// PushStackToken
//--------------------------------------------------------------------------
HRESULT PushStackToken(LPQUERYTOKEN pToken, LPQUERYTOKEN *ppStackTop) { // Trace
TraceCall("PushStackToken");
// Set pStackPrevious
pToken->pPrevious = (*ppStackTop);
// Update Stack Top
(*ppStackTop) = pToken;
// AddRef the Token
pToken->cRefs++;
// Done
return(S_OK); }
//--------------------------------------------------------------------------
// PopStackToken
//--------------------------------------------------------------------------
HRESULT PopStackToken(LPQUERYTOKEN *ppToken, LPQUERYTOKEN *ppStackTop) { // Trace
TraceCall("PopStackToken");
// Validate
Assert(ppToken && ppStackTop);
// No more tokens...
if (NULL == *ppStackTop) return TraceResult(DB_E_BADEXPRESSION);
// Set Token
*ppToken = (*ppStackTop);
// Goto Previous
(*ppStackTop) = (*ppToken)->pPrevious;
// Release the Token
//(*ppToken)->cRefs--;
// Done
return(S_OK); }
//--------------------------------------------------------------------------
// LinkToken
//--------------------------------------------------------------------------
HRESULT LinkToken(LPQUERYTOKEN pToken, LPQUERYTOKEN *ppHead, LPQUERYTOKEN *ppTail) { // Trace
TraceCall("LinkToken");
// Invalid Args
Assert(pToken && ppTail);
// No Next and No Previous
pToken->pNext = pToken->pPrevious = NULL;
// No Head yet ?
if (ppHead && NULL == *ppHead) { // Set the Head and Tail
*ppHead = pToken; }
// Otherwise, append to the end
else if (*ppTail) { // Set ppTail->pNext
(*ppTail)->pNext = pToken;
// Set Previous
pToken->pPrevious = (*ppTail); }
// Update the Tail
*ppTail = pToken;
// AddRef the Token
pToken->cRefs++;
// Done
return(S_OK); }
//--------------------------------------------------------------------------
// ReleaseToken
//--------------------------------------------------------------------------
HRESULT ReleaseToken(LPQUERYTOKEN *ppToken, CDatabase *pDB) { // Trace
TraceCall("ReleaseToken");
// Token
if (*ppToken) { // Validate Reference Count
Assert((*ppToken)->cRefs);
// Decrement Reference Count
(*ppToken)->cRefs--;
// No more refs...
if (0 == (*ppToken)->cRefs) { // Free pData
pDB->HeapFree((*ppToken)->Operand.pRelease);
// Free pElement
pDB->HeapFree((*ppToken)); }
// Don't Release Again
*ppToken = NULL; }
// Done
return(S_OK); }
//--------------------------------------------------------------------------
// ReleaseTokenList
//--------------------------------------------------------------------------
HRESULT ReleaseTokenList(BOOL fReverse, LPQUERYTOKEN *ppHead, CDatabase *pDB) { // Locals
LPQUERYTOKEN pNext; LPQUERYTOKEN pToken=(*ppHead);
// Trace
TraceCall("ReleaseTokenList");
// Walk the Linked List
while (pToken) { // Save Next
pNext = (fReverse ? pToken->pPrevious : pToken->pNext);
// Free this token
ReleaseToken(&pToken, pDB);
// Goto Next
pToken = pNext; }
// Don't Free Again
*ppHead = NULL;
// Done
return(S_OK); }
//--------------------------------------------------------------------------
// PGetOperandData
//--------------------------------------------------------------------------
LPVOID PGetOperandData(OPERANDTYPE tyOperand, LPOPERANDINFO pOperand, LPVOID pBinding, LPCTABLESCHEMA pSchema, CDatabase *pDB, IDatabaseExtension *pExtension) { // Locals
LPVOID pValue=NULL;
// Trace
TraceCall("PGetOperandData");
// OPERAND_COLUMN
if (OPERAND_COLUMN == pOperand->tyOperand) { // Get the Tag
LPCTABLECOLUMN pColumn = &pSchema->prgColumn[pOperand->iColumn];
// MapColumnType
MapColumnType(pColumn->type, pOperand, pColumn, pBinding, &pValue); }
// OPERAND_STRING
else if (OPERAND_STRING == pOperand->tyOperand) { // Better want a string out
Assert(OPERAND_STRING == tyOperand);
// Return Data Pointer
pValue = pOperand->pszString; }
// OPERAND_DWORD
else if (OPERAND_DWORD == pOperand->tyOperand) { // Better want a dword out
Assert(OPERAND_DWORD == tyOperand);
// Return Data Pointer
pValue = (LPVOID)&pOperand->dwValue; }
// OPERAND_METHOD
else if (OPERAND_METHOD == pOperand->tyOperand && pExtension) { // Better want a dword out
Assert(OPERAND_DWORD == tyOperand);
// Call the Method on the Extension
pExtension->OnExecuteMethod(pOperand->idMethod, pBinding, &pOperand->dwReserved);
// Return Data Pointer
pValue = (LPVOID)&pOperand->dwReserved; }
// No Data ?
if (NULL == pValue) { // What type of operand was wanted
switch(tyOperand) { case OPERAND_STRING: pValue = (LPVOID)c_szEmpty; break;
case OPERAND_DWORD: pOperand->dwReserved = 0; pValue = (LPVOID)&pOperand->dwReserved; break;
default: AssertSz(FALSE, "While go ahead and Jimmy my buffet.."); break; } }
// Done
return(pValue); }
//--------------------------------------------------------------------------
// GetCommonOperandType
//--------------------------------------------------------------------------
OPERANDTYPE GetCommonOperandType(LPOPERANDINFO pLeft, LPOPERANDINFO pRight, LPCTABLESCHEMA pSchema) { // Locals
OPERANDTYPE tyLeft = (OPERAND_STRING == pLeft->tyOperand ? OPERAND_STRING : OPERAND_DWORD); OPERANDTYPE tyRight = (OPERAND_STRING == pRight->tyOperand ? OPERAND_STRING : OPERAND_DWORD);
// Trace
TraceCall("GetCommonOperandType");
// Left is a column
if (OPERAND_COLUMN == pLeft->tyOperand) { // Maps to a string
if (OPERAND_STRING == g_rgColumnTypeInfo[pSchema->prgColumn[pLeft->iColumn].type].tyOperand) tyLeft = OPERAND_STRING; }
// Right is a string
if (OPERAND_COLUMN == pRight->tyOperand) { // Maps to a String ?
if (OPERAND_STRING == g_rgColumnTypeInfo[pSchema->prgColumn[pRight->iColumn].type].tyOperand) tyRight = OPERAND_STRING; }
// Better be the Same
Assert(tyLeft == tyRight);
// Return tyLeft since they are the same
return(tyLeft); }
//--------------------------------------------------------------------------
// EvaluateClause
//--------------------------------------------------------------------------
HRESULT EvaluateClause(OPERATORTYPE tyOperator, LPVOID pBinding, LPCTABLESCHEMA pSchema, LPQUERYTOKEN *ppStackTop, CDatabase *pDB, IDatabaseExtension *pExtension) { // Locals
HRESULT hr=S_OK; LPVOID pDataLeft=NULL; LPVOID pDataRight=NULL; LPQUERYTOKEN pTokenResult=NULL; LPQUERYTOKEN pTokenRight=NULL; LPQUERYTOKEN pTokenLeft=NULL; OPERANDTYPE tyOperand; INT nCompare;
// Trace
TraceCall("EvaluateClause");
// Pop the right token
IF_FAILEXIT(hr = PopStackToken(&pTokenRight, ppStackTop));
// Pop the left token
IF_FAILEXIT(hr = PopStackToken(&pTokenLeft, ppStackTop));
// Better have Data
Assert(TOKEN_OPERAND == pTokenLeft->tyToken && TOKEN_OPERAND == pTokenRight->tyToken);
// Compute Operand type
tyOperand = GetCommonOperandType(&pTokenLeft->Operand, &pTokenRight->Operand, pSchema);
// Get Left Data
pDataLeft = PGetOperandData(tyOperand, &pTokenLeft->Operand, pBinding, pSchema, pDB, pExtension);
// Get Right Data
pDataRight = PGetOperandData(tyOperand, &pTokenRight->Operand, pBinding, pSchema, pDB, pExtension);
// Create new Token to push back onto the stack
IF_NULLEXIT(pTokenResult = (LPQUERYTOKEN)pDB->PHeapAllocate(HEAP_ZERO_MEMORY, sizeof(QUERYTOKEN)));
// Set Reference Count
pTokenResult->cRefs = 1;
// No Token foundyet
pTokenResult->tyToken = TOKEN_OPERAND;
// Invalid Symbol Index
pTokenResult->Operand.iSymbol = 0xffffffff;
// Set Result
pTokenResult->Operand.tyOperand = OPERAND_DWORD;
// EvaluateData
pTokenResult->Operand.dwValue = EvaluateOperator(tyOperator, tyOperand, pDataLeft, pDataRight);
// Push the result operand
PushStackToken(pTokenResult, ppStackTop); exit: // Cleanup
ReleaseToken(&pTokenLeft, pDB); ReleaseToken(&pTokenRight, pDB); ReleaseToken(&pTokenResult, pDB);
// Done
return(hr); }
//--------------------------------------------------------------------------
// EvaluateEqual
//--------------------------------------------------------------------------
DWORD EvaluateEqual(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (0 == CompareOperands(tyOperand, pDataLeft, pDataRight) ? TRUE : FALSE); }
//--------------------------------------------------------------------------
// EvaluateNotEqual
//--------------------------------------------------------------------------
DWORD EvaluateNotEqual(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (0 != CompareOperands(tyOperand, pDataLeft, pDataRight) ? TRUE : FALSE); }
//--------------------------------------------------------------------------
// EvaluateLessThanEqual
//--------------------------------------------------------------------------
DWORD EvaluateLessThanEqual(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (CompareOperands(tyOperand, pDataLeft, pDataRight) <= 0 ? TRUE : FALSE); }
//--------------------------------------------------------------------------
// EvaluateLessThan
//--------------------------------------------------------------------------
DWORD EvaluateLessThan(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (CompareOperands(tyOperand, pDataLeft, pDataRight) < 0 ? TRUE : FALSE); }
//--------------------------------------------------------------------------
// EvaluateGreaterThanEqual
//--------------------------------------------------------------------------
DWORD EvaluateGreaterThanEqual(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (CompareOperands(tyOperand, pDataLeft, pDataRight) >= 0 ? TRUE : FALSE); }
//--------------------------------------------------------------------------
// EvaluateGreaterThan
//--------------------------------------------------------------------------
DWORD EvaluateGreaterThan(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (CompareOperands(tyOperand, pDataLeft, pDataRight) > 0 ? TRUE : FALSE); }
//--------------------------------------------------------------------------
// EvaluateAnd
//--------------------------------------------------------------------------
DWORD EvaluateAnd(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (INT)(*((DWORD *)pDataLeft) && *((DWORD *)pDataRight)); }
//--------------------------------------------------------------------------
// EvaluateBitwiseAnd
//--------------------------------------------------------------------------
DWORD EvaluateBitwiseAnd(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (INT)(*((DWORD *)pDataLeft) & *((DWORD *)pDataRight)); }
//--------------------------------------------------------------------------
// EvaluateOr
//--------------------------------------------------------------------------
DWORD EvaluateOr(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (INT)(*((DWORD *)pDataLeft) || *((DWORD *)pDataRight)); }
//--------------------------------------------------------------------------
// EvaluateBitwiseOr
//--------------------------------------------------------------------------
DWORD EvaluateBitwiseOr(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (INT)(*((DWORD *)pDataLeft) | *((DWORD *)pDataRight)); }
//--------------------------------------------------------------------------
// EvaluateStrStrI
//--------------------------------------------------------------------------
DWORD EvaluateStrStrI(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (NULL == StrStrIA((LPCSTR)pDataLeft, (LPCSTR)pDataRight) ? FALSE : TRUE); }
//--------------------------------------------------------------------------
// EvaluateStrStr
//--------------------------------------------------------------------------
DWORD EvaluateStrStr(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (NULL == StrStrA((LPCSTR)pDataLeft, (LPCSTR)pDataRight) ? FALSE : TRUE); }
//--------------------------------------------------------------------------
// EvaluateStrcmpi
//--------------------------------------------------------------------------
DWORD EvaluateStrcmpi(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (lstrcmpi((LPCSTR)pDataLeft, (LPCSTR)pDataRight) == 0 ? TRUE : FALSE); }
//--------------------------------------------------------------------------
// EvaluateStrcmp
//--------------------------------------------------------------------------
DWORD EvaluateStrcmp(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (lstrcmp((LPCSTR)pDataLeft, (LPCSTR)pDataRight) == 0 ? TRUE : FALSE); }
//--------------------------------------------------------------------------
// EvaluateAdd
//--------------------------------------------------------------------------
DWORD EvaluateAdd(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (INT)(*((DWORD *)pDataLeft) + *((DWORD *)pDataRight)); }
//--------------------------------------------------------------------------
// EvaluateSubtract
//--------------------------------------------------------------------------
DWORD EvaluateSubtract(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (INT)(*((DWORD *)pDataLeft) - *((DWORD *)pDataRight)); }
//--------------------------------------------------------------------------
// EvaluateMultiply
//--------------------------------------------------------------------------
DWORD EvaluateMultiply(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (INT)(*((DWORD *)pDataLeft) * *((DWORD *)pDataRight)); }
//--------------------------------------------------------------------------
// EvaluateDivide
//--------------------------------------------------------------------------
DWORD EvaluateDivide(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (INT)(*((DWORD *)pDataLeft) / *((DWORD *)pDataRight)); }
//--------------------------------------------------------------------------
// EvaluateModula
//--------------------------------------------------------------------------
DWORD EvaluateModula(OPERANDTYPE tyOperand, LPVOID pDataLeft, LPVOID pDataRight) { return (INT)(*((DWORD *)pDataLeft) % *((DWORD *)pDataRight)); }
|