diff options
Diffstat (limited to 'gobi-api/GobiAPI_1.0.40/Core/CoreDatabase.cpp')
-rwxr-xr-x | gobi-api/GobiAPI_1.0.40/Core/CoreDatabase.cpp | 3187 |
1 files changed, 3187 insertions, 0 deletions
diff --git a/gobi-api/GobiAPI_1.0.40/Core/CoreDatabase.cpp b/gobi-api/GobiAPI_1.0.40/Core/CoreDatabase.cpp new file mode 100755 index 0000000..e9bf5e4 --- /dev/null +++ b/gobi-api/GobiAPI_1.0.40/Core/CoreDatabase.cpp @@ -0,0 +1,3187 @@ +/*=========================================================================== +FILE: + CoreDatabase.cpp + +DESCRIPTION: + Implementation of cCoreDatabase class + +PUBLIC CLASSES AND METHODS: + cCoreDatabase + This class represents the run-time (read only) version of the + core library database + +Copyright (c) 2011, Code Aurora Forum. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Code Aurora Forum nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +===========================================================================*/ + +//--------------------------------------------------------------------------- +// Include Files +//--------------------------------------------------------------------------- +#include "StdAfx.h" + +#include "CoreDatabase.h" +#include "DB2NavTree.h" + +#include "CoreUtilities.h" + +//--------------------------------------------------------------------------- +// Definitions +//--------------------------------------------------------------------------- + +// Uncomment out to enable database load/save timing through cCoreDatabase +// #define TIME_DB 1 + +// Database table file names +LPCSTR DB2_FILE_PROTOCOL_FIELD = "Field.txt"; +LPCSTR DB2_FILE_PROTOCOL_STRUCT = "Struct.txt"; +LPCSTR DB2_FILE_PROTOCOL_ENTITY = "Entity.txt"; +LPCSTR DB2_FILE_ENUM_MAIN = "Enum.txt"; +LPCSTR DB2_FILE_ENUM_ENTRY = "EnumEntry.txt"; + +// Database table file names +LPCSTR DB2_TABLE_PROTOCOL_FIELD = "Field"; +LPCSTR DB2_TABLE_PROTOCOL_STRUCT = "Struct"; +LPCSTR DB2_TABLE_PROTOCOL_ENTITY = "Entity"; +LPCSTR DB2_TABLE_ENUM_MAIN = "Enum"; +LPCSTR DB2_TABLE_ENUM_ENTRY = "Enum Entry"; + +// An empty (but not NULL) string +LPCSTR EMPTY_STRING = ""; + +// Value seperator for database text +LPCSTR DB2_VALUE_SEP = "^"; + +// Sub-value (i.e. within a particular value) seperator for database text +LPCSTR DB2_SUBVAL_SEP = ","; + +// Maximum amount of recursion allowed in protocol entity structure processing +const ULONG MAX_NESTING_LEVEL = 32; + +// The default logger (for backwards compatibility) +cDB2TraceLog gDB2DefaultLog; + +/*=========================================================================*/ +// Free Methods +/*=========================================================================*/ + +/*=========================================================================== +METHOD: + CopyQuotedString (Public Method) + +DESCRIPTION: + Convert a string (in quotes) to a string (minus) quotes and copy + into an allocated buffer + +PARAMETERS: + pString [ I ] - The string being de-quoted/copied + +RETURN VALUE: + LPSTR: The copy (returns 0 upon error) +===========================================================================*/ +LPCSTR CopyQuotedString( LPSTR pString ) +{ + // Get string length + ULONG len = (ULONG)strlen( pString ); + + // Adjust to remove trailing spaces + while (len > 0 && pString[len - 1] == ' ') + { + pString[len - 1] = 0; + len--; + } + + // Long enough (and quoted?) + if ( (len >= 2) + && (pString[0] == '\"') + && (pString[len - 1] == '\"') ) + { + if (len == 2) + { + return EMPTY_STRING; + } + else + { + // Attempt to allocate a copy + LPSTR pRet = new char[len - 1]; + if (pRet != 0) + { + ULONG bytes = (len - 2) * sizeof( char ); + memcpy( (PVOID)pRet, (LPCVOID)&pString[1], (SIZE_T)bytes ); + pRet[len - 2] = 0; + + return pRet; + } + } + } + + return 0; +} + +/*=========================================================================*/ +// sDB2ProtocolEntity Methods +/*=========================================================================*/ + +/*=========================================================================== +METHOD: + FromString (Public Method) + +DESCRIPTION: + Populate this object from a string + +PARAMETERS: + pStr [ I ] - String to populate object from + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2ProtocolEntity::FromString( LPSTR pStr ) +{ + bool bRC = false; + + // Should be + // 0: Type + // 1: "Key" + // 2: "Name" + // 3: Struct ID + // 4: Format specifier ID (optional) + // 5: Internal only flag (optional) + // 6: Extended format specifier ID (optional) + const ULONG NUM_REQ_VALS = 4; + + std::vector <LPSTR> tokens; + ParseTokens( DB2_VALUE_SEP, pStr, tokens ); + + ULONG toks = (ULONG)tokens.size(); + if (toks >= NUM_REQ_VALS) + { + // Remove quotes from name string and copy + LPCSTR pCopy = CopyQuotedString( tokens[2] ); + if (pCopy != 0) + { + mpName = pCopy; + mType = (eDB2EntityType)strtol( tokens[0], 0, 10 ); + + // Convert key/populate ID + mID.push_back( (ULONG)mType ); + CSVStringToContainer( DB2_SUBVAL_SEP, tokens[1], mID, false ); + + mStructID = strtol( tokens[3], 0, 10 ); + + // Format specifier? + if (toks > NUM_REQ_VALS) + { + mFormatID = strtol( tokens[NUM_REQ_VALS], 0, 10 ); + } + + // Internal only flag? + if (toks > NUM_REQ_VALS + 1) + { + mbInternal = (strtoul( tokens[NUM_REQ_VALS + 1], 0, 10 ) != 0); + } + + // Extended format specifier ID? + if (toks > NUM_REQ_VALS + 2) + { + mFormatExID = strtol( tokens[NUM_REQ_VALS + 2], 0, 10 ); + } + + bRC = IsValid(); + } + } + + return bRC; +} + +/*=========================================================================== +METHOD: + IsValid (Public Method) + +DESCRIPTION: + Is this object valid? + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2ProtocolEntity::IsValid() const +{ + // The type has to be valid + if (::IsValid( mType ) == false) + { + return false; + } + + // The ID must consists of at least two entries + if (mID.size() < 2) + { + return false; + } + + // The first entry in the ID has to be the type + if (mID[0] != (ULONG)mType) + { + return false; + } + + // The structure ID has to be >= -1) + if (mStructID < -1) + { + return false; + } + + // The format specifier has to be >= -1) + if (mFormatID < -1) + { + return false; + } + + // There has to be a non-empty name + if (mpName == 0 || mpName[0] == 0) + { + return false; + } + + return true; +} + +/*=========================================================================*/ +// sDB2Fragment Methods +/*=========================================================================*/ + +/*=========================================================================== +METHOD: + FromString (Public Method) + +DESCRIPTION: + Populate this object from a string + +PARAMETERS: + pStr [ I ] - String to populate object from + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2Fragment::FromString( LPSTR pStr ) +{ + bool bRC = false; + + // Should be + // 0: ID + // 1: Order + // 2: Type + // 3: Val + // 4: "Name" + // 5: Offset + // 6: Mod Type + // 7: "Mod Value" + const ULONG NUM_REQ_VALS = 8; + + std::vector <LPSTR> tokens; + ParseTokens( DB2_VALUE_SEP, pStr, tokens ); + + ULONG toks = (ULONG)tokens.size(); + if (toks >= NUM_REQ_VALS) + { + // Remove quotes from modifier value and copy + LPCSTR pVal = CopyQuotedString( tokens[7] ); + if (pVal != 0) + { + // Remove quotes from name string and copy + LPCSTR pCopy = CopyQuotedString( tokens[4] ); + if (pCopy != 0) + { + mStructID = strtoul( tokens[0], 0, 10 ); + mFragmentOrder = strtoul( tokens[1], 0, 10 ); + mFragmentValue = strtoul( tokens[3], 0, 10 ); + mFragmentOffset = strtol( tokens[5], 0, 10 ); + mFragmentType = (eDB2FragmentType)strtol( tokens[2], 0, 10 ); + mModifierType = (eDB2ModifierType)strtol( tokens[6], 0, 10 );; + mpModifierValue = pVal; + mpName = pCopy; + + bRC = IsValid(); + } + } + } + + return bRC; +} + +/*=========================================================================== +METHOD: + IsValid (Public Method) + +DESCRIPTION: + Is this object valid? + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2Fragment::IsValid() const +{ + // The fragment type has to be valid + if (::IsValid( mFragmentType ) == false) + { + return false; + } + + // The modifier type has to be valid + if (::IsValid( mModifierType ) == false) + { + return false; + } + + // There has to be a name (possibly empty) + if (mpName == 0) + { + return false; + } + + // There has to be a modifier value (possibly empty) + if (mpModifierValue == 0) + { + return false; + } + + // Directives can only be given for the first fragment + if ( (mFragmentType == eDB2_FRAGMENT_MSB_2_LSB) + || (mFragmentType == eDB2_FRAGMENT_LSB_2_MSB) ) + { + if (mFragmentOrder > 0) + { + return false; + } + } + + // Validate modifier + switch (mModifierType) + { + case eDB2_MOD_NONE: + if (mpModifierValue != 0 && mpModifierValue[0] != 0) + { + // Modifier string needs to be empty + return false; + } + break; + + case eDB2_MOD_CONSTANT_ARRAY: + case eDB2_MOD_VARIABLE_ARRAY: + case eDB2_MOD_OPTIONAL: + case eDB2_MOD_VARIABLE_ARRAY2: + case eDB2_MOD_VARIABLE_ARRAY3: + if (mpModifierValue == 0 || mpModifierValue[0] == 0) + { + // Needs to be a modifier string + return false; + } + break; + + case eDB2_MOD_VARIABLE_STRING1: + case eDB2_MOD_VARIABLE_STRING2: + case eDB2_MOD_VARIABLE_STRING3: + if (mpModifierValue == 0 || mpModifierValue[0] == 0) + { + // Needs to be a modifier string + return false; + } + + if (mFragmentType != eDB2_FRAGMENT_FIELD) + { + // Only valid when modifying fields (strings) + return false; + } + break; + + } + + if (mFragmentType == eDB2_FRAGMENT_CONSTANT_PAD && mFragmentValue == 0) + { + return false; + } + + return true; +} + +/*=========================================================================== +METHOD: + BuildCondition (Static Public Method) + +DESCRIPTION: + Build a simple condition string + +PARAMETERS: + id [ I ] - Field ID + op [ I ] - Operator + val [ I ] - Value (or field ID) + bF2F [ I ] - Field to field expression? + +RETURN VALUE: + std::string +===========================================================================*/ +std::string sDB2Fragment::BuildCondition( + ULONG id, + eDB2Operator op, + LONGLONG val, + bool bF2F ) +{ + std::ostringstream tmp; + + if (::IsValid( op ) == true) + { + if (bF2F == false) + { + switch (op) + { + case eDB2_OP_LT: + tmp << (UINT)id << " " << "<" << val; + break; + + case eDB2_OP_LTE: + tmp << (UINT)id << " " << "<=" << val; + break; + + case eDB2_OP_EQ: + tmp << (UINT)id << " " << "=" << val; + break; + + case eDB2_OP_NEQ: + tmp << (UINT)id << " " << "!=" << val; + break; + + case eDB2_OP_GTE: + tmp << (UINT)id << " " << ">=" << val; + break; + + case eDB2_OP_GT: + tmp << (UINT)id << " " << ">" << val; + break; + + case eDB2_OP_DIV: + tmp << (UINT)id << " " << "%" << val; + break; + + case eDB2_OP_NDIV: + tmp << (UINT)id << " " << "!%" << val; + break; + } + } + else + { + switch (op) + { + case eDB2_OP_LT: + tmp << (UINT)id << " " << "f<" << val; + break; + + case eDB2_OP_LTE: + tmp << (UINT)id << " " << "f<=" << val; + break; + + case eDB2_OP_EQ: + tmp << (UINT)id << " " << "f=" << val; + break; + + case eDB2_OP_NEQ: + tmp << (UINT)id << " " << "f!=" << val; + break; + + case eDB2_OP_GTE: + tmp << (UINT)id << " " << "f>=" << val; + break; + + case eDB2_OP_GT: + tmp << (UINT)id << " " << "f>" << val; + break; + + case eDB2_OP_DIV: + tmp << (UINT)id << " " << "f%" << val; + break; + + case eDB2_OP_NDIV: + tmp << (UINT)id << " " << "f!%" << val; + break; + } + } + } + + std::string retStr = tmp.str(); + + return retStr; +} + +/*=========================================================================== +METHOD: + EvaluateCondition (Static Public Method) + +DESCRIPTION: + Evaluate a simple condition + +PARAMETERS: + valA [ I ] - Left value + op [ I ] - Operator + valB [ I ] - Right value + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2Fragment::EvaluateCondition( + LONGLONG valA, + eDB2Operator op, + LONGLONG valB ) +{ + bool bOK = false; + if (::IsValid( op ) == true) + { + switch (op) + { + case eDB2_OP_LT: + bOK = (valA < valB); + break; + + case eDB2_OP_LTE: + bOK = (valA <= valB); + break; + + case eDB2_OP_EQ: + bOK = (valA == valB); + break; + + case eDB2_OP_NEQ: + bOK = (valA != valB); + break; + + case eDB2_OP_GTE: + bOK = (valA >= valB); + break; + + case eDB2_OP_GT: + bOK = (valA > valB); + break; + + case eDB2_OP_DIV: + bOK = ((valA % valB) == 0); + break; + + case eDB2_OP_NDIV: + bOK = ((valA % valB) != 0); + break; + } + } + + return bOK; +} + +/*=========================================================================== +METHOD: + ParseCondition (Static Public Method) + +DESCRIPTION: + Parse a simple condition + +PARAMETERS: + pCondition [ I ] - Condition string + id [ O ] - Field ID + op [ O ] - Operator + val [ O ] - Value (or field ID) + bF2F [ O ] - Field to field expression? + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2Fragment::ParseCondition( + LPCSTR pCondition, + ULONG & id, + eDB2Operator & op, + LONGLONG & val, + bool & bF2F ) +{ + // Assume error + bool bOK = false; + + // Even a condition to start with? + if (pCondition == 0 || pCondition == EMPTY_STRING) + { + return bOK; + } + + // Parse condition to tokens (field ID operator value) + int nSize = strlen( pCondition ) + 1; + + char * pCopy = new char[ nSize ]; + if (pCopy == NULL) + { + return false; + } + + memcpy( pCopy, pCondition, nSize ); + + std::vector <LPSTR> tokens; + ParseTokens( " ", pCopy, tokens ); + + if (tokens.size() == 3) + { + // Covert first token to field ID + ULONG fieldID = strtoul( tokens[0], 0, 10 ); + + // Grab the value for the given field ID + LONGLONG fieldVal = 0; + bOK = StringToLONGLONG( tokens[2], 0, fieldVal ); + if (bOK == true) + { + std::string opStr = tokens[1]; + + // std::string version of Trim() + int nFirst = opStr.find_first_not_of( ' ' ); + int nLast = opStr.find_last_not_of( ' ' ); + if (nFirst == -1 || nLast == -1) + { + // Something went horribly wrong, empty string or all spaces + delete [] pCopy; + return false; + } + + opStr = opStr.substr( nFirst, nLast - nFirst + 1 ); + + // std::string version of MakeLower() + transform( opStr.begin(), opStr.end(), opStr.begin(), tolower ); + + bF2F = false; + if (opStr == "<") + { + op = eDB2_OP_LT; + } + else if (opStr == "<=") + { + op = eDB2_OP_LTE; + } + else if (opStr == "=") + { + op = eDB2_OP_EQ; + } + else if (opStr == "!=") + { + op = eDB2_OP_NEQ; + } + else if (opStr == ">=") + { + op = eDB2_OP_GTE; + } + else if (opStr == ">") + { + op = eDB2_OP_GT; + } + else if (opStr == "%") + { + op = eDB2_OP_DIV; + } + else if (opStr == "!%") + { + op = eDB2_OP_NDIV; + } + else if (opStr == "f<") + { + bF2F = true; + op = eDB2_OP_LT; + } + else if (opStr == "f<=") + { + bF2F = true; + op = eDB2_OP_LTE; + } + else if (opStr == "f=") + { + bF2F = true; + op = eDB2_OP_EQ; + } + else if (opStr == "f!=") + { + bF2F = true; + op = eDB2_OP_NEQ; + } + else if (opStr == "f>=") + { + bF2F = true; + op = eDB2_OP_GTE; + } + else if (opStr == "f>") + { + bF2F = true; + op = eDB2_OP_GT; + } + else if (opStr == "f%") + { + bF2F = true; + op = eDB2_OP_DIV; + } + else if (opStr == "f!%") + { + bF2F = true; + op = eDB2_OP_NDIV; + } + else + { + bOK = false; + } + + if (bOK == true) + { + id = fieldID; + val = fieldVal; + } + } + } + + delete [] pCopy; + + return bOK; +} + +/*=========================================================================== +METHOD: + BuildExpression (Static Public Method) + +DESCRIPTION: + Build a simple expression string + +PARAMETERS: + id [ I ] - Field ID + op [ I ] - Operator + val [ I ] - Value (or field ID) + bF2F [ I ] - Field to field expression? + +RETURN VALUE: + std::string +===========================================================================*/ +std::string sDB2Fragment::BuildExpression( + ULONG id, + eDB2ExpOperator op, + LONGLONG val, + bool bF2F ) +{ + std::ostringstream tmp; + + if (::IsValid( op ) == true) + { + if (bF2F == false) + { + switch (op) + { + case eDB2_EXPOP_ADD: + tmp << (UINT)id << " " << "+" << val; + break; + + case eDB2_EXPOP_SUB: + tmp << (UINT)id << " " << "-" << val; + break; + + case eDB2_EXPOP_MUL: + tmp << (UINT)id << " " << "*" << val; + break; + + case eDB2_EXPOP_DIV: + tmp << (UINT)id << " " << "/" << val; + break; + + case eDB2_EXPOP_REM: + tmp << (UINT)id << " " << "%" << val; + break; + + case eDB2_EXPOP_MIN: + tmp << (UINT)id << " " << "min" << val; + break; + + case eDB2_EXPOP_MAX: + tmp << (UINT)id << " " << "max" << val; + break; + } + } + else + { + switch (op) + { + case eDB2_EXPOP_ADD: + tmp << (UINT)id << " " << "f+" << val; + break; + + case eDB2_EXPOP_SUB: + tmp << (UINT)id << " " << "f-" << val; + break; + + case eDB2_EXPOP_MUL: + tmp << (UINT)id << " " << "f*" << val; + break; + + case eDB2_EXPOP_DIV: + tmp << (UINT)id << " " << "f/" << val; + break; + + case eDB2_EXPOP_REM: + tmp << (UINT)id << " " << "f%" << val; + break; + + case eDB2_EXPOP_MIN: + tmp << (UINT)id << " " << "fmin" << val; + break; + + case eDB2_EXPOP_MAX: + tmp << (UINT)id << " " << "fmax" << val; + break; + } + } + } + + std::string retStr = tmp.str(); + + return retStr; +} + +/*=========================================================================== +METHOD: + EvaluateExpression (Static Public Method) + +DESCRIPTION: + Evaluate a simple expression + +PARAMETERS: + valA [ I ] - Left value + op [ I ] - Operator + valB [ I ] - Right value + res [ O ] - Resulting value + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2Fragment::EvaluateExpression( + LONGLONG valA, + eDB2ExpOperator op, + LONGLONG valB, + LONGLONG & res ) +{ + bool bOK = false; + if (::IsValid( op ) == true) + { + bOK = true; + switch (op) + { + case eDB2_EXPOP_ADD: + res = valA + valB; + break; + + case eDB2_EXPOP_SUB: + res = valA - valB; + break; + + case eDB2_EXPOP_MUL: + res = valA * valB; + break; + + case eDB2_EXPOP_DIV: + res = valA / valB; + break; + + case eDB2_EXPOP_REM: + res = valA % valB; + break; + + case eDB2_EXPOP_MIN: + res = valA; + if (valA > valB) + { + res = valB; + } + break; + + case eDB2_EXPOP_MAX: + res = valA; + if (valA < valB) + { + res = valB; + } + break; + + default: + bOK = false; + break; + } + } + + return bOK; +} + +/*=========================================================================== +METHOD: + ParseExpression (Static Public Method) + +DESCRIPTION: + Parse a simple expression + +PARAMETERS: + pExpr [ I ] - Expression string + id [ O ] - Field ID + op [ O ] - Operator + val [ O ] - Value (or Field ID) + bF2F [ O ] - Field to field expression? + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2Fragment::ParseExpression( + LPCSTR pExpr, + ULONG & id, + eDB2ExpOperator & op, + LONGLONG & val, + bool & bF2F ) +{ + // Assume error + bool bOK = false; + + // Even a condition to start with? + if (pExpr == 0 || pExpr == EMPTY_STRING) + { + return bOK; + } + + // Parse condition to tokens (field ID operator value) + int nSize = strlen( pExpr ) + 1; + + char * pCopy = new char[ nSize ]; + if (pCopy == NULL) + { + return false; + } + + memcpy( pCopy, pExpr, nSize ); + + std::vector <LPSTR> tokens; + ParseTokens( " ", pCopy, tokens ); + + if (tokens.size() == 3) + { + // Covert first token to field ID + ULONG fieldID = strtoul( tokens[0], 0, 10 ); + + // Grab the value for the given field ID + LONGLONG fieldVal = 0; + bOK = StringToLONGLONG( tokens[2], 0, fieldVal ); + if (bOK == true) + { + std::string opStr = tokens[1]; + + // std::string version of Trim() + int nFirst = opStr.find_first_not_of( ' ' ); + int nLast = opStr.find_last_not_of( ' ' ); + if (nFirst == -1 || nLast == -1) + { + // Something went horribly wrong, empty string or all spaces + delete [] pCopy; + return false; + } + + opStr = opStr.substr( nFirst, nLast - nFirst + 1 ); + + // std::string version of MakeLower() + transform( opStr.begin(), opStr.end(), opStr.begin(), tolower ); + + bF2F = false; + if (opStr == "+") + { + op = eDB2_EXPOP_ADD; + } + else if (opStr == "-") + { + op = eDB2_EXPOP_SUB; + } + else if (opStr == "*") + { + op = eDB2_EXPOP_MUL; + } + else if (opStr == "/") + { + op = eDB2_EXPOP_DIV; + } + else if (opStr == "%") + { + op = eDB2_EXPOP_REM; + } + else if (opStr == "min") + { + op = eDB2_EXPOP_MIN; + } + else if (opStr == "max") + { + op = eDB2_EXPOP_MAX; + } + else if (opStr == "f+") + { + bF2F = true; + op = eDB2_EXPOP_ADD; + } + else if (opStr == "f-") + { + bF2F = true; + op = eDB2_EXPOP_SUB; + } + else if (opStr == "f*") + { + bF2F = true; + op = eDB2_EXPOP_MUL; + } + else if (opStr == "f/") + { + bF2F = true; + op = eDB2_EXPOP_DIV; + } + else if (opStr == "f%") + { + bF2F = true; + op = eDB2_EXPOP_REM; + } + else if (opStr == "fmin") + { + bF2F = true; + op = eDB2_EXPOP_MIN; + } + else if (opStr == "fmax") + { + bF2F = true; + op = eDB2_EXPOP_MAX; + } + else + { + bOK = false; + } + + if (bOK == true) + { + id = fieldID; + val = fieldVal; + } + } + } + + delete [] pCopy; + return bOK; +} + +/*=========================================================================*/ +// sDB2Field Methods +/*=========================================================================*/ + +/*=========================================================================== +METHOD: + FromString (Public Method) + +DESCRIPTION: + Populate this object from a string + +PARAMETERS: + pStr [ I ] - String to populate object from + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2Field::FromString( LPSTR pStr ) +{ + bool bRC = false; + + // Should be + // 0: ID + // 1: "Name" + // 2: Size + // 3: Field type + // 4: Field type value + // 5: Hexadecimal + // 6: Description ID (optional) + // 7: Internal only flag (optional) + const ULONG NUM_REQ_VALS = 6; + + std::vector <LPSTR> tokens; + ParseTokens( DB2_VALUE_SEP, pStr, tokens ); + + ULONG toks = (ULONG)tokens.size(); + + if (toks >= NUM_REQ_VALS) + { + // Remove quotes from name string and copy + LPCSTR pCopy = CopyQuotedString( tokens[1] ); + if (pCopy != 0) + { + mID = strtoul( tokens[0], 0, 10 ); + mSize = strtoul( tokens[2], 0, 10 ); + mpName = pCopy; + mType = (eDB2FieldType)strtol( tokens[3], 0, 10 ); + mTypeVal = strtoul( tokens[4], 0, 10 ); + mbHex = (strtoul( tokens[5], 0, 10 ) != 0); + + // Description ID? + if (toks > NUM_REQ_VALS) + { + mDescriptionID = strtol( tokens[NUM_REQ_VALS], 0, 10 ); + } + + // Internal only flag? + if (toks > NUM_REQ_VALS + 1) + { + mbInternal = (strtoul( tokens[NUM_REQ_VALS + 1], 0, 10 ) != 0); + } + + bRC = IsValid(); + } + } + + return bRC; +} + +/*=========================================================================== +METHOD: + IsValid (Public Method) + +DESCRIPTION: + Is this object valid? + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2Field::IsValid() const +{ + // There has to be a non-empty name + if (mpName == 0 || mpName[0] == 0) + { + return false; + } + + // The field type must be valid + if (::IsValid( mType ) == false) + { + return false; + } + + // For validating size + ULONG minSz = 1; + ULONG maxSz = 8; + ULONG modVal = 0; + + // What type of field is this? + if (mType == eDB2_FIELD_STD) + { + eDB2StdFieldType ft = (eDB2StdFieldType)mTypeVal; + if (::IsValid( ft ) == false) + { + return false; + } + + switch (ft) + { + case eDB2_FIELD_STDTYPE_BOOL: + maxSz = 64; + break; + + case eDB2_FIELD_STDTYPE_INT16: + case eDB2_FIELD_STDTYPE_UINT16: + maxSz = 16; + break; + + case eDB2_FIELD_STDTYPE_INT32: + case eDB2_FIELD_STDTYPE_UINT32: + case eDB2_FIELD_STDTYPE_FLOAT32: + maxSz = 32; + break; + + case eDB2_FIELD_STDTYPE_INT64: + case eDB2_FIELD_STDTYPE_UINT64: + case eDB2_FIELD_STDTYPE_FLOAT64: + maxSz = 64; + break; + + case eDB2_FIELD_STDTYPE_STRING_A: + case eDB2_FIELD_STDTYPE_STRING_U8: + // One character, no maximum + minSz = 8; + maxSz = 0; + modVal = 8; + break; + + case eDB2_FIELD_STDTYPE_STRING_U: + // One UNICODE character, no maximum + minSz = 16; + maxSz = 0; + modVal = 16; + break; + + case eDB2_FIELD_STDTYPE_STRING_ANT: + case eDB2_FIELD_STDTYPE_STRING_UNT: + case eDB2_FIELD_STDTYPE_STRING_U8NT: + // Size needs to be specified as 0 + minSz = maxSz = 0; + break; + } + } + else + { + // Enum must be between 1 - 32 bits in size + maxSz = 32; + } + + if (mSize < minSz) + { + return false; + } + + if (maxSz != 0 && mSize > maxSz) + { + return false; + } + + if (modVal != 0 && (mSize % modVal) != 0) + { + return false; + } + + if (mDescriptionID < -1) + { + return false; + } + + // The name must be valid + std::string name = mpName; + if (name.find( DB2_VALUE_SEP ) != -1 || name.find( DB2_SUBVAL_SEP ) != -1) + { + return false; + } + + return true; +} + +/*=========================================================================*/ +// sDB2Category Methods +/*=========================================================================*/ + +/*=========================================================================== +METHOD: + FromString (Public Method) + +DESCRIPTION: + Populate this object from a string + +PARAMETERS: + pStr [ I ] - String to populate object from + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2Category::FromString( LPSTR pStr ) +{ + bool bRC = false; + + // Should be + // 0: ID + // 1: "Name" + // 2: Description ID + // 3: Parent ID + const ULONG NUM_REQ_VALS = 4; + + std::vector <LPSTR> tokens; + ParseTokens( DB2_VALUE_SEP, pStr, tokens ); + + ULONG toks = (ULONG)tokens.size(); + if (toks >= NUM_REQ_VALS) + { + // Remove quotes from name string and copy + LPCSTR pCopy = CopyQuotedString( tokens[1] ); + if (pCopy != 0) + { + mID = strtoul( tokens[0], 0, 10 ); + mParentID = strtol( tokens[3], 0, 10 ); + mpName = pCopy; + + // Old format used to be a description string, so + // first check for quotes + if (tokens[2][0] != '\"') + { + mDescriptionID = strtol( tokens[2], 0, 10 ); + } + + bRC = IsValid(); + } + } + + return bRC; +} + +/*=========================================================================== +METHOD: + IsValid (Public Method) + +DESCRIPTION: + Is this object valid? + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2Category::IsValid() const +{ + // The parent ID has to be greater than or equal to -1 + if (mParentID < -1) + { + return false; + } + + // There has to be a non-empty name + if (mpName == 0 || mpName[0] == 0) + { + return false; + } + + if (mDescriptionID < -1) + { + return false; + } + + return true; +} + +/*=========================================================================*/ +// sDB2NVItem Methods +/*=========================================================================*/ + +/*=========================================================================== +METHOD: + FromString (Public Method) + +DESCRIPTION: + Populate this object from a string + +PARAMETERS: + pStr [ I ] - String to populate object from + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2NVItem::FromString( LPSTR pStr ) +{ + bool bRC = false; + + // Should be + // 0: NV Item number + // 1: "Name" + // 2: "Categories" + // 3: Description ID + const ULONG NUM_REQ_VALS = 4; + + std::vector <LPSTR> tokens; + ParseTokens( DB2_VALUE_SEP, pStr, tokens ); + + ULONG toks = (ULONG)tokens.size(); + if (toks >= NUM_REQ_VALS) + { + // Remove quotes from name string and copy + LPCSTR pCopy = CopyQuotedString( tokens[1] ); + if (pCopy != 0) + { + CSVStringToContainer( DB2_SUBVAL_SEP, tokens[2], mCategoryIDs ); + + mItem = strtoul( tokens[0], 0, 10 ); + mpName = pCopy; + + // Old format used to be a description string, so + // first check for quotes + if (tokens[3][0] != '\"') + { + mDescriptionID = strtol( tokens[3], 0, 10 ); + } + + bRC = IsValid(); + } + } + + return bRC; +} + +/*=========================================================================== +METHOD: + IsValid (Public Method) + +DESCRIPTION: + Is this object valid? + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2NVItem::IsValid() const +{ + // There has to be at least one category ID + ULONG cats = (ULONG)mCategoryIDs.size(); + if (cats < 1) + { + return false; + } + + // The category IDs have to be greater than or equal to -1 + std::set <int>::const_iterator pIter = mCategoryIDs.begin(); + while (pIter != mCategoryIDs.end()) + { + if (*pIter++ < -1) + { + return false; + } + } + + // There has to be a non-empty name + if (mpName == 0 || mpName[0] == 0) + { + return false; + } + + if (mDescriptionID < -1) + { + return false; + } + + return true; +} + +/*=========================================================================*/ +// sDB2Enum Methods +/*=========================================================================*/ + +/*=========================================================================== +METHOD: + FromString (Public Method) + +DESCRIPTION: + Populate this object from a string + +PARAMETERS: + pStr [ I ] - String to populate object from + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2Enum::FromString( LPSTR pStr ) +{ + bool bRC = false; + + // Should be + // 0: ID + // 1: "Name" + // 2: Description ID + // 3: Internal? + const ULONG NUM_REQ_VALS = 4; + + std::vector <LPSTR> tokens; + ParseTokens( DB2_VALUE_SEP, pStr, tokens ); + + ULONG toks = (ULONG)tokens.size(); + if (toks >= NUM_REQ_VALS) + { + // Remove quotes from name string and copy + LPCSTR pCopy = CopyQuotedString( tokens[1] ); + if (pCopy != 0) + { + mID = strtoul( tokens[0], 0, 10 ); + mbInternal = (strtoul( tokens[3], 0, 10 ) != 0); + mpName = pCopy; + + // Old format used to be a description string, so + // first check for quotes + if (tokens[2][0] != '\"') + { + mDescriptionID = strtol( tokens[2], 0, 10 ); + } + + bRC = IsValid(); + } + } + + return bRC; +} + +/*=========================================================================== +METHOD: + IsValid (Public Method) + +DESCRIPTION: + Is this object valid? + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2Enum::IsValid() const +{ + // There has to be a non-empty name + if (mpName == 0 || mpName[0] == 0) + { + return false; + } + + if (mDescriptionID < -1) + { + return false; + } + + return true; +} + +/*=========================================================================*/ +// sDB2EnumEntry Methods +/*=========================================================================*/ + +/*=========================================================================== +METHOD: + FromString (Public Method) + +DESCRIPTION: + Populate this object from a string + +PARAMETERS: + pStr [ I ] - String to populate object from + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2EnumEntry::FromString( LPSTR pStr ) +{ + bool bRC = false; + + // Should be + // 0: ID + // 1: Value + // 2: "Name" + // 3: Description ID (optional) + const ULONG NUM_REQ_VALS = 3; + + std::vector <LPSTR> tokens; + ParseTokens( DB2_VALUE_SEP, pStr, tokens ); + + ULONG toks = (ULONG)tokens.size(); + if (toks >= NUM_REQ_VALS) + { + // Remove quotes from name string and copy + LPCSTR pCopy = CopyQuotedString( tokens[2] ); + if (pCopy != 0) + { + mID = strtoul( tokens[0], 0, 10 ); + mpName = pCopy; + + // Enum entries are signed by definition, but can be entered + // in hexadecimal as they may be unsigned in practice + LONG val = -1; + StringToLONG( tokens[1], 0, val ); + mValue = (INT)val; + + // Determine hexadecimal flag by performing case-insensitve comparison + // of the value string's first two characters with "0x" + mbHex = (strncmp( tokens[1], "0x", 2 ) == 0); + + // Description ID? + if (toks > NUM_REQ_VALS) + { + mDescriptionID = strtol( tokens[NUM_REQ_VALS], 0, 10 ); + } + + bRC = IsValid(); + } + } + + return bRC; +} + +/*=========================================================================== +METHOD: + IsValid (Public Method) + +DESCRIPTION: + Is this object valid? + +RETURN VALUE: + bool +===========================================================================*/ +bool sDB2EnumEntry::IsValid() const +{ + // There has to be a non-empty name + if (mpName == 0 || mpName[0] == 0) + { + return false; + } + + if (mDescriptionID < -1) + { + return false; + } + + return true; +} + +/*=========================================================================*/ +// cCoreDatabase Methods +/*=========================================================================*/ + +/*=========================================================================== +METHOD: + cCoreDatabase (Public Method) + +DESCRIPTION: + Constructor + +RETURN VALUE: + None +===========================================================================*/ +cCoreDatabase::cCoreDatabase() + : mpLog( &gDB2DefaultLog ) +{ + // Nothing to do - database empty, call Initialize() +} + +/*=========================================================================== +METHOD: + ~cCoreDatabase (Public Method) + +DESCRIPTION: + Destructor + +RETURN VALUE: + None +===========================================================================*/ +cCoreDatabase::~cCoreDatabase() +{ + Exit(); +} + +/*=========================================================================== +METHOD: + Initialize (Public Method) + +DESCRIPTION: + Version to Load from file + Initialize the database - this must be done once (and only once) + prior to the database being accessed + +PARAMETERS + pBasePath [ I ] - Base path to database files + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::Initialize( LPCSTR pBasePath ) +{ + bool bRC = true; + + // Cleanup the last database (if necessary) + Exit(); + + bRC &= LoadEnumTables( pBasePath ); + bRC &= LoadStructureTables( pBasePath ); + + // Build the modifier tables + bRC &= BuildModifierTables(); + + return bRC; +} + +/*=========================================================================== +METHOD: + Initialize (Public Method) + +DESCRIPTION: + Version to Load from internal pointers + Initialize the database - this must be done once (and only once) + prior to the database being accessed + +PARAMETERS + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::Initialize() +{ + bool bRC = true; + + // Cleanup the last database (if necessary) + Exit(); + + bRC &= LoadEnumTables(); + bRC &= LoadStructureTables(); + + // Build the modifier tables + bRC &= BuildModifierTables(); + + return bRC; +} + +/*=========================================================================== +METHOD: + Exit (Public Method) + +DESCRIPTION: + Exit (cleanup) the database + +RETURN VALUE: + None +===========================================================================*/ +void cCoreDatabase::Exit() +{ + FreeDB2Table( mEntityFields ); + FreeDB2Table( mEntityStructs ); + FreeDB2Table( mProtocolEntities ); + + FreeDB2Table( mEnumNameMap ); + FreeDB2Table( mEnumEntryMap ); + + tDB2EntityNavMap::iterator pIter = mEntityNavMap.begin(); + while (pIter != mEntityNavMap.end()) + { + cDB2NavTree * pNav = pIter->second; + if (pNav != 0) + { + delete pNav; + } + + pIter++; + } + + mEntityNavMap.clear(); +} + +/*=========================================================================== +METHOD: + GetEntityNavTree (Public Method) + +DESCRIPTION: + Get the entity navigation tree for the given protocol entity, if none + exists one will be built and returned + +PARAMETERS + key [ I ] - Protocol entity key + +RETURN VALUE: + const cDB2NavTree * (0 upon error) +===========================================================================*/ +const cDB2NavTree * cCoreDatabase::GetEntityNavTree( + const std::vector <ULONG> & key ) const +{ + // Look up entity definition (to find DB string address) + sDB2ProtocolEntity tmpEntity; + bool bFound = FindEntity( key, tmpEntity ); + + // Did we find it? + if (bFound == false) + { + // No matching definition in database + return 0; + } + + // Obtain the canonical key and use it to look up the nav tree + tDB2EntityNavMap::const_iterator pIter = mEntityNavMap.find( key ); + if (pIter != mEntityNavMap.end()) + { + return pIter->second; + } + + // None found, go ahead and build one + cDB2NavTree * pNavTree = new cDB2NavTree( *this ); + if (pNavTree != 0) + { + bool bOK = pNavTree->BuildTree( key ); + if (bOK == true) + { + // Store it and return it to the user + std::pair <std::vector <ULONG>, cDB2NavTree *> e( key, pNavTree ); + mEntityNavMap.insert( e ); + } + else + { + delete pNavTree; + pNavTree = 0; + } + } + + return pNavTree; +} + +/*=========================================================================== +METHOD: + FindEntity (Public Method) + +DESCRIPTION: + Find the protocol entity with the specified extended ID + +PARAMETERS + key [ I ] - Protocol entity key to find + entity [ O ] - Protocol entity (if found) + +RETURN VALUE: + bool - Success? +===========================================================================*/ +bool cCoreDatabase::FindEntity( + const std::vector <ULONG> & key, + sDB2ProtocolEntity & entity ) const +{ + // Assume failure + bool bFound = false; + + tDB2EntityMap::const_iterator pEntity = mProtocolEntities.find( key ); + if (pEntity != mProtocolEntities.end()) + { + entity = pEntity->second; + bFound = true; + } + + return bFound; +} + +/*=========================================================================== +METHOD: + FindEntity (Public Method) + +DESCRIPTION: + Find the protocol entity with the specified name + +PARAMETERS + pEntityName [ I ] - Protocol entity name to find + entity [ O ] - Protocol entity (if found) + +RETURN VALUE: + bool - Success? +===========================================================================*/ +bool cCoreDatabase::FindEntity( + LPCSTR pEntityName, + sDB2ProtocolEntity & entity ) const +{ + // Assume failure + bool bFound = false; + if (pEntityName != 0 && pEntityName[0] != 0) + { + tDB2EntityNameMap::const_iterator pIter = mEntityNames.find( pEntityName ); + if (pIter != mEntityNames.end()) + { + const std::vector <ULONG> & key = pIter->second; + bFound = FindEntity( key, entity ); + } + } + + return bFound; +} + +/*=========================================================================== +METHOD: + MapEntityNameToID (Public Method) + +DESCRIPTION: + Map a protocol entity name to an ID + +PARAMETERS + pName [ I ] - Protocol entity name + key [ O ] - Upon success, the ID corresponding to protocol entity + +RETURN VALUE: + bool - Success? +===========================================================================*/ +bool cCoreDatabase::MapEntityNameToID( + LPCSTR pName, + std::vector <ULONG> & key ) const +{ + // Assume failure + bool bOK = false; + + if (pName != 0 && pName[0] != 0) + { + std::string tmp = pName; + + // std::string version of Trim() + int nFirst = tmp.find_first_not_of( ' ' ); + int nLast = tmp.find_last_not_of( ' ' ); + if (nFirst == -1 || nLast == -1) + { + // Something went wrong, empty string or all spaces + return false; + } + + tmp = tmp.substr( nFirst, nLast - nFirst + 1 ); + + + tDB2EntityNameMap::const_iterator pIter = mEntityNames.find( tmp.c_str() ); + if (pIter != mEntityNames.end()) + { + key = pIter->second; + bOK = true; + } + } + + return bOK; +} + +/*=========================================================================== +METHOD: + MapEnumToString (Public Method) + +DESCRIPTION: + Map the given enum value (specified by enum ID, and enum value) to + the enum value name string + +PARAMETERS + enumID [ I ] - ID of the enumeration + enumVal [ I ] - Enum value to map + bSimpleErrFmt [ I ] - If the eunum value cannot be mapped to a string + what should this method return? + + If 'true' then just the value as a string + If 'false' then the enum ID, value, and 'Unknown' + + bHex [ I ] - Hexadecimal output on mapping error? + +RETURN VALUE: + std::string - The enum name (or error string if enum value is not found) +===========================================================================*/ +std::string cCoreDatabase::MapEnumToString( + ULONG enumID, + int enumVal, + bool bSimpleErrFmt, + bool bHex ) const +{ + std::string retStr = ""; + + // Form the lookup key + std::pair <ULONG, int> key( enumID, enumVal ); + + // Look up the enum value descriptor + tDB2EnumEntryMap::const_iterator pVals = mEnumEntryMap.find( key ); + if (pVals != mEnumEntryMap.end()) + { + const sDB2EnumEntry & entry = pVals->second; + retStr = entry.mpName; + } + + // No string? + if (retStr.size() <= 0) + { + std::ostringstream tmp; + + if (bSimpleErrFmt == false) + { + tmp << "Unknown [" << (UINT)enumID << "/"; + } + + if (bHex == true) + { + tmp << std::ios_base::hex << std::ios_base::uppercase + << std::ios_base::showbase << enumVal; + } + else + { + tmp << enumVal; + } + + retStr = tmp.str(); + } + + return retStr; +} + +/*=========================================================================== +METHOD: + MapEnumToString (Public Method) + +DESCRIPTION: + Map the given enum value (specified by enum name, and enum value) to + the enum value name string + +PARAMETERS + pEnumName [ I ] - Name of the enumeration + enumVal [ I ] - Enum value to map + bSimpleErrFmt [ I ] - If the eunum value cannot be mapped to a string + what should this method return? + + If 'true' then just the value as a string + If 'false' then the enum ID, value, and 'Unknown' + + bHex [ I ] - Hexadecimal output on mapping error? + +RETURN VALUE: + std::string - The enum name (or error string if enum value is not found) +===========================================================================*/ +std::string cCoreDatabase::MapEnumToString( + LPCSTR pEnumName, + int enumVal, + bool bSimpleErrFmt, + bool bHex ) const +{ + std::string retStr = ""; + + tDB2EnumMap::const_iterator pEnumMapIter = mEnumMap.find( pEnumName ); + if (pEnumMapIter != mEnumMap.end()) + { + const std::map <int, LPCSTR> & entries = pEnumMapIter->second.second; + std::map <int, LPCSTR>::const_iterator pEntry; + + pEntry = entries.find( enumVal ); + if (pEntry != entries.end()) + { + retStr = pEntry->second; + } + } + + // No string? + if (retStr.size() <= 0) + { + std::ostringstream tmp; + + if (bSimpleErrFmt == false) + { + if (pEnumName == 0) + { + pEnumName = "?"; + } + + tmp << "Unknown [" << pEnumName << "/"; + } + + if (bHex == true) + { + tmp << std::ios_base::hex << std::ios_base::uppercase + << std::ios_base::showbase << enumVal; + } + else + { + tmp << enumVal; + } + + retStr = tmp.str(); + } + + return retStr; +} + +/*=========================================================================== +METHOD: + AssembleEnumMap (Internal Method) + +DESCRIPTION: + Assemble the internal enum map from the enum and enum entry tables + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::AssembleEnumMap() +{ + bool bOK = true; + + // Empty it out first + mEnumMap.clear(); + + tDB2EnumEntryMap::const_iterator pEntry = mEnumEntryMap.begin(); + if (pEntry == mEnumEntryMap.end()) + { + return bOK; + } + + // Set initial enum ID + ULONG currentID = pEntry->second.mID; + + std::map <int, LPCSTR> entries; + while (pEntry != mEnumEntryMap.end()) + { + const sDB2EnumEntry & entry = pEntry->second; + pEntry++; + + if (entry.IsValid() == false) + { + continue; + } + + if (currentID != entry.mID) + { + if (entries.size() > 0) + { + // Look up the enum name + tDB2EnumNameMap::const_iterator pEnum; + pEnum = mEnumNameMap.find( currentID ); + + if (pEnum != mEnumNameMap.end()) + { + const sDB2Enum & dbEnum = pEnum->second; + if (mEnumMap.find( dbEnum.mpName ) == mEnumMap.end()) + { + tDB2EnumMapPair tmp( dbEnum.mID, entries ); + mEnumMap[dbEnum.mpName] = tmp; + } + else + { + // Hmm, duplicate enum names discovered + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_ENUM_MAIN + << "] Duplicate enum (by name) detected \'" + << dbEnum.mpName << "\'"; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bOK = false; + } + } + else + { + // Hmm, missing enum ID discovered + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_ENUM_MAIN + << "] Missing enum ID detected " + << currentID; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bOK = false; + } + + // Clear out enum entries for next pass and add this entry + entries.clear(); + entries[entry.mValue] = entry.mpName; + + // Adjust current enum ID + currentID = entry.mID; + } + } + else + { + if (entries.find( entry.mValue ) == entries.end()) + { + entries[entry.mValue] = entry.mpName; + } + else + { + // Hmm, duplicate enum entry values discovered + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_ENUM_ENTRY + << "] Duplicate enum entries detected \'" + << entry.mpName << "\', " << entry.mValue; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bOK = false; + } + } + } + + // Add in the last enum + if (mEnumEntryMap.size() > 0 && entries.size() > 0) + { + // Look up the enum name + tDB2EnumNameMap::const_iterator pEnum; + pEnum = mEnumNameMap.find( currentID ); + + if (pEnum != mEnumNameMap.end()) + { + const sDB2Enum & dbEnum = pEnum->second; + if (mEnumMap.find( dbEnum.mpName ) == mEnumMap.end()) + { + tDB2EnumMapPair tmp( dbEnum.mID, entries ); + mEnumMap[dbEnum.mpName] = tmp; + } + else + { + // Hmm, duplicate enum names discovered + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_ENUM_MAIN + << "] Duplicate enum (by name) detected \'" + << dbEnum.mpName << "\'"; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bOK = false; + } + } + else + { + // Hmm, missing enum ID discovered + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_ENUM_MAIN + << "] Missing enum ID detected " << currentID; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bOK = false; + } + } + + return bOK; +} + +/*=========================================================================== +METHOD: + AssembleEntityNameMap (Internal Method) + +DESCRIPTION: + Assemble the internal protocol entity name map + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::AssembleEntityNameMap() +{ + // Assume success + bool bOK = true; + + // Empty it out first + mEntityNames.clear(); + + // Go through and build the event name table + tDB2EntityMap::const_iterator pIter = mProtocolEntities.begin(); + while (pIter != mProtocolEntities.end()) + { + const sDB2ProtocolEntity & obj = pIter->second; + pIter++; + + if (obj.IsValid() == false) + { + continue; + } + + tDB2EntityNameMap::const_iterator pNames; + pNames = mEntityNames.find( obj.mpName ); + if (pNames == mEntityNames.end()) + { + mEntityNames[obj.mpName] = obj.GetKey(); + } + else + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_ENTITY + << "] Duplicate protocol entity (by name) detected \'" + << obj.mpName << "\'"; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bOK = false; + } + } + + return bOK; +} + +/*=========================================================================== +METHOD: + BuildModifierTables (Internal Method) + +DESCRIPTION: + Build the parsed fragment modifier maps, i.e. convert the modifier + text string to something more useful by database clients + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::BuildModifierTables() +{ + // Assume success + bool bOK = true; + + // Parse all fragment modifiers + tDB2FragmentMap::const_iterator pFragIter = mEntityStructs.begin(); + while (pFragIter != mEntityStructs.end()) + { + // Grab new fragment + const sDB2Fragment & frag = pFragIter->second; + pFragIter++; + + // Skip invalid/unmodified fragments + if ( (frag.IsValid() == false) + || (frag.mpModifierValue == 0) + || (frag.mpModifierValue == EMPTY_STRING) ) + { + continue; + } + + switch (frag.mModifierType) + { + case eDB2_MOD_CONSTANT_ARRAY: + case eDB2_MOD_VARIABLE_ARRAY: + case eDB2_MOD_VARIABLE_STRING1: + case eDB2_MOD_VARIABLE_STRING2: + case eDB2_MOD_VARIABLE_STRING3: + { + ULONG val = strtoul( frag.mpModifierValue, 0, 0 ); + mArray1ModMap[frag.mpModifierValue] = val; + } + break; + + case eDB2_MOD_VARIABLE_ARRAY2: + { + // Parse modifier to tokens (start stop) + int nSize = strlen( frag.mpModifierValue ) + 1; + + char * pCopy = new char[ nSize ]; + if (pCopy == NULL) + { + return false; + } + + memcpy( pCopy, frag.mpModifierValue, nSize ); + + std::vector <ULONG> indices; + CSVStringToContainer( " ", pCopy, indices ); + + delete [] pCopy; + if (indices.size() == 2) + { + std::pair <ULONG, ULONG> val; + val.first = indices[0]; + val.second = indices[1]; + mArray2ModMap[frag.mpModifierValue] = val; + } + } + break; + + case eDB2_MOD_OPTIONAL: + { + sDB2SimpleCondition con; + + // Parse condition to tokens (field ID operator value) + bool bRC = sDB2Fragment::ParseCondition( frag.mpModifierValue, + con.mID, + con.mOperator, + con.mValue, + con.mbF2F ); + + if (bRC == true) + { + mOptionalModMap[frag.mpModifierValue] = con; + } + } + break; + + case eDB2_MOD_VARIABLE_ARRAY3: + { + sDB2SimpleExpression exp; + + // Parse condition to tokens (field ID operator value) + bool bRC = sDB2Fragment::ParseExpression( frag.mpModifierValue, + exp.mID, + exp.mOperator, + exp.mValue, + exp.mbF2F ); + + if (bRC == true) + { + mExpressionModMap[frag.mpModifierValue] = exp; + } + } + break; + } + } + + return bOK; +} + + +/*=========================================================================== +METHOD: + CheckAndSetBasePath (Internal Method) + +DESCRIPTION: + Check and set the passed in path to something that is useful + +PARAMETERS + pBasePath [ I ] - Base path + +RETURN VALUE: + std::string - The enum name (or error string if enum value is not found) +===========================================================================*/ +std::string cCoreDatabase::CheckAndSetBasePath( LPCSTR pBasePath ) const +{ + std::string basePath = "."; + if (pBasePath != 0 && pBasePath[0] != 0) + { + struct stat fileInfo; + if (stat( pBasePath, &fileInfo ) == 0) + { + if (S_ISDIR( fileInfo.st_mode ) == true) + { + // It's a directory + basePath = pBasePath; + } + } + } + + return basePath; +} + +/*=========================================================================== +METHOD: + LoadStructureTables (Internal Method) + +DESCRIPTION: + Load all tables related to structure (entity, struct, field, format spec) + +PARAMETERS + pBasePath [ I ] - Base path to database files + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::LoadStructureTables( LPCSTR pBasePath ) +{ + bool bRC = true; + + std::string basePath = CheckAndSetBasePath( pBasePath ); + basePath += "/"; + + std::string fn = basePath; + fn += DB2_FILE_PROTOCOL_FIELD; + bRC &= LoadDB2Table( (LPCSTR)fn.c_str(), + mEntityFields, + false, + DB2_TABLE_PROTOCOL_FIELD, + *mpLog ); + + fn = basePath; + fn += DB2_FILE_PROTOCOL_STRUCT; + bRC &= LoadDB2Table( (LPCSTR)fn.c_str(), + mEntityStructs, + false, + DB2_TABLE_PROTOCOL_STRUCT, + *mpLog ); + + fn = basePath; + fn += DB2_FILE_PROTOCOL_ENTITY; + bRC &= LoadDB2Table( (LPCSTR)fn.c_str(), + mProtocolEntities, + false, + DB2_TABLE_PROTOCOL_ENTITY, + *mpLog ); + + // Validate protocol entities + bRC &= ValidateStructures(); + + // Build internal protocol entity name map + bRC &= AssembleEntityNameMap(); + + return bRC; +} + +/*=========================================================================== +METHOD: + LoadStructureTables (Internal Method) + +DESCRIPTION: + Load all tables related to structure (entity, struct, field) + +PARAMETERS + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::LoadStructureTables() +{ + bool bRC = true; + + // Calculate sizes + int nFieldSize = (const char*)&_binary_QMI_Field_txt_end - + (const char*)&_binary_QMI_Field_txt_start; + int nStructSize = (const char*)&_binary_QMI_Struct_txt_end - + (const char*)&_binary_QMI_Struct_txt_start; + int nEntitySize = (const char*)&_binary_QMI_Entity_txt_end - + (const char*)&_binary_QMI_Entity_txt_start; + + bRC &= LoadDB2Table( (const char*)&_binary_QMI_Field_txt_start, + nFieldSize, + mEntityFields, + false, + DB2_TABLE_PROTOCOL_FIELD, + *mpLog ); + + bRC &= LoadDB2Table( (const char*)&_binary_QMI_Struct_txt_start, + nStructSize, + mEntityStructs, + false, + DB2_TABLE_PROTOCOL_STRUCT, + *mpLog ); + + bRC &= LoadDB2Table( (const char*)&_binary_QMI_Entity_txt_start, + nEntitySize, + mProtocolEntities, + false, + DB2_TABLE_PROTOCOL_ENTITY, + *mpLog ); + + // Validate protocol entities + bRC &= ValidateStructures(); + + // Build internal protocol entity name map + bRC &= AssembleEntityNameMap(); + + return bRC; +} + +/*=========================================================================== +METHOD: + LoadEnumTables (Internal Method) + +DESCRIPTION: + Load all enumeration tables + +PARAMETERS + pBasePath [ I ] - Base path to database files + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::LoadEnumTables( LPCSTR pBasePath ) +{ + bool bRC = true; + + std::string basePath = CheckAndSetBasePath( pBasePath ); + basePath += "/"; + + + std::string fn = basePath; + fn += DB2_FILE_ENUM_MAIN; + bRC &= LoadDB2Table( (LPCSTR)fn.c_str(), + mEnumNameMap, + false, + DB2_TABLE_ENUM_MAIN, + *mpLog ); + + fn = basePath; + fn += DB2_FILE_ENUM_ENTRY; + bRC &= LoadDB2Table( (LPCSTR)fn.c_str(), + mEnumEntryMap, + false, + DB2_TABLE_ENUM_ENTRY, + *mpLog ); + + // Build the enum map + bRC &= AssembleEnumMap(); + + return bRC; +} + +/*=========================================================================== +METHOD: + LoadEnumTables (Internal Method) + +DESCRIPTION: + Load all enumeration tables + +PARAMETERS + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::LoadEnumTables() +{ + bool bRC = true; + // Calculate sizes + int nEnumSize = (const char*)&_binary_QMI_Enum_txt_end - + (const char*)&_binary_QMI_Enum_txt_start; + int nEnumEntrySize = (const char*)&_binary_QMI_EnumEntry_txt_end - + (const char*)&_binary_QMI_EnumEntry_txt_start; + + bRC &= LoadDB2Table( (const char*)&_binary_QMI_Enum_txt_start, + nEnumSize, + mEnumNameMap, + false, + DB2_TABLE_ENUM_MAIN, + *mpLog ); + + bRC &= LoadDB2Table( (const char*)&_binary_QMI_EnumEntry_txt_start, + nEnumEntrySize, + mEnumEntryMap, + false, + DB2_TABLE_ENUM_ENTRY, + *mpLog ); + + // Build the enum map + bRC &= AssembleEnumMap(); + + return bRC; +} + +/*=========================================================================== +METHOD: + ValidateStructures (Internal Method) + +DESCRIPTION: + Validate (and attempt repair of) structure related tables + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::ValidateStructures() +{ + // Assume success + bool bRC = true; + + tDB2EntityMap::iterator pEntity = mProtocolEntities.begin(); + while (pEntity != mProtocolEntities.end()) + { + sDB2ProtocolEntity & entity = pEntity->second; + + // Structure ID given? + if (entity.mStructID != -1) + { + // Yes, validate individual structure + std::set <ULONG> fields; + bool bValid = ValidateStructure( (ULONG)entity.mStructID, fields, 0 ); + + // Not valid? + if (bValid == false) + { + // Invalid structure, reset to none + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid struct, ID " << entity.mStructID; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + entity.mStructID = -1; + + // We found at least one bad structure + bRC = false; + } + } + + pEntity++; + } + + return bRC; +} + +/*=========================================================================== +METHOD: + ValidateStructure (Internal Method) + +DESCRIPTION: + Validate a single structure + +PARAMETERS: + structID [ I ] - ID of structure being evaluated + fields [I/O] - List of 'known' field IDs + depth [I/O] - Recursion depth + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::ValidateStructure( + ULONG structID, + std::set <ULONG> & fields, + ULONG depth ) +{ + // Assume success + bool bRC = true; + + // Reached our limit? + if (depth++ >= MAX_NESTING_LEVEL) + { + // Invalid structure + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Max depth exceeded, possible loop, struct ID " << structID; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + return false; + } + + // Grab first fragment of structure + std::pair <ULONG, ULONG> id( structID, 0 ); + tDB2FragmentMap::const_iterator pFrag = mEntityStructs.find( id ); + + // Did we find the first fragment? + if (pFrag == mEntityStructs.end()) + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Missing initial fragment, struct ID " << structID; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bRC = false; + } + + // Iterate over each fragment in the structure + while (pFrag != mEntityStructs.end() && pFrag->second.mStructID == structID) + { + // Grab fragment + const sDB2Fragment & frag = pFrag->second; + + // Variable array or optional fragment? + if ( (frag.mModifierType == eDB2_MOD_VARIABLE_ARRAY) + || (frag.mModifierType == eDB2_MOD_VARIABLE_ARRAY2) ) + { + bRC = ValidateArraySpecifier( frag, fields ); + } + else if (frag.mModifierType == eDB2_MOD_OPTIONAL) + { + bRC = ValidateOptionalSpecifier( frag, fields ); + } + else if (frag.mModifierType == eDB2_MOD_VARIABLE_ARRAY3) + { + bRC = ValidateExpressionSpecifier( frag, fields ); + } + else if ( (frag.mModifierType == eDB2_MOD_VARIABLE_STRING1) + || (frag.mModifierType == eDB2_MOD_VARIABLE_STRING2) + || (frag.mModifierType == eDB2_MOD_VARIABLE_STRING3) ) + { + bRC = ValidateArraySpecifier( frag, fields ); + if (bRC == true) + { + // The field being modified has to be a fixed length string + ULONG fieldID = frag.mFragmentValue; + tDB2FieldMap::const_iterator pIter = mEntityFields.find( fieldID ); + if (pIter != mEntityFields.end()) + { + bool bString = false; + + const sDB2Field & ft = pIter->second; + if (ft.mType == eDB2_FIELD_STD) + { + if ( (ft.mTypeVal == (ULONG)eDB2_FIELD_STDTYPE_STRING_A) + || (ft.mTypeVal == (ULONG)eDB2_FIELD_STDTYPE_STRING_U) + || (ft.mTypeVal == (ULONG)eDB2_FIELD_STDTYPE_STRING_U8) ) + { + if ( (ft.mTypeVal != (ULONG)eDB2_FIELD_STDTYPE_STRING_U8) + || (frag.mModifierType != eDB2_MOD_VARIABLE_STRING3) ) + { + // Not the invalid combination of character length and + // varaible length characters + bString = true; + } + } + } + + if (bString == false) + { + // Not a string so why the string modifier? + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid string modifier, struct ID " << structID + << ", ID " << fieldID; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bRC = false; + } + } + } + } + + if (bRC == true) + { + // What type of fragment is this? + switch (frag.mFragmentType) + { + case eDB2_FRAGMENT_FIELD: + { + ULONG fieldID = frag.mFragmentValue; + bRC = ValidateField( structID, fieldID, fields ); + } + break; + + case eDB2_FRAGMENT_VARIABLE_PAD_BITS: + case eDB2_FRAGMENT_VARIABLE_PAD_BYTES: + { + // Does this field exist in the entity? + ULONG fieldID = frag.mFragmentValue; + if (fields.find( fieldID ) == fields.end()) + { + // No + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid pad, struct ID " << structID + << ", ID " << fieldID; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bRC = false; + } + } + break; + + case eDB2_FRAGMENT_STRUCT: + { + // Grab structure ID and recurse + ULONG structID = frag.mFragmentValue; + bRC = ValidateStructure( structID, fields, depth ); + } + break; + + default: + break; + } + } + + // Did an error occur? + if (bRC == false) + { + break; + } + + pFrag++; + } + + return bRC; +} + +/*=========================================================================== +METHOD: + ValidateField (Internal Method) + +DESCRIPTION: + Validate a single field + +PARAMETERS: + structID [ I ] - ID of referencing structure + fieldID [ I ] - ID of field being evaluated + fields [I/O] - List of 'known' field IDs + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::ValidateField( + ULONG structID, + ULONG fieldID, + std::set <ULONG> & fields ) +{ + // Assume success + bool bRC = true; + + tDB2FieldMap::const_iterator pIter = mEntityFields.find( fieldID ); + if (pIter == mEntityFields.end()) + { + // No + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid field, struct ID " << structID + << ", ID " << fieldID; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bRC = false; + } + else + { + // Mark field as part of this structure + fields.insert( fieldID ); + + // Is this field an enumeration? + const sDB2Field & theField = pIter->second; + if ( (theField.mType == eDB2_FIELD_ENUM_UNSIGNED) + || (theField.mType == eDB2_FIELD_ENUM_SIGNED) ) + { + // Yes, check that the enum exists + if (mEnumNameMap.find( theField.mTypeVal ) == mEnumNameMap.end()) + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_FIELD + << "] Invalid enumeration ID, field ID " << fieldID + << ", enum ID " << theField.mTypeVal; + + mpLog->Log( tmp.str(), eDB2_STATUS_WARNING ); + } + } + } + + return bRC; +} + +/*=========================================================================== +METHOD: + ValidateArraySpecifier (Internal Method) + +DESCRIPTION: + Validate an array specifier + +PARAMETERS: + frag [ I ] - Fragment containing array specifier + fields [ I ] - List of 'known' field IDs + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::ValidateArraySpecifier( + const sDB2Fragment & frag, + const std::set <ULONG> & fields ) +{ + // Assume success + bool bRC = true; + + // Even an array specifier to start with? + if (frag.mpModifierValue == 0 || frag.mpModifierValue == EMPTY_STRING) + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Missing array specifier, struct ID " << frag.mStructID; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bRC = false; + } + else if ( (frag.mModifierType == eDB2_MOD_VARIABLE_ARRAY) + || (frag.mModifierType == eDB2_MOD_VARIABLE_STRING1) + || (frag.mModifierType == eDB2_MOD_VARIABLE_STRING2) + || (frag.mModifierType == eDB2_MOD_VARIABLE_STRING3) ) + { + ULONG id = strtoul( frag.mpModifierValue, 0, 0 ); + if (fields.find( id ) == fields.end()) + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid modifier specifier, struct ID " << frag.mStructID + << ", ID " << id; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bRC = false; + } + } + else if (frag.mModifierType == eDB2_MOD_VARIABLE_ARRAY2) + { + // Parse condition to tokens (start stop) + int nSize = strlen( frag.mpModifierValue ) + 1; + + char * pCopy = new char[ nSize ]; + if (pCopy == NULL) + { + return false; + } + + memcpy( pCopy, frag.mpModifierValue, nSize ); + + std::vector <ULONG> indices; + CSVStringToContainer( " ", pCopy, indices ); + + delete [] pCopy; + if (indices.size() != 2) + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid array specifier, struct ID " << frag.mStructID + << ", " << frag.mpModifierValue; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bRC = false; + } + else + { + ULONG sID = indices[0]; + ULONG eID = indices[1]; + + if ( (fields.find( sID ) == fields.end()) + || (fields.find( eID ) == fields.end()) ) + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid array specifier, struct ID " << frag.mStructID + << ", IDs " << sID << " " << eID; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bRC = false; + } + } + } + else + { + ASSERT( 0 ); + } + + return bRC; +} + +/*=========================================================================== +METHOD: + ValidateOptionalSpecifier (Internal Method) + +DESCRIPTION: + Validate a simple optional fragment specifier + +PARAMETERS: + frag [ I ] - Fragment containing optional fragment specifier + fields [ I ] - List of 'known' field IDs + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::ValidateOptionalSpecifier( + const sDB2Fragment & frag, + const std::set <ULONG> & fields ) +{ + // Assume success + bool bRC = true; + + ASSERT( frag.mModifierType == eDB2_MOD_OPTIONAL ); + + // Even an optional specifier to start with? + if (frag.mpModifierValue == 0 || frag.mpModifierValue == EMPTY_STRING) + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Missing optional specifier, struct ID " << frag.mStructID; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + return false; + } + + ULONG conID; + eDB2Operator conOp; + LONGLONG conVal; + bool bF2F; + + // Parse condition + LPCSTR pCon = frag.mpModifierValue; + bRC = sDB2Fragment::ParseCondition( pCon, conID, conOp, conVal, bF2F ); + if (bRC == true) + { + // Does the given field ID exist as part of this entity? + if (fields.find( conID ) == fields.end()) + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid optional specifier, struct ID " << frag.mStructID + << ", unknown field ID " << conID << "/" << frag.mpModifierValue; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bRC = false; + } + + if (bF2F == true) + { + // Does the given field ID exist as part of this entity? + if (fields.find( (ULONG)conVal ) == fields.end()) + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid optional specifier, struct ID " << frag.mStructID + << ", unknown field ID " << (ULONG)conVal + << "/" << frag.mpModifierValue; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bRC = false; + } + } + } + else + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid optional specifier, struct ID " << frag.mStructID + << ", " << frag.mpModifierValue; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + } + + return bRC; +} + +/*=========================================================================== +METHOD: + ValidateExpressionSpecifier (Internal Method) + +DESCRIPTION: + Validate a simple expression fragment specifier + +PARAMETERS: + frag [ I ] - Fragment containing expression fragment specifier + fields [ I ] - List of 'known' field IDs + +RETURN VALUE: + bool +===========================================================================*/ +bool cCoreDatabase::ValidateExpressionSpecifier( + const sDB2Fragment & frag, + const std::set <ULONG> & fields ) +{ + // Assume success + bool bRC = true; + + ASSERT( frag.mModifierType == eDB2_MOD_VARIABLE_ARRAY3 ); + + // Even an expression specifier to start with? + if (frag.mpModifierValue == 0 || frag.mpModifierValue == EMPTY_STRING) + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Missing array specifier, struct ID " << frag.mStructID; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + return false; + } + + ULONG exprID; + eDB2ExpOperator exprOp; + LONGLONG exprVal; + bool bF2F; + + // Parse expression + LPCSTR pExpr = frag.mpModifierValue; + bRC = sDB2Fragment::ParseExpression( pExpr, exprID, exprOp, exprVal, bF2F ); + if (bRC == true) + { + // Does the given field ID exist as part of this entity? + if (fields.find( exprID ) == fields.end()) + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid optional specifier, struct ID " << frag.mStructID + << ", unknown field ID " << exprID + << "/" << frag.mpModifierValue; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bRC = false; + } + + if (bF2F == true) + { + // Does the given field ID exist as part of this entity? + if (fields.find( (ULONG)exprVal ) == fields.end()) + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid optional specifier, struct ID " << frag.mStructID + << ", unknown field ID " << (ULONG)exprID + << "/" << frag.mpModifierValue; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + + bRC = false; + } + } + } + else + { + std::ostringstream tmp; + tmp << "DB [" << DB2_TABLE_PROTOCOL_STRUCT + << "] Invalid optional specifier, struct ID " << frag.mStructID + << ", " << frag.mpModifierValue; + + mpLog->Log( tmp.str(), eDB2_STATUS_ERROR ); + } + + return bRC; +} + |