diff --git a/schema/ssp/SSPTraceabilityCommon.xsd b/schema/ssp/SSPTraceabilityCommon.xsd new file mode 100644 index 000000000..f69f2281a --- /dev/null +++ b/schema/ssp/SSPTraceabilityCommon.xsd @@ -0,0 +1,896 @@ + + + + + + + + + + + + + + + + + This element is used to encapsulate general information about the + simulation task, which is not part of any specific phase or step. + + + + + + + This element can be used to provide the set of file information that + was used to derive the current file. I.e. if the content of the current + file can be considered to be derived from one or a set of other STC + files, then the top level meta data and DerivationChain information of + those files should be included in their original order as entries in + this file's DerivationChain element. + + + + + + + + + + + + + + + + + + + + + + + + + Common element content for all modeling elements of the STC file. + + + + + + + This element, which can occur multiple times, provides a set of classifications + of an STC modeling element, provided as Keyword Value Pairs (KWP), the meaning + of which is interpreted according to the name of the classification provided in + the name attribute. + + This approach can be used, for example, to provide searchable keywords for + content, or to assign and track quality or validation level requirements + across the STC process, or to maintain variant or other classification + content across the process. + + + + + + + + This element provides a keyword value pair entry, with the + keyword provided through the keyword attribute and the value + being the contents of the element. + + + + + + + + + + This attribute gives the keyword for the classification entry + (i.e. keyword value pair). It is left undefined whether this + must be unique across the entries of the Classification element, + or whether repeated entries are allowed. This will depend on + the definition of the classification. + + + + + + + This optional attribute specifies the MIME type of the value of + the classification entry, i.e. the element content. It defaults + to text/plain, but e.g. text/markdown is commonly supported for + more structured text. + + + + + + + + This attribute gives an optional link for the classification + entry (i.e. keyword value pair). This link can be given in + addition to any content of the classification entry, or it + can be the sole information of the classification entry. + The rules will depend on the definition of the classification. + + + + + + + This optional attribute specifies the MIME type of the resource + pointed to by the xlink:href attribute of the classification + entry. There is no default value, i.e. if the attribute is not + given then other mechanisms to determine the MIME type of the + resource should be used. If it is given, it shall override any + other mechanism to determine the MIME type of the referenced + resource. + + + + + + + + + + + This attribute provides the name of the type of classification + being provided. The name should be unique across the Classification + elements of the immediately enclosing element. + + In order to ensure uniqueness all types should be identified + with reverse domain name notation (cf. Java package names + or Apple UTIs) of a domain that is controlled by the entity + defining the semantics and content of the classification. + + + + + + + + This attribute gives an optional link for the classification + itself. This link can be given to provide additional, + potentially human readable information on the classification + type that tools can use to provide this information to the + user, especially for unknown classification types. + + + + + + + This optional attribute specifies the MIME type of the resource + pointed to by the xlink:href attribute of the classification. + There is no default value, i.e. if the attribute is not given + then other mechanisms to determine the MIME type of the resource + should be used. If it is given, it shall override any other + mechanism to determine the MIME type of the referenced resource. + + + + + + + + + + + + + + + + + + + + + This element contains life cycle information about the enclosing phase or or step + element. Due to the inherent dependencies of life cycles, life cycle information + at later phases will be dependent on life cycle status of former phases to a + certain extent: For example, if the Implementation Phase is designated as having + reached the status "Validated", it would create a contradiction if the Requirements + Phase has only reached status "Drafted". + + Multiple life cycle information entries can be present, in order to record the + historical progression of the life cycle status, however only the last entry in + document order, which will also be of the highest maturity, will be considered + valid for the current file contents, earlier states only recording historical + data. + + + + + + + Defines that the subject is in draft state and still in progress. This + can also mean that the information is not complete and is still being + finalized. + + + + + + + Defines that the subject is considered complete and may be subject to + review or validation. + + + + + + + Defines that the subject has been reviewed and validated. + + + + + + + Defines that the subject has been approved based on review and + validation. + + + + + + + Defines that the subject has been set as valid and remains valid for + this instance of the GlueParticle, but may not be reused for similar + steps or phases in other GlueParticles (reuse is not allowed). + + + + + + + Defines that the subject has been withdrawn and is considered invalid + or may need to be revised. + + + + + + + + + + + + + + This element can contain digital signature information on the checksum + attribute of the life cycle entry element. It is left unspecified what types + of signatures are used and/or available for now. Multiple or no signature elements + may be present. + + + + + + + + + Timestamp when life cycle entry was assigned. Note that the time stamp data type makes + timezone information mandatory, so that a full ordering of times is possible. + + + + + + + This attribute gives the checksum over the phase/step information stored in the enclosing + phase/step element, calculated according to the STC specification. This attribute is optional + if the life cycle stage is not Approved or Archived, but becomes required if the life cycle stage + is Approved or Archived. Optionally, digital signatures over this checksum can be provided using + Signature elements in the enclosing life cycle entry element. + + The checksum is calculated using the algorithm indicated by the checksumType attribute. + + + + + + + This attribute gives the algorithm for the calculation of the checksum attribute. MUST be + SHA3-256 for now, indicating a SHA3 256bit secure hash algorithm, as specified in FIPS 202. + In the future other checksum algorithms might be supported. + + + + + + + + + This type specifies the content of each individual step inside a phase of the overall Simulation Task. + + + + + + + This particle contains any input information relevant to perform a step. + + + + + + + This particle contains all information how a step should be or has been + performed. + + + + + + + This particle contains all relevant work results of the step. + + + + + + + This particle contains all rationales explaining why the step was + performed in a certain way. + + + + + + + + + + + + + This type specifies the content of each individual particle inside a + step of a phase of the overall Simulation Task. + + + + + + + + + + + + This element provides a set of links that provide more detailed + relationship information between parts of resources or other information + relevant to a phase or step. + + + + + + + This element provides an extended link conforming to the XLink + specification. It provides detailed relationship information between + (parts of) resources or other information relevant to a phase or step. + + An extended link relates 2 or more locators (which identify a particular + piece of information through an URI). It can provide navigation + information between these locators through arcs. + + Locators, arcs and the link itself can further specify their semantic + meaning through optional role or arcrole attributes. The SSP + Traceability specification currently provides no predefined roles. + + All individual elements and attributes are as specified in the XLink + specification. + + + + + + + + This element provides a locator conforming to the XLink specification. + It identifies a particular piece of information through an URI, that is + taking part in the linking relationship. Locators can further specify + their semantic meaning through an optional role attribute. The SSP + Traceability specification currently provides no predefined roles. + + + + + + + + + + + + + + + This element provides an arc conforming to the XLink specification. An + arc relates sets of locators in a navigable relationship, including + directionality information. Arcs can further specify their semantic + meaning through an optional arcrole attribute. The SSP Traceability + specification currently provides no predefined roles. + + + + + + + + + + + + + + + + + + + + + + + + + This element provides information on one resource that is related to the + particular step and particle. Multiple (or no) resources may be present. + + + + + + + This optional element can contain inlined content of the resource. If it + is present, then the attribute source of the Resource element must not be + present. + + + + + + + This element provides an optional summary of the resource being referenced. The + summary information is intended for human consumption to get an overview of the + resource content without looking at the content itself. The summary content can + be provided inline through the Content element, or it can be provided through the + source URI attribute. + + + + + + + + This optional element can contain inlined content of the resource summary. If it + is present, then the attribute source of the Summary element must not be present. + + + + + + + This element can contain digital signature information on the summary referenced + by the enclosing Summary element. It is left unspecified what types of signatures + are used and/or available for now. Multiple or no signature elements may be present. + + + + + + + + + This mandatory attribute specifies the MIME type of the resource summary, which + does not have a default value. If no specific MIME type can be indicated, then + the type application/octet-stream is to be used. If markdown content is used, + then the type text/markdown shall be used. + + + + + + + This attribute indicates the source of the resource summary as a + URI (cf. RFC 3986). For purposes of the resolution of relative URIs + the base URI is the URI of the STC, if the sourceBase attribute is + not specified or is specified as STC, and the URI of the referenced + resource if the sourceBase attribute is specified as resource. + + This allows the specification of summary sources that reside + inside the resource (e.g. an FMU) through relative URIs. + + For summaries that are located alongside the STC, relative URIs + without scheme and authority can and should be used to specify the + summary sources. For summaries that are packaged inside an SSP + that contains this STC, this is mandatory (in this way, the STC + URIs remain valid after unpacking the SSP into the filesystem). + + If the source attribute is missing, the summary is provided + inline as contents of the Content element, which must not be + present otherwise. + + + + + + + Defines the base the source URI is resolved against: If the attribute + is missing or is specified as STC, the source is resolved against the + URI of the STC, if the attribute is specified as resource the URI is + resolved against the (resolved) URI of the resource source. + + + + + + + + + + + + + + + + This element can specify additional meta data for the given resource. Multiple + (or no) MetaData elements may be present. + + + + + + + + This optional element can contain inlined content of the resource meta data. If it + is present, then the attribute source of the MetaData element must not be present. + + + + + + + This element can contain digital signature information on the meta data referenced + by the enclosing MetaData element. It is left unspecified what types of signatures + are used and/or available for now. Multiple or no signature elements may be present. + + + + + + + + + This attribute indicates the kind of resource meta data that is referenced, i.e. + what role it plays in relation to the resource being described. + + + + + + + + + + + + + This mandatory attribute specifies the MIME type of the resource meta data, which + does not have a default value. If no specific MIME type can be indicated, then + the type application/octet-stream is to be used. + + + + + + + This attribute indicates the source of the resource meta data as a + URI (cf. RFC 3986). For purposes of the resolution of relative URIs + the base URI is the URI of the STC, if the sourceBase attribute is + not specified or is specified as STC, and the URI of the referenced + resource if the sourceBase attribute is specified as resource. + + This allows the specification of meta data sources that reside + inside the resource (e.g. an FMU) through relative URIs. + + For meta data that are located alongside the STC, relative URIs + without scheme and authority can and should be used to specify the + meta data sources. For meta data that are packaged inside an SSP + that contains this STC, this is mandatory (in this way, the STC + URIs remain valid after unpacking the SSP into the filesystem). + + If the source attribute is missing, the meta data is provided + inline as contents of the Content element, which must not be + present otherwise. + + + + + + + Defines the base the source URI is resolved against: If the attribute + is missing or is specified as STC, the source is resolved against the + URI of the STC, if the attribute is specified as resource the URI is + resolved against the (resolved) URI of the resource source. + + + + + + + + + + + + + + + + This element can contain digital signature information on the resource referenced + by the enclosing Resource element. It is left unspecified what types of signatures + are used and/or available for now. Multiple or no signature elements may be present. + + + + + + + + + This attribute indicates the kind of resource that is referenced, i.e. what role it + plays in relation to the particle being described. If no more precise label applies, + the kind document can be used. + + + + + + + + + + + + + + + + + + + + + + + + + + This attribute indicates the scope or level that a resource is specific to, i.e. whether the + resource applies at a global, system, subsystem or component level. The use of this attribute + is optional, i.e. it should only be specified where it makes sense to give this kind of + information. + + + + + + + + + + + + + + + This mandatory attribute specifies the MIME type of the resource, which does not + have a default value. If no specific MIME type can be indicated, then the type + application/octet-stream is to be used. + + + + + + + This attribute indicates the source of the resource as a URI + (cf. RFC 3986). For purposes of the resolution of relative URIs + the base URI is the URI of the STC. Therefore for resources + that are located alongside the STC, relative URIs without scheme + and authority can and should be used to specify the component + sources. For resources that are packaged inside an SSP that + contains this STC, this is mandatory (in this way, the STC URIs + remain valid after unpacking the SSP into the filesystem). + + If the source attribute is missing, the resource is provided + inline as contents of the Content element, which must not be + present otherwise. If the placeholder attribute is true, then + both the source attribute and the Content element can be missing. + + + + + + + This attribute, if present, indicates the original, canonical master source for the resource. + If it is present, it indicates that the content provided via source attribute and/or Content + element is only a copy of the original, canonical data, and this attributes provides the + URI reference to that original canonical master data. + + + + + + + This attribute, if true, indicates that the given resource is just a placeholder, + meaning that it should be replaced by actual content at a later stage of the process + execution. Any source or Content supplied can be regarded as being provided just for + information in this case. If the placeholder attribute is true, then both the source + attribute and the Content element can be left unspecified to indicate no informational + placeholder content. + + + + + + + + + + + + + + This mandatory attribute specifies the role this signature has in the overall + process. It indicates whether the digital signature is intended to just convey + the authenticity of the information, or whether a claim for suitability of + the information for certain purposes is made. In the later case, the digital + signature format should include detailed information about what suitability + claims are being made. + + + + + + + + + + + + + This mandatory attribute specifies the MIME type of the resource signature, which + does not have a default value. If no specific MIME type can be indicated, then + the type application/octet-stream is to be used. + + + + + + + This attribute indicates the source of the resource signature as a + URI (cf. RFC 3986). For purposes of the resolution of relative URIs + the base URI is the URI of the STC, if the sourceBase attribute is + not specified or is specified as STC, and the URI of the referenced + resource if the sourceBase attribute is specified as resource. + + This allows the specification of signature sources that reside + inside the resource (e.g. an FMU) through relative URIs. + + For signatures that are located alongside the STC, relative URIs + without scheme and authority can and should be used to specify the + signature sources. For signatures that are packaged inside an SSP + that contains this STC, this is mandatory (in this way, the STC + URIs remain valid after unpacking the SSP into the filesystem). + + If the source attribute is missing, the signature is provided + inline as contents of the Content element, which must not be + present otherwise. + + + + + + + Defines the base the source URI is resolved against: If the attribute + is missing or is specified as STC, the source is resolved against the + URI of the STC, if the attribute is specified as resource the URI is + resolved against the (resolved) URI of the resource source. + + + + + + + + + + + + + + + This optional element can contain inlined content of an entity. If it is present, + then the attribute source of the enclosing element must not be present. + + + + + + + + + + + This element gives information on the responsible entity for a given step. + + + + + + This attribute gives the organization that is responsible for a given step. + + + + + + + This attribute gives the role of the person that is responsible for a given step. + + + + + + + This attribute gives the name of the person that is responsible for a given step. + + + + + + + + + This group provides a choice between a resource and a resource reference, which references + a resource defined in another location in the file or somewhere else. + + + + + + + + This element references a resource element defined in another place, that is + related to the particular step and particle. The referenced resource is + specified using a URI. The resource reference element conforms to the simple + link type of the XLink specification. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/schema/ssp/SimulationResourceMetaData.xsd b/schema/ssp/SimulationResourceMetaData.xsd new file mode 100644 index 000000000..d041b1af1 --- /dev/null +++ b/schema/ssp/SimulationResourceMetaData.xsd @@ -0,0 +1,80 @@ + + + + + + + + + + This element specifies the structure of a Simulation Resource Meta Data file. + + + + + + + + Version of SRMD format, 1.0.0 for this release. + + + + + + + + + + + + This attribute gives the simulation resource meta data a name, + which can be used for purposes of presenting the simulation resource + meta data to the user. + + + + + + + This optional attribute gives a URI to the data item this + resource meta data applies to. If this attribute is not + present, then the data this resource meta data applies to + is provided outside of the meta data (e.g. by embedding + SRMD into the data format, or providing it as meta data in + an STMD file). + + + + + + + This attribute gives the checksum over the data item this meta data + applies to. This is optional information to allow the identification + of the data item and the precise algorithm + specifying + The checksum is calculated using the algorithm indicated by the checksumType attribute. + + + + + + + This attribute gives the algorithm for the calculation of the checksum attribute. MUST be + SHA3-256 for now, indicating a SHA3 256bit secure hash algorithm, as specified in FIPS 202. + In the future other checksum algorithms might be supported. + + + + + + + + + \ No newline at end of file diff --git a/schema/ssp/xlink.xsd b/schema/ssp/xlink.xsd new file mode 100644 index 000000000..ff7a97dfe --- /dev/null +++ b/schema/ssp/xlink.xsd @@ -0,0 +1,293 @@ + + + + + This schema is not normative, or even definitive. The +prose copy in the XLink 1.1 recommendation (http://www.w3.org/TR/xlink11/) is +definitive, although it should not differ from this file, except for the +absence of these two initial comments. + + + + In keeping with the W3C's standard versioning + policy, this schema document will persist at + http://www.w3.org/XML/2008/06/xlink.xsd. + At the date of issue it can also be found at + http://www.w3.org/1999/xlink.xsd. + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML Schema + itself, or with the XLink namespace itself. In other words, if the XML + Schema or XLink namespaces change, the version of this document at + http://www.w3.org/1999/xlink.xsd will change + accordingly; the version at + http://www.w3.org/2008/06/xlink.xsd will not change. + + + + + This schema document provides attribute declarations and +attribute group, complex type and simple type definitions which can be used in +the construction of user schemas to define the structure of particular linking +constructs, e.g. + + + + + + + ... + + ... + + + ... +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Intended for use as the type of user-declared elements to make them + simple links. + + + + + + + + + + + + + + + + + + + + + + + + + Intended for use as the type of user-declared elements to make them + extended links. + Note that the elements referenced in the content model are all abstract. + The intention is that by simply declaring elements with these as their + substitutionGroup, all the right things will happen. + + + + + + + + + + + + + + xml:lang is not required, but provides much of the + motivation for title elements in addition to attributes, and so + is provided here for convenience. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + label is not required, but locators have no particular + XLink function if they are not labeled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + from and to have default behavior when values are missing + + + + + + + + + + + + + + + + + diff --git a/src/OMSimulatorLib/Model.cpp b/src/OMSimulatorLib/Model.cpp index 4009163f2..5f0a29236 100644 --- a/src/OMSimulatorLib/Model.cpp +++ b/src/OMSimulatorLib/Model.cpp @@ -40,11 +40,14 @@ #include "Scope.h" #include "ssd/Tags.h" #include "System.h" +#include "XercesValidator.h" #include "minizip.h" #include #include /* std::unique and std::find are defined here */ +using namespace xercesc_3_2; + oms::Model::Model(const oms::ComRef& cref, const std::string& tempDir) : cref(cref), tempDir(tempDir), resultFilename(std::string(cref) + "_res.mat") { @@ -678,6 +681,21 @@ oms_status_enu_t oms::Model::addResources(const oms::ComRef& cref, const std::st fileName = path_.filename().generic_string(); } + // TODO: this is a temporary workaround, we need a proper helper function to get the extension, .srmd is bigger that 4 so the old check is not valid + std::string extension = filesystem::path(fileName).extension().generic_string(); + + // initialize validator + XercesValidator validator; + + // validate the srmd file + if (extension == ".srmd") + { + oms_status_enu_t status = validator.validateSRMD(path_.generic_string()); + if (status != oms_status_ok) + logError("SRMD format validation of \"" + path + "\" failed"); + return status; + } + // copy the file to temp directory filesystem::path temp_root(getTempDirectory()); filesystem::path temp_temp = temp_root / "temp"; diff --git a/src/OMSimulatorLib/Scope.cpp b/src/OMSimulatorLib/Scope.cpp index 4edff38e3..e8cdcd467 100644 --- a/src/OMSimulatorLib/Scope.cpp +++ b/src/OMSimulatorLib/Scope.cpp @@ -185,9 +185,8 @@ oms_status_enu_t oms::Scope::importModel(const std::string& filename, char** _cr if (_cref) *_cref = NULL; - std::string extension = ""; - if (filename.length() > 4) - extension = filename.substr(filename.length() - 4); + + std::string extension = filesystem::path(filename).extension().generic_string(); if (extension != ".ssp") return logError("filename extension must be \".ssp\"; no other formats are supported"); @@ -260,6 +259,16 @@ oms_status_enu_t oms::Scope::importModel(const std::string& filename, char** _cr model->importedResources.push_back(entry.path().filename().generic_string()); snapshot.importResourceFile(naive_uncomplete(entry.path(), model->getTempDirectory()), model->getTempDirectory()); } + + if (".srmd" == entry.path().extension()) + { + oms_status_enu_t status = xercesValidator.validateSRMD(entry.path().generic_string()); + if (status != oms_status_ok) + logWarning("SRMD format validation of \"" + filesystem::relative(filename).generic_string() + "\" failed"); + + model->importedResources.push_back(entry.path().filename().generic_string()); + snapshot.importResourceFile(naive_uncomplete(entry.path(), model->getTempDirectory()), model->getTempDirectory()); + } } // snapshot.debugPrintAll(); diff --git a/src/OMSimulatorLib/XercesValidator.cpp b/src/OMSimulatorLib/XercesValidator.cpp index cba591a42..2e477422a 100644 --- a/src/OMSimulatorLib/XercesValidator.cpp +++ b/src/OMSimulatorLib/XercesValidator.cpp @@ -35,6 +35,8 @@ #include "Logging.h" #include "OMSFileSystem.h" #include "OMSString.h" +#include +#include #include #include @@ -229,7 +231,7 @@ oms_status_enu_t oms::XercesValidator::validateSSP(const char *ssd, const std::s oms_status_enu_t oms::XercesValidator::validateFMU(const char *modeldescription, const std::string& filePath) { - + std::string relativeFilePath = filesystem::relative(filePath).generic_string(); std::string extension = filesystem::path(filePath).extension().generic_string(); if (extension != ".fmu") @@ -284,7 +286,7 @@ oms_status_enu_t oms::XercesValidator::validateFMU(const char *modeldescription, if (domParser.loadGrammar(schemaFmiModeldescriptionPath.generic_string().c_str(), Grammar::SchemaGrammarType) == NULL) return logWarning("could not load the FMI schema file: " + filesystem::absolute(schemaFmiModeldescriptionPath).generic_string() + ", hence validation of \"modeldescription.xml\" with FMI 2.0 standard will not be performed"); - ParserErrorHandler parserErrorHandler("modeldescription.xml", filePath.c_str()); + ParserErrorHandler parserErrorHandler("modeldescription.xml", relativeFilePath.c_str()); domParser.setErrorHandler(&parserErrorHandler); domParser.cacheGrammarFromParse(true); @@ -303,3 +305,152 @@ oms_status_enu_t oms::XercesValidator::validateFMU(const char *modeldescription, return oms_status_ok; } + +oms_status_enu_t oms::XercesValidator::validateSRMD(const std::string &filePath) { + // Validate file extension + oms_status_enu_t status = isSupportedExtension(filePath, {".srmd"}); + if (status != oms_status_ok) + return status; + + // Initialize Xerces + status = initializeXerces(); + if (status != oms_status_ok) + return status; + + // Retrieve schema paths + std::map schemaPaths; + const std::vector> schemaFiles = { + {"SystemStructureCommon.xsd","http://ssp-standard.org/SSP1/SystemStructureCommon", "ssp"}, + {"SSPTraceabilityCommon.xsd","http://ssp-standard.org/SSPTraceability1/SSPTraceabilityCommon", "ssp"}, + {"SimulationResourceMetaData.xsd","http://ssp-standard.org/SSPTraceability1/SimulationResourceMetaData", "ssp"}, + {"xlink.xsd", "http://www.w3.org/1999/xlink", "ssp"} + }; + status = resolveSchemaPaths(schemaPaths, schemaFiles); + if (status != oms_status_ok) + return status; + + // Configure the parser + XercesDOMParser domParser; + + std::string relativeFilePath = filesystem::relative(filePath).generic_string(); + ParserErrorHandler parserErrorHandler("SimulationResourceMetaData", relativeFilePath.c_str()); + domParser.setErrorHandler(&parserErrorHandler); + + status = loadSchema(domParser, schemaPaths); + if (status != oms_status_ok) + return status; + + //iterate and print all + + // Parse the provided XML + status = parseXML(domParser, filePath); + if (status != oms_status_ok) + return status; + + return oms_status_ok; +} + +oms_status_enu_t oms::XercesValidator::isSupportedExtension(const std::string &filePath, const std::vector &validExtensions) { + std::string extension = filesystem::path(filePath).extension().generic_string(); + if (std::find(validExtensions.begin(), validExtensions.end(), extension) == validExtensions.end()) { + logWarning("Unsupported file extension: " + extension); + return oms_status_warning; + } + return oms_status_ok; +} + +oms_status_enu_t oms::XercesValidator::initializeXerces() { + static bool initialized = false; // Tracks if Xerces has already been initialized + if (initialized) { + return oms_status_ok; + } + + try { + XMLPlatformUtils::Initialize(); + initialized = true; // Mark Xerces as initialized + return oms_status_ok; + } catch (const XMLException &toCatch) { + char *message = XMLString::transcode(toCatch.getMessage()); + logError("Xerces initialization error: " + std::string(message)); + XMLString::release(&message); + return oms_status_error; + } +} + +oms_status_enu_t oms::XercesValidator::resolveSchemaPaths(std::map &paths, const std::vector> &schemaFiles) { + std::string basePath = getExecutablePath(); + if (basePath.empty()) { + logError("Executable path could not be found."); + return oms_status_error; + } + + for (const auto& [file, ns, dir] : schemaFiles) { + const std::vector potentialRoots = { + "../share/OMSimulator/schema/" + dir, + "../../share/OMSimulator/schema/" + dir, + "../../../share/OMSimulator/schema/" + dir, + "schema/" + dir + }; + + for (const auto &root : potentialRoots) { + filesystem::path path = filesystem::path(basePath) / root / file; + if (filesystem::exists(path)) { + paths[ns] = path.generic_string(); + } + } + + if (paths.find(ns) == paths.end()) { + logWarning("Schema file not found: " + file); + return oms_status_warning; + } + } + + return oms_status_ok; +} + +oms_status_enu_t oms::XercesValidator::loadSchema(XercesDOMParser &parser, const std::map &schemaPaths) { + for (const auto &[namespaceUri, path] : schemaPaths) { + if (parser.loadGrammar(path.c_str(), Grammar::SchemaGrammarType, true) == nullptr) { + logWarning("Could not load schema file: " + path); + return oms_status_warning; + } + } + + std::string schemaLocation; + for (const auto &[namespaceUri, path] : schemaPaths) { + schemaLocation += namespaceUri + " " + path + " "; + } + + parser.setExternalSchemaLocation(schemaLocation.c_str()); + parser.cacheGrammarFromParse(true); + parser.setValidationScheme(XercesDOMParser::Val_Always); + parser.setDoNamespaces(true); + parser.setDoSchema(true); + parser.setValidationSchemaFullChecking(true); + parser.setValidationConstraintFatal(true); + + return oms_status_ok; +} + +oms_status_enu_t oms::XercesValidator::parseXML(XercesDOMParser &parser, const std::string &filePath) { + try { + parser.parse(filePath.c_str()); + + if (parser.getErrorCount() > 0) { + logWarning("XML parse error: validation failed."); + return oms_status_warning; + } + + return oms_status_ok; + } catch (const XMLException &e) { + char *message = XMLString::transcode(e.getMessage()); + logError("Xerces parse error: " + std::string(message)); + XMLString::release(&message); + return oms_status_error; + } catch (const DOMException &e) { + char *message = XMLString::transcode(e.msg); + logError("DOM parse error: " + std::string(message)); + XMLString::release(&message); + return oms_status_error; + } +} diff --git a/src/OMSimulatorLib/XercesValidator.h b/src/OMSimulatorLib/XercesValidator.h index 28e419fac..351151ba8 100644 --- a/src/OMSimulatorLib/XercesValidator.h +++ b/src/OMSimulatorLib/XercesValidator.h @@ -38,6 +38,7 @@ #include "OMSimulator/Types.h" #include +#include namespace oms { @@ -49,6 +50,14 @@ namespace oms oms_status_enu_t validateSSP(const char * ssd, const std::string& filePath); oms_status_enu_t validateFMU(const char * modeldescription, const std::string& filePath); std::string getExecutablePath(); + oms_status_enu_t validateSRMD(const std::string &filePath); + + private: + oms_status_enu_t isSupportedExtension(const std::string &filePath, const std::vector &validExtensions); + oms_status_enu_t initializeXerces(); + oms_status_enu_t resolveSchemaPaths(std::map &paths, const std::vector> &schemaFiles); + oms_status_enu_t loadSchema(xercesc_3_2::XercesDOMParser &parser, const std::map &schemaPaths); + oms_status_enu_t parseXML(xercesc_3_2::XercesDOMParser &parser, const std::string &filePath); }; } diff --git a/testsuite/Makefile b/testsuite/Makefile index 2322a0ca3..3bddfbc09 100644 --- a/testsuite/Makefile +++ b/testsuite/Makefile @@ -2,7 +2,7 @@ all: difftool resources test -test: api.log AircraftVehicleDemonstrator.log import.log export.log simulation.log assc.log reference-fmus.log +test: api.log AircraftVehicleDemonstrator.log import.log export.log simulation.log assc.log reference-fmus.log validate.log partest: difftool resources cd partest && time ./runtests.pl -nocolour -with-xml @@ -40,3 +40,7 @@ assc.log: difftool reference-fmus.log: difftool @$(MAKE) -C reference-fmus -f Makefile test > $@ @grep == reference-fmus.log + +validate.log: difftool + @$(MAKE) -C validate -f Makefile test > $@ + @grep == validate.log \ No newline at end of file diff --git a/testsuite/resources/Makefile b/testsuite/resources/Makefile index 4ae344ef7..4ffe696bc 100644 --- a/testsuite/resources/Makefile +++ b/testsuite/resources/Makefile @@ -82,6 +82,7 @@ import_export_parameters1 \ import_export_parameters2 \ import_export_parameters3 \ importExportAllResources \ +invalidSRMD \ invalidSSD \ invalidSSV \ invalidSSM \ diff --git a/testsuite/resources/invalidSRMD/SystemStructure.ssd b/testsuite/resources/invalidSRMD/SystemStructure.ssd new file mode 100644 index 000000000..a0e78eb2e --- /dev/null +++ b/testsuite/resources/invalidSRMD/SystemStructure.ssd @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testsuite/resources/invalidSRMD/resources/0001_addP.fmu b/testsuite/resources/invalidSRMD/resources/0001_addP.fmu new file mode 100644 index 000000000..1f4141e85 Binary files /dev/null and b/testsuite/resources/invalidSRMD/resources/0001_addP.fmu differ diff --git a/testsuite/resources/invalidSRMD/resources/0002_P.fmu b/testsuite/resources/invalidSRMD/resources/0002_P.fmu new file mode 100644 index 000000000..2c54dd0d2 Binary files /dev/null and b/testsuite/resources/invalidSRMD/resources/0002_P.fmu differ diff --git a/testsuite/resources/invalidSRMD/resources/0003_addI.fmu b/testsuite/resources/invalidSRMD/resources/0003_addI.fmu new file mode 100644 index 000000000..d5cf51a21 Binary files /dev/null and b/testsuite/resources/invalidSRMD/resources/0003_addI.fmu differ diff --git a/testsuite/resources/invalidSRMD/resources/SRMD_example_D16.srmd b/testsuite/resources/invalidSRMD/resources/SRMD_example_D16.srmd new file mode 100644 index 000000000..46e356110 --- /dev/null +++ b/testsuite/resources/invalidSRMD/resources/SRMD_example_D16.srmd @@ -0,0 +1,42 @@ + + + + + + + + Initial hypercube provided by model designer Mr/Mrs. X. + + + + + + + + + + + + High confidence operational domain of no error requirement, + confidence level of 100%. + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/resources/invalidSRMD/resources/import_export_parameters.ssv b/testsuite/resources/invalidSRMD/resources/import_export_parameters.ssv new file mode 100644 index 000000000..d72338e6d --- /dev/null +++ b/testsuite/resources/invalidSRMD/resources/import_export_parameters.ssv @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testsuite/resources/invalidSRMD/resources/signalFilter.xml b/testsuite/resources/invalidSRMD/resources/signalFilter.xml new file mode 100644 index 000000000..4247b7729 --- /dev/null +++ b/testsuite/resources/invalidSRMD/resources/signalFilter.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testsuite/validate/Makefile b/testsuite/validate/Makefile index db16ccc46..fd1822428 100644 --- a/testsuite/validate/Makefile +++ b/testsuite/validate/Makefile @@ -4,6 +4,8 @@ TESTFILES = \ validateSSD.py \ validateSSV.py \ validateSSM.py \ +validateSRMD.py \ +validateSRMD.lua \ validateModeldescription.py \ # Run make failingtest diff --git a/testsuite/validate/validateModeldescription.py b/testsuite/validate/validateModeldescription.py index 9a7916825..5642f8a62 100644 --- a/testsuite/validate/validateModeldescription.py +++ b/testsuite/validate/validateModeldescription.py @@ -10,17 +10,17 @@ oms = OMSimulator() oms.setCommandLineOption("--suppressPath=true") -oms.setTempDirectory("./invalidmodeldescription/") -oms.setWorkingDirectory("./invalidmodeldescription/") +oms.setTempDirectory("./invalidmodeldescription-py/") +oms.setWorkingDirectory("./invalidmodeldescription-py/") oms.newModel("model") oms.addSystem("model.root", oms.system_wc) -oms.addSubModel("model.root.add", "../../resources/invalidmodeldescription.fmu") +oms.addSubModel("model.root.add", "../../resources/invalidModeldescription.fmu") ## Result: -## warning: invalid "modeldescription.xml" detected in file "C:/OPENMODELICAGIT/OpenModelica/OMSimulator/testsuite/resources/invalidmodeldescription.fmu" at line: 188 column: 6, value 'xxxx' does not match regular expression facet '[+\-]?[0-9]+' +## warning: invalid "modeldescription.xml" detected in file "../../resources/invalidModeldescription.fmu" at line: 188 column: 6, value 'xxxx' does not match regular expression facet '[+\-]?[0-9]+' ## warning: "modeldescription.xml" does not conform to the FMI-2.0 standard schema ## info: 2 warnings ## info: 0 errors diff --git a/testsuite/validate/validateSRMD.lua b/testsuite/validate/validateSRMD.lua new file mode 100644 index 000000000..20f4cf657 --- /dev/null +++ b/testsuite/validate/validateSRMD.lua @@ -0,0 +1,23 @@ +-- status: correct +-- teardown_command: rm -rf validateSRMD-lua/ +-- linux: yes +-- ucrt64: yes +-- win: yes +-- mac: yes +-- asan: yes + +oms_setCommandLineOption('--suppressPath=true') +oms_setTempDirectory('./validateSRMD-lua/') +oms_setWorkingDirectory("./validateSRMD-lua/") + +model = oms_importFile('../../resources/invalidSRMD.ssp') +oms_terminate(model) +oms_delete(model) + +-- Result: +-- warning: invalid "SimulationResourceMetaData" detected in file "resources/SRMD_example_D16.srmd" at line: 9 column: 44, no declaration found for element 'OperationalDomain' +-- warning: XML parse error: validation failed. +-- warning: SRMD format validation of "../../resources/invalidSRMD.ssp" failed +-- info: 3 warnings +-- info: 0 errors +-- endResult diff --git a/testsuite/validate/validateSRMD.py b/testsuite/validate/validateSRMD.py new file mode 100644 index 000000000..54d196023 --- /dev/null +++ b/testsuite/validate/validateSRMD.py @@ -0,0 +1,24 @@ +## status: correct +## teardown_command: rm -rf validateSRMD-py/ +## linux: yes +## mac: no +## mingw32: no +## mingw64: yes +## win: yes + +import OMSimulator as oms + +oms.setCommandLineOption('--suppressPath=true') +oms.setTempDirectory('./validateSRMD-py/') + +model = oms.importFile('../resources/invalidSRMD.ssp') + +model.delete() + +## Result: +## warning: invalid "SimulationResourceMetaData" detected in file "resources/SRMD_example_D16.srmd" at line: 9 column: 44, no declaration found for element 'OperationalDomain' +## warning: XML parse error: validation failed. +## warning: SRMD format validation of "../resources/invalidSRMD.ssp" failed +## info: 3 warnings +## info: 0 errors +## endResult diff --git a/testsuite/validate/validateSSD.py b/testsuite/validate/validateSSD.py index 45132eece..74121bb5a 100644 --- a/testsuite/validate/validateSSD.py +++ b/testsuite/validate/validateSSD.py @@ -16,7 +16,7 @@ model.delete() ## Result: -## warning: invalid "SystemStructureDescription detected in file "../resources/invalidSSP.ssp" at line: 16 column: 22, attribute 'type' is not declared for element 'Connector' +## warning: invalid "SystemStructureDescription" detected in file "../resources/invalidSSD.ssp" at line: 16 column: 22, attribute 'type' is not declared for element 'Connector' ## warning: "SystemStructureDescription" does not conform to the SSP standard schema ## info: 2 warnings ## info: 0 errors