]> gerrit.simantics Code Review - simantics/fmil.git/blob - org.simantics.fmil.core/native/FMILibrary/src/XML/src/FMI/fmi_xml_context.c
Add FMILibrary-2.0.3 to org.simantics.fmil.core\native.
[simantics/fmil.git] / org.simantics.fmil.core / native / FMILibrary / src / XML / src / FMI / fmi_xml_context.c
1 /*
2     Copyright (C) 2012 Modelon AB
3
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the BSD style license.
6
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.
11
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>.
14 */
15
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdarg.h>
19
20 #include "fmi_xml_context_impl.h"
21
22 static char* MODULE="FMIXML";
23
24 fmi_xml_context_t* fmi_xml_allocate_context( jm_callbacks* callbacks) {
25         jm_callbacks* cb;
26         fmi_xml_context_t* c;
27
28         jm_log_debug(callbacks, MODULE, "Allocating context for XML parsing module");
29
30     if(callbacks) {
31         cb = callbacks;
32     }
33     else {
34         cb = jm_get_default_callbacks();
35     }
36     c = cb->malloc(sizeof(fmi_xml_context_t));
37     if(!c) {
38                 jm_log_fatal(callbacks, MODULE, "Could not allocate memory");
39                 return 0;
40         }
41         c->callbacks = callbacks;
42         c->parser = 0;
43         c->fmi_version = fmi_version_unknown_enu;
44     c->configuration = 0;
45         jm_log_debug(callbacks, MODULE, "Returning allocated context");
46     return c;\r
47 }\r
48
49 void fmi_xml_free_context(fmi_xml_context_t *context) {
50         jm_log_debug(context->callbacks, MODULE, "Releasing XML parsing module memory");
51     if(!context) return;
52     if(context->parser) {
53         XML_ParserFree(context->parser);
54         context->parser = 0;
55     }
56     context->callbacks->free(context);
57 }
58
59 void fmi_xml_set_configuration(fmi_xml_context_t *context, int configuration) {
60     context->configuration = configuration;
61 }
62
63 void fmi_xml_fatal(fmi_xml_context_t *context, const char* fmt, ...) {
64     va_list args;
65
66     va_start (args, fmt);
67
68         jm_log_fatal_v(context->callbacks, MODULE, fmt, args);
69
70     va_end (args);
71
72         XML_StopParser(context->parser,0);
73 }
74
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;
78         int i = 0;
79
80         if(strcmp(elm, "fmiModelDescription") != 0) {
81                 fmi_xml_fatal(context, "First element in XML must be fmiModelDescription");
82                 return;
83         }
84         while(attr[i]) {
85                 if(strcmp(attr[i], "fmiVersion") == 0) {
86                         fmiVersion = attr[i+1];
87                         break;
88                 }
89                 i+=2;
90         }
91         if(!fmiVersion) {
92                 fmi_xml_fatal(context, "Could not find fmiVersion attribute in the XML. Cannot proceed.");
93                 return;
94         }
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);
99                 return;
100         }
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);
105                 return;
106         }
107         else {
108                 fmi_xml_fatal(context, "This version of FMI standard is not supported (fmiVersion=%s)", fmiVersion);
109                 return;
110         }
111 }
112
113 void XMLCALL fmi_xml_parse_element_end(void* c, const char *elm) {
114 }
115
116 void XMLCALL fmi_xml_parse_element_data(void* c, const XML_Char *s, int len) {
117 }
118
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;
122     FILE* file;
123
124         jm_log_verbose(context->callbacks, MODULE, "Parsing XML to detect FMI standard version");
125
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);
130
131     if(! parser) {
132         fmi_xml_fatal(context, "Could not initialize XML parsing library.");
133         fmi_xml_free_context(context);
134         return fmi_version_unknown_enu;
135     }
136
137     XML_SetUserData( parser, context);
138
139     XML_SetElementHandler(parser, fmi_xml_parse_element_start, fmi_xml_parse_element_end);
140
141     XML_SetCharacterDataHandler(parser, fmi_xml_parse_element_data);
142
143     file = fopen(filename, "rb");
144     if (file == NULL) {
145         fmi_xml_fatal(context, "Cannot open file '%s' for parsing", filename);
146         return fmi_version_unknown_enu;
147     }
148
149         context->fmi_version = fmi_version_unknown_enu;
150
151 #define XML_BLOCK_SIZE 1000
152
153     while (!feof(file)) {
154         char text[XML_BLOCK_SIZE];
155         int n = (int)fread(text, sizeof(char), XML_BLOCK_SIZE, file);
156         if(ferror(file)) {
157             fmi_xml_fatal(context, "Error reading from file %s", filename);
158             fclose(file);
159             return fmi_version_unknown_enu;
160         }
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)));
165              fclose(file);
166              return fmi_version_unknown_enu; /* failure */
167         }
168                 if(context->fmi_version != fmi_version_unknown_enu) break;
169     }
170     fclose(file);
171
172         if(context->fmi_version == fmi_version_unknown_enu) {
173              fmi_xml_fatal(context, "Could not detect FMI standard version");
174         }
175
176     return context->fmi_version;
177 }