/*=========================================================================== 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 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 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 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 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 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 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 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 ::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 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 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 & 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 , 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 & 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 & 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 & 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 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 & entries = pEnumMapIter->second.second; std::map ::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 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 indices; CSVStringToContainer( " ", pCopy, indices ); delete [] pCopy; if (indices.size() == 2) { std::pair 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 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 & 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 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 & 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 & 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 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 & 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 & 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; }