/******************************************************************************** * Copyright (c) 2025-2026 ZF Friedrichshafen AG * * This program and the accompanying materials are made available under the * terms of the Apache License Version 2.0 which is available at * https://www.apache.org/licenses/LICENSE-2.0 * * SPDX-License-Identifier: Apache-2.0 * * Contributors: * Erik Verhoeven - initial API and implementation ********************************************************************************/ #include "dbcparser.h" #include #include #ifdef min #undef min #endif #ifdef max #undef max #endif #ifdef _MSC_VER // Prevent warnings about uninitialized members within unions during static code analysis. #pragma warning(push) #pragma warning(disable : 26495) #endif /** * @brief DBC namespace */ namespace dbc { /** * @brief Internal namespace */ namespace internal { /** * @brief Check for equality, ignoring the case. * @param[in] rss1 Reference to the first string. * @param[in] rss2 Reference to the second string. * @return The result of the comparison. */ inline bool EqualNC(const std::string& rss1, const std::string& rss2) { if (rss1.length() != rss2.length()) return false; for (size_t n = 0; n < rss1.length(); n++) if (std::tolower(rss1[n]) != std::tolower(rss2[n])) return false; return true; } } CDbcSource::CDbcSource(const std::filesystem::path& rpathDbcfile) : m_pathFile(rpathDbcfile) { std::ifstream stream; stream.open(rpathDbcfile); if (!stream.is_open()) throw SDbcParserException("Failed to open the %1 file for reading.", rpathDbcfile); // Read the complete source std::stringstream sstream; sstream << stream.rdbuf(); m_ssContent = std::move(sstream.str()); } CDbcSource::CDbcSource(const std::string& rssContent) : m_ssContent(rssContent) {} bool CDbcSource::IsValid() const { return !m_ssContent.empty(); } const std::filesystem::path& CDbcSource::Path() const { return m_pathFile; } const std::string& CDbcSource::Content() const { return m_ssContent; } const char* CDbcSource::ContentPtr() const { return m_ssContent.c_str() + std::min(m_nPos, m_ssContent.size()); } char CDbcSource::CurrentChar() const { return IsEOF() ? '\0' : m_ssContent[m_nPos]; } const size_t& CDbcSource::Pos() const { return m_nPos; } size_t& CDbcSource::Pos() { return m_nPos; } void CDbcSource::ResetPos() { m_nPos = 0; } bool CDbcSource::IsEOF() const { return m_nPos >= m_ssContent.size(); } CDbcSource::SPosLock::SPosLock(CDbcSource& rThis) : pSource(&rThis), nStoredPos(rThis.Pos()) {} CDbcSource::SPosLock::SPosLock(SPosLock&& rsPosLock) noexcept : pSource(rsPosLock.pSource), nStoredPos(rsPosLock.nStoredPos) { rsPosLock.pSource = nullptr; rsPosLock.nStoredPos = 0; } CDbcSource::SPosLock::~SPosLock() { // Automatically rollback Rollback(); } CDbcSource::SPosLock& CDbcSource::SPosLock::operator=(SPosLock&& rsPosLock) noexcept { pSource = rsPosLock.pSource; nStoredPos = rsPosLock.nStoredPos; rsPosLock.pSource = nullptr; rsPosLock.nStoredPos = 0; return *this; } void CDbcSource::SPosLock::Promote() { // Invalidate. Do not rollback to the stored position. pSource = nullptr; nStoredPos = 0; } void CDbcSource::SPosLock::Rollback() { // Can rollback? if (pSource) pSource->Pos() = nStoredPos; // Invalidate. pSource = nullptr; nStoredPos = 0; } CDbcSource::SPosLock CDbcSource::CreatePosLock() { return SPosLock(*this); } size_t CDbcSource::CalcLine() const { size_t nLine = m_ssContent.empty() ? 0 : 1; nLine += std::count(m_ssContent.begin(), IsEOF() ? m_ssContent.end() : m_ssContent.begin() + m_nPos, '\n'); return nLine; } size_t CDbcSource::CalcColumn() const { size_t nBOL = m_nPos ? m_ssContent.find_last_of('\n', m_nPos - 1) : std::string::npos; if (nBOL == std::string::npos) nBOL = 0; else nBOL++; size_t nCol = 0; for (size_t nIndex = nBOL; nIndex < std::min(m_nPos, m_ssContent.size()); nIndex++) { if (m_ssContent[nIndex] == '\t') { // Increase until nIndex is at the tab position. nCol += 4 - nCol % 4; } else nCol++; } return nCol + 1; } SAttributeDef::SAttributeDef(SAttributeDef::EType eTypeParam) : eType(eTypeParam) { switch (eType) { case EType::integer: sIntValues.iMinimum = 0; sIntValues.iMaximum = 0; sIntValues.iDefault = 0; break; case EType::hex_integer: sHexValues.uiMinimum = 0u; sHexValues.uiMaximum = 0u; sHexValues.uiDefault = 0u; break; case EType::floating_point: sFltValues.dMinimum = 0.0; sFltValues.dMaximum = 0.0; sFltValues.dDefault = 0.0; break; case EType::string: new (&sStringValues.ssDefault) std::string; break; case EType::enumerator: new (&sEnumValues.vecEnumValues) std::vector; new (&sEnumValues.ssDefault) std::string; break; default: throw SDbcParserException("Internal error: invalid attribute definition type."); break; } } SAttributeDef::~SAttributeDef() { switch (eType) { case EType::string: sStringValues.ssDefault.~basic_string(); break; case EType::enumerator: sEnumValues.vecEnumValues.~vector(); sEnumValues.ssDefault.~basic_string(); break; default: break; } } SAttributeDef::SAttributeDef(const SAttributeDef& rAttrDef) : eObjType(rAttrDef.eObjType), ssName(rAttrDef.ssName), eType(rAttrDef.eType) { switch (eType) { case EType::integer: sIntValues.iMinimum = rAttrDef.sIntValues.iMinimum; sIntValues.iMaximum = rAttrDef.sIntValues.iMaximum; sIntValues.iDefault = rAttrDef.sIntValues.iDefault; break; case EType::hex_integer: sHexValues.uiMinimum = rAttrDef.sHexValues.uiMinimum; sHexValues.uiMaximum = rAttrDef.sHexValues.uiMaximum; sHexValues.uiDefault = rAttrDef.sHexValues.uiDefault; break; case EType::floating_point: sFltValues.dMinimum = rAttrDef.sFltValues.dMinimum; sFltValues.dMaximum = rAttrDef.sFltValues.dMaximum; sFltValues.dDefault = rAttrDef.sFltValues.dDefault; break; case EType::string: new (&sStringValues.ssDefault) std::string(rAttrDef.sStringValues.ssDefault); break; case EType::enumerator: new (&sEnumValues.vecEnumValues) std::vector(rAttrDef.sEnumValues.vecEnumValues); new (&sEnumValues.ssDefault) std::string(rAttrDef.sEnumValues.ssDefault); break; default: throw SDbcParserException("Internal error: invalid attribute definition type."); break; } } SAttributeDef::SAttributeDef(SAttributeDef&& rAttrDef) : eObjType(rAttrDef.eObjType), ssName(std::move(rAttrDef.ssName)), eType(rAttrDef.eType) { switch (eType) { case EType::integer: sIntValues.iMinimum = rAttrDef.sIntValues.iMinimum; sIntValues.iMaximum = rAttrDef.sIntValues.iMaximum; sIntValues.iDefault = rAttrDef.sIntValues.iDefault; rAttrDef.sIntValues.iMinimum = 0; rAttrDef.sIntValues.iMaximum = 0; rAttrDef.sIntValues.iDefault = 0; break; case EType::hex_integer: sHexValues.uiMinimum = rAttrDef.sHexValues.uiMinimum; sHexValues.uiMaximum = rAttrDef.sHexValues.uiMaximum; sHexValues.uiDefault = rAttrDef.sHexValues.uiDefault; rAttrDef.sHexValues.uiMinimum = 0u; rAttrDef.sHexValues.uiMaximum = 0u; rAttrDef.sHexValues.uiDefault = 0u; break; case EType::floating_point: sFltValues.dMinimum = rAttrDef.sFltValues.dMinimum; sFltValues.dMaximum = rAttrDef.sFltValues.dMaximum; sFltValues.dDefault = rAttrDef.sFltValues.dDefault; rAttrDef.sFltValues.dMinimum = 0.0; rAttrDef.sFltValues.dMaximum = 0.0; rAttrDef.sFltValues.dDefault = 0.0; break; case EType::string: new (&sStringValues.ssDefault) std::string(std::move(rAttrDef.sStringValues.ssDefault)); break; case EType::enumerator: new (&sEnumValues.vecEnumValues) std::vector(std::move(rAttrDef.sEnumValues.vecEnumValues)); new (&sEnumValues.ssDefault) std::string(std::move(rAttrDef.sEnumValues.ssDefault)); break; default: throw SDbcParserException("Internal error: invalid attribute definition type."); break; } } SAttributeDef& SAttributeDef::operator=(const SAttributeDef& rAttrDef) { // Destroy the current definition this->~SAttributeDef(); // Construct new definition new (this) SAttributeDef(rAttrDef); return *this; } SAttributeDef& SAttributeDef::operator=(SAttributeDef&& rAttrDef) { // Destroy the current definition this->~SAttributeDef(); // Construct new definition new (this) SAttributeDef(std::move(rAttrDef)); return *this; } SAttributeValue::SAttributeValue(TAttributeDefPtr& ptrAttrDefParam) : ptrAttrDef(ptrAttrDefParam) { switch (ptrAttrDef->eType) { case SAttributeDef::EType::integer: iValue = 0; break; case SAttributeDef::EType::hex_integer: uiValue = 0u; break; case SAttributeDef::EType::floating_point: dValue = 0; break; case SAttributeDef::EType::string: new (&ssValue) std::string; break; case SAttributeDef::EType::enumerator: new (&ssValue) std::string; break; default: throw SDbcParserException("Internal error: invalid attribute definition type."); break; } } SAttributeValue::~SAttributeValue() { switch (ptrAttrDef->eType) { case SAttributeDef::EType::string: ssValue.~basic_string(); break; case SAttributeDef::EType::enumerator: ssValue.~basic_string(); break; default: break; } } SAttributeValue::SAttributeValue(const SAttributeValue& rAttrVal) : ptrAttrDef(rAttrVal.ptrAttrDef) { switch (ptrAttrDef->eType) { case SAttributeDef::EType::integer: iValue = rAttrVal.iValue; break; case SAttributeDef::EType::hex_integer: uiValue = rAttrVal.uiValue; break; case SAttributeDef::EType::floating_point: dValue = rAttrVal.dValue; break; case SAttributeDef::EType::string: new (&ssValue) std::string(rAttrVal.ssValue); break; case SAttributeDef::EType::enumerator: new (&ssValue) std::string(rAttrVal.ssValue); break; default: throw SDbcParserException("Internal error: invalid attribute definition type."); break; } } SAttributeValue::SAttributeValue(SAttributeValue&& rAttrVal) : ptrAttrDef(rAttrVal.ptrAttrDef) { switch (ptrAttrDef->eType) { case SAttributeDef::EType::integer: iValue = rAttrVal.iValue; break; case SAttributeDef::EType::hex_integer: uiValue = rAttrVal.uiValue; break; case SAttributeDef::EType::floating_point: dValue = rAttrVal.dValue; break; case SAttributeDef::EType::string: new (&ssValue) std::string(std::move(rAttrVal.ssValue)); break; case SAttributeDef::EType::enumerator: new (&ssValue) std::string(std::move(rAttrVal.ssValue)); break; default: throw SDbcParserException("Internal error: invalid attribute definition type."); break; } } SAttributeValue& SAttributeValue::operator=(const SAttributeValue& rAttrVal) { // Destroy the current value this->~SAttributeValue(); // Construct new value new (this) SAttributeValue(rAttrVal); return *this; } SAttributeValue& SAttributeValue::operator=(SAttributeValue&& rAttrVal) { // Destroy the current value this->~SAttributeValue(); // Construct new value new (this) SAttributeValue(std::move(rAttrVal)); return *this; } CDbcParser::CDbcParser(bool bNoDefaultDef /*= false*/) { if (!bNoDefaultDef) { // Parse the standard attribute definitions CDbcSource source(std::string(R"code( BA_DEF_ BO_ "VFrameFormat" ENUM "StandardCAN","ExtendedCAN","StandardFD","ExtendedFD"; BA_DEF_ BO_ "GenMsgSendType" ENUM "cyclic","triggered","cyclicIfActive","cyclicAndTriggered","cyclicIfActiveAndTriggered","none"; BA_DEF_ BO_ "GenMsgCycleTime" INT 0 10000; BA_DEF_ BO_ "GenMsgStartDelayTime" INT 0 10000; BA_DEF_ BO_ "GenMsgDelayTime" INT 0 0; BA_DEF_ SG_ "GenSigSendType" ENUM "none","Cyclic","OnWrite","OnChange"; BA_DEF_ SG_ "GenSigCycleTime" INT 0 10000; BA_DEF_ SG_ "GenSigDelayTime" INT 0 10000; BA_DEF_ SG_ "GenSigStartDelayTime" INT 0 10000; BA_DEF_ SG_ "GenSigStartValue" INT 0 0; BA_DEF_DEF_ "VFrameFormat" "StandardCAN"; BA_DEF_DEF_ "GenMsgSendType" "none"; BA_DEF_DEF_ "GenMsgCycleTime" 0; BA_DEF_DEF_ "GenMsgStartDelayTime" 0; BA_DEF_DEF_ "GenMsgDelayTime" 0; BA_DEF_DEF_ "GenSigSendType" "none"; BA_DEF_DEF_ "GenSigDelayTime" 0; BA_DEF_DEF_ "GenSigCycleTime" 0; BA_DEF_DEF_ "GenSigStartDelayTime" 0; BA_DEF_DEF_ "GenSigStartValue" 0; )code")); Parse(source); } } void CDbcParser::Parse(CDbcSource& rSource) { // Add to the list of sources. m_vecSources.push_back(rSource); // Reset the ID of the Vector independent message m_uiIndepMsgId = 0xffffffff; try { SkipWhitespace(rSource); while (!rSource.IsEOF()) { // Expecting a keyword std::string ssKeyword = GetIdentifier(rSource); if (ssKeyword.empty()) throw SDbcParserException("Keyword expected"); if (ssKeyword == "VERSION") ReadVersion(rSource); else if (ssKeyword == "NS_") ReadNewSymbols(rSource); else if (ssKeyword == "BS_") ReadBitTiming(rSource); else if (ssKeyword == "BU_") ReadNodeDef(rSource); else if (ssKeyword == "VAL_TABLE_") ReadValTable(rSource); else if (ssKeyword == "BO_") ReadMessageDef(rSource); else if (ssKeyword == "SIG_VALTYPE_") ReadSignalValueTypeDef(rSource); else if (ssKeyword == "BO_TX_BU_") ReadMessageTransmitters(rSource); else if (ssKeyword == "VAL_") ReadValueDescriptions(rSource); else if (ssKeyword == "EV_") ReadEnvVarDef(rSource); else if (ssKeyword == "ENVVAR_DATA_") ReadEnvVarData(rSource); else if (ssKeyword == "SGTYPE_") ReadSignalTypeDef(rSource); else if (ssKeyword == "SIG_GROUP_") ReadSignalGroupDef(rSource); else if (ssKeyword == "CM_") ReadCommentDef(rSource); else if (ssKeyword == "BA_DEF_") ReadAttrDef(rSource); else if (ssKeyword == "BA_DEF_DEF_") ReadAttrDefaultDef(rSource); else if (ssKeyword == "BA_") ReadAttributes(rSource); else if (ssKeyword == "SG_MUL_VAL_") ReadSignalMultiplexDef(rSource); else throw SDbcParserException(rSource, "Unknown keyword '%1'.", ssKeyword); SkipWhitespace(rSource); } } catch (SDbcParserException& rsException) { // Add the source if (!rsException.Source().IsValid()) rsException.Source(rSource); // Retrow throw; } } void CDbcParser::Clear() { m_vecVersions.clear(); m_mapNodes.clear(); m_mapValueTables.clear(); m_mapMsgDefByName.clear(); m_mapMsgDefById.clear(); } const std::vector& CDbcParser::GetSources() const { return m_vecSources; } const std::vector& CDbcParser::GetVersions() const { return m_vecVersions; } bool CDbcParser::HasNodeDef(const std::string& rssNodeDefName) const { return m_mapNodes.find(rssNodeDefName) != m_mapNodes.end(); } const std::vector CDbcParser::GetNodeDefNames() const { std::vector vecNodes; for (auto prNode : m_mapNodes) vecNodes.push_back(prNode.first); return vecNodes; } std::pair CDbcParser::GetNodeDef(const std::string& rssNodeDefName) const { auto itNode = m_mapNodes.find(rssNodeDefName); if (itNode == m_mapNodes.end()) return std::make_pair(SNodeDef(), false); return std::make_pair(itNode->second, true); } bool CDbcParser::HasValueTable(const std::string& rssName) const { return m_mapValueTables.find(rssName) != m_mapValueTables.end(); } bool CDbcParser::HasValue(const std::string& rssTableName, uint32_t uiValue) const { auto itTable = m_mapValueTables.find(rssTableName); if (itTable == m_mapValueTables.end()) return false; return itTable->second.find(uiValue) != itTable->second.end(); } std::string CDbcParser::GetValue(const std::string& rssTableName, uint32_t uiValue) const { auto itTable = m_mapValueTables.find(rssTableName); if (itTable == m_mapValueTables.end()) return std::string(); auto itValue = itTable->second.find(uiValue); if (itValue == itTable->second.end()) return std::string(); return itValue->second; } std::vector CDbcParser::GetValueTableNames() const { std::vector vecTables; for (auto prTable : m_mapValueTables) vecTables.push_back(prTable.first); return vecTables; } std::pair, bool> CDbcParser::GetValues(const std::string& rssTableName) const { // Find the table auto itTable = m_mapValueTables.find(rssTableName); std::vector vecEntries; if (itTable == m_mapValueTables.end()) return std::make_pair(vecEntries, false); for (auto prEntry : itTable->second) vecEntries.push_back(prEntry.first); return std::make_pair(std::move(vecEntries), true); } bool CDbcParser::HasMsgDef(const std::string& rssName) const { return m_mapMsgDefByName.find(rssName) != m_mapMsgDefByName.end(); } bool CDbcParser::HasMsgDef(uint32_t uiRawId) const { return m_mapMsgDefById.find(uiRawId) != m_mapMsgDefById.end(); } bool CDbcParser::HasMsgDefStdId(uint32_t uiStdId) const { if (uiStdId >= 1u << 11) return false; return m_mapMsgDefById.find(uiStdId) != m_mapMsgDefById.end(); } bool CDbcParser::HasMsgDefExtId(uint32_t uiExtId) const { if (uiExtId >= 1u << 29) return false; return m_mapMsgDefById.find(uiExtId | 0x80000000u) != m_mapMsgDefById.end(); } std::vector CDbcParser::GetMessageIDs() const { std::vector vecMsgIDs; for (auto prMsgDef : m_mapMsgDefById) vecMsgIDs.push_back(prMsgDef.first); return vecMsgIDs; } std::pair CDbcParser::ExtractMsgId(uint32_t uiRawId) { return std::make_pair(uiRawId & 0x7fffffffu, uiRawId & 0x80000000u ? true : false); } uint32_t CDbcParser::ComposeRawId(uint32_t uiMsgId, bool bExtended) { return uiMsgId | (bExtended ? 0x80000000u : 0x00000000u); } std::pair CDbcParser::GetMsgDef(const std::string& rssName) const { auto itMsgDef = m_mapMsgDefByName.find(rssName); if (itMsgDef == m_mapMsgDefByName.end()) return std::make_pair(SMessageDef(), false); return std::make_pair(*itMsgDef->second, true); } std::pair CDbcParser::GetMsgDef(uint32_t uiRawId) const { auto itMsgDef = m_mapMsgDefById.find(uiRawId); if (itMsgDef == m_mapMsgDefById.end()) return std::make_pair(SMessageDef(), false); return std::make_pair(*itMsgDef->second, true); } std::pair CDbcParser::GetMsgDefStdId(uint32_t uiStdId) const { if (uiStdId >= 1u << 11) return std::make_pair(SMessageDef(), false); auto itMsgDef = m_mapMsgDefById.find(uiStdId); if (itMsgDef == m_mapMsgDefById.end()) return std::make_pair(SMessageDef(), false); return std::make_pair(*itMsgDef->second, true); } std::pair CDbcParser::GetMsgDefExtId(uint32_t uiExtId) const { if (uiExtId >= 1u << 29) return std::make_pair(SMessageDef(), false); auto itMsgDef = m_mapMsgDefById.find(uiExtId | 0x80000000u); if (itMsgDef == m_mapMsgDefById.end()) return std::make_pair(SMessageDef(), false); return std::make_pair(*itMsgDef->second, true); } bool CDbcParser::HasSignalDef(const std::string& rssMsgName, const std::string& rssSignalName) const { auto prMsgDef = GetMsgDef(rssMsgName); if (!prMsgDef.second) return false; return std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(), [&](const SSignalDef& rsSignalDef) -> bool { return rsSignalDef.ssName == rssSignalName; }) != prMsgDef.first.vecSignals.end(); } bool CDbcParser::HasSignalDef(uint32_t uiRawMsgId, const std::string & rssSignalName) const { auto prMsgDef = GetMsgDef(uiRawMsgId); if (!prMsgDef.second) return false; return std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(), [&](const SSignalDef& rsSignalDef) -> bool { return rsSignalDef.ssName == rssSignalName; }) != prMsgDef.first.vecSignals.end(); } bool CDbcParser::HasSignalDefStdId(uint32_t uiStdMsgId, const std::string & rssSignalName) const { auto prMsgDef = GetMsgDefStdId(uiStdMsgId); if (!prMsgDef.second) return false; return std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(), [&](const SSignalDef& rsSignalDef) -> bool { return rsSignalDef.ssName == rssSignalName; }) != prMsgDef.first.vecSignals.end(); } bool CDbcParser::HasSignalDefExtId(uint32_t uiExtMsgId, const std::string & rssSignalName) const { auto prMsgDef = GetMsgDefExtId(uiExtMsgId); if (!prMsgDef.second) return false; return std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(), [&](const SSignalDef& rsSignalDef) -> bool { return rsSignalDef.ssName == rssSignalName; }) != prMsgDef.first.vecSignals.end(); } std::vector CDbcParser::GetSignalNames(uint32_t uiRawMsgId) const { auto prMsgDef = GetMsgDef(uiRawMsgId); if (!prMsgDef.second) return std::vector(); std::vector vecSigNames; for (const SSignalDef& rsSignalDef : prMsgDef.first.vecSignals) vecSigNames.push_back(rsSignalDef.ssName); return vecSigNames; } std::pair CDbcParser::GetSignalDef(const std::string & rssMsgName, const std::string & rssSignalName) const { auto prMsgDef = GetMsgDef(rssMsgName); if (!prMsgDef.second) return std::make_pair(SSignalDef(), false); auto itSignalDef = std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(), [&](const SSignalDef& rsSignalDef) -> bool { return rsSignalDef.ssName == rssSignalName; }); if (itSignalDef == prMsgDef.first.vecSignals.end()) return std::make_pair(SSignalDef(), false); return std::make_pair(*itSignalDef, true); } std::pair CDbcParser::GetSignalDef(uint32_t uiRawMsgId, const std::string & rssSignalName) const { auto prMsgDef = GetMsgDef(uiRawMsgId); if (!prMsgDef.second) return std::make_pair(SSignalDef(), false); auto itSignalDef = std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(), [&](const SSignalDef& rsSignalDef) -> bool { return rsSignalDef.ssName == rssSignalName; }); if (itSignalDef == prMsgDef.first.vecSignals.end()) return std::make_pair(SSignalDef(), false); return std::make_pair(*itSignalDef, true); } std::pair CDbcParser::GetSignalDefStdId(uint32_t uiStdMsgId, const std::string & rssSignalName) const { auto prMsgDef = GetMsgDefStdId(uiStdMsgId); if (!prMsgDef.second) return std::make_pair(SSignalDef(), false); auto itSignalDef = std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(), [&](const SSignalDef& rsSignalDef) -> bool { return rsSignalDef.ssName == rssSignalName; }); if (itSignalDef == prMsgDef.first.vecSignals.end()) return std::make_pair(SSignalDef(), false); return std::make_pair(*itSignalDef, true); } std::pair CDbcParser::GetSignalDefExtId(uint32_t uiExtMsgId, const std::string & rssSignalName) const { auto prMsgDef = GetMsgDefExtId(uiExtMsgId); if (!prMsgDef.second) return std::make_pair(SSignalDef(), false); auto itSignalDef = std::find_if(prMsgDef.first.vecSignals.begin(), prMsgDef.first.vecSignals.end(), [&](const SSignalDef& rsSignalDef) -> bool { return rsSignalDef.ssName == rssSignalName; }); if (itSignalDef == prMsgDef.first.vecSignals.end()) return std::make_pair(SSignalDef(), false); return std::make_pair(*itSignalDef, true); } std::vector CDbcParser::GetEnvVarNames() const { std::vector vecEnvVars; for (auto prEnvVar : m_mapEnvVars) vecEnvVars.push_back(prEnvVar.first); return vecEnvVars; } std::pair CDbcParser::GetEnvVarDef(const std::string& rssVarName) const { auto itVarDef = m_mapEnvVars.find(rssVarName); if (itVarDef == m_mapEnvVars.end()) return std::make_pair(SEnvVarDef(), false); return std::make_pair(itVarDef->second, true); } std::vector CDbcParser::GetSignalTypeDefNames() const { std::vector vecTypeDefs; for (auto prTypeDef : m_mapSigTypeDefs) vecTypeDefs.push_back(prTypeDef.first); return vecTypeDefs; } std::pair CDbcParser::GetSignalTypeDef(const std::string& rssSignalTypeDefName) const { auto itTypeDef = m_mapSigTypeDefs.find(rssSignalTypeDefName); if (itTypeDef == m_mapSigTypeDefs.end()) return std::make_pair(SSignalTypeDef(), false); return std::make_pair(itTypeDef->second, true); } std::vector CDbcParser::GetSignalGroupDefNames(uint32_t uiRawMsgId) const { std::vector vecGroupDefs; auto itMsgDef = m_mapMsgDefById.find(uiRawMsgId); if (itMsgDef != m_mapMsgDefById.end()) { for (auto prGroupDef : itMsgDef->second->mapSigGroups) vecGroupDefs.push_back(prGroupDef.first); } return vecGroupDefs; } std::pair CDbcParser::GetSignalGroupDef(uint32_t uiRawMsgId, const std::string& rssSignalGroupDefName) const { auto itMsgDef = m_mapMsgDefById.find(uiRawMsgId); if (itMsgDef == m_mapMsgDefById.end()) return std::make_pair(SSignalGroupDef(), false); auto itSigGroupDef = itMsgDef->second->mapSigGroups.find(rssSignalGroupDefName); if (itSigGroupDef == itMsgDef->second->mapSigGroups.end()) return std::make_pair(SSignalGroupDef(), false); return std::make_pair(itSigGroupDef->second, true); } const std::vector& CDbcParser::GetComments() const { return m_vecComments; } std::vector CDbcParser::GetAttributeDefNames() const { std::vector vecAttrDefs; for (auto prAttrDef : m_mapAttrDefs) vecAttrDefs.push_back(prAttrDef.first); return vecAttrDefs; } std::pair CDbcParser::GetAttributeDef(const std::string& rssAttributeDefName) const { auto itAttrDef = m_mapAttrDefs.find(rssAttributeDefName); if (itAttrDef == m_mapAttrDefs.end()) return std::make_pair(SAttributeDef(SAttributeDef::EType::integer), false); return std::make_pair(*itAttrDef->second, true); } const std::vector& CDbcParser::GetAttributes() const { return m_vecAttributes; } void CDbcParser::SkipWhitespace(CDbcSource& rSource) { // NOTE: Comments are not part of the official standard. while (!rSource.IsEOF()) { if (std::isspace(rSource.CurrentChar())) { rSource.Pos()++; continue; } if (rSource.CurrentChar() == '/') { auto sPosLock = rSource.CreatePosLock(); rSource.Pos()++; if (rSource.CurrentChar() == '/') { // Skip the rest of the line sPosLock.Promote(); while (!rSource.IsEOF() && rSource.CurrentChar() != '\n') rSource.Pos()++; continue; } } break; } } std::pair CDbcParser::GetUInt(CDbcSource& rSource) { SkipWhitespace(rSource); if (rSource.IsEOF()) return std::make_pair(0u, false); const char* szBegin = rSource.ContentPtr(); char* szEnd = nullptr; uint32_t uiVal = static_cast(std::strtoul(szBegin, &szEnd, 10)); if (errno == ERANGE) return std::make_pair(0u, false); if (!szEnd || szEnd == szBegin) return std::make_pair(0u, false); rSource.Pos() += (szEnd - szBegin); return std::make_pair(uiVal, true); } std::pair CDbcParser::GetInt(CDbcSource& rSource) { SkipWhitespace(rSource); if (rSource.IsEOF()) return std::make_pair(0, false); const char* szBegin = rSource.ContentPtr(); char* szEnd = nullptr; int32_t iVal = static_cast(std::strtol(szBegin, &szEnd, 10)); if (errno == ERANGE) return std::make_pair(0, false); if (!szEnd || szEnd == szBegin) return std::make_pair(0, false); rSource.Pos() += (szEnd - szBegin); return std::make_pair(iVal, true); } std::pair CDbcParser::GetDouble(CDbcSource& rSource) { SkipWhitespace(rSource); if (rSource.IsEOF()) return std::make_pair(0.0, false); const char* szBegin = rSource.ContentPtr(); char* szEnd = nullptr; double dVal = std::strtod(szBegin, &szEnd); if (errno == ERANGE) return std::make_pair(0.0, false); if (!szEnd || szEnd == szBegin) return std::make_pair(0.0, false); rSource.Pos() += (szEnd - szBegin); return std::make_pair(dVal, true); } bool CDbcParser::ExpectChar(char c, CDbcSource& rSource) { SkipWhitespace(rSource); if (rSource.IsEOF()) return false; if (rSource.CurrentChar() != c) return false; rSource.Pos()++; return true; } std::pair CDbcParser::GetString(CDbcSource& rSource) { SkipWhitespace(rSource); if (rSource.IsEOF()) return std::pair{std::string(), false}; // A string should start with a quote if (rSource.CurrentChar() != '\"') return std::pair{std::string(), false}; // Search for the next quote - skip escaped quotes std::string ssResult; do { size_t nBegin = ++rSource.Pos(); size_t nEnd = rSource.Content().find_first_of("\"\\", nBegin); if (nEnd == std::string::npos) return std::pair{std::string(), false}; ssResult += rSource.Content().substr(nBegin, nEnd - nBegin); rSource.Pos() = nEnd + 1; if (rSource.Content()[nEnd] != '\\') break; // Escaped character. Add and continue. ssResult += rSource.Content()[nEnd + 1]; rSource.Pos() = nEnd + 1; } while (true); return std::pair{ssResult, true}; } std::string CDbcParser::GetIdentifier(CDbcSource& rSource) { SkipWhitespace(rSource); std::string ssIdentifier; while (!rSource.IsEOF()) { char c = rSource.CurrentChar(); // Allowed are '_' and alphanumerical characters. The identifier is not allowed to start with a number // Undocumented extension: '-', '<' and '>' are also allowed. if (c != '_' && c != '-' && c != '<' && c != '>' && !(ssIdentifier.empty() ? std::isalpha(c) : std::isalnum(c))) break; ssIdentifier += c; rSource.Pos()++; } return ssIdentifier; } bool CDbcParser::IsDbcIdentifier(const std::string& rssIdentifier) { const char* rgszDbcKeywords[] = { "VERSION", "NS_", "NS_DESC_", "CM_", "BA_DEF_", "BA_", "VAL_", "CAT_DEF_", "CAT_", "FILTER", "BA_DEF_DEF_", "EV_DATA_", "ENVVAR_DATA_", "SGTYPE_", "SGTYPE_VAL_", "BA_DEF_SGTYPE_", "BA_SGTYPE_", "SIG_TYPE_REF_", "VAL_TABLE_", "SIG_GROUP_", "SIG_VALTYPE_", "SIGTYPE_VALTYPE_", "BO_TX_BU_", "BA_DEF_REL_", "BA_REL_", "BA_DEF_DEF_REL_", "BU_SG_REL_", "BU_EV_REL_", "BU_BO_REL_", "SG_MUL_VAL_", "BS_", "BU_", "BO_", "SG_", "EV_", "VECTOR__XXX" }; // Check whether the identifier does not correspond to one within the keyword list auto itDbcKeyword = std::find(std::begin(rgszDbcKeywords), std::end(rgszDbcKeywords), rssIdentifier); return itDbcKeyword != std::end(rgszDbcKeywords); } void CDbcParser::ReadVersion(CDbcSource& rSource) { auto prVersion = GetString(rSource); if (!prVersion.second) throw SDbcParserException("String expected following 'VERSION' keyword"); m_vecVersions.push_back(prVersion.first); } void CDbcParser::ReadNewSymbols(CDbcSource& rSource) { const char* rgszNewSymbols[] = { "CM_", "NS_DESC_", "BA_DEF_", "BA_", "VAL_", "CAT_DEF_", "CAT_", "FILTER", "BA_DEF_DEF_", "EV_DATA_", "ENVVAR_DATA_", "SGTYPE_", "SGTYPE_VAL_", "BA_DEF_SGTYPE_", "BA_SGTYPE_", "SIG_TYPE_REF_", "VAL_TABLE_", "SIG_GROUP_", "SIG_VALTYPE_", "SIGTYPE_VALTYPE_", "BO_TX_BU_", "BA_DEF_REL_", "BA_REL_", "BA_DEF_DEF_REL_", "BU_SG_REL_", "BU_EV_REL_", "BU_BO_REL_", "SG_MUL_VAL_" }; // Expect separator if (!ExpectChar(':', rSource)) throw SDbcParserException("Colon ':' expected following 'NS_' keyword"); // Zero or more symbols from the above list can be defined. do { // Get the next identifier auto sPosLock = rSource.CreatePosLock(); std::string ssSymbol = GetIdentifier(rSource); if (ssSymbol.empty()) break; // Check whether the identifier corresponds to one of the above list auto itSymbol = std::find(std::begin(rgszNewSymbols), std::end(rgszNewSymbols), ssSymbol); if (itSymbol == std::end(rgszNewSymbols)) break; // Update the position and check for the next symbol. sPosLock.Promote(); } while (!rSource.IsEOF()); } void CDbcParser::ReadBitTiming(CDbcSource& rSource) { // Expect separator if (!ExpectChar(':', rSource)) throw SDbcParserException("Colon ':' expected following 'BS_' keyword"); // Optionally the timing could be specified (since this section has been defined obsolete, it is more likely that // nothing is specified). auto prBaudrate = GetUInt(rSource); if (prBaudrate.second) { if (!ExpectChar(':', rSource)) throw SDbcParserException("Colon ':' expected following baudrate value."); auto prBTR1 = GetUInt(rSource); if (!prBTR1.second) throw SDbcParserException("BTR1 register value expected."); if (!ExpectChar(',', rSource)) throw SDbcParserException("Comma ',' expected following BTR1 register value"); auto prBTR2 = GetUInt(rSource); if (!prBTR2.second) throw SDbcParserException("BTR2 register value expected."); } } void CDbcParser::ReadNodeDef(CDbcSource& rSource) { // Expect separator if (!ExpectChar(':', rSource)) throw SDbcParserException("Colon ':' expected following 'BU_' keyword."); // Zero or more nodes can be defined std::map mapNodesLocal; do { // Get the next identifier SNodeDef sNodeDef; auto sPosLock = rSource.CreatePosLock(); sNodeDef.ssName = GetIdentifier(rSource); if (sNodeDef.ssName.empty()) break; // Check whether the identifier is a DBC identifier if (IsDbcIdentifier(sNodeDef.ssName)) break; // Add the node name to the local node name list. sPosLock.Promote(); if (mapNodesLocal.find(sNodeDef.ssName) != mapNodesLocal.end()) throw SDbcParserException("Duplicate nodes defined."); mapNodesLocal.insert(std::make_pair(sNodeDef.ssName, sNodeDef)); } while (!rSource.IsEOF()); // Add the local nodes to the global node set (if not already existing). m_mapNodes.insert(mapNodesLocal.begin(), mapNodesLocal.end()); } void CDbcParser::ReadValTable(CDbcSource& rSource) { // Get the name of the table std::string ssTableName = GetIdentifier(rSource); if (ssTableName.empty() || IsDbcIdentifier(ssTableName)) throw SDbcParserException("Expecting a name for the value table."); if (m_mapValueTables.find(ssTableName) != m_mapValueTables.end()) throw SDbcParserException("Duplicate value table definition."); // Zero or more definitions can follow TValDescMap mapValues; do { auto prValue = GetUInt(rSource); if (!prValue.second) break; // Not a value auto prString = GetString(rSource); if (!prString.second) throw SDbcParserException("Expecting a string following the value."); // Duplicate values are not allowed if (mapValues.find(prValue.first) != mapValues.end()) throw SDbcParserException("Duplicate value definition."); // Insert the value. mapValues.insert(std::make_pair(prValue.first, prString.first)); } while (!rSource.IsEOF()); // Expect terminator if (!ExpectChar(';', rSource)) throw SDbcParserException("Semi-colon ';' expected finalizing the definition of the 'VAL_TABLE_'"); // Insert the table m_mapValueTables.insert(std::make_pair(ssTableName, mapValues)); } void CDbcParser::ReadMessageDef(CDbcSource& rSource) { // Get the message ID auto prId = GetUInt(rSource); if (!prId.second) throw SDbcParserException("Expecting an ID for the message."); uint32_t uiId = prId.first; // Get the name of the message std::string ssMessageName = GetIdentifier(rSource); if (ssMessageName.empty() || IsDbcIdentifier(ssMessageName)) throw SDbcParserException("Expecting a name for the message."); // Correct the ID for the default message (enforce the same ID for this message). if (ssMessageName == "VECTOR__INDEPENDENT_SIG_MSG") { m_uiIndepMsgId = uiId; uiId = 0xffffffff; } else { if (uiId & 0x80000000) // Differentiate between extended and standard ID { if ((uiId & 0x7fffffff) >= 1u<<29) throw SDbcParserException("Specified extended message ID is larger than the 29 bits."); } else { if ((uiId & 0x7fffffff) >= 1u<<11) throw SDbcParserException("Specified standard message ID is larger than the 11 bits."); } } // Expect separator if (!ExpectChar(':', rSource)) throw SDbcParserException("Colon ':' expected following 'BO_' message definition"); // Get the message size auto prSize = GetUInt(rSource); if (!prSize.second) throw SDbcParserException("Expecting a size for the message."); // Get the transmitter name std::string ssTransmitter = GetIdentifier(rSource); if (ssTransmitter.empty()) throw SDbcParserException("Expecting a transmitter name for the message."); if (ssTransmitter != "Vector__XXX" && ssTransmitter != "Vector_XXX" && m_mapNodes.find(ssTransmitter) == m_mapNodes.end()) throw SDbcParserException("Expecting a valid pre-defined transmitter name for the message."); // Duplicate definitions are not allowed. // Except when the message is named "VECTOR__INDEPENDENT_SIG_MSG", which is just a placeholder. In the latter case, the // message is extended with the defined signals. auto itMessage = m_mapMsgDefByName.find(ssMessageName); if (itMessage == m_mapMsgDefByName.end()) { auto ptrMessage = std::make_shared(); auto prResult1 = m_mapMsgDefByName.emplace(std::make_pair(ssMessageName, ptrMessage)); if (!prResult1.second) throw SDbcParserException("Failed to construct message definition for '%1' and ID %2.", ssMessageName, uiId); itMessage = prResult1.first; auto prResult2 = m_mapMsgDefById.emplace(std::make_pair(uiId, ptrMessage)); if (!prResult2.second) { m_mapMsgDefByName.erase(prResult1.first); throw SDbcParserException("Failed to construct message definition for '%1' and ID %2.", ssMessageName, uiId); } } else { if (ssMessageName != "VECTOR__INDEPENDENT_SIG_MSG") throw SDbcParserException("Duplicate message definition for ID '%1' and ID %2.", ssMessageName, uiId); } // Set the message information itMessage->second->ssName = ssMessageName; itMessage->second->uiId = uiId; itMessage->second->uiSize += prSize.first; itMessage->second->vecTransmitters.push_back(ssTransmitter); // Check for signals do { // Try peeking for the signal definition. Us a position lock to be able to rollback if the identifier doesn't represent a // signal definition. auto sPosLock = rSource.CreatePosLock(); std::string ssIdentfier = GetIdentifier(rSource); if (ssIdentfier != "SG_") break; sPosLock.Promote(); ReadSignalDef(rSource, *itMessage->second); } while (true); } void CDbcParser::ReadSignalTypeDefBase(CDbcSource& rSource, SSignalTypeBase& rsSignalTypeDefBase) { // Get size auto prSize = GetUInt(rSource); if (!prSize.second) throw SDbcParserException("Expecting the signal size."); rsSignalTypeDefBase.uiSize = prSize.first; // Expect separator if (!ExpectChar('@', rSource)) throw SDbcParserException("At-sign '@' expected following size in the signal definition"); // Get byte order auto prByteOrder = GetUInt(rSource); if (!prByteOrder.second) throw SDbcParserException("Expecting the byte order indicator."); if (prByteOrder.first > 1) throw SDbcParserException("Invalid byte order indicator for the signal (0=big endian or 1=little endian are allowed)."); rsSignalTypeDefBase.eByteOrder = prByteOrder.first ? SSignalDef::EByteOrder::little_endian : SSignalDef::EByteOrder::big_endian; // Get the value type if (ExpectChar('+', rSource)) rsSignalTypeDefBase.eValType = SSignalDef::EValueType::unsigned_integer; else if (ExpectChar('-', rSource)) rsSignalTypeDefBase.eValType = SSignalDef::EValueType::signed_integer; else throw SDbcParserException("Invalid value type ('+'=unsigned or '-'=signed are allowed)."); // Get the opening bracket if (!ExpectChar('(', rSource)) throw SDbcParserException("Left bracket '(' expected following the value type in the signal definition"); // Get the factor auto prFactor = GetDouble(rSource); if (!prFactor.second) throw SDbcParserException("Expecting the factor value."); if (prFactor.first == 0.0) throw SDbcParserException("A factor value of 0 is not valid."); rsSignalTypeDefBase.dFactor = prFactor.first; // Get the comma if (!ExpectChar(',', rSource)) throw SDbcParserException("Comma '(' expected following the factor value in the signal definition"); // Get the offset auto prOffset = GetDouble(rSource); if (!prOffset.second) throw SDbcParserException("Expecting the offset value."); rsSignalTypeDefBase.dOffset = prOffset.first; // Get the closing bracket if (!ExpectChar(')', rSource)) throw SDbcParserException("Right bracket ')' expected following the offset value in the signal definition"); // Get the opening square-bracket if (!ExpectChar('[', rSource)) throw SDbcParserException("Left square-bracket '[' expected following the factor and offset in the signal definition"); // Get the minimum auto prMinimum = GetDouble(rSource); if (!prMinimum.second) throw SDbcParserException("Expecting the minimum value."); rsSignalTypeDefBase.dMinimum = prMinimum.first; // Expect separator if (!ExpectChar('|', rSource)) throw SDbcParserException("Pipe '|' expected following the minimum in the signal definition"); // Get the maximum auto prMaximum = GetDouble(rSource); if (!prMaximum.second) throw SDbcParserException("Expecting the maximum value."); rsSignalTypeDefBase.dMaximum = prMaximum.first; // Get the closing square-bracket if (!ExpectChar(']', rSource)) throw SDbcParserException("Right square-bracket ']' expected following the maximum in the signal definition"); // Get the unit string auto prUnit = GetString(rSource); if (!prUnit.second) throw SDbcParserException("String expected following the minimum and maximum in the signal definition"); rsSignalTypeDefBase.ssUnit = prUnit.first; } void CDbcParser::ReadSignalDef(CDbcSource& rSource, SMessageDef& rsMsgDef) { SSignalDef sSignalDef; // Set the message ID sSignalDef.uiMsgId = rsMsgDef.uiId; // Get the name of the signal sSignalDef.ssName = GetIdentifier(rSource); if (sSignalDef.ssName.empty() || IsDbcIdentifier(sSignalDef.ssName)) throw SDbcParserException("Expecting a name for the signal."); if (std::find_if(rsMsgDef.vecSignals.begin(), rsMsgDef.vecSignals.end(), [&](const SSignalDef& rsSignal) -> bool { return rsSignal.ssName == sSignalDef.ssName; }) != rsMsgDef.vecSignals.end()) throw SDbcParserException("Duplicate signal defined within the message."); // Check for the multiplexer indicator. if (ExpectChar('m', rSource)) { sSignalDef.uiMultiplexBitmask |= static_cast(SSignalDef::EMultiplexBitmask::mltplx_val); auto prCaseVal = GetInt(rSource); if (!prCaseVal.second) throw SDbcParserException("Expecting a multiplexed switch case value."); sSignalDef.iMltplxCase = prCaseVal.first; } if (ExpectChar('M', rSource)) sSignalDef.uiMultiplexBitmask |= static_cast(SSignalDef::EMultiplexBitmask::mltplx_switch); // Expect separator if (!ExpectChar(':', rSource)) throw SDbcParserException("Colon ':' expected following 'SG_' signal definition"); // Get start bit auto prStartBit = GetUInt(rSource); if (!prStartBit.second) throw SDbcParserException("Expecting the start bit."); if (rsMsgDef.uiId != 0xffffffff && prStartBit.first >= 8 * rsMsgDef.uiSize) throw SDbcParserException("Start bit has been defined beyond the size of the message."); sSignalDef.uiStartBit = prStartBit.first; // Expect separator if (!ExpectChar('|', rSource)) throw SDbcParserException("Pipe '|' expected following start bit in the signal definition"); // Get the signal type def - base part ReadSignalTypeDefBase(rSource, sSignalDef); // Check correct size if (sSignalDef.eByteOrder == SSignalDef::EByteOrder::little_endian) { // The signal occupies the area from start-bit until start-bit + size. if (rsMsgDef.uiId != 0xffffffff && sSignalDef.uiStartBit + sSignalDef.uiSize > rsMsgDef.uiSize * 8) throw SDbcParserException("The length of the signal positioned at the start bit exceeds the length of the message."); } else // big endian { // The signal occupies the byte where the start bit determines the MSB and any number of following bytes that start with // the most significant bit. For example: // Signal 1: start=7 length = 4 // Signal 2: start=3 length = 8 // Signal 3: start=11 length = 6 // Signal 4: start=21 length = 6 // Signal 5: start=31 length = 8 // Signal 6: start=39 length = 32 // 7 6 5 4 3 2 1 0 // 0 | Signal 1 | Signal 2 MSB | // 1 | signal 2 LSB | Signal 3 MSB | // 2 | Sig 3 | Signal 4 | // 3 | Signal 5 | // 4 | Signal 6 MSB | // 5 | | // 6 | | // 7 | Signal 6 LSB | auto fnInverseBitPos = [](uint32_t uiPos) -> uint32_t { uint32_t uiInverseStartBit = (uiPos >> 3) << 3; uint32_t uiInverseStartBitInByte = (8 - ((uiPos + 1) & 7)) & 7; return uiInverseStartBit + uiInverseStartBitInByte; }; if (rsMsgDef.uiId != 0xffffffff && fnInverseBitPos(sSignalDef.uiStartBit) + sSignalDef.uiSize > rsMsgDef.uiSize * 8) throw SDbcParserException("The length of the signal positioned at the start bit exceeds the length of the message."); } // Get one or more receivers do { // Get the receiver std::string ssReceiver = GetIdentifier(rSource); if (ssReceiver.empty() || IsDbcIdentifier(ssReceiver)) throw SDbcParserException("Expecting a receiver for the signal."); // Check the receiver with the predefined nodes (except for "Vector__XXX" node) if (ssReceiver != "Vector__XXX" && ssReceiver != "Vector_XXX" && m_mapNodes.find(ssReceiver) == m_mapNodes.end()) throw SDbcParserException("Expecting a valid pre-defined receiver name for the signal."); // Check for multiple definitions if (std::find(sSignalDef.vecReceivers.begin(), sSignalDef.vecReceivers.end(), ssReceiver) != sSignalDef.vecReceivers.end()) throw SDbcParserException("Duplicate receiver name defined for the signal."); // Add to the receiver vector sSignalDef.vecReceivers.push_back(std::move(ssReceiver)); // Check for additional receivers if (!ExpectChar(',', rSource)) break; } while(true); // Add the signal to the message rsMsgDef.vecSignals.push_back(std::move(sSignalDef)); } void CDbcParser::ReadSignalValueTypeDef(CDbcSource& rSource) { // Get the message ID auto prMsgId = GetUInt(rSource); if (!prMsgId.second) throw SDbcParserException("Expecting the message ID."); if (prMsgId.first == m_uiIndepMsgId) prMsgId.first = 0xffffffff; auto itMsgDef = m_mapMsgDefById.find(prMsgId.first); if (itMsgDef == m_mapMsgDefById.end()) throw SDbcParserException("Could not find message with supplied ID."); // Get the signal name std::string ssSignalName = GetIdentifier(rSource); auto itSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(), [&](const SSignalDef& rsSignalDef) { return rsSignalDef.ssName == ssSignalName; }); if (itSignal == itMsgDef->second->vecSignals.end()) throw SDbcParserException("Could not find signal with supplied name."); // DEVIATION: The specification doesn't specifies a colon; CANdb++ inserts a colon ExpectChar(':', rSource); // Get the value type and if necessary update the value type enum of the signal. auto prValType = GetUInt(rSource); if (!prValType.second) throw SDbcParserException("Expecting the value type (0..2)."); switch (prValType.first) { case 0: // Integer (signed/unsigned) is per default. break; case 1: // IEEE float itSignal->eValType = SSignalDef::EValueType::ieee_float; break; case 2: // IEEE double itSignal->eValType = SSignalDef::EValueType::ieee_double; break; default: throw SDbcParserException("Invalid value type (0..2)."); break; } // Expecting the ending if (!ExpectChar(';', rSource)) throw SDbcParserException("Semi-colon ';' expected."); } void CDbcParser::ReadMessageTransmitters(CDbcSource& rSource) { // Get the message ID auto prMsgId = GetUInt(rSource); if (!prMsgId.second) throw SDbcParserException("Expecting the message ID."); if (prMsgId.first == m_uiIndepMsgId) prMsgId.first = 0xffffffff; auto itMsgDef = m_mapMsgDefById.find(prMsgId.first); if (itMsgDef == m_mapMsgDefById.end()) throw SDbcParserException("Could not find message with supplied ID."); // Expect separator if (!ExpectChar(':', rSource)) throw SDbcParserException("Colon ':' expected following 'BO_TX_BU_' message transmitters definition"); // Expect zero or more transmitters do { // Check for semi-colon indicating the end of the definition. if (ExpectChar(';', rSource)) break; // Get the transmitter name std::string ssTransmitter = GetIdentifier(rSource); if (ssTransmitter.empty()) throw SDbcParserException("Expecting a transmitter name for the message."); if (ssTransmitter != "Vector__XXX" && ssTransmitter != "Vector_XXX" && m_mapNodes.find(ssTransmitter) == m_mapNodes.end()) throw SDbcParserException("Expecting a valid pre-defined transmitter name for the message."); if (std::find(itMsgDef->second->vecTransmitters.begin(), itMsgDef->second->vecTransmitters.end(), ssTransmitter) != itMsgDef->second->vecTransmitters.end()) throw SDbcParserException("Duplicate transmitter defined for the message."); // Add the transmitter. itMsgDef->second->vecTransmitters.push_back(ssTransmitter); } while(true); } void CDbcParser::ReadValueDescriptions(CDbcSource& rSource) { TValDescMap* pmapValues = nullptr; // Get the message ID - if existing, this indicates a signal value descriptions. // Or a name - this indicates an environment variable auto prMsgId = GetUInt(rSource); if (prMsgId.second) { if (prMsgId.first == m_uiIndepMsgId) prMsgId.first = 0xffffffff; auto itMsgDef = m_mapMsgDefById.find(prMsgId.first); if (itMsgDef == m_mapMsgDefById.end()) throw SDbcParserException("Could not find message with supplied ID."); // Get the signal name std::string ssSignalName = GetIdentifier(rSource); auto itSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(), [&](const SSignalDef& rsSignalDef) { return rsSignalDef.ssName == ssSignalName; }); if (itSignal == itMsgDef->second->vecSignals.end()) throw SDbcParserException("Could not find signal with supplied name."); if (!itSignal->mapValueDescriptions.empty()) throw SDbcParserException("Duplicate value assignment."); pmapValues = &itSignal->mapValueDescriptions; } else { std::string ssEnvVarName = GetIdentifier(rSource); if (ssEnvVarName.empty()) throw SDbcParserException("Could not find message or environment variable."); auto itVarDef = m_mapEnvVars.find(ssEnvVarName); if (itVarDef == m_mapEnvVars.end()) throw SDbcParserException("Could not find environment variable with supplied name."); pmapValues = &itVarDef->second.mapValueDescriptions; } if (!pmapValues) throw SDbcParserException("Could not find message or environment variable."); // Zero or more definitions can follow TValDescMap mapValues; do { auto prValue = GetUInt(rSource); if (!prValue.second) break; // Not a value auto prString = GetString(rSource); if (!prString.second) throw SDbcParserException("Expecting a string following the value."); // Duplicate values are not allowed if (mapValues.find(prValue.first) != mapValues.end()) throw SDbcParserException("Duplicate value definition."); // Insert the value. mapValues.insert(std::make_pair(prValue.first, prString.first)); } while (!rSource.IsEOF()); // Expect terminator if (!ExpectChar(';', rSource)) throw SDbcParserException("Semi-colon ';' expected finalizing the definition of the 'VAL_'"); // Assign the values *pmapValues = std::move(mapValues); } void CDbcParser::ReadEnvVarDef(CDbcSource& rSource) { SEnvVarDef sEnvVarDef; // Get the name of the variable sEnvVarDef.ssName = GetIdentifier(rSource); if (sEnvVarDef.ssName.empty() || IsDbcIdentifier(sEnvVarDef.ssName)) throw SDbcParserException("Expecting a name for the environment variable."); if (m_mapEnvVars.find(sEnvVarDef.ssName) != m_mapEnvVars.end()) throw SDbcParserException("Duplicate environment variable defined."); // Expect separator if (!ExpectChar(':', rSource)) throw SDbcParserException("Colon ':' expected following 'EV_' environment variable definition"); // Get the variable type auto prType = GetUInt(rSource); if (!prType.second) throw SDbcParserException("Expecting the byte order indicator."); switch (prType.first) { case 0: sEnvVarDef.eType = SEnvVarDef::EType::integer; break; case 1: sEnvVarDef.eType = SEnvVarDef::EType::floating_point; break; case 2: sEnvVarDef.eType = SEnvVarDef::EType::string; break; default: throw SDbcParserException("Invalid type defined for environment variable definition (0=integer, 1=float and 2=string are allowed)."); break; } // Get the opening square-bracket if (!ExpectChar('[', rSource)) throw SDbcParserException("Left square-bracket '[' expected following the variable type in the environment variable definition"); // Get the minimum auto prMinimum = GetDouble(rSource); if (!prMinimum.second) throw SDbcParserException("Expecting the minimum value."); sEnvVarDef.dMinimum = prMinimum.first; // Expect separator if (!ExpectChar('|', rSource)) throw SDbcParserException("Pipe '|' expected following the minimum in the environment variable definition"); // Get the maximum auto prMaximum = GetDouble(rSource); if (!prMaximum.second) throw SDbcParserException("Expecting the maximum value."); sEnvVarDef.dMaximum = prMaximum.first; // Get the closing square-bracket if (!ExpectChar(']', rSource)) throw SDbcParserException("Right square-bracket ']' expected following the maximum in the environment variable definition"); // Get the unit string auto prUnit = GetString(rSource); if (!prUnit.second) throw SDbcParserException("String expected following the minimum and maximum in the environment variable definition"); sEnvVarDef.ssUnit = prUnit.first; // Get the initial value auto prInitVal = GetDouble(rSource); if (!prInitVal.second) throw SDbcParserException("Expecting the initial value."); sEnvVarDef.dInitVal = prInitVal.first; // Get the variable ID auto prId = GetUInt(rSource); if (!prId.second) throw SDbcParserException("Expecting the environment variable ID."); sEnvVarDef.uiId = prId.first; // Get the access type std::string ssAccess = GetIdentifier(rSource); if (ssAccess == "DUMMY_NODE_VECTOR0") sEnvVarDef.eAccess = SEnvVarDef::EAccessType::unrestricted; else if (ssAccess == "DUMMY_NODE_VECTOR1") sEnvVarDef.eAccess = SEnvVarDef::EAccessType::read; else if (ssAccess == "DUMMY_NODE_VECTOR2") sEnvVarDef.eAccess = SEnvVarDef::EAccessType::write; else if (ssAccess == "DUMMY_NODE_VECTOR3") sEnvVarDef.eAccess = SEnvVarDef::EAccessType::readwrite; else if (ssAccess == "DUMMY_NODE_VECTOR8000") { if (sEnvVarDef.eType != SEnvVarDef::EType::string) throw SDbcParserException("The access type expects the environment variable to be a string."); sEnvVarDef.eAccess = SEnvVarDef::EAccessType::unrestricted; } else if (ssAccess == "DUMMY_NODE_VECTOR8001") { if (sEnvVarDef.eType != SEnvVarDef::EType::string) throw SDbcParserException("The access type expects the environment variable to be a string."); sEnvVarDef.eAccess = SEnvVarDef::EAccessType::read; } else if (ssAccess == "DUMMY_NODE_VECTOR8002") { if (sEnvVarDef.eType != SEnvVarDef::EType::string) throw SDbcParserException("The access type expects the environment variable to be a string."); sEnvVarDef.eAccess = SEnvVarDef::EAccessType::write; } else if (ssAccess == "DUMMY_NODE_VECTOR8003") { if (sEnvVarDef.eType != SEnvVarDef::EType::string) throw SDbcParserException("The access type expects the environment variable to be a string."); sEnvVarDef.eAccess = SEnvVarDef::EAccessType::readwrite; } else throw SDbcParserException("Invalid access type for the environment variable."); // Get one or more access nodes do { // Get the access node std::string ssNode = GetIdentifier(rSource); if (ssNode.empty() || IsDbcIdentifier(ssNode)) throw SDbcParserException("Expecting an access node for the environment variable."); // Check the access node with the predefined nodes (except for "Vector__XXX" node) if (ssNode != "Vector__XXX" && ssNode != "Vector_XXX" && m_mapNodes.find(ssNode) == m_mapNodes.end()) throw SDbcParserException("Expecting a valid pre-defined access node name for the environment variable."); // Check for multiple definitions if (std::find(sEnvVarDef.vecNodes.begin(), sEnvVarDef.vecNodes.end(), ssNode) != sEnvVarDef.vecNodes.end()) throw SDbcParserException("Duplicate access node name defined for the environment variable."); // Add to the receiver vector sEnvVarDef.vecNodes.push_back(std::move(ssNode)); // Check for additional receivers if (!ExpectChar(',', rSource)) break; } while(true); // Expecting the ending if (!ExpectChar(';', rSource)) throw SDbcParserException("Semi-colon ';' expected."); // Add the variable to the message m_mapEnvVars.insert(std::make_pair(sEnvVarDef.ssName, sEnvVarDef)); } void CDbcParser::ReadEnvVarData(CDbcSource& rSource) { std::string ssEnvVarName = GetIdentifier(rSource); if (ssEnvVarName.empty()) throw SDbcParserException("Expected environment variable name."); auto itVarDef = m_mapEnvVars.find(ssEnvVarName); if (itVarDef == m_mapEnvVars.end()) throw SDbcParserException("Could not find environment variable with supplied name."); // Expect separator if (!ExpectChar(':', rSource)) throw SDbcParserException("Colon ':' expected following 'ENVVAR_DATA_' environment variable data definition"); // Get the data size auto prSize = GetUInt(rSource); if (!prSize.second) throw SDbcParserException("Expecting the data size."); // Expecting the ending if (!ExpectChar(';', rSource)) throw SDbcParserException("Semi-colon ';' expected."); // Promote the data type of the variable to "data" and set the data size itVarDef->second.eType = SEnvVarDef::EType::data; itVarDef->second.uiDataSize = prSize.first; } void CDbcParser::ReadSignalTypeDef(CDbcSource& rSource) { // Get the message ID - if existing, this indicates a signal type def assignment. // Or a name - this indicates a signal type definition. auto prMsgId = GetUInt(rSource); if (prMsgId.second) { if (prMsgId.first == m_uiIndepMsgId) prMsgId.first = 0xffffffff; auto itMsgDef = m_mapMsgDefById.find(prMsgId.first); if (itMsgDef == m_mapMsgDefById.end()) throw SDbcParserException("Could not find message with supplied ID."); // Get the signal name std::string ssSignalName = GetIdentifier(rSource); auto itSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(), [&](const SSignalDef& rsSignalDef) { return rsSignalDef.ssName == ssSignalName; }); if (itSignal == itMsgDef->second->vecSignals.end()) throw SDbcParserException("Could not find signal with supplied name."); if (!itSignal->ssSignalTypeDef.empty()) throw SDbcParserException("Duplicate signal type definition assignment."); // Expect separator if (!ExpectChar(':', rSource)) throw SDbcParserException("Colon ':' expected following 'SGTYPE_' signal type definition"); // Get the name of the signal type definition std::string ssSignalTypeDef = GetIdentifier(rSource); if (m_mapSigTypeDefs.find(ssSignalTypeDef) == m_mapSigTypeDefs.end()) throw SDbcParserException("Could not find signal type definition with supplied name."); itSignal->ssSignalTypeDef = ssSignalTypeDef; } else { SSignalTypeDef sSignalTypeDef; sSignalTypeDef.ssName = GetIdentifier(rSource); if (sSignalTypeDef.ssName.empty()) throw SDbcParserException("Could not find signal type definition name."); auto itTypeDef = m_mapSigTypeDefs.find(sSignalTypeDef.ssName); if (itTypeDef != m_mapSigTypeDefs.end()) throw SDbcParserException("Duplicate signal type definition with supplied name."); // Expect separator if (!ExpectChar(':', rSource)) throw SDbcParserException("Colon ':' expected following 'SGTYPE_' signal type definition"); // Get the signal type def - base part ReadSignalTypeDefBase(rSource, sSignalTypeDef); // Get the default value auto prDefaultVal = GetDouble(rSource); if (!prDefaultVal.second) throw SDbcParserException("Expecting the default value."); sSignalTypeDef.dDefaultValue = prDefaultVal.first; // Expect separator if (!ExpectChar(',', rSource)) throw SDbcParserException("Comma ',' expected following default value in signal type definition"); // Value table name sSignalTypeDef.ssValueTable = GetIdentifier(rSource); if (sSignalTypeDef.ssValueTable != "Vector__XXX" && sSignalTypeDef.ssValueTable != "Vector_XXX") { if (sSignalTypeDef.ssValueTable.empty()) throw SDbcParserException("Expecting a value table name."); if (m_mapValueTables.find(sSignalTypeDef.ssValueTable) == m_mapValueTables.end()) throw SDbcParserException("Value table not found."); } // Add the signal type definition m_mapSigTypeDefs.insert(std::make_pair(sSignalTypeDef.ssName, sSignalTypeDef)); } // Expecting the ending if (!ExpectChar(';', rSource)) throw SDbcParserException("Semi-colon ';' expected."); } void CDbcParser::ReadSignalGroupDef(CDbcSource& rSource) { // Get the message ID and the belonging message auto prMsgId = GetUInt(rSource); if (!prMsgId.second) throw SDbcParserException("No message ID supplied."); if (prMsgId.first == m_uiIndepMsgId) prMsgId.first = 0xffffffff; auto itMsgDef = m_mapMsgDefById.find(prMsgId.first); if (itMsgDef == m_mapMsgDefById.end()) throw SDbcParserException("Could not find message with supplied ID."); // Get the signal group name SSignalGroupDef sSigGrpDef; sSigGrpDef.ssName = GetIdentifier(rSource); if (sSigGrpDef.ssName.empty()) throw SDbcParserException("Missing signal group name."); if (IsDbcIdentifier(sSigGrpDef.ssName)) throw SDbcParserException("Invalid signal group name."); if (itMsgDef->second->mapSigGroups.find(sSigGrpDef.ssName) != itMsgDef->second->mapSigGroups.end()) throw SDbcParserException("Duplicate signal group definition."); // Get repetition auto prRepetition = GetUInt(rSource); if (!prRepetition.second) throw SDbcParserException("Expected repetition factor following the signal group name."); sSigGrpDef.uiRepetitions = prRepetition.first; // Expect separator if (!ExpectChar(':', rSource)) throw SDbcParserException("Colon ':' expected following 'SIG_GROUP_' signal group definition"); // Expect zero or more signal definitions do { // Check for semi-colon indicating the end of the definition. if (ExpectChar(';', rSource)) break; // Get the signal name std::string ssSignalName = GetIdentifier(rSource); if (ssSignalName.empty()) throw SDbcParserException("Expecting a signal name."); auto itSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(), [&](const SSignalDef& rsSignalDef) { return rsSignalDef.ssName == ssSignalName; }); if (itSignal == itMsgDef->second->vecSignals.end()) throw SDbcParserException("Could not find signal with supplied name."); // Add the signal name. sSigGrpDef.vecSignals.push_back(ssSignalName); // DEVIATION: The specification doesn't specifies a comma ExpectChar(',', rSource); } while(true); // Add the group to the message itMsgDef->second->mapSigGroups.insert(std::make_pair(sSigGrpDef.ssName, sSigGrpDef)); } void CDbcParser::ReadCommentDef(CDbcSource& rSource) { // Determine the entity the comment is for std::vector* pvecComments = nullptr; std::string ssEntity = GetIdentifier(rSource); if (ssEntity == "BU_") { // Find the node std::string ssNodeName = GetIdentifier(rSource); auto itNode = m_mapNodes.find(ssNodeName); if (itNode == m_mapNodes.end()) throw SDbcParserException("Invalid node name."); pvecComments = &itNode->second.vecComments; } else if (ssEntity == "BO_") { // Find the message auto prMsgId = GetUInt(rSource); if (!prMsgId.second) throw SDbcParserException("Expecting the message ID."); if (prMsgId.first == m_uiIndepMsgId) prMsgId.first = 0xffffffff; auto itMsgDef = m_mapMsgDefById.find(prMsgId.first); if (itMsgDef == m_mapMsgDefById.end()) throw SDbcParserException("Could not find message with supplied ID."); pvecComments = &itMsgDef->second->vecComments; } else if (ssEntity == "SG_") { // Find the message auto prMsgId = GetUInt(rSource); if (!prMsgId.second) throw SDbcParserException("Expecting the message ID."); if (prMsgId.first == m_uiIndepMsgId) prMsgId.first = 0xffffffff; auto itMsgDef = m_mapMsgDefById.find(prMsgId.first); if (itMsgDef == m_mapMsgDefById.end()) throw SDbcParserException("Could not find message with supplied ID."); // Find the signal std::string ssSignalName = GetIdentifier(rSource); auto itSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(), [&](const SSignalDef& rsSignalDef) { return rsSignalDef.ssName == ssSignalName; }); if (itSignal == itMsgDef->second->vecSignals.end()) throw SDbcParserException("Could not find signal with supplied name."); pvecComments = &itSignal->vecComments; } else if (ssEntity == "EV_") { // Find the environment variable std::string ssEnvVarName = GetIdentifier(rSource); if (ssEnvVarName.empty()) throw SDbcParserException("Could not find message or environment variable."); auto itVarDef = m_mapEnvVars.find(ssEnvVarName); if (itVarDef == m_mapEnvVars.end()) throw SDbcParserException("Could not find environment variable with supplied name."); pvecComments = &itVarDef->second.vecComments; } else pvecComments = &m_vecComments; // Global comments // There should be a valid comments vector. if (!pvecComments) throw SDbcParserException("Internal error with comments vector."); // Get the comment auto prComment = GetString(rSource); if (!prComment.second) throw SDbcParserException("Mising comment string."); // Add comment to definition pvecComments->push_back(prComment.first); // Expect terminator if (!ExpectChar(';', rSource)) throw SDbcParserException("Semi-colon ';' expected finalizing the comment 'CM_'"); } void CDbcParser::ReadAttrDef(CDbcSource& rSource) { std::string ssEntity = GetIdentifier(rSource); SAttributeDef::EObjectType eObjType = SAttributeDef::EObjectType::global; if (ssEntity == "BU_") eObjType = SAttributeDef::EObjectType::node; else if (ssEntity == "BO_") eObjType = SAttributeDef::EObjectType::message; else if (ssEntity == "SG_") eObjType = SAttributeDef::EObjectType::signal; else if (ssEntity == "EV_") eObjType = SAttributeDef::EObjectType::envvar; else if (!ssEntity.empty()) throw SDbcParserException("Invalid object type."); // Expect opening quote if (!ExpectChar('\"', rSource)) throw SDbcParserException("Quote '\"' expected preceding attribute definition name"); // Get the name std::string ssName = GetIdentifier(rSource); if (ssName.empty() || IsDbcIdentifier(ssName)) throw SDbcParserException("Expecting a name for the attribute definition."); // Expect closing quote if (!ExpectChar('\"', rSource)) throw SDbcParserException("Quote '\"' expected following attribute definition name"); // Get the value type std::string ssValueType = GetIdentifier(rSource); TAttributeDefPtr ptrAttrDef = std::make_shared(SAttributeDef::EType::integer); if (ssValueType == "INT") { auto prMin = GetInt(rSource); if (!prMin.second) throw SDbcParserException("Expecting minimum value for integer attribute definition."); ptrAttrDef->sIntValues.iMinimum = prMin.first; auto prMax = GetInt(rSource); if (!prMax.second) throw SDbcParserException("Expecting maximum value for integer attribute definition."); ptrAttrDef->sIntValues.iMaximum = prMax.first; } else if (ssValueType == "HEX") { ptrAttrDef = std::move(std::make_shared(SAttributeDef::EType::hex_integer)); auto prMin = GetUInt(rSource); if (!prMin.second) throw SDbcParserException("Expecting minimum value for hexadecimal attribute definition."); ptrAttrDef->sHexValues.uiMinimum = prMin.first; auto prMax = GetUInt(rSource); if (!prMax.second) throw SDbcParserException("Expecting maximum value for hexadecimal attribute definition."); ptrAttrDef->sHexValues.uiMaximum = prMax.first; } else if (ssValueType == "FLOAT") { ptrAttrDef = std::move(std::make_shared(SAttributeDef::EType::floating_point)); auto prMin = GetDouble(rSource); if (!prMin.second) throw SDbcParserException("Expecting minimum value for floating point attribute definition."); ptrAttrDef->sFltValues.dMinimum = prMin.first; auto prMax = GetDouble(rSource); if (!prMax.second) throw SDbcParserException("Expecting maximum value for floating point attribute definition."); ptrAttrDef->sFltValues.dMaximum = prMax.first; } else if (ssValueType == "STRING") { ptrAttrDef = std::move(std::make_shared(SAttributeDef::EType::string)); } else if (ssValueType == "ENUM") { ptrAttrDef = std::move(std::make_shared(SAttributeDef::EType::enumerator)); // Zero or more strings could available bool bInitial = true; do { // Try getting the enum entry string auto prEnumEntry = GetString(rSource); if (!bInitial && !prEnumEntry.second) throw SDbcParserException("Expecting an enumerator entry string."); bInitial = false; // Not used or not applicable entries are added, but can be redundant. // The use of "n/a" and "not-used" is not part of the official standard. if (prEnumEntry.first != "not-used" && prEnumEntry.first != "n/a") { if (std::find(ptrAttrDef->sEnumValues.vecEnumValues.begin(), ptrAttrDef->sEnumValues.vecEnumValues.end(), prEnumEntry.first) != ptrAttrDef->sEnumValues.vecEnumValues.end()) throw SDbcParserException("Duplicate enumerator entry string."); } // Add the value. ptrAttrDef->sEnumValues.vecEnumValues.push_back(prEnumEntry.first); // Another entry if a comma is provided if (!ExpectChar(',', rSource)) break; } while (true); } else throw SDbcParserException("Invalid attribute definition value type."); // Add the attribute definition ptrAttrDef->eObjType = eObjType; ptrAttrDef->ssName = ssName; m_mapAttrDefs.insert_or_assign(ssName, std::move(ptrAttrDef)); // Expect terminator SkipWhitespace(rSource); if (!ExpectChar(';', rSource)) throw SDbcParserException("Semi-colon ';' expected finalizing the attribute definition 'AB_DEF_'"); } void CDbcParser::ReadAttrDefaultDef(CDbcSource& rSource) { // Expect opening quote if (!ExpectChar('\"', rSource)) throw SDbcParserException("Quote '\"' expected preceding attribute definition name"); // Get the name std::string ssName = GetIdentifier(rSource); auto itAttrDef = m_mapAttrDefs.find(ssName); if (itAttrDef == m_mapAttrDefs.end()) throw SDbcParserException("Cannot find attribute definition with supplied name."); // Expect closing quote if (!ExpectChar('\"', rSource)) throw SDbcParserException("Quote '\"' expected following attribute definition name"); // Get the value switch (itAttrDef->second->eType) { case SAttributeDef::EType::integer: { // Some definitions use a float for defining an integer. auto prFloat = GetDouble(rSource); if (!prFloat.second) throw SDbcParserException("Expecting an integer value for the default value of the attribute definition"); itAttrDef->second->sIntValues.iDefault = static_cast(prFloat.first); break; } case SAttributeDef::EType::hex_integer: { // Some definitions use a float for defining an integer. auto prFloat = GetDouble(rSource); if (!prFloat.second) throw SDbcParserException("Expecting an unsigned integer value for the default value of the attribute definition"); if (prFloat.first < 0.0) throw SDbcParserException("Expecting an unsigned integer value for the default value of the attribute definition"); itAttrDef->second->sHexValues.uiDefault = static_cast(prFloat.first); break; } case SAttributeDef::EType::floating_point: { auto prFlt = GetDouble(rSource); if (!prFlt.second) throw SDbcParserException("Expecting a floating point value for the default value of the attribute definition"); itAttrDef->second->sFltValues.dDefault = prFlt.first; break; } case SAttributeDef::EType::string: { auto prStr = GetString(rSource); if (!prStr.second) throw SDbcParserException("Expecting a string value for the default value of the attribute definition"); itAttrDef->second->sStringValues.ssDefault = std::move(prStr.first); break; } case SAttributeDef::EType::enumerator: { auto prStr = GetString(rSource); if (!prStr.second) { auto prInt = GetUInt(rSource); if (!prInt.second) throw SDbcParserException("Expecting a string value for the default value of the attribute definition"); if (prInt.first >= itAttrDef->second->sEnumValues.vecEnumValues.size()) throw SDbcParserException("Default value out of range for the attribute definition"); itAttrDef->second->sEnumValues.ssDefault = itAttrDef->second->sEnumValues.vecEnumValues[prInt.first]; } else { // Non-documented extension: check the enum values without case consideration. if (std::find_if(itAttrDef->second->sEnumValues.vecEnumValues.begin(), itAttrDef->second->sEnumValues.vecEnumValues.end(), [&](const std::string& rss) {return internal::EqualNC(rss, prStr.first);}) == itAttrDef->second->sEnumValues.vecEnumValues.end()) throw SDbcParserException("The enum value doesn't fit the list of the predefined values."); itAttrDef->second->sEnumValues.ssDefault = std::move(prStr.first); } break; } default: throw SDbcParserException("Internal error: invalid attribute definition value type."); break; } // Expect terminator if (!ExpectChar(';', rSource)) throw SDbcParserException("Semi-colon ';' expected finalizing the attribute definition 'AB_DEF_DEF_'"); } void CDbcParser::ReadAttributes(CDbcSource& rSource) { // Expect opening quote if (!ExpectChar('\"', rSource)) throw SDbcParserException("Quote '\"' expected preceding attribute definition name"); // Get the name std::string ssName = GetIdentifier(rSource); auto itAttrDef = m_mapAttrDefs.find(ssName); if (itAttrDef == m_mapAttrDefs.end()) throw SDbcParserException("Cannot find attribute definition with supplied name."); // Expect closing quote if (!ExpectChar('\"', rSource)) throw SDbcParserException("Quote '\"' expected following attribute definition name"); std::string ssEntity = GetIdentifier(rSource); SAttributeDef::EObjectType eObjType = SAttributeDef::EObjectType::global; std::vector* pAttrVals = nullptr; if (ssEntity == "BU_") { eObjType = SAttributeDef::EObjectType::node; // Get the node definition std::string ssNode = GetIdentifier(rSource); auto itNode = m_mapNodes.find(ssNode); if (itNode == m_mapNodes.end()) throw SDbcParserException("Cannot find node with supplied name."); pAttrVals = &itNode->second.vecAttributes; } else if (ssEntity == "BO_") { eObjType = SAttributeDef::EObjectType::message; // Get the message definition auto prMsgId = GetUInt(rSource); if (!prMsgId.second) throw SDbcParserException("Expecting the message ID."); if (prMsgId.first == m_uiIndepMsgId) prMsgId.first = 0xffffffff; auto itMsgDef = m_mapMsgDefById.find(prMsgId.first); if (itMsgDef == m_mapMsgDefById.end()) throw SDbcParserException("Could not find message with supplied ID."); pAttrVals = &itMsgDef->second->vecAttributes; } else if (ssEntity == "SG_") { eObjType = SAttributeDef::EObjectType::signal; // Get the message definition auto prMsgId = GetUInt(rSource); if (!prMsgId.second) throw SDbcParserException("Expecting the message ID."); if (prMsgId.first == m_uiIndepMsgId) prMsgId.first = 0xffffffff; auto itMsgDef = m_mapMsgDefById.find(prMsgId.first); if (itMsgDef == m_mapMsgDefById.end()) throw SDbcParserException("Could not find message with supplied ID."); // Get the signal definition std::string ssSignalDef = GetIdentifier(rSource); auto itSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(), [&](const SSignalDef& rsSignalDef) { return rsSignalDef.ssName == ssSignalDef; }); if (itSignal == itMsgDef->second->vecSignals.end()) throw SDbcParserException("Could not find signal with supplied name."); pAttrVals = &itSignal->vecAttributes; } else if (ssEntity == "EV_") { eObjType = SAttributeDef::EObjectType::envvar; // Get the environment variable definition std::string ssEnvVarDef = GetIdentifier(rSource); auto itEnvVarDef = m_mapEnvVars.find(ssEnvVarDef); if (itEnvVarDef == m_mapEnvVars.end()) throw SDbcParserException("Cannot find environment variable definition with supplied name."); pAttrVals = &itEnvVarDef->second.vecAttributes; } else if (ssEntity.empty()) { eObjType = SAttributeDef::EObjectType::global; // Global entity pAttrVals = &m_vecAttributes; } // Check whether the object types match if (itAttrDef->second->eObjType != eObjType) throw SDbcParserException("Object type of attribute value is not fitting the object type of the attribute definition."); // Get the attribute value SAttributeValue sAttrVal(itAttrDef->second); switch (itAttrDef->second->eType) { case SAttributeDef::EType::integer: { // Some definitions use a float for defining an integer. auto prFloat = GetDouble(rSource); if (!prFloat.second) throw SDbcParserException("Expecting an integer value for the default value of the attribute definition"); sAttrVal.iValue = static_cast(prFloat.first); break; } case SAttributeDef::EType::hex_integer: { // Some definitions use a float for defining an integer. auto prFloat = GetDouble(rSource); if (!prFloat.second) throw SDbcParserException("Expecting an unsigned integer value for the default value of the attribute definition"); if (prFloat.first < 0.0) throw SDbcParserException("Expecting an unsigned integer value for the default value of the attribute definition"); sAttrVal.uiValue = static_cast(prFloat.first); break; } case SAttributeDef::EType::floating_point: { auto prFlt = GetDouble(rSource); if (!prFlt.second) throw SDbcParserException("Expecting a floating point value for the default value of the attribute definition"); sAttrVal.dValue = prFlt.first; break; } case SAttributeDef::EType::string: { auto prStr = GetString(rSource); if (!prStr.second) throw SDbcParserException("Expecting a string value for the default value of the attribute definition"); sAttrVal.ssValue = std::move(prStr.first); break; } case SAttributeDef::EType::enumerator: { auto prStr = GetString(rSource); if (!prStr.second) { auto prInt = GetUInt(rSource); if (!prInt.second) throw SDbcParserException("Expecting a string value for the default value of the attribute definition"); if (prInt.first >= itAttrDef->second->sEnumValues.vecEnumValues.size()) throw SDbcParserException("Default value out of range for the attribute definition"); sAttrVal.ssValue = itAttrDef->second->sEnumValues.vecEnumValues[prInt.first]; } else { if (std::find(itAttrDef->second->sEnumValues.vecEnumValues.begin(), itAttrDef->second->sEnumValues.vecEnumValues.end(), prStr.first) == itAttrDef->second->sEnumValues.vecEnumValues.end()) throw SDbcParserException("The enum value doesn't fit the list of the predefined values."); sAttrVal.ssValue = std::move(prStr.first); } break; } default: throw SDbcParserException("Internal error: invalid attribute definition value type."); break; } // Add the value if (!pAttrVals) throw SDbcParserException("Internal error: attribute value vector not existing."); pAttrVals->push_back(std::move(sAttrVal)); // Expect terminator if (!ExpectChar(';', rSource)) throw SDbcParserException("Semi-colon ';' expected finalizing the attribute value 'AB_'"); } void CDbcParser::ReadSignalMultiplexDef(CDbcSource& rSource) { // Get the message definition auto prMsgId = GetUInt(rSource); if (!prMsgId.second) throw SDbcParserException("Expecting the message ID."); if (prMsgId.first == m_uiIndepMsgId) prMsgId.first = 0xffffffff; auto itMsgDef = m_mapMsgDefById.find(prMsgId.first); if (itMsgDef == m_mapMsgDefById.end()) throw SDbcParserException("Could not find message with supplied ID."); // Get the signal definition for the multiplexed signal std::string ssMultiplexedSignalDef = GetIdentifier(rSource); auto itMultiplexedSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(), [&](const SSignalDef& rsSignalDef) { return rsSignalDef.ssName == ssMultiplexedSignalDef; }); if (itMultiplexedSignal == itMsgDef->second->vecSignals.end()) throw SDbcParserException("Could not find multiplexed signal with supplied name."); // Get the signal definition for the multiplexor signal std::string ssMultiplexorSignalDef = GetIdentifier(rSource); auto itMultiplexorSignal = std::find_if(itMsgDef->second->vecSignals.begin(), itMsgDef->second->vecSignals.end(), [&](const SSignalDef& rsSignalDef) { return rsSignalDef.ssName == ssMultiplexorSignalDef; }); if (itMultiplexorSignal == itMsgDef->second->vecSignals.end()) throw SDbcParserException("Could not find multiplexor signal with supplied name."); itMultiplexorSignal->uiMultiplexBitmask |= static_cast(SSignalDef::EMultiplexBitmask::mltplx_switch); // Create the information structure SSignalDef::SExtendedMultiplex sExtMultiplex{ *itMultiplexorSignal, {} }; // Read zero or more ranges do { auto itLow = GetUInt(rSource); if (!itLow.second) break; if (!ExpectChar('-', rSource)) throw SDbcParserException("Expecting dash '-' between low and and high range value for a multiplexed signal."); auto itHigh = GetUInt(rSource); if (!itHigh.second) throw SDbcParserException("Missing high range value for a multiplexed signal."); sExtMultiplex.vecRanges.push_back(std::make_pair(itLow.first, itHigh.first)); // DEVIATION: The specification doesn't specifies a comma; the example does ExpectChar(',', rSource); } while (true); // Add the multiplexed structure to the multiplexed signal itMultiplexedSignal->vecExtMultiplex.push_back(std::move(sExtMultiplex)); // Expect terminator if (!ExpectChar(';', rSource)) throw SDbcParserException("Semi-colon ';' expected finalizing the extended multiplexer definition 'SG_MUL_VAL_'"); } } // namespace dbc #ifdef _MSC_VER #pragma warning(pop) #endif