libqmi-qmuxd/gobi-api/GobiAPI_1.0.40/Core/CoreDatabase.cpp

3188 lines
81 KiB
C++
Executable File

/*===========================================================================
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;
}