/** * @file * * @copyright * @verbatim Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. @endverbatim */ #include "ddlprinter.h" #include "a_util/result/error_def.h" #include "legacy_error_macros.h" #include "ddlcontainer.h" #include "ddldescription.h" #include "ddlunit.h" #include "ddlbaseunit.h" #include "ddlprefix.h" #include "ddldatatype.h" #include "ddlenum.h" #include "ddlcomplex.h" #include "ddlstream.h" #include "ddlstreammetatype.h" #include "ddlheader.h" #include "ddlextdeclaration.h" #include "ddlrefunit.h" #include "ddlelement.h" #include "ddlstreamstruct.h" #include "ddlversion.h" namespace ddl { //define all needed error types and values locally _MAKE_RESULT(-4, ERR_POINTER) _MAKE_RESULT(-16, ERR_NOT_IMPL) _MAKE_RESULT(-20, ERR_NOT_FOUND) _MAKE_RESULT(-38, ERR_FAILED) _MAKE_RESULT(-44, ERR_INVALID_VERSION) DDLPrinter::DDLPrinter(const bool& full_out): _dom{}, _version(DDLVersion::ddl_version_invalid), _full_out{full_out}, _last_path{}, _forced_version(DDLVersion::ddl_version_invalid) { #if defined(WIN32) && _MSC_VER < 1900 _set_output_format(_TWO_DIGIT_EXPONENT); #endif // WIN32 } template a_util::result::Result AcceptAll(DDLContainer& oElems, V* pVisitor) { for (typename DDLContainer::iterator itElem = oElems.begin(); itElem != oElems.end(); ++itElem) { RETURN_IF_FAILED((*itElem)->accept(pVisitor)); } return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visitDDL(const DDLDescription* poDescription) { if (!poDescription) { return ERR_POINTER; } _dom.reset(); _dom.fromString("\n \ \n \ "); RETURN_IF_FAILED(poDescription->getHeader()->accept(this)); _dom.getRoot().createChild("units"); DDLContainer vecDDLBaseunits = poDescription->getBaseunits(); RETURN_IF_FAILED(AcceptAll(vecDDLBaseunits, this)); DDLContainer vecDDLPrefixes = poDescription->getPrefixes(); RETURN_IF_FAILED(AcceptAll(vecDDLPrefixes, this)); DDLContainer vecDDLUnits = poDescription->getUnits(); RETURN_IF_FAILED(AcceptAll(vecDDLUnits, this)); _dom.getRoot().createChild("datatypes"); DDLContainer vecDDLDataTypes = poDescription->getDatatypes(); RETURN_IF_FAILED(AcceptAll(vecDDLDataTypes, this)); _dom.getRoot().createChild("enums"); DDLContainer vecDDLEnums = poDescription->getEnums(); RETURN_IF_FAILED(AcceptAll(vecDDLEnums, this)); _dom.getRoot().createChild("structs"); DDLContainer vecStructs = poDescription->getStructs(); RETURN_IF_FAILED(AcceptAll(vecStructs, this)); _dom.getRoot().createChild("streams"); DDLContainer vecStreams = poDescription->getStreams(); RETURN_IF_FAILED(AcceptAll(vecStreams, this)); if (poDescription->getHeader()->getLanguageVersion() >= DDLVersion::ddl_version_40) { _dom.getRoot().createChild("streammetatypes"); DDLContainer vecStreamMetaTypes = poDescription->getStreamMetaTypes(); RETURN_IF_FAILED(AcceptAll(vecStreamMetaTypes, this)); } return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLHeader* poHeader) { if (!poHeader) { return ERR_POINTER; } a_util::xml::DOMElement oHeaderElem = _dom.getRoot().createChild("header"); a_util::xml::DOMElement oLangElem = oHeaderElem.createChild("language_version"); if (_forced_version == DDLVersion::ddl_version_invalid) { _version = poHeader->getLanguageVersion(); } else { _version = _forced_version; } oLangElem.setData(_version.toString()); a_util::xml::DOMElement oAutElem = oHeaderElem.createChild("author"); oAutElem.setData(poHeader->getAuthor()); a_util::xml::DOMElement oDateElem = oHeaderElem.createChild("date_creation"); a_util::datetime::Date sDateTmp = poHeader->getDateCreation(); oDateElem.setData(sDateTmp.format("%d.%m.%Y")); a_util::xml::DOMElement oChangeElem = oHeaderElem.createChild("date_change"); sDateTmp = poHeader->getDateChange(); oChangeElem.setData(sDateTmp.format("%d.%m.%Y")); a_util::xml::DOMElement oDescElem = oHeaderElem.createChild("description"); oDescElem.setData(poHeader->getDescription()); DDLExtDeclarationVec vecExtDecls = poHeader->getExtDeclarations(); for (DDLExtDeclarationIt itED = vecExtDecls.begin(); vecExtDecls.end() != itED; ++itED) { RETURN_IF_FAILED((*itED)->accept(this)); } return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLExtDeclaration* poExtDeclaration) { if (!poExtDeclaration) { return ERR_POINTER; } a_util::xml::DOMElement oHeader; if (!_dom.getRoot().findNode("header", oHeader)) { return ERR_NOT_FOUND; } a_util::xml::DOMElement oEDElement = oHeader.createChild("ext_declaration"); oEDElement.setAttribute("key", poExtDeclaration->getKey()); oEDElement.setAttribute("value", poExtDeclaration->getValue()); return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLBaseunit* poBaseunit) { if (!poBaseunit) { return ERR_POINTER; } a_util::xml::DOMElement oUnits; if (!_dom.getRoot().findNode("units", oUnits)) { return ERR_NOT_FOUND; } a_util::xml::DOMElement oBUElement = oUnits.createChild("baseunit"); oBUElement.setAttribute("name", poBaseunit->getName()); oBUElement.setAttribute("symbol", poBaseunit->getSymbol()); oBUElement.setAttribute("description", poBaseunit->getDescription()); return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLPrefix* poPrefix) { if (!poPrefix) { return ERR_POINTER; } a_util::xml::DOMElement oUnits; if (!_dom.getRoot().findNode("units", oUnits)) { return ERR_NOT_FOUND; } a_util::xml::DOMElement oPrefixElement = oUnits.createChild("prefixes"); oPrefixElement.setAttribute("name", poPrefix->getName()); oPrefixElement.setAttribute("symbol", poPrefix->getSymbol()); oPrefixElement.setAttribute("power", a_util::strings::toString((int32_t)poPrefix->getPower())); return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLUnit* poUnit) { if (!poUnit) { return ERR_POINTER; } a_util::xml::DOMElement oUnits; if (!_dom.getRoot().findNode("units", oUnits)) { return ERR_NOT_FOUND; } a_util::xml::DOMElement oUnitElement = oUnits.createChild("unit"); oUnitElement.setAttribute("name", poUnit->getName()); a_util::xml::DOMElement oTmpElement = oUnitElement.createChild("numerator"); oTmpElement.setData(poUnit->getNumerator()); oTmpElement = oUnitElement.createChild("denominator"); oTmpElement.setData(poUnit->getDenominator()); oTmpElement = oUnitElement.createChild("offset"); oTmpElement.setData(a_util::strings::toString(static_cast (poUnit->getOffset()))); std::vector vecDDLRefUnits = poUnit->getRefUnits(); _last_path = a_util::strings::format("%s[@name='%s']", oUnitElement.getPath().c_str(), oUnitElement.getAttribute("name").c_str()); for (size_t i = 0; i < vecDDLRefUnits.size(); i++) { RETURN_IF_FAILED(vecDDLRefUnits[i]->accept(this)); } _last_path.clear(); return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLRefUnit* poRefUnit) { if (!poRefUnit) { return ERR_POINTER; } a_util::xml::DOMElement oParent; if (!_dom.findNode(_last_path, oParent)) { return ERR_NOT_FOUND; } a_util::xml::DOMElement oRUElement = oParent.createChild("refUnit"); oRUElement.setAttribute("name", poRefUnit->getName()); oRUElement.setAttribute("power", a_util::strings::toString((int32_t)poRefUnit->getPower())); oRUElement.setAttribute("prefix", poRefUnit->getPrefix()); if (_full_out) { a_util::xml::DOMElement oElem; if (!_dom.findNode(a_util::strings::format("//units/prefixes[@name=\"%s\"]", poRefUnit->getPrefix().c_str()), oElem)) { RETURN_IF_FAILED(poRefUnit->getPrefixObject()->accept(this)); } if (!_dom.findNode(a_util::strings::format("//units/baseunit[@name=\"%s\"]", poRefUnit->getName().c_str()), oElem)) { if (!_dom.findNode(a_util::strings::format("//units/unit[@name=\"%s\"]", poRefUnit->getName().c_str()), oElem)) { RETURN_IF_FAILED(poRefUnit->getUnitObject()->accept(this)); } } } return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLDataType* poDataType) { if (!poDataType) { return ERR_POINTER; } a_util::xml::DOMElement oDatatypes; if (!_dom.getRoot().findNode("datatypes", oDatatypes)) { return ERR_NOT_FOUND; } a_util::xml::DOMElement oDTElement = oDatatypes.createChild("datatype"); if (_version < DDLVersion::ddl_version_11) { oDTElement.setAttribute("type", poDataType->getName()); } else { oDTElement.setAttribute("name", poDataType->getName()); } oDTElement.setAttribute("size", a_util::strings::toString(static_cast(poDataType->getNumBits()))); if (!poDataType->getDescription().empty()) { oDTElement.setAttribute("description", poDataType->getDescription()); } if(poDataType->getArraysize() > 1) { oDTElement.setAttribute("arraysize", a_util::strings::toString(static_cast (poDataType->getArraysize()))); } if (!poDataType->getUnit().empty()) { oDTElement.setAttribute("unit", poDataType->getUnit()); } if (_version >= DDLVersion::ddl_version_30) { // min and max values are supported since DDL 3.0 if (poDataType->isMinValid()) { oDTElement.setAttribute("min", poDataType->getMinValue()); } if (poDataType->isMaxValid()) { oDTElement.setAttribute("max", poDataType->getMaxValue()); } } return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLComplex* poStruct) { if (!poStruct) { return ERR_POINTER; } a_util::xml::DOMElement oStructs; if (_dom.findNode(a_util::strings::format("//structs/struct[@name=\"%s\"]", poStruct->getName().c_str()), oStructs)) { //already added return a_util::result::SUCCESS; } if (!_dom.getRoot().findNode("structs", oStructs)) { return ERR_NOT_FOUND; } a_util::xml::DOMElement oStructElement = oStructs.createChild("struct"); oStructElement.setAttribute("name", poStruct->getName()); oStructElement.setAttribute("version", a_util::strings::toString(static_cast(poStruct->getVersion()))); if (!poStruct->getComment().empty()) { oStructElement.setAttribute("comment", poStruct->getComment()); } if (_version >= DDLVersion::ddl_version_11) { oStructElement.setAttribute("alignment", DDLAlignment::toString(poStruct->getAlignment())); } if (_version != poStruct->getDDLVersion()) { oStructElement.setAttribute("ddlversion", poStruct->getDDLVersion().toString()); } std::vector vecDDLElements = poStruct->getElements(); for (size_t i = 0; i < vecDDLElements.size(); i++) { _last_path = a_util::strings::format("%s[@name='%s']", oStructElement.getPath().c_str(), poStruct->getName().c_str()); RETURN_IF_FAILED(vecDDLElements[i]->accept(this)); } _last_path.clear(); return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLElement* poElement) { if (!poElement) { return ERR_POINTER; } a_util::xml::DOMElement oParent; a_util::xml::DOMElement oDomElem; if (!_dom.findNode(_last_path, oParent)) { return ERR_NOT_FOUND; } a_util::xml::DOMElement oElem = oParent.createChild("element"); oElem.setAttribute("type", poElement->getType()); oElem.setAttribute("name", poElement->getName()); if (_full_out) { if (!_dom.findNode(a_util::strings::format("//structs/struct[@name=\"%s\"]", poElement->getType().c_str()), oDomElem)) { if (!_dom.findNode(a_util::strings::format("//datatypes/datatype[@name=\"%s\"]", poElement->getType().c_str()), oDomElem)) { if (!_dom.findNode(a_util::strings::format("//enums/enum[@name=\"%s\"]", poElement->getType().c_str()), oDomElem)) { RETURN_IF_FAILED(poElement->getTypeObject()->accept(this)); } } } } a_util::xml::DOMElement oDeserializedElement = oElem; a_util::xml::DOMElement oSerializedElement = oElem; if (_version >= DDLVersion::ddl_version_40) { oDeserializedElement = oElem.createChild("deserialized"); oSerializedElement = oElem.createChild("serialized"); } oSerializedElement.setAttribute("bytepos", a_util::strings::toString(static_cast (poElement->getBytepos()))); if ((_version < DDLVersion::ddl_version_11 && poElement->getBitpos() != 1) || (_version >= DDLVersion::ddl_version_11 && poElement->getBitpos() > 0)) { oSerializedElement.setAttribute("bitpos", a_util::strings::toString(static_cast (poElement->getBitpos()))); } if (poElement->getNumBits() > 0) { oSerializedElement.setAttribute("numbits", a_util::strings::toString(static_cast (poElement->getNumBits()))); } oSerializedElement.setAttribute("byteorder", DDLByteorder::toString(poElement->getByteorder())); oDeserializedElement.setAttribute("alignment", DDLAlignment::toString(poElement->getAlignment())); if (!poElement->getDescription().empty()) { oElem.setAttribute("description", poElement->getDescription()); } if(poElement->getArraysize() == 0 || !poElement->getArraySizeSource().empty()) { oElem.setAttribute("arraysize", poElement->getArraySizeSource()); } else { oElem.setAttribute("arraysize", a_util::strings::toString(static_cast (poElement->getArraysize()))); } if (!poElement->getUnit().empty()) { oElem.setAttribute("unit", poElement->getUnit()); } if (!poElement->getComment().empty()) { oElem.setAttribute("comment", poElement->getComment()); } if (!poElement->getConstantValue().empty()) { oElem.setAttribute("value", poElement->getConstantValue()); } if (_version >= DDLVersion::ddl_version_30) { // min, max, default, scale, and offset values are supported since DDL 3.0 if (poElement->isMinValid()) { oElem.setAttribute("min", poElement->getMinValue()); } if (poElement->isMaxValid()) { oElem.setAttribute("max", poElement->getMaxValue()); } if (poElement->isDefaultValid()) { oElem.setAttribute("default", poElement->getDefaultValue()); } if (poElement->isScaleValid()) { oElem.setAttribute("scale", poElement->getScaleValue()); } if (poElement->isOffsetValid()) { oElem.setAttribute("offset", poElement->getOffsetValue()); } } return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLStream* poStream) { if (!poStream) { return ERR_POINTER; } a_util::xml::DOMElement oStreams; if (!_dom.getRoot().findNode("streams", oStreams)) { return ERR_NOT_FOUND; } a_util::xml::DOMElement oStreamElement = oStreams.createChild("stream"); if (!poStream->getName().empty()) { oStreamElement.setAttribute("name", poStream->getName()); } oStreamElement.setAttribute("type", poStream->getType()); if (_full_out) { a_util::xml::DOMElement oElem; if (!_dom.findNode(a_util::strings::format("//structs/struct[@name=\"%s\"]", poStream->getType().c_str()), oElem)) { RETURN_IF_FAILED(poStream->getTypeObject()->accept(this)); } } if (!poStream->getDescription().empty()) { oStreamElement.setAttribute("description", poStream->getDescription()); } std::vector vecStructs = poStream->getStructs(); _last_path = a_util::strings::format("%s[@name='%s']", oStreamElement.getPath().c_str(), oStreamElement.getAttribute("name").c_str()); for (size_t i = 0; i < vecStructs.size(); i++) { RETURN_IF_FAILED(vecStructs[i]->accept(this)); } _last_path.clear(); return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLStreamStruct* poStreamStruct) { if (!poStreamStruct) { return ERR_POINTER; } a_util::xml::DOMElement oParent; if (!_dom.findNode(_last_path, oParent)) { return ERR_NOT_FOUND; } a_util::xml::DOMElement oStruct = oParent.createChild("struct"); oStruct.setAttribute("type", poStreamStruct->getType()); if (!poStreamStruct->getName().empty()) { oStruct.setAttribute("name", poStreamStruct->getName()); } if (_full_out) { a_util::xml::DOMElement oElem; if (!_dom.findNode(a_util::strings::format("//structs/struct[@name=\"%s\"]", poStreamStruct->getType().c_str()), oElem)) { RETURN_IF_FAILED(poStreamStruct->getTypeObject()->accept(this)); } } oStruct.setAttribute("bytepos", a_util::strings::toString(static_cast (poStreamStruct->getBytepos()))); return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLEnum* poEnum ) { if (!poEnum) { return ERR_POINTER; } a_util::xml::DOMElement oEnums; if (_dom.findNode(a_util::strings::format("//enums/enum[@name=\"%s\"]", poEnum->getName().c_str()), oEnums)) { //already added return a_util::result::SUCCESS; } if (!_dom.getRoot().findNode("enums", oEnums)) { return ERR_NOT_FOUND; } a_util::xml::DOMElement oEnumElement = oEnums.createChild("enum"); oEnumElement.setAttribute("name", poEnum->getName()); if (!poEnum->getType().empty()) { oEnumElement.setAttribute("type", poEnum->getType()); } EnumNameValueVec vecNameValues = poEnum->getValues(); for (EnumNameValueVec::iterator itElement = vecNameValues.begin(); itElement != vecNameValues.end(); ++itElement) { a_util::xml::DOMElement oEnumValueElement = oEnumElement.createChild("element"); oEnumValueElement.setAttribute("name", itElement->first); oEnumValueElement.setAttribute("value", itElement->second); } return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLStreamMetaType* poStreamMetaType) { a_util::xml::DOMElement oStreamMetaTypes; if (!_dom.getRoot().findNode("streammetatypes", oStreamMetaTypes)) { return ERR_NOT_FOUND; } a_util::xml::DOMElement oElement = oStreamMetaTypes.createChild("streammetatype"); oElement.setAttribute("name", poStreamMetaType->getName()); oElement.setAttribute("version", poStreamMetaType->getVersion()); if (poStreamMetaType->getParentObject()) { oElement.setAttribute("parent", poStreamMetaType->getParent()); } const DDLPropertyVec& vecProperties = poStreamMetaType->getProperties(); for (DDLPropertyVec::const_iterator it = vecProperties.cbegin(); it != vecProperties.cend(); ++it) { a_util::xml::DOMElement oPropertyNode = oElement.createChild("property"); oPropertyNode.setAttribute("name", (*it)->getName()); oPropertyNode.setAttribute("type", (*it)->getType()); } return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::visit(const DDLProperty* poProperty) { return ERR_NOT_IMPL; } std::string DDLPrinter::getXML() const { return std::string(_dom.toString()); } a_util::result::Result DDLPrinter::toFile(const std::string& strFilename) const { if (!_dom.save(strFilename)) { return ERR_FAILED; } return a_util::result::SUCCESS; } a_util::result::Result DDLPrinter::forceVersion(const DDLVersion& forced_version) { if (!forced_version.isValidVersion()) { return ERR_INVALID_VERSION; } else { _forced_version = forced_version; return a_util::result::SUCCESS; } } } // namespace ddl