| /*=========================================================================== |
| FILE: |
| DataPacker.cpp |
| |
| DESCRIPTION: |
| Implementation of sUnpackedField and cDataPacker |
| |
| PUBLIC CLASSES AND METHODS: |
| sUnpackedField |
| Structure to represent a single unpacked (input) field - i.e. the |
| field value as a string and an optional field name (either fully |
| qualified) or partial |
| |
| cDataPacker |
| Class to pack bit/byte specified fields into a buffer accordinging |
| to a database description, uses cProtocolEntityNav to navigate the DB |
| definition |
| |
| 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 "DataPacker.h" |
| |
| #include "CoreDatabase.h" |
| #include "DB2Utilities.h" |
| |
| #include <climits> |
| |
| //--------------------------------------------------------------------------- |
| // Definitions |
| //--------------------------------------------------------------------------- |
| |
| /*=========================================================================*/ |
| // cDataPacker Methods |
| /*=========================================================================*/ |
| |
| /*=========================================================================== |
| METHOD: |
| cDataPacker (Public Method) |
| |
| DESCRIPTION: |
| Constructor |
| |
| PARAMETERS: |
| db [ I ] - Database to use |
| key [ I ] - Key into protocol entity table |
| fields [ I ] - Fields to pack into buffer |
| |
| RETURN VALUE: |
| None |
| ===========================================================================*/ |
| cDataPacker::cDataPacker( |
| const cCoreDatabase & db, |
| const std::vector <ULONG> & key, |
| const std::list <sUnpackedField> & fields ) |
| : cProtocolEntityNav( db ), |
| mKey( key ), |
| mbValuesOnly( true ), |
| mProcessedFields( 0 ), |
| mbPacked( false ) |
| { |
| // Initialize internal buffer |
| memset( &mBuffer[0], 0, (SIZE_T)MAX_SHARED_BUFFER_SIZE ); |
| |
| // Compute bits left in buffer |
| ULONG bits = MAX_SHARED_BUFFER_SIZE * BITS_PER_BYTE; |
| if (mKey.size() > 0) |
| { |
| eDB2EntityType et = (eDB2EntityType)mKey[0]; |
| bits = DB2GetMaxBufferSize( et ) * BITS_PER_BYTE; |
| } |
| |
| // Setup the bit packer |
| mBitsy.SetData( mBuffer, bits ); |
| |
| // Copy fields/set value only flag |
| std::list <sUnpackedField>::const_iterator pIter = fields.begin(); |
| while (pIter != fields.end()) |
| { |
| if (pIter->mName.size() > 0) |
| { |
| mbValuesOnly = false; |
| } |
| |
| mFields.push_back( *pIter ); |
| pIter++; |
| } |
| } |
| |
| /*=========================================================================== |
| METHOD: |
| ~cDataPacker (Public Method) |
| |
| DESCRIPTION: |
| Destructor |
| |
| RETURN VALUE: |
| None |
| ===========================================================================*/ |
| cDataPacker::~cDataPacker() |
| { |
| // Ask bit packer to release data |
| mBitsy.ReleaseData(); |
| } |
| |
| /*=========================================================================== |
| METHOD: |
| Pack (Public Method) |
| |
| DESCRIPTION: |
| Pack the buffer |
| |
| RETURN VALUE: |
| bool |
| ===========================================================================*/ |
| bool cDataPacker::Pack() |
| { |
| // Process (pack) the protocol entity |
| if (mbPacked == false) |
| { |
| mbPacked = ProcessEntity( mKey ); |
| if (mbPacked == false) |
| { |
| // Failed due to no structure ID? |
| if (mEntity.IsValid() == true && mEntity.mStructID == -1) |
| { |
| // Yes, for us that means instant success (no payload to pack) |
| mbPacked = true; |
| } |
| } |
| } |
| |
| return mbPacked; |
| } |
| |
| /*=========================================================================== |
| METHOD: |
| GetBuffer (Public Method) |
| |
| DESCRIPTION: |
| Get packed buffer contents |
| |
| PARAMETERS: |
| bufferLen [ O ] - Length of packed buffer (in bytes) |
| |
| RETURN VALUE: |
| const BYTE * - Packed buffer (0 upon error) |
| ===========================================================================*/ |
| const BYTE * cDataPacker::GetBuffer( ULONG & bufferLen ) |
| { |
| if (mbPacked == false) |
| { |
| bufferLen = 0; |
| return 0; |
| } |
| |
| // Payload size in bytes |
| bufferLen = mBitsy.GetTotalBitsWritten() + BITS_PER_BYTE - 1; |
| bufferLen /= BITS_PER_BYTE; |
| |
| // Payload is our buffer |
| const BYTE * pBuffer = 0; |
| if (bufferLen > 0) |
| { |
| pBuffer = (const BYTE *)&mBuffer[0]; |
| } |
| |
| return pBuffer; |
| } |
| |
| /*=========================================================================== |
| METHOD: |
| LoadValues (Static Public Method) |
| |
| DESCRIPTION: |
| Load values by parsing a 'summary' string of values, an example of |
| which would be: |
| |
| 0 1 100 "Foo Foo Foo" 15 -1 |
| |
| PARAMETERS: |
| vals [ I ] - Value string |
| |
| RETURN VALUE: |
| std::list <sUnpackedField> |
| ===========================================================================*/ |
| std::list <sUnpackedField> cDataPacker::LoadValues( const std::string & vals ) |
| { |
| std::list <sUnpackedField> retList; |
| if (vals.size() <= 0) |
| { |
| return retList; |
| } |
| |
| std::vector <std::string> tokens; |
| ParseCommandLine( vals, tokens ); |
| |
| std::string name = ""; |
| std::string val = ""; |
| |
| std::vector <std::string>::const_iterator pIter = tokens.begin(); |
| while (pIter != tokens.end()) |
| { |
| val = *pIter++; |
| |
| sUnpackedField entry( name, val ); |
| retList.push_back( entry ); |
| } |
| |
| return retList; |
| } |
| |
| /*=========================================================================== |
| METHOD: |
| LoadValues (Static Public Method) |
| |
| DESCRIPTION: |
| Load values by parsing a vector of string values, an example of |
| which would be: |
| |
| [0] 0 |
| [1] 1 |
| [2] 100 |
| [3] "Foo Foo Foo" |
| [4] 15 |
| [5] -1 |
| |
| PARAMETERS: |
| vals [ I ] - Vector of values |
| startIndex [ I ] - Where in above vector values start |
| |
| RETURN VALUE: |
| std::list <sUnpackedField> |
| ===========================================================================*/ |
| std::list <sUnpackedField> cDataPacker::LoadValues( |
| std::vector <std::string> & vals, |
| ULONG startIndex ) |
| { |
| std::list <sUnpackedField> retList; |
| |
| ULONG sz = (ULONG)vals.size(); |
| if (startIndex >= sz) |
| { |
| return retList; |
| } |
| |
| std::string name = ""; |
| std::string val = ""; |
| |
| for (ULONG v = startIndex; v < sz; v++) |
| { |
| val = vals[v]; |
| |
| sUnpackedField entry( name, val ); |
| retList.push_back( entry ); |
| } |
| |
| return retList; |
| } |
| |
| /*=========================================================================== |
| METHOD: |
| GetLastValue (Internal Method) |
| |
| DESCRIPTION: |
| Working from the back of the current value list find and return the |
| value for the specified field ID as a LONGLONG (field type must have |
| been able to fit in a LONGLONG for a value to be stored in value list |
| and thus returned) |
| |
| PARAMETERS: |
| fieldID [ I ] - Field ID we are looking for |
| val [ O ] - The value |
| |
| RETURN VALUE: |
| bool |
| ===========================================================================*/ |
| bool cDataPacker::GetLastValue( |
| ULONG fieldID, |
| LONGLONG & val ) |
| { |
| // Assume failure |
| bool bRC = false; |
| |
| std::list < std::pair <ULONG, LONGLONG> >::reverse_iterator pValues; |
| pValues = mValues.rbegin(); |
| while (pValues != mValues.rend()) |
| { |
| std::pair <ULONG, LONGLONG> & entry = *pValues; |
| if (entry.first == fieldID) |
| { |
| val = entry.second; |
| |
| // Success! |
| bRC = true; |
| break; |
| } |
| |
| pValues++; |
| } |
| |
| return bRC; |
| } |
| |
| /*=========================================================================== |
| METHOD: |
| GetValueString (Internal Method) |
| |
| DESCRIPTION: |
| For the given field return the (input) value string |
| |
| PARAMETERS: |
| field [ I ] - The field being processed |
| fieldName [ I ] - Partial (or fully qualified) field name |
| pValueString [ O ] - Value string |
| |
| RETURN VALUE: |
| bool |
| ===========================================================================*/ |
| bool cDataPacker::GetValueString( |
| const sDB2Field & field, |
| const std::string & fieldName, |
| LPCSTR & pValueString ) |
| { |
| // Assume failure |
| pValueString = 0; |
| |
| // Create fully qualified field name |
| std::string fullName = GetFullFieldName( fieldName ); |
| |
| std::vector <sUnpackedField>::const_iterator pVals = mFields.begin(); |
| while (pVals != mFields.end()) |
| { |
| const std::string & inName = pVals->mName; |
| if (fieldName == inName || fullName == inName) |
| { |
| pValueString = (LPCSTR)pVals->mValueString.c_str(); |
| break; |
| } |
| |
| pVals++; |
| } |
| |
| // Value provided? |
| if (pValueString == 0) |
| { |
| // No, are we in value only mode? |
| if (mbValuesOnly == true) |
| { |
| if (mProcessedFields < (ULONG)mFields.size()) |
| { |
| sUnpackedField & upf = mFields[mProcessedFields++]; |
| |
| // Set field name (partial) |
| upf.mName = fieldName; |
| |
| // Grab field value |
| pValueString = (LPCSTR)upf.mValueString.c_str(); |
| } |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| // Value provided? |
| if (pValueString == 0) |
| { |
| return false; |
| } |
| |
| // Meaningful value provided? |
| if (pValueString[0] == 0) |
| { |
| // No value provided for field? Is it a string? |
| if (field.mType == eDB2_FIELD_STD) |
| { |
| if ( (field.mTypeVal != eDB2_FIELD_STDTYPE_STRING_A) |
| && (field.mTypeVal != eDB2_FIELD_STDTYPE_STRING_U) |
| && (field.mTypeVal != eDB2_FIELD_STDTYPE_STRING_U8) |
| && (field.mTypeVal != eDB2_FIELD_STDTYPE_STRING_ANT) |
| && (field.mTypeVal != eDB2_FIELD_STDTYPE_STRING_UNT) |
| && (field.mTypeVal != eDB2_FIELD_STDTYPE_STRING_U8NT) ) |
| { |
| // No, unable to proceed |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| /*=========================================================================== |
| METHOD: |
| PackString (Internal Method) |
| |
| DESCRIPTION: |
| Pack the string (described by the given arguments) into the buffer |
| |
| PARAMETERS: |
| numChars [ I ] - Number of characters to pack (0 = NULL terminated) |
| pStr [ I ] - String to pack |
| |
| RETURN VALUE: |
| bool |
| ===========================================================================*/ |
| bool cDataPacker::PackString( |
| ULONG numChars, |
| LPCSTR pStr ) |
| { |
| // Sanity check string pointer |
| if (pStr == 0) |
| { |
| return false; |
| } |
| |
| // Assume success |
| bool bOK = true; |
| |
| // Convert native string type to desired output type |
| const BYTE * pTmp = (const BYTE *)pStr; |
| |
| // Have we reached the practical end of a fixed length string? |
| ULONG numBytes = 0; |
| |
| numBytes = (ULONG)strlen( (LPCSTR)pTmp ); |
| if (numChars == 0) |
| { |
| // We pack the string plus the NULL character |
| numChars = (ULONG)strlen( (LPCSTR)pTmp ) + 1; |
| } |
| |
| // String size too long? |
| if (numBytes > numChars) |
| { |
| return false; |
| } |
| |
| // Pack the string one byte at a time |
| for (ULONG c = 0; c < numChars; c++) |
| { |
| BYTE val = 0; |
| if (c < numBytes) |
| { |
| val = pTmp[c]; |
| } |
| |
| DWORD rc = mBitsy.Set( BITS_PER_BYTE, val ); |
| if (rc != NO_ERROR) |
| { |
| bOK = false; |
| break; |
| } |
| } |
| |
| return bOK; |
| } |
| |
| /*=========================================================================== |
| METHOD: |
| ProcessField (Internal Method) |
| |
| DESCRIPTION: |
| Process the given field (described by the given arguments) by packing |
| the value into the buffer |
| |
| PARAMETERS: |
| pField [ I ] - The field being processed |
| fieldName [ I ] - Field name (partial) |
| arrayIndex [ I ] - Not used |
| |
| RETURN VALUE: |
| bool |
| ===========================================================================*/ |
| bool cDataPacker::ProcessField( |
| const sDB2Field * pField, |
| const std::string & fieldName, |
| LONGLONG /* arrayIndex */ ) |
| { |
| // Assume failure |
| bool bOK = false; |
| if (pField == 0) |
| { |
| return bOK; |
| } |
| |
| // Find given value for field |
| LPCSTR pVal = 0; |
| bool bVal = GetValueString( *pField, fieldName, pVal ); |
| if (bVal == false) |
| { |
| return bOK; |
| } |
| |
| // Grab field ID |
| ULONG id = pField->mID; |
| |
| // What type is this field? |
| switch (pField->mType) |
| { |
| case eDB2_FIELD_STD: |
| { |
| // Standard field, what kind? |
| eDB2StdFieldType ft = (eDB2StdFieldType)pField->mTypeVal; |
| switch (ft) |
| { |
| // Field is a boolean (0/1, false/true)/8-bit unsigned integer |
| case eDB2_FIELD_STDTYPE_BOOL: |
| case eDB2_FIELD_STDTYPE_UINT8: |
| { |
| // We pack as a UCHAR |
| UCHAR val = 0; |
| bool bVal = ::FromString( pVal, val ); |
| if (bVal == true) |
| { |
| if (ft == eDB2_FIELD_STDTYPE_BOOL && val > 1) |
| { |
| val = 1; |
| } |
| |
| DWORD rc = mBitsy.Set( pField->mSize, val ); |
| if (rc == NO_ERROR) |
| { |
| // Success! |
| std::pair <ULONG, LONGLONG> entry( id, (LONGLONG)val ); |
| mValues.push_back( entry ); |
| bOK = true; |
| } |
| } |
| } |
| break; |
| |
| // Field is 8-bit signed integer |
| case eDB2_FIELD_STDTYPE_INT8: |
| { |
| // We pack as a CHAR |
| CHAR val = 0; |
| bool bVal = ::FromString( pVal, val ); |
| if (bVal == true) |
| { |
| DWORD rc = mBitsy.Set( pField->mSize, val ); |
| if (rc == NO_ERROR) |
| { |
| // Success! |
| std::pair <ULONG, LONGLONG> entry( id, (LONGLONG)val ); |
| mValues.push_back( entry ); |
| bOK = true; |
| } |
| } |
| } |
| break; |
| |
| // Field is 16-bit signed integer |
| case eDB2_FIELD_STDTYPE_INT16: |
| { |
| // We pack as a SHORT |
| SHORT val = 0; |
| bool bVal = ::FromString( pVal, val ); |
| if (bVal == true) |
| { |
| DWORD rc = mBitsy.Set( pField->mSize, val ); |
| if (rc == NO_ERROR) |
| { |
| // Success! |
| std::pair <ULONG, LONGLONG> entry( id, (LONGLONG)val ); |
| mValues.push_back( entry ); |
| bOK = true; |
| } |
| } |
| } |
| break; |
| |
| // Field is 16-bit unsigned integer |
| case eDB2_FIELD_STDTYPE_UINT16: |
| { |
| // We pack as a USHORT |
| USHORT val = 0; |
| bool bVal = ::FromString( pVal, val ); |
| if (bVal == true) |
| { |
| DWORD rc = mBitsy.Set( pField->mSize, val ); |
| if (rc == NO_ERROR) |
| { |
| // Success! |
| std::pair <ULONG, LONGLONG> entry( id, (LONGLONG)val ); |
| mValues.push_back( entry ); |
| bOK = true; |
| } |
| } |
| } |
| break; |
| |
| // Field is 32-bit signed integer |
| case eDB2_FIELD_STDTYPE_INT32: |
| { |
| // We pack as a LONG |
| LONG val = 0; |
| bool bVal = ::FromString( pVal, val ); |
| if (bVal == true) |
| { |
| DWORD rc = mBitsy.Set( pField->mSize, val ); |
| if (rc == NO_ERROR) |
| { |
| // Success! |
| std::pair <ULONG, LONGLONG> entry( id, (LONGLONG)val ); |
| mValues.push_back( entry ); |
| bOK = true; |
| } |
| } |
| } |
| break; |
| |
| // Field is 32-bit unsigned integer |
| case eDB2_FIELD_STDTYPE_UINT32: |
| { |
| // We pack as a ULONG |
| ULONG val = 0; |
| bool bVal = ::FromString( pVal, val ); |
| if (bVal == true) |
| { |
| DWORD rc = mBitsy.Set( pField->mSize, val ); |
| if (rc == NO_ERROR) |
| { |
| // Success! |
| std::pair <ULONG, LONGLONG> entry( id, (LONGLONG)val ); |
| mValues.push_back( entry ); |
| bOK = true; |
| } |
| } |
| } |
| break; |
| |
| // Field is 64-bit signed integer |
| case eDB2_FIELD_STDTYPE_INT64: |
| { |
| // We pack as a LONGLONG |
| LONGLONG val = 0; |
| bool bVal = ::FromString( pVal, val ); |
| if (bVal == true) |
| { |
| DWORD rc = mBitsy.Set( pField->mSize, val ); |
| if (rc == NO_ERROR) |
| { |
| // Success! |
| std::pair <ULONG, LONGLONG> entry( id, val ); |
| mValues.push_back( entry ); |
| bOK = true; |
| } |
| } |
| } |
| break; |
| |
| // Field is 64-bit unsigned integer |
| case eDB2_FIELD_STDTYPE_UINT64: |
| { |
| // We pack as a ULONGLONG |
| ULONGLONG val = 0; |
| bool bVal = ::FromString( pVal, val ); |
| if (bVal == true) |
| { |
| DWORD rc = mBitsy.Set( pField->mSize, val ); |
| if (rc == NO_ERROR) |
| { |
| // Success! |
| if (val <= LLONG_MAX) |
| { |
| std::pair <ULONG, LONGLONG> entry( id, (LONGLONG)val ); |
| mValues.push_back( entry ); |
| } |
| |
| bOK = true; |
| } |
| } |
| } |
| break; |
| |
| // ANSI/UNICODE strings |
| case eDB2_FIELD_STDTYPE_STRING_A: |
| case eDB2_FIELD_STDTYPE_STRING_U: |
| case eDB2_FIELD_STDTYPE_STRING_ANT: |
| case eDB2_FIELD_STDTYPE_STRING_UNT: |
| { |
| // Set the character size |
| ULONG charSz = sizeof(CHAR); |
| if ( (ft == eDB2_FIELD_STDTYPE_STRING_U) |
| || (ft == eDB2_FIELD_STDTYPE_STRING_UNT) ) |
| { |
| charSz = sizeof(USHORT); |
| } |
| |
| // Compute the number of characters? |
| ULONG numChars = 0; |
| if ( (ft == eDB2_FIELD_STDTYPE_STRING_A) |
| || (ft == eDB2_FIELD_STDTYPE_STRING_U) ) |
| { |
| numChars = (pField->mSize / BITS_PER_BYTE) / charSz; |
| } |
| |
| // Pack the string |
| bOK = PackString( numChars, pVal ); |
| } |
| break; |
| |
| // UTF-8 strings |
| case eDB2_FIELD_STDTYPE_STRING_U8: |
| case eDB2_FIELD_STDTYPE_STRING_U8NT: |
| { |
| // Unsupported in the Linux adaptation |
| bOK = false; |
| } |
| break; |
| |
| // Field is 32-bit floating point value |
| case eDB2_FIELD_STDTYPE_FLOAT32: |
| { |
| // We pack as a ULONG |
| FLOAT val = (float)atof( (LPCSTR)pVal ); |
| ULONG * pTmp = (ULONG *)&val; |
| |
| DWORD rc = mBitsy.Set( pField->mSize, *pTmp ); |
| if (rc == NO_ERROR) |
| { |
| // Success! |
| bOK = true; |
| } |
| } |
| break; |
| |
| // Field is 64-bit floating point value |
| case eDB2_FIELD_STDTYPE_FLOAT64: |
| { |
| // We pack as a ULONGLONG |
| double val = atof( (LPCSTR)pVal ); |
| ULONGLONG * pTmp = (ULONGLONG *)&val; |
| |
| DWORD rc = mBitsy.Set( pField->mSize, *pTmp ); |
| if (rc == NO_ERROR) |
| { |
| // Success! |
| bOK = true; |
| } |
| } |
| break; |
| |
| default: |
| { |
| bOK = false; |
| } |
| break; |
| } |
| } |
| break; |
| |
| case eDB2_FIELD_ENUM_UNSIGNED: |
| { |
| // We pack as a ULONG |
| ULONG val = 0; |
| bool bVal = ::FromString( pVal, val ); |
| if (bVal == true) |
| { |
| DWORD rc = mBitsy.Set( pField->mSize, val ); |
| if (rc == NO_ERROR) |
| { |
| // Success! |
| std::pair <ULONG, LONGLONG> entry( id, (LONGLONG)val ); |
| mValues.push_back( entry ); |
| bOK = true; |
| } |
| } |
| } |
| break; |
| |
| case eDB2_FIELD_ENUM_SIGNED: |
| { |
| // We pack as a LONG |
| LONG val = 0; |
| bool bVal = ::FromString( pVal, val ); |
| if (bVal == true) |
| { |
| DWORD rc = mBitsy.Set( pField->mSize, val ); |
| if (rc == NO_ERROR) |
| { |
| // Success! |
| std::pair <ULONG, LONGLONG> entry( id, (LONGLONG)val ); |
| mValues.push_back( entry ); |
| bOK = true; |
| } |
| } |
| } |
| break; |
| |
| default: |
| { |
| bOK = false; |
| } |
| break; |
| } |
| |
| return bOK; |
| } |