/******************************************************************************* | |
* Copyright (c) 2010 - 2015 ACIN, fortiss GmbH | |
* | |
* This program and the accompanying materials are made available under the | |
* terms of the Eclipse Public License 2.0 which is available at | |
* http://www.eclipse.org/legal/epl-2.0. | |
* | |
* SPDX-License-Identifier: EPL-2.0 | |
* | |
* Contributors: | |
* Ingo Hegny, Alois Zoitl | |
* - initial implementation and rework communication infrastructure | |
*******************************************************************************/ | |
#include "forte_struct.h" | |
#ifdef FORTE_ENABLE_GENERATED_SOURCE_CPP | |
#include "forte_struct_gen.cpp" | |
#endif | |
#include <stdlib.h> | |
#ifdef FORTE_SUPPORT_ARRAYS | |
# include "forte_array.h" | |
#endif | |
CIEC_STRUCT::CIEC_STRUCT(CStringDictionary::TStringId paTypeName, TForteUInt16 paLength, const CStringDictionary::TStringId paElementTypes[], | |
const CStringDictionary::TStringId paElementNames[], TForteUInt8 paTypeID, TStructInitialValues *paInitialValues) { | |
setup(paTypeName, paLength, paElementTypes, paElementNames, paTypeID, paInitialValues); | |
} | |
CIEC_STRUCT::CIEC_STRUCT(const CIEC_STRUCT& paValue) : | |
CIEC_ANY_DERIVED() { | |
if(0 != paValue.getStructSize()) { | |
setGenData( | |
reinterpret_cast<TForteByte*>(new CStructSpecs(paValue.getStructTypeNameID(), paValue.getStructSize(), paValue.elementNames(), | |
paValue.getASN1StructType()))); | |
CIEC_ANY *localMembers = getMembers(); | |
const CIEC_ANY* sourceMembers = paValue.getMembers(); | |
for(size_t i = 0; i < getStructSize(); ++i) { | |
sourceMembers[i].clone(reinterpret_cast<TForteByte *>(&(localMembers[i]))); //clone is faster than the CTypeLib call | |
} | |
} | |
} | |
CIEC_STRUCT::~CIEC_STRUCT(){ | |
clear(); | |
} | |
void CIEC_STRUCT::setup(CStringDictionary::TStringId paTypeName, TForteUInt16 paLength, const CStringDictionary::TStringId paElementTypes[], | |
const CStringDictionary::TStringId paElementNames[], TForteUInt8 paTypeID, TStructInitialValues *paInitialValues) { | |
if(0 != paLength) { | |
setGenData(reinterpret_cast<TForteByte*>(new CStructSpecs(paTypeName, paLength, paElementNames, paTypeID))); | |
CIEC_ANY* localMembers = getMembers(); | |
for(size_t i = 0; i < paLength; ++i) { | |
CIEC_ANY *retVal = CTypeLib::createDataTypeInstance(*paElementTypes, reinterpret_cast<TForteByte *>(&(localMembers[i]))); | |
++paElementTypes; | |
if(0 != retVal) { | |
#ifdef FORTE_SUPPORT_ARRAYS | |
if(g_nStringIdARRAY == paElementTypes[-1]) { | |
//For an array we have to do more | |
(static_cast<CIEC_ARRAY *>(retVal))->setup(static_cast<TForteUInt16>(*paElementTypes), paElementTypes[1]); | |
paElementTypes += 2; | |
} | |
#endif | |
if(paInitialValues && paInitialValues[i]) { | |
retVal->fromString(paInitialValues[i]); | |
} | |
} else { //datatype not found, clear everything and return | |
clear(); | |
break; | |
} | |
} | |
} | |
} | |
void CIEC_STRUCT::setValue(const CIEC_ANY& paValue){ | |
if(paValue.getDataTypeID() == e_STRUCT && (getStructTypeNameID() == static_cast<const CIEC_STRUCT&>(paValue).getStructTypeNameID())){ | |
CIEC_ANY *localMembers = getMembers(); | |
const CIEC_ANY* srcMembers = static_cast<const CIEC_STRUCT&>(paValue).getMembers(); | |
for(size_t i = 0; i < getStructSize(); ++i) { | |
localMembers[i].setValue(srcMembers[i]); | |
} | |
} | |
} | |
void CIEC_STRUCT::clear() { | |
if(0 != getGenData()) { | |
delete getSpecs(); | |
setGenData(0); | |
} | |
} | |
int CIEC_STRUCT::fromString(const char *paValue){ | |
int nRetVal = -1; | |
if('(' == paValue[0]){ | |
const char *pcRunner = paValue; | |
bool errorOcurred = false; | |
pcRunner++; | |
while(('\0' != *pcRunner) && (')' != *pcRunner) && !errorOcurred) { | |
//first extract the element name | |
int nLength = 0; | |
CStringDictionary::TStringId unElementNameId = parseNextElementId(pcRunner, nLength); | |
if(CStringDictionary::scm_nInvalidStringId != unElementNameId) { | |
pcRunner += nLength; | |
CIEC_ANY *poMember = getMemberNamed(unElementNameId); | |
if(0 != poMember) { | |
if(!initializeFromString(&nLength, poMember, &pcRunner, &errorOcurred)) { | |
break; | |
} | |
} else { | |
errorOcurred = true; | |
} | |
}else{ | |
errorOcurred = true; | |
} | |
pcRunner++; | |
} | |
if(')' == *pcRunner && !errorOcurred) { | |
//structs have to have an opening and a closing round bracket | |
nRetVal = static_cast<int>(pcRunner - paValue + 1); //+1 from the closing round bracket | |
} | |
} | |
return nRetVal; | |
} | |
bool CIEC_STRUCT::initializeFromString(int *paLength, CIEC_ANY *paMember, const char** paRunner, bool* paErrorOcurred) { | |
bool retVal = true; | |
*paLength = paMember->fromString(*paRunner); | |
if(0 < *paLength) { | |
*paRunner += *paLength; | |
findNextNonBlankSpace(paRunner); | |
if(',' != **paRunner) { | |
retVal = false; | |
} | |
} else { | |
//we have an error or the end bracket | |
*paErrorOcurred = true; | |
} | |
return retVal; | |
} | |
CStringDictionary::TStringId CIEC_STRUCT::parseNextElementId(const char *paRunner, int &paCounter){ | |
CStringDictionary::TStringId unElementNameId = CStringDictionary::scm_nInvalidStringId; | |
TIdentifier acIdentifier; | |
//remove any leading whitespaces before the identifier | |
while(' ' == *paRunner){ | |
paRunner++; | |
paCounter++; | |
} | |
for(size_t i = 0; (('\0' != *paRunner) && (')' != *paRunner)); ++i, ++paCounter, ++paRunner) { | |
if(i >= cg_nIdentifierLength){ | |
//currently we only allow identifiers smaller that size | |
return CStringDictionary::scm_nInvalidStringId; | |
} | |
if((':' == *paRunner) || (' ' == *paRunner)){ | |
acIdentifier[i] = '\0'; //close identifier string | |
break; | |
} | |
acIdentifier[i] = *paRunner; | |
} | |
//remove any whitespaces between identifier and assignment operator | |
while(' ' == *paRunner){ | |
paRunner++; | |
paCounter++; | |
} | |
if(':' == *paRunner){ | |
//only if we have a : we have a correct identifier | |
paRunner++; | |
paCounter++; | |
if('=' == *paRunner){ | |
unElementNameId = CStringDictionary::getInstance().getId(acIdentifier); | |
paRunner++; | |
paCounter++; | |
//remove any whitespaces between assignment operator and value | |
while(' ' == *paRunner){ | |
paRunner++; | |
paCounter++; | |
} | |
if(('\0' == *paRunner) || (')' == *paRunner)){ | |
return CStringDictionary::scm_nInvalidStringId; | |
} | |
} | |
} | |
return unElementNameId; | |
} | |
int CIEC_STRUCT::toString(char* paValue, size_t paBufferSize) const { | |
int nBytesUsed = -1; | |
if(paBufferSize) { | |
*paValue = '('; | |
paValue++; | |
paBufferSize--; | |
nBytesUsed = 1; | |
TForteUInt16 unSize = getStructSize(); | |
const CStringDictionary::TStringId *punMemberNameIds = elementNames(); | |
const CIEC_ANY *poMembers = getMembers(); | |
for(size_t i = 0; i < unSize; ++i, ++poMembers, ++punMemberNameIds) { | |
const char *acMemberName = CStringDictionary::getInstance().get(*punMemberNameIds); | |
int nUsedBytesByElement; | |
if(strlen(acMemberName) + 2 > paBufferSize){ | |
return -1; | |
} | |
strncpy(paValue, acMemberName, strlen(acMemberName)); | |
paValue += strlen(acMemberName); | |
*paValue = ':'; | |
paValue++; | |
*paValue = '='; | |
paValue++; | |
paBufferSize -= strlen(acMemberName) + 2; | |
nBytesUsed += static_cast<int>(strlen(acMemberName) + 2); | |
nUsedBytesByElement = poMembers->toString(paValue, paBufferSize); | |
if(-1 == nUsedBytesByElement){ | |
return -1; | |
} | |
paBufferSize -= nUsedBytesByElement; | |
paValue += nUsedBytesByElement; | |
if(!paBufferSize){ | |
return -1; | |
} | |
nBytesUsed += nUsedBytesByElement; | |
if(i != static_cast<size_t>(unSize - 1)) { | |
*paValue = ','; | |
paValue++; | |
++nBytesUsed; | |
paBufferSize--; | |
} | |
} | |
if(paBufferSize < 2){ | |
return -1; | |
} | |
*paValue = ')'; | |
paValue[1] = '\0'; | |
nBytesUsed++; | |
} | |
return nBytesUsed; | |
} | |
CIEC_ANY *CIEC_STRUCT::getMemberNamed(CStringDictionary::TStringId paMemberNameId){ | |
CIEC_ANY *poRetVal = 0; | |
CIEC_ANY *poMembers = getMembers(); | |
const CStringDictionary::TStringId *punMemberNameIds = elementNames(); | |
for(size_t i = 0; i < getStructSize(); ++i, ++poMembers, ++punMemberNameIds) { | |
if(*punMemberNameIds == paMemberNameId){ | |
poRetVal = poMembers; | |
break; | |
} | |
} | |
return poRetVal; | |
} | |
size_t CIEC_STRUCT::getToStringBufferSize() const { | |
size_t retVal = 3; // 2 bytes for the open and closing brackets one for the '\0' | |
TForteUInt16 nSize = getStructSize(); | |
retVal += (nSize > 1) ? (nSize - 1) : 0; //for the commas between the elements | |
retVal += (nSize * 2); //for the := of each element | |
const CIEC_ANY *poMembers = getMembers(); | |
if(0 != poMembers) { | |
for(size_t i = 0; i < nSize; i++) { | |
retVal += strlen(CStringDictionary::getInstance().get(elementNames()[i])); //element name | |
retVal += (poMembers[i].getToStringBufferSize() - 1); //length of the element itself. -1 for the included \0 in each element | |
} | |
} | |
return retVal; | |
} | |
void CIEC_STRUCT::findNextNonBlankSpace(const char** paRunner) { | |
while(' ' == **paRunner) { | |
(*paRunner)++; | |
} | |
} |