aboutsummaryrefslogtreecommitdiffstats
path: root/gobi-api/GobiAPI_1.0.40/Core/CoreDatabase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gobi-api/GobiAPI_1.0.40/Core/CoreDatabase.cpp')
-rwxr-xr-xgobi-api/GobiAPI_1.0.40/Core/CoreDatabase.cpp3187
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;
+}
+