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.
 
 
 
 
 
 

730 lines
22 KiB

/*++
Copyright (C) 1998-2001 Microsoft Corporation
Module Name:
CONVERTER.CPP
Abstract:
<sequence> ::= <number> | <number><separator><sequence>
<separator> ::= [<whitespace>],[<whitespace>] | <whitespace>
<number> ::= <whitespace>[-]0x<hexfield>[<comment>] | <whitespace>[-]<digitfield>[<comment>]
<decfield> ::= <decdigit> | <decdigit><decfield>
<decdigit> ::= 0..9
<hexfield> ::= <hexdigit> | <hexdigit><hexfield>
<hexdigit> ::= 1..9 | A | B | C | D | E | F
<comment> ::= [<whitespace>](<string>)[<whitespace>]
<whitespace> ::= SP | TAB | CR | LF
History:
--*/
#include "precomp.h"
#include <stdio.h>
#include <stdlib.h>
#include <wtypes.h>
#include "wbemcli.h"
#include "var.h"
#include "WT_Converter.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CConverter::CConverter(const char* szString, CIMType ct)
{
int nSize = strlen(szString);
m_szString = new char[nSize + 1]; // Made to fit
strcpy(m_szString, szString);
m_ct = ct; // CIM_TYPE
}
CConverter::~CConverter()
{
delete m_szString;
}
/******************************************************************
//
// Helper Functions
//
*******************************************************************/
UINT CConverter::SetBoundary(BOOL bNeg, ULONG *uMaxSize)
//////////////////////////////////////////////////////////////////////
//
// Establishs the outer boundary of a give CIM type. Returns the
// maximum absolute value, including an offset if the value is
// negative. (Compensating for the additional size of 2's complement
// negative values)
//
//////////////////////////////////////////////////////////////////////
{
*uMaxSize = 0;
switch (m_ct)
{
case CIM_UINT8:
*uMaxSize = 0x000000FF; break;
case CIM_SINT8:
*uMaxSize = (bNeg ? 0x00000080 : 0x0000007F); break;
case CIM_UINT16:
*uMaxSize = 0x0000FFFF; break;
case CIM_SINT16:
*uMaxSize = (bNeg ? 0x00008000 : 0x00007FFF); break;
case CIM_UINT32:
*uMaxSize = 0xFFFFFFFF; break;
case CIM_SINT32:
*uMaxSize = (bNeg ? 0x80000000 : 0x7FFFFFFF); break;
case NULL:
return ERR_NULL_CIMTYPE;
default:
return ERR_UNKNOWN;
}
return ERR_NOERROR;
}
BOOL CConverter::IsValidDec(char ch)
//////////////////////////////////////////////////////////////////////
//
// PARAMETERS : a character to be validated as decimal
// RETURNS: TRUE only if the character is a valid decimal character
//
//////////////////////////////////////////////////////////////////////
{
return (('0' <= ch) && ('9' >= ch));
}
BOOL CConverter::IsValidHex(char ch)
//////////////////////////////////////////////////////////////////////
//
// PARAMETERS : a character to be validated as hexadecimal
// RETURNS: TRUE only if the character is a valid hexadecimal character
//
//////////////////////////////////////////////////////////////////////
{
return ((('0' <= ch) && ('9' >= ch)) || (('a' <= ch) && ('f' <= ch)));
}
/******************************************************************
//
// Parser Functions
//
*******************************************************************/
char CConverter::PeekToken(char *ch)
//////////////////////////////////////////////////////////////////////
//
// PARAMETERS: the token pointer (by val)
// RETURNS: the character following the current token pointer. Does
// not increment the token pointer.
//
//////////////////////////////////////////////////////////////////////
{
// ch is passed by value; change is local to method
ch++;
// Ensure lower case
if (('A' <= *ch) && ('Z' >= *ch))
*ch += ('a' - 'A');
return *ch;
}
BOOL CConverter::GetToken(char **ch)
//////////////////////////////////////////////////////////////////////
//
// If the token pointer is not at the end of the string, it will be
// incremented and the current token will be converted into lower
// case and passed back. If the pointer is at the end of the string,
// NULL will be passed and the pointer unaffected.
//
// PARAMETERS: the token pointer (by ref)
//
// RETURNS: TRUE if the token pointer is mid-string, and FALSE if it
// is at the end of the string.
//
//////////////////////////////////////////////////////////////////////
{
// Increment pointer by 1 byte
if ('\0' != **ch)
*ch += 1;
// Ensure lower case
if (('A' <= **ch) && ('Z' >= **ch))
**ch += ('a' - 'A');
// End of the line?
return ('\0' != **ch);
}
void CConverter::ReplaceToken(char **ch)
//////////////////////////////////////////////////////////////////////
//
// If not at the front of the string, the token pointer will be
// decremented one place towards the head of the string.
//
// PARAMETERS: the token pointer (by ref)
//
// RETURNS: void
//
//////////////////////////////////////////////////////////////////////
{
if (*ch != m_szString)
*ch -= 1;
return;
}
BOOL CConverter::Done(char *ch)
//////////////////////////////////////////////////////////////////////
//
// Checks for additional non-whitespace tokens following current
// token. Does not validate token.
//
// PARAMETERS: the token pointer (by ref)
//
// RETURNS: TRUE if no further non-whitespace tokens follow the
// current token pointer
//
//////////////////////////////////////////////////////////////////////
{
if ('\0' == *ch)
return TRUE;
while (isspace(*ch))
ch++;
return ('\0' == *ch);
}
/******************************************************************
//
// Token Functions
//
*******************************************************************/
UINT CConverter::Token_Sequence(CVar *pVar)
//////////////////////////////////////////////////////////////////////
//
// Root of parsing for single (non-array) values. Sets up token
// pointer (ch), and parses one number. If tokens remain in the
// input string following the parsing of the first number, then
// the input string is invalid.
//
// If the parsing fails, the value of pVar is not changed
//
// PARAMETERS: a variant for the result (by ref)
//
// RETURNS: the result state of the parsing
//
//////////////////////////////////////////////////////////////////////
{
CVar aVar; // A temporary result variant
char *ch = m_szString; // The token pointer
UINT uRes; // A generic result sink
// Parse out the number
uRes = Token_Number(&ch, &aVar);
if (ERR_NOERROR != uRes)
return uRes;
// Check for remaining tokens
if (!Done(ch))
return ERR_INVALID_INPUT_STRING;
// Parsing ok, copy temp variant into final destiation
*pVar = aVar;
return ERR_NOERROR;
}
UINT CConverter::Token_Sequence(CVarVector *pVarVec)
//////////////////////////////////////////////////////////////////////
//
// Root of parsing for multiple (array) values. Sets up token
// pointer (ch), and parses the input string. It starts with a
// single number, and then enters the loop, verifying a seperator
// between each subsequent number. Each number is added to the
// variant array as it is parsed.
//
// If the parsing fails, the value if pVarVec is not changed
//
// PARAMETERS: a variant vector for the result (by ref)
//
// RETURNS: the result state of the parsing
//
//////////////////////////////////////////////////////////////////////
{
CVar aVar; // A temporary result variant
char *ch = m_szString; // The token pointer
UINT uRes; // A generic result sink
UINT uVTType;
switch (m_ct)
{
case CIM_UINT8:
uVTType = VT_UI1;break;
case CIM_SINT8:
case CIM_SINT16:
uVTType = VT_I2;break;
case CIM_UINT16:
case CIM_UINT32:
case CIM_SINT32:
uVTType = VT_I4;break;
}
CVarVector aVarVec(uVTType);// A temporary result variant vector
// Parse out the first number
uRes = Token_Number(&ch, &aVar);
if (ERR_NOERROR != uRes)
return uRes;
// Add to array, and clear temporary variant
aVarVec.Add(aVar);
// If more tokens exist, continue
while (!Done(ch))
{
// Verify separator
uRes = Token_Separator(&ch);
if (ERR_NOERROR != uRes)
return uRes;
// Parse out next number
uRes = Token_Number(&ch, &aVar);
if (ERR_NOERROR != uRes)
return uRes;
// Add to array, and clear temporary variant
aVarVec.Add(aVar);
}
// Parsing ok, copy temp variant vector into final destiation
*pVarVec = aVarVec;
return ERR_NOERROR;
}
UINT CConverter::Token_WhiteSpace(char **ch)
//////////////////////////////////////////////////////////////////////
//
// Move token pointer to the next non-white space token
//
// PARAMETERS: the token pointer (by ref)
//
// RETURNS: the result state of the parsing
//
//////////////////////////////////////////////////////////////////////
{
while (isspace(**ch))
GetToken(ch);
return ERR_NOERROR;
}
UINT CConverter::Token_Separator(char **ch)
//////////////////////////////////////////////////////////////////////
//
// A valid separator is either white space or a comma optionally
// preceeded by white space. Parese out white space. Stop when
// a non-whitespace character is encountered. If a comma, then
// there must be a following non-whitespace token.
//
// PARAMETERS: the token pointer (by ref)
//
// RETURNS: the result state of the parsing
//
//////////////////////////////////////////////////////////////////////
{
BOOL bComma = FALSE;
while ((isspace(**ch) || (',' == **ch)) && !bComma)
{
if (',' == **ch)
bComma = TRUE;
// If a comma exists, the string must not be done
if (!GetToken(ch) && bComma)
return ERR_INVALID_TOKEN;
}
return ERR_NOERROR;
}
UINT CConverter::Token_Number(char **ch, CVar *pVar)
//////////////////////////////////////////////////////////////////////
//
// Determines the sign and base values of the number, and then
// calls either Token_HexField or Token_DecField to continue
// parsing the digit fields. The numerical value returned from
// the parsing is unsigned. If the value is signed and negative
// the value is negated. Comments are then parsed out.
//
// If the parsing fails, the value of pVar does not change
//
// PARAMETERS: the token pointer (by ref) and a Variant representing
// the number (by ref)
//
// RETURNS: the result state of the parsing
//
//////////////////////////////////////////////////////////////////////
{
ULONG aVal; // Temp value returned from Token_XXXField
USHORT uBase = BASE_DEC; // Base of number
BOOL bNegative = FALSE; // Sign of number
UINT uRes; // Generic result sink
// Parse out white space
uRes = Token_WhiteSpace(ch);
if (ERR_NOERROR != uRes)
return uRes;
// Determines the sign (assumed positive) and validates against type
if (**ch == '-')
{
if ((CIM_UINT8 == m_ct) || (CIM_UINT16 == m_ct) || (CIM_UINT32 == m_ct))
return ERR_INVALID_SIGNED_VALUE;
//else
bNegative = TRUE;
GetToken(ch); // Get the next token to handle
}
// Determine Base (we have initialized as decimal)
if (**ch == '0')
{
if (PeekToken(*ch) == 'x') // Hexadecimal!
{
uBase = BASE_HEX; // Modify base
GetToken(ch); // Get Rid of the 'x' token
GetToken(ch); // Get the next token to handle
}
}
// Parse digit field and put result in aVal
if (BASE_HEX == uBase)
uRes = Token_HexField(ch, bNegative, &aVal);
else if (BASE_DEC == uBase)
uRes = Token_DecField(ch, bNegative, &aVal);
else
return ERR_UNKNOWN_BASE;
if (ERR_NOERROR != uRes)
return uRes;
// NOTE: signed operation on unsigned value
// -this may cause a problem on some platforms
if (bNegative)
aVal *= (-1);
// Set variant
pVar->SetLong(aVal);
// Parse out comments
uRes = Token_Comment(ch);
if (ERR_NOERROR != uRes)
return uRes;
return ERR_NOERROR;
}
UINT CConverter::Token_DecField(char **ch, BOOL bNeg, ULONG *pVal)
//////////////////////////////////////////////////////////////////////
//
// Token_DecField first determines the maximum possible value of
// the number based on the CIM type for the purpose of bonuds checking.
// The digit field is parsed, withe each token being added to the
// previous tally value after it has increased in magnitude.
//
// Prior to the tally increasing, the proposed tally is validated
// using an algorithm that assumes that the current value is in
// range, and verifies that the proposed value will be in range
// by working back from the maximum value. This algorithm works,
// given that the initial value is 0, which is guarenteed to be
// within range. The difference between the current tally, and the
// proposed tally is subtracted from the maximum value, and if the
// result is larger than the current tally, then the propsed value
// is valid.
//
// This algorithm assumes that we are using unsigend values. Signed
// negative values are constructed as positive values, and then
// converted. In this case, the maximum value is one larger than the
// positive maximum value, according to the rules of 2's complement.
//
// If the parsing fails, the value of pVal does not change
//
// PARAMETERS: the token pointer (by ref), the sign flag (by val)
// and a the unsigned value of the number (by ref)
//
// RETURNS: the result state of the parsing
//
//////////////////////////////////////////////////////////////////////
{
ULONG uMaxSize; // Boundary value
ULONG aVal = 0; // Tally value
ULONG uDigitVal; // Return digit from Token_DecDigit
UINT uRes; // Generic result sink
// Sets the maximum value of the tally
uRes = SetBoundary(bNeg, &uMaxSize);
if (ERR_NOERROR != uRes)
return uRes;
// Pareses the first digit
uRes = Token_DecDigit(ch, &uDigitVal);
if (ERR_NOERROR != uRes)
return uRes;
// Adds to tally
aVal = uDigitVal;
// If more decimal tokens...
while (IsValidDec(**ch))
{
// Parse the token
uRes = Token_DecDigit(ch, &uDigitVal);
if (ERR_NOERROR != uRes)
return uRes;
// Test the bounds of the proposed tally
if (((uMaxSize - uDigitVal) / BASE_DEC ) < aVal)
return ERR_OUT_OF_RANGE;
// Increase the magnitude and add the token digit value
aVal = (aVal * BASE_DEC) + uDigitVal;
}
// Parsing ok, copy the temp to the destination
*pVal = aVal;
return ERR_NOERROR;
}
UINT CConverter::Token_HexField(char **ch, BOOL bNeg, ULONG *pVal)
//////////////////////////////////////////////////////////////////////
//
// See Token_DecField
//
//////////////////////////////////////////////////////////////////////
{
ULONG uMaxSize; // Boundary value
ULONG aVal = 0; // Tally value
ULONG uDigitVal; // Return digit from Token_DecDigit
UINT uRes; // Generic result
// Sets the maximum value of the tally
uRes = SetBoundary(bNeg, &uMaxSize);
if (ERR_NOERROR != uRes)
return uRes;
// Pareses the first digit
uRes = Token_HexDigit(ch, &uDigitVal);
if (ERR_NOERROR != uRes)
return uRes;
// Adds to tally
aVal = uDigitVal;
// If more decimal tokens...
while (IsValidHex(**ch))
{
// Parse the token
uRes = Token_HexDigit(ch, &uDigitVal);
if (ERR_NOERROR != uRes)
return uRes;
// Test the bounds of next tally
if (((uMaxSize - uDigitVal) / BASE_HEX ) < aVal)
return ERR_OUT_OF_RANGE;
// Increase the magnitude and add the token digit value
aVal = (aVal * BASE_HEX) + uDigitVal;
}
// Parsing ok, copy the temp to the destination
*pVal = aVal;
return ERR_NOERROR;
}
UINT CConverter::Token_DecDigit(char **ch, ULONG *pVal)
//////////////////////////////////////////////////////////////////////
//
// Validates the token, and converts to numerical equivalent
//
// If the parsing fails, the value of pVal does not change
//
// PARAMETERS: the token pointer (by ref) and a the value
// of the digit (by ref)
//
// RETURNS: the result state of the parsing
//
//////////////////////////////////////////////////////////////////////
{
ULONG uVal = 0; // Temp value
// Validate digit & convert
if (('0' <= **ch) && ('9' >= **ch))
uVal = **ch - '0';
else if ('\0' == **ch)
return ERR_NULL_TOKEN;
else
return ERR_INVALID_TOKEN;
// Parsing ok, copy value to destination
*pVal = uVal;
// Move token pointer
GetToken(ch);
return ERR_NOERROR;
}
UINT CConverter::Token_HexDigit(char **ch, ULONG *pVal)
//////////////////////////////////////////////////////////////////////
//
// Validates the token, and converts to numerical equivalent
//
// If the parsing fails, the value of pVal does not change
//
// PARAMETERS: the token pointer (by ref) and a the value
// of the digit (by ref)
//
// RETURNS: the result state of the parsing
//
//////////////////////////////////////////////////////////////////////
{
ULONG uVal = 0; // Temp value
// Validate digit & convert
if (('a' <= **ch) && ('f' >= **ch))
uVal = 0xA + (**ch - 'a');
else if (('0' <= **ch) && ('9' >= **ch))
uVal = **ch - '0';
else if ('\0' == **ch)
return ERR_NULL_TOKEN;
else
return ERR_INVALID_TOKEN;
// Parsing ok, copy value to destination
*pVal = uVal;
// Move token pointer
GetToken(ch);
return ERR_NOERROR;
}
UINT CConverter::Token_Comment(char** ch)
//////////////////////////////////////////////////////////////////////
//
// Parses out white space and contents between braces, if they exist.
// If an opening brace is encountered, all of the contents, including
// the braces, are ignored. If an opening brace is encountered, a
// closing brace must follow.
//
// NOTE: Nested comments are not allowed
//
// PARAMETERS: the token pointer (by ref)
//
// RETURNS: the result state of the parsing
//
//////////////////////////////////////////////////////////////////////
{
// Parse out white space
UINT uRes = Token_WhiteSpace(ch);
if (ERR_NOERROR != uRes)
return uRes;
// If the token following the white space is an opening brace,
// parse out the contents, and verify the existance of the
// closing brace
if ('(' == **ch)
{
while ((')' != **ch))
{
if (!GetToken(ch))
return ERR_UNMATCHED_BRACE;
}
GetToken(ch); // Purge closing brace
}
return ERR_NOERROR;
}
/******************************************************************
//
// Static Functions
//
*******************************************************************/
UINT CConverter::Convert(const char* szString, CIMType ct, CVar *pVar)
/////////////////////////////////////////////////////////////////////
//
// Convert is a static method that creates an instance of the
// Converter object and converts the string to a variant. If an
// error occurs, the value of pVar is not affected.
//
// PARAMETERS: the input string (by val), the CIM type (by val) and
// the outout variant (by ref)
//
// RETURNS: the result state of the parsing
//
/////////////////////////////////////////////////////////////////////
{
// Checks the CIM type is initialized
if (NULL == ct)
return ERR_NULL_CIMTYPE;
CConverter converter(szString, ct); // The converter object
CVar aVar; // Temp variant
// Parse out the first number
UINT uRes = converter.Token_Sequence(&aVar);
// Check return code
if (ERR_NOERROR != uRes)
return uRes;
// Parsing ok, copy temp to destination
*pVar = aVar;
return ERR_NOERROR;
}
UINT CConverter::Convert(const char* szString, CIMType ct, CVarVector *pVarVec)
/////////////////////////////////////////////////////////////////////
//
// Convert is a static method that creates an instance of the
// Converter object and converts the string to an array of values.
// If an error occurs, the value of pVarVec is not affected.
//
// PARAMETERS: the input string (by val), the CIM type (by val) and
// the outout variant vecter (by ref)
//
// Returns the result state of the parsing
//
/////////////////////////////////////////////////////////////////////
{
// Checks the CIM type is initialized
if (NULL == ct)
return ERR_NULL_CIMTYPE;
CConverter converter(szString, ct); // The converter object
CVarVector aVarVec; // Temp variant vector
// Parse out the first number
UINT uRes = converter.Token_Sequence(&aVarVec);
// Check return code
if (ERR_NOERROR != uRes)
return uRes;
// Parsing ok, copy temp to destination
*pVarVec = aVarVec;
return ERR_NOERROR;
}