2 Copyright (C) 2012 Modelon AB
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the BSD style license.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 FMILIB_License.txt file for more details.
12 You should have received a copy of the FMILIB_License.txt file
13 along with this program. If not, contact Modelon AB <http://www.modelon.com>.
20 #include "fmi_xml_context_impl.h"
22 static char* MODULE="FMIXML";
24 fmi_xml_context_t* fmi_xml_allocate_context( jm_callbacks* callbacks) {
28 jm_log_debug(callbacks, MODULE, "Allocating context for XML parsing module");
34 cb = jm_get_default_callbacks();
36 c = cb->malloc(sizeof(fmi_xml_context_t));
38 jm_log_fatal(callbacks, MODULE, "Could not allocate memory");
41 c->callbacks = callbacks;
43 c->fmi_version = fmi_version_unknown_enu;
45 jm_log_debug(callbacks, MODULE, "Returning allocated context");
49 void fmi_xml_free_context(fmi_xml_context_t *context) {
50 jm_log_debug(context->callbacks, MODULE, "Releasing XML parsing module memory");
53 XML_ParserFree(context->parser);
56 context->callbacks->free(context);
59 void fmi_xml_set_configuration(fmi_xml_context_t *context, int configuration) {
60 context->configuration = configuration;
63 void fmi_xml_fatal(fmi_xml_context_t *context, const char* fmt, ...) {
68 jm_log_fatal_v(context->callbacks, MODULE, fmt, args);
72 XML_StopParser(context->parser,0);
75 void XMLCALL fmi_xml_parse_element_start(void *c, const char *elm, const char **attr) {
76 fmi_xml_context_t *context = (fmi_xml_context_t*)c;
77 const char* fmiVersion = 0;
80 if(strcmp(elm, "fmiModelDescription") != 0) {
81 fmi_xml_fatal(context, "First element in XML must be fmiModelDescription");
85 if(strcmp(attr[i], "fmiVersion") == 0) {
86 fmiVersion = attr[i+1];
92 fmi_xml_fatal(context, "Could not find fmiVersion attribute in the XML. Cannot proceed.");
95 if( strcmp(fmiVersion, "1.0") == 0 ) {
96 jm_log_verbose(context->callbacks, MODULE, "XML specifies FMI 1.0");
97 context->fmi_version = fmi_version_1_enu;
98 XML_StopParser(context->parser,0);
101 else if( strcmp(fmiVersion, "2.0") == 0 ) {
102 jm_log_verbose(context->callbacks, MODULE, "XML specifies FMI 2.0");
103 context->fmi_version = fmi_version_2_0_enu;
104 XML_StopParser(context->parser,0);
108 fmi_xml_fatal(context, "This version of FMI standard is not supported (fmiVersion=%s)", fmiVersion);
113 void XMLCALL fmi_xml_parse_element_end(void* c, const char *elm) {
116 void XMLCALL fmi_xml_parse_element_data(void* c, const XML_Char *s, int len) {
119 fmi_version_enu_t fmi_xml_get_fmi_version(fmi_xml_context_t* context, const char* filename) {
120 XML_Memory_Handling_Suite memsuite;
121 XML_Parser parser = NULL;
124 jm_log_verbose(context->callbacks, MODULE, "Parsing XML to detect FMI standard version");
126 memsuite.malloc_fcn = context->callbacks->malloc;
127 memsuite.realloc_fcn = context->callbacks->realloc;
128 memsuite.free_fcn = context->callbacks->free;
129 context -> parser = parser = XML_ParserCreate_MM(0, &memsuite, 0);
132 fmi_xml_fatal(context, "Could not initialize XML parsing library.");
133 fmi_xml_free_context(context);
134 return fmi_version_unknown_enu;
137 XML_SetUserData( parser, context);
139 XML_SetElementHandler(parser, fmi_xml_parse_element_start, fmi_xml_parse_element_end);
141 XML_SetCharacterDataHandler(parser, fmi_xml_parse_element_data);
143 file = fopen(filename, "rb");
145 fmi_xml_fatal(context, "Cannot open file '%s' for parsing", filename);
146 return fmi_version_unknown_enu;
149 context->fmi_version = fmi_version_unknown_enu;
151 #define XML_BLOCK_SIZE 1000
153 while (!feof(file)) {
154 char text[XML_BLOCK_SIZE];
155 int n = (int)fread(text, sizeof(char), XML_BLOCK_SIZE, file);
157 fmi_xml_fatal(context, "Error reading from file %s", filename);
159 return fmi_version_unknown_enu;
161 if (!XML_Parse(parser, text, n, feof(file)) && (context->fmi_version == fmi_version_unknown_enu)) {
162 fmi_xml_fatal(context, "Parse error at line %d:\n%s",
163 (int)XML_GetCurrentLineNumber(parser),
164 XML_ErrorString(XML_GetErrorCode(parser)));
166 return fmi_version_unknown_enu; /* failure */
168 if(context->fmi_version != fmi_version_unknown_enu) break;
172 if(context->fmi_version == fmi_version_unknown_enu) {
173 fmi_xml_fatal(context, "Could not detect FMI standard version");
176 return context->fmi_version;