]> gerrit.simantics Code Review - simantics/fmil.git/blob - org.simantics.fmil.core/native/FMILibrary/src/XML/src/FMI1/fmi1_xml_parser.c
Switch to full JavaSE-11+ compatibility
[simantics/fmil.git] / org.simantics.fmil.core / native / FMILibrary / src / XML / src / FMI1 / fmi1_xml_parser.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
19 /* For checking variable naming conventions */
20 #include <fmi1_xml_variable_name_parser.tab.h>
21 #define YYSTYPE YYFMI1STYPE
22 #include <fmi1_xml_variable_name_lex.h>
23
24 #include "fmi1_xml_model_description_impl.h"
25 #include "fmi1_xml_parser.h"
26
27 static const char * module = "FMI1XML";
28
29 #define ATTR_STR(attr) #attr
30 const char *fmi1_xmlAttrNames[] = {
31     FMI1_XML_ATTRLIST(ATTR_STR)
32 };
33
34 /* fmi1_xml_scheme_ defines give parent ID, the index in a sequence among siblings, flag if multiple elems are allowed */
35 #define fmi1_xml_scheme_fmiModelDescription {fmi1_xml_elmID_none, 0, 0}
36 #define fmi1_xml_scheme_UnitDefinitions {fmi1_xml_elmID_fmiModelDescription, 0, 0}
37 #define fmi1_xml_scheme_BaseUnit {fmi1_xml_elmID_UnitDefinitions, 0, 1}
38 #define fmi1_xml_scheme_DisplayUnitDefinition {fmi1_xml_elmID_BaseUnit, 0, 1}
39 #define fmi1_xml_scheme_TypeDefinitions {fmi1_xml_elmID_fmiModelDescription, 1, 0}
40 #define fmi1_xml_scheme_Type {fmi1_xml_elmID_TypeDefinitions, 0, 1}
41 #define fmi1_xml_scheme_RealType {fmi1_xml_elmID_Type, 0, 0}
42 #define fmi1_xml_scheme_IntegerType {fmi1_xml_elmID_Type, 0, 0}
43 #define fmi1_xml_scheme_BooleanType {fmi1_xml_elmID_Type, 0, 0}
44 #define fmi1_xml_scheme_StringType {fmi1_xml_elmID_Type, 0, 0}
45 #define fmi1_xml_scheme_EnumerationType {fmi1_xml_elmID_Type, 0, 0}
46 #define fmi1_xml_scheme_Item {fmi1_xml_elmID_EnumerationType, 0, 1}
47 #define fmi1_xml_scheme_DefaultExperiment {fmi1_xml_elmID_fmiModelDescription, 2, 0}
48 #define fmi1_xml_scheme_VendorAnnotations {fmi1_xml_elmID_fmiModelDescription, 3, 0}
49 #define fmi1_xml_scheme_Tool {fmi1_xml_elmID_VendorAnnotations, 0, 1}
50 #define fmi1_xml_scheme_Annotation {fmi1_xml_elmID_Tool, 0, 1}
51 #define fmi1_xml_scheme_ModelVariables {fmi1_xml_elmID_fmiModelDescription, 4, 0}
52 #define fmi1_xml_scheme_ScalarVariable {fmi1_xml_elmID_ModelVariables, 0, 1}
53 #define fmi1_xml_scheme_DirectDependency {fmi1_xml_elmID_ScalarVariable, 1, 0}
54 #define fmi1_xml_scheme_Name {fmi1_xml_elmID_DirectDependency, 0, 1}
55 #define fmi1_xml_scheme_Real {fmi1_xml_elmID_ScalarVariable, 0, 0}
56 #define fmi1_xml_scheme_Integer {fmi1_xml_elmID_ScalarVariable, 0, 0}
57 #define fmi1_xml_scheme_Boolean {fmi1_xml_elmID_ScalarVariable, 0, 0}
58 #define fmi1_xml_scheme_String {fmi1_xml_elmID_ScalarVariable, 0, 0}
59 #define fmi1_xml_scheme_Enumeration {fmi1_xml_elmID_ScalarVariable, 0, 0}
60 #define fmi1_xml_scheme_Implementation {fmi1_xml_elmID_fmiModelDescription, 5, 0}
61 #define fmi1_xml_scheme_CoSimulation_StandAlone {fmi1_xml_elmID_Implementation, 0, 0}
62 /* NOTE: Capabilities need special handling since it can appear both under
63         CoSimulation_StandAlone and CoSimulation_Tool
64 */
65 #define fmi1_xml_scheme_Capabilities {fmi1_xml_elmID_CoSimulation_StandAlone, 0, 0}
66 #define fmi1_xml_scheme_CoSimulation_Tool {fmi1_xml_elmID_Implementation, 0, 0}
67 #define fmi1_xml_scheme_Model {fmi1_xml_elmID_CoSimulation_Tool, 1, 0}
68 #define fmi1_xml_scheme_File {fmi1_xml_elmID_Model, 0, 1}
69
70 #define EXPAND_ELM_SCHEME(elm) fmi1_xml_scheme_##elm ,
71
72 fmi1_xml_scheme_info_t fmi1_xml_scheme_info[fmi1_xml_elm_number] = {
73     FMI1_XML_ELMLIST(EXPAND_ELM_SCHEME)
74 };
75
76 #define EXPAND_ELM_NAME(elm) { #elm, fmi1_xml_handle_##elm, fmi1_xml_elmID_##elm},
77
78 fmi1_xml_element_handle_map_t fmi1_element_handle_map[fmi1_xml_elm_number] = {
79     FMI1_XML_ELMLIST(EXPAND_ELM_NAME)
80 };
81
82 void fmi1_xml_parse_free_context(fmi1_xml_parser_context_t *context) {
83     if(!context) return;
84     if(context->modelDescription)
85         fmi1_xml_clear_model_description(context->modelDescription);
86     if(context->parser) {
87         XML_ParserFree(context->parser);
88         context->parser = 0;
89     }
90     fmi1_xml_free_parse_buffer(context);
91     if(context->attrMap) {
92         jm_vector_free(jm_named_ptr)(context->attrMap);
93         context->attrMap = 0;
94     }
95     if(context->elmMap) {
96         jm_vector_free(fmi1_xml_element_handle_map_t)(context->elmMap);
97         context->elmMap = 0;
98     }
99     if(context->attrBuffer) {
100         jm_vector_free(jm_string)(context->attrBuffer);
101         context->attrBuffer = 0;
102     }
103     jm_stack_free_data(int)(& context->elmStack );
104     jm_vector_free_data(char)( &context->elmData );
105
106     jm_vector_free_data(jm_voidp)(&context->directDependencyBuf);
107     jm_vector_foreach(jm_string)(&context->directDependencyStringsStore, (void(*)(jm_string))context->callbacks->free);
108     jm_vector_free_data(jm_string)(&context->directDependencyStringsStore);
109
110     context->callbacks->free(context);
111 }
112
113 void fmi1_xml_parse_fatal(fmi1_xml_parser_context_t *context, const char* fmt, ...) {
114     va_list args;
115     va_start (args, fmt);
116         jm_log_fatal_v(context->callbacks, module, fmt, args);
117     va_end (args);
118     XML_StopParser(context->parser,0);
119 }
120
121 void fmi1_xml_parse_error(fmi1_xml_parser_context_t *context, const char* fmt, ...) {
122     va_list args;
123     va_start (args, fmt);
124         if(context->parser) {
125         jm_log_error(context->callbacks, module, "Detected on line:%u of modelDescription.xml", XML_GetCurrentLineNumber(context->parser));
126         jm_log_error_v(context->callbacks, module, fmt, args);
127     }
128         else
129                 jm_log_error_v(context->callbacks, module, fmt, args);
130     va_end (args);
131 }
132
133
134 int fmi1_xml_is_attr_defined(fmi1_xml_parser_context_t *context, fmi1_xml_attr_enu_t attrID) {
135     return ( jm_vector_get_item(jm_string)(context->attrBuffer, attrID) != 0);
136 }
137
138 static int fmi1_get_attr_str(fmi1_xml_parser_context_t *context, fmi1_xml_elm_enu_t elmID, fmi1_xml_attr_enu_t attrID, int required,const char** valp) {
139
140     jm_string elmName, attrName, value;
141
142     elmName = fmi1_element_handle_map[elmID].elementName;
143     attrName = fmi1_xmlAttrNames[attrID];
144     value = jm_vector_get_item(jm_string)(context->attrBuffer, attrID);
145     *valp =  value;
146     jm_vector_set_item(jm_string)(context->attrBuffer, attrID, 0);
147     if(!(*valp)) {
148         if (required) {
149             fmi1_xml_parse_fatal(context, "Parsing XML element '%s': required attribute '%s' not found", elmName, attrName);
150             return -1;
151         }
152         else
153             return 0;
154     }
155     return 0;
156 }
157
158 int fmi1_xml_set_attr_string(fmi1_xml_parser_context_t *context, fmi1_xml_elm_enu_t elmID, fmi1_xml_attr_enu_t attrID, int required, jm_vector(char)* field) {
159     int ret;
160     jm_string elmName, attrName, val;
161     size_t len;
162     ret = fmi1_get_attr_str(context, elmID, attrID,required,&val);
163     if(ret) return ret;
164     if((!val || !val[0]) && !required) {
165         jm_vector_resize(char)(field, 1);
166         jm_vector_set_item(char)(field, 0, 0);
167         jm_vector_resize(char)(field, 0);
168         return 0;
169     }
170     elmName = fmi1_element_handle_map[elmID].elementName;
171     attrName = fmi1_xmlAttrNames[attrID];
172
173     len = strlen(val) + 1;
174     if(jm_vector_resize(char)(field, len) < len) {
175         fmi1_xml_parse_fatal(context, "XML element '%s': could not allocate memory for setting '%s'='%s'", elmName, attrName, val);
176         return -1;
177     }
178     /* copy terminating 0 as well but set vector size to be actual string length */
179     memcpy(jm_vector_get_itemp(char)(field,0), val, len);
180     jm_vector_resize(char)(field, len - 1);
181     return 0;
182 }
183
184 int fmi1_xml_set_attr_uint(fmi1_xml_parser_context_t *context, fmi1_xml_elm_enu_t elmID, fmi1_xml_attr_enu_t attrID, int required, unsigned int* field, unsigned int defaultVal) {
185     int ret;
186     jm_string elmName, attrName, strVal;
187
188     ret = fmi1_get_attr_str(context, elmID, attrID,required,&strVal);
189     if(ret) return ret;
190     if(!strVal && !required) {
191         *field = defaultVal;
192         return 0;
193     }
194
195     elmName = fmi1_element_handle_map[elmID].elementName;
196     attrName = fmi1_xmlAttrNames[attrID];
197
198     if(sscanf(strVal, "%u", field) != 1) {
199         fmi1_xml_parse_error(context, "XML element '%s': could not parse value for attribute '%s'='%s'", elmName, attrName, strVal);
200         return -1;
201     }
202     return 0;
203 }
204
205
206 int fmi1_xml_set_attr_enum(fmi1_xml_parser_context_t *context, fmi1_xml_elm_enu_t elmID, fmi1_xml_attr_enu_t attrID, int required, unsigned int* field, unsigned int defaultVal, jm_name_ID_map_t* nameMap) {
207     int ret, i;
208     jm_string elmName, attrName, strVal;
209
210     ret = fmi1_get_attr_str(context, elmID, attrID,required,&strVal);
211     if(ret) return ret;
212     if(!strVal && !required) {
213         *field = defaultVal;
214         return 0;
215     }
216
217     elmName = fmi1_element_handle_map[elmID].elementName;
218     attrName = fmi1_xmlAttrNames[attrID];
219
220     i = 0;
221     while(nameMap[i].name && strcmp(nameMap[i].name, strVal)) i++;
222     if(!nameMap[i].name) {
223         fmi1_xml_parse_fatal(context, "XML element '%s': could not parse value for attribute '%s'='%s'", elmName, attrName, strVal);
224         return -1;
225     }
226     *field = nameMap[i].ID;
227     return 0;
228 }
229
230 int fmi1_xml_set_attr_boolean(fmi1_xml_parser_context_t *context, fmi1_xml_elm_enu_t elmID, fmi1_xml_attr_enu_t attrID, int required, int* field, int defaultVal) {
231     jm_name_ID_map_t fmi_boolean_i_dMap[] = {{"true", 1},{"false", 0}, {"1", 1},{"0", 0}, {0,0}};
232     return fmi1_xml_set_attr_enum(context,elmID, attrID,required, (unsigned*)field, (unsigned)defaultVal, fmi_boolean_i_dMap);
233 }
234
235 int fmi1_xml_set_attr_int(fmi1_xml_parser_context_t *context, fmi1_xml_elm_enu_t elmID, fmi1_xml_attr_enu_t attrID, int required, int* field, int defaultVal) {
236     int ret;
237     jm_string elmName, attrName, strVal;
238
239     ret = fmi1_get_attr_str(context, elmID, attrID,required,&strVal);
240     if(ret) return ret;
241     if(!strVal && !required) {
242         *field = defaultVal;
243         return 0;
244     }
245
246     elmName = fmi1_element_handle_map[elmID].elementName;
247     attrName = fmi1_xmlAttrNames[attrID];
248
249     if(sscanf(strVal, "%d", field) != 1) {
250         fmi1_xml_parse_error(context, "XML element '%s': could not parse value for attribute '%s'='%s'", elmName, attrName, strVal);
251         return -1;
252     }
253     return 0;
254 }
255
256 int fmi1_xml_set_attr_double(fmi1_xml_parser_context_t *context, fmi1_xml_elm_enu_t elmID, fmi1_xml_attr_enu_t attrID, int required, double* field, double defaultVal) {
257
258     int ret;
259     jm_string elmName, attrName, strVal;
260
261
262     ret = fmi1_get_attr_str(context, elmID, attrID,required,&strVal);
263     if(ret) return ret;
264     if(!strVal && !required) {
265         *field = defaultVal;
266         return 0;
267     }
268
269     elmName = fmi1_element_handle_map[elmID].elementName;
270     attrName = fmi1_xmlAttrNames[attrID];
271
272     if(sscanf(strVal, "%lf", field) != 1) {
273         fmi1_xml_parse_fatal(context, "XML element '%s': could not parse value for attribute '%s'='%s'", elmName, attrName, strVal);
274         return -1;
275     }
276     return 0;
277 }
278
279 int fmi1_xml_alloc_parse_buffer(fmi1_xml_parser_context_t *context, size_t items) {
280
281     jm_vector(jm_voidp)* parseBuffer = &context->parseBuffer;
282
283     if(jm_vector_init(jm_voidp)(parseBuffer,items,context->callbacks) < items) {
284         fmi1_xml_parse_fatal(context, "Could not allocate buffer for parsing XML");
285         return -1;
286     }
287     jm_vector_zero(jm_voidp)(parseBuffer);
288     return 0;
289 }
290
291 void fmi1_xml_free_parse_buffer(fmi1_xml_parser_context_t *context) {
292     size_t i;
293     jm_vector(jm_voidp)* parseBuffer = &context->parseBuffer;
294
295     for(i=0; i < jm_vector_get_size(jm_voidp)(parseBuffer); i++) {
296         jm_vector(char) * item = jm_vector_get_item(jm_voidp)(parseBuffer,i);
297         if(item) jm_vector_free(char)(item);
298     }
299     jm_vector_free_data(jm_voidp)(parseBuffer);
300 }
301
302 jm_vector(char) * fmi1_xml_reserve_parse_buffer(fmi1_xml_parser_context_t *context, size_t index, size_t size) {
303
304     jm_vector(jm_voidp)* parseBuffer = &context->parseBuffer;
305     jm_vector(char) * item = jm_vector_get_item(jm_voidp)(parseBuffer,index);
306     if(!item) {
307         item = jm_vector_alloc(char)(size,size,context->callbacks);
308         jm_vector_set_item(jm_voidp)(parseBuffer,index,item);
309         if(!item) {
310             fmi1_xml_parse_fatal(context, "Could not allocate a buffer for parsing XML");
311             return 0;
312         }
313     }
314     else {
315         if(jm_vector_resize(char)(item, size) < size ) {
316             fmi1_xml_parse_fatal(context, "Could not allocate a buffer for parsing XML");
317             return 0;
318         }
319     }
320     return item;
321 }
322
323 jm_vector(char) * fmi1_xml_get_parse_buffer(fmi1_xml_parser_context_t *context, size_t index) {
324     jm_vector(jm_voidp)* parseBuffer = &context->parseBuffer;
325     return jm_vector_get_item(jm_voidp)(parseBuffer,index);
326 }
327
328
329
330 int fmi1_create_attr_map(fmi1_xml_parser_context_t* context) {
331     int i;
332     context->attrBuffer = jm_vector_alloc(jm_string)(fmi1_xml_attr_number, fmi1_xml_attr_number, context->callbacks);
333     if(!context->attrBuffer) return -1;
334     context->attrMap = jm_vector_alloc(jm_named_ptr)(fmi1_xml_attr_number, fmi1_xml_attr_number, context->callbacks);
335     if(!context->attrMap) return -1;
336     for(i = 0; i < fmi1_xml_attr_number; i++) {
337         jm_named_ptr map;
338         jm_vector_set_item(jm_string)(context->attrBuffer, i, 0);
339         map.name = fmi1_xmlAttrNames[i];
340         map.ptr = (void*)(jm_vector_get_itemp(jm_string)(context->attrBuffer, i));
341         jm_vector_set_item(jm_named_ptr)(context->attrMap, i, map);
342     }
343     jm_vector_qsort(jm_named_ptr)(context->attrMap, jm_compare_named);
344     return 0;
345 }
346
347 int fmi1_create_elm_map(fmi1_xml_parser_context_t* context) {
348     size_t i;
349     context->elmMap = jm_vector_alloc(fmi1_xml_element_handle_map_t)(fmi1_xml_elm_number, fmi1_xml_elm_number, context->callbacks);
350     if(!context->elmMap) return -1;
351     for(i = 0; i < fmi1_xml_elm_number; i++) {
352         fmi1_xml_element_handle_map_t item = fmi1_element_handle_map[i];
353         jm_vector_set_item(fmi1_xml_element_handle_map_t)(context->elmMap, i, item);
354     }
355     jm_vector_qsort(fmi1_xml_element_handle_map_t)(context->elmMap, fmi1_xml_compare_elmName);
356     return 0;
357 }
358
359 static void XMLCALL fmi1_parse_element_start(void *c, const char *elm, const char **attr) {
360     jm_named_ptr key;
361     fmi1_xml_element_handle_map_t keyEl;
362     fmi1_xml_element_handle_map_t* currentElMap;
363     jm_named_ptr* currentMap;
364         fmi1_xml_elm_enu_t currentID;
365     int i;
366     fmi1_xml_parser_context_t *context = c;
367
368         if(context->skipElementCnt) {
369                 context->skipElementCnt++;
370         jm_log_warning(context->callbacks, module, "[Line:%u] Skipping nested XML element '%s'",
371                         XML_GetCurrentLineNumber(context->parser), elm);
372                 return;
373         }
374
375         keyEl.elementName = elm;
376         /* find the element handle by name */
377     currentElMap = jm_vector_bsearch(fmi1_xml_element_handle_map_t)(context->elmMap, &keyEl, fmi1_xml_compare_elmName);
378     if(!currentElMap) {
379         /* not found error*/
380         jm_log_error(context->callbacks, module, "[Line:%u] Unknown element '%s' in XML, skipping",
381                         XML_GetCurrentLineNumber(context->parser), elm);
382                 context->skipElementCnt = 1;
383         return;
384     }
385
386     currentID = currentElMap->elemID;
387         /* Check that parent-child & siblings are fine */
388         {
389                 fmi1_xml_elm_enu_t parentID = context->currentElmID;
390                 fmi1_xml_elm_enu_t siblingID =  context->lastElmID;
391
392                 if((fmi1_xml_scheme_info[currentID].parentID != parentID) &&
393                         ((currentID != fmi1_xml_elmID_Capabilities) || (parentID != fmi1_xml_elmID_CoSimulation_Tool))) {
394                                 jm_log_error(context->callbacks, module,
395                                         "[Line:%u] XML element '%s' cannot be placed inside '%s', skipping",
396                                         XML_GetCurrentLineNumber(context->parser), elm, fmi1_element_handle_map[parentID].elementName);
397                                 context->skipElementCnt = 1;
398                                 return;
399                 }
400                 if(siblingID != fmi1_xml_elmID_none) {
401                         if(siblingID == currentID) {
402                                 if(!fmi1_xml_scheme_info[currentID].multipleAllowed) {
403                                         jm_log_error(context->callbacks, module,
404                                                 "[Line:%u] Multiple instances of XML element '%s' are not allowed, skipping",
405                                                 XML_GetCurrentLineNumber(context->parser), elm);
406                                         context->skipElementCnt = 1;
407                                         return;
408                                 }
409                         }
410                         else {
411                                 int lastSiblingIndex = fmi1_xml_scheme_info[siblingID].siblingIndex;
412                                 int curSiblingIndex = fmi1_xml_scheme_info[currentID].siblingIndex;
413
414                                 if(lastSiblingIndex >= curSiblingIndex) {
415                                         jm_log_error(context->callbacks, module,
416                                                 "[Line:%u] XML element '%s' cannot be placed after element '%s', skipping",
417                                                 XML_GetCurrentLineNumber(context->parser), elm, fmi1_element_handle_map[siblingID].elementName);
418                                         context->skipElementCnt = 1;
419                                         return;
420                                 }
421                         }
422                 }
423                 context->lastElmID = fmi1_xml_elmID_none;
424         }
425
426     /* process the attributes  */
427     i = 0;
428     while(attr[i]) {
429         key.name = attr[i];
430         /* find attribute by name  */
431         currentMap = jm_vector_bsearch(jm_named_ptr)(context->attrMap, &key, jm_compare_named);
432         if(!currentMap) {
433             /* not found error*/
434                         jm_log_error(context->callbacks, module, "Unknown attribute '%s' in XML", attr[i]);
435         }
436                 else  {
437             /* save attr value (still as string) for further handling  */
438             const char** mapItem = (const char**)currentMap->ptr;
439             *mapItem = attr[i+1];
440         }
441         i += 2;
442     }
443
444     /* handle the element */
445         if( currentElMap->elementHandle(context, 0) ) {
446         return;
447     }
448         if(context->skipElementCnt) return;
449     /* check that the element handle had process all the attributes */
450     for(i = 0; i < fmi1_xml_attr_number; i++) {
451         if(jm_vector_get_item(jm_string)(context->attrBuffer, i)) {
452             if(!context->skipOneVariableFlag)
453                 jm_log_warning(context->callbacks,module, "Attribute '%s' not processed by element '%s' handle", fmi1_xmlAttrNames[i], elm);
454             jm_vector_set_item(jm_string)(context->attrBuffer, i,0);
455         }
456     }
457     if(context -> currentElmID != fmi1_xml_elmID_none) { /* with nested elements: put the parent on the stack*/
458         jm_stack_push(int)(&context->elmStack, context -> currentElmID);
459     }
460     context -> currentElmID = currentID;
461 }
462
463 static void XMLCALL fmi1_parse_element_end(void* c, const char *elm) {
464
465     fmi1_xml_element_handle_map_t keyEl;
466     fmi1_xml_element_handle_map_t* currentElMap;
467         fmi1_xml_elm_enu_t currentID;
468     fmi1_xml_parser_context_t *context = c;
469
470         if(context->skipElementCnt) {
471                 context->skipElementCnt--;
472                 return;
473         }
474
475     keyEl.elementName = elm;
476     currentElMap = jm_vector_bsearch(fmi1_xml_element_handle_map_t)(context->elmMap, &keyEl, fmi1_xml_compare_elmName);
477     if(!currentElMap) {
478         /* not found error*/
479         fmi1_xml_parse_fatal(context, "Unknown element end in XML (element: %s)", elm);
480         return;
481     }
482     currentID = currentElMap->elemID;
483
484     if(currentID != context -> currentElmID) {
485         /* missmatch error*/
486         fmi1_xml_parse_fatal(context, "Element end '%s' does not match element start '%s' in XML", elm,
487                         fmi1_element_handle_map[context -> currentElmID].elementName);
488         return;
489     }
490
491     jm_vector_push_back(char)(&context->elmData, 0);
492
493         if( currentElMap->elementHandle(context, jm_vector_get_itemp(char)(&context->elmData, 0) )) {
494         return;
495     }
496     jm_vector_resize(char)(&context->elmData, 0);
497
498     /* record the last handle and pop the stack */
499     context->lastElmID = currentID;
500
501     if(jm_stack_is_empty(int)(&context->elmStack)) {
502         context -> currentElmID = fmi1_xml_elmID_none;
503     }
504     else {
505         context -> currentElmID = (fmi1_xml_elm_enu_t)jm_stack_pop(int)(&context->elmStack);
506     }
507 }
508
509 /*
510 *  Called to handle element data, e.g. "xy" in <Name>xy</Name>
511 *  Can be called many times, e.g. with "x" and then with "y" in the example above.
512 *  Feature in expat:
513 *  For some reason, if the element data is the empty string (Eg. <a></a>)
514 *  instead of an empty string with len == 0 we get "\n". The workaround is
515 *  to replace this with the empty string whenever we encounter "\n".
516 */
517 static void XMLCALL fmi1_parse_element_data(void* c, const XML_Char *s, int len) {
518         fmi1_xml_parser_context_t *context = c;
519         int i;
520         jm_vector_reserve(char)(&context->elmData, len + jm_vector_get_size(char)(&context->elmData) + 1);
521         for(i = 0; i< len;i++) {
522             char ch = s[i];
523             if(ch != '\n') {
524                 jm_vector_push_back(char)(&context->elmData, ch);
525             }
526         }
527 }
528
529 static int is_cs_fmu(fmi1_xml_model_description_t *md)
530 {
531     return md->fmuKind == fmi1_fmu_kind_enu_cs_tool ||
532            md->fmuKind == fmi1_fmu_kind_enu_cs_standalone;
533 }
534
535 static void fmi1_check_variable_naming_conventions(fmi1_xml_model_description_t *md) {
536     size_t n = jm_vector_get_size(jm_named_ptr)(&md->variablesByName);
537     size_t k;
538     yyscan_t scanner;
539     YY_BUFFER_STATE buf;
540
541     /* check for duplicate variable names */
542     for (k = 1; k < n; k++) {
543         const char *v1 = jm_vector_get_item(jm_named_ptr)(&md->variablesByName, k - 1).name;
544         const char *v2 = jm_vector_get_item(jm_named_ptr)(&md->variablesByName, k).name;
545         if(strcmp(v1, v2) == 0) {
546             jm_log_error(md->callbacks, module,
547                     "Two variables with the same name %s found. This is not allowed.",
548                     v1);
549         }
550     }
551
552     /* check variable name syntax */
553     if (md->namingConvension == fmi1_naming_enu_structured) {
554         yyfmi1lex_init(&scanner);
555         for (k = 0; k < n; k++) {
556             char *name = ((fmi1_xml_variable_t *) jm_vector_get_item(jm_voidp)(
557                     md->variablesOrigOrder, k))->name;
558             buf = yyfmi1_scan_string(name, scanner);
559             yyfmi1parse(scanner, md->callbacks, name);
560             yyfmi1_delete_buffer(buf, scanner);
561         }
562         yyfmi1lex_destroy(scanner);
563     }
564 }
565
566 int fmi1_xml_parse_model_description(fmi1_xml_model_description_t* md, const char* filename, int configuration) {
567     XML_Memory_Handling_Suite memsuite;
568     fmi1_xml_parser_context_t* context;
569     XML_Parser parser = NULL;
570     FILE* file;
571
572     context = (fmi1_xml_parser_context_t*)md->callbacks->calloc(1, sizeof(fmi1_xml_parser_context_t));
573     if(!context) {
574         jm_log_fatal(md->callbacks, module,
575                      "Could not allocate memory for XML parser context");
576     }
577     context->callbacks = md->callbacks;
578     context->modelDescription = md;
579     if(fmi1_xml_alloc_parse_buffer(context, 16)) return -1;
580     if(fmi1_create_attr_map(context) || fmi1_create_elm_map(context)) {
581         fmi1_xml_parse_fatal(context, "Error in parsing initialization");
582         fmi1_xml_parse_free_context(context);
583         return -1;
584     }
585     context->lastBaseUnit = 0;
586     jm_vector_init(jm_voidp)(&context->directDependencyBuf, 0, context->callbacks);
587     jm_vector_init(jm_string)(&context->directDependencyStringsStore, 0, context->callbacks);
588     context->skipOneVariableFlag = 0;
589         context->skipElementCnt = 0;
590     jm_stack_init(int)(&context->elmStack,  context->callbacks);
591     jm_vector_init(char)(&context->elmData, 0, context->callbacks);
592     context->lastElmID = fmi1_xml_elmID_none;
593     context->currentElmID = fmi1_xml_elmID_none;
594
595     memsuite.malloc_fcn = context->callbacks->malloc;
596     memsuite.realloc_fcn = context->callbacks->realloc;
597     memsuite.free_fcn = context->callbacks->free;
598     context -> parser = parser = XML_ParserCreate_MM(0, &memsuite, 0);
599
600     if(! parser) {
601         fmi1_xml_parse_fatal(context, "Could not initialize XML parsing library.");
602         fmi1_xml_parse_free_context(context);
603         return -1;
604     }
605
606     XML_SetUserData( parser, context);
607
608     XML_SetElementHandler(parser, fmi1_parse_element_start, fmi1_parse_element_end);
609
610     XML_SetCharacterDataHandler(parser, fmi1_parse_element_data);
611
612     file = fopen(filename, "rb");
613     if (file == NULL) {
614         fmi1_xml_parse_fatal(context, "Cannot open file '%s' for parsing", filename);
615         fmi1_xml_parse_free_context(context);
616         return -1;
617     }
618
619     while (!feof(file)) {
620         char * text = jm_vector_get_itemp(char)(fmi1_xml_reserve_parse_buffer(context,0,XML_BLOCK_SIZE),0);
621         int n = (int)fread(text, sizeof(char), XML_BLOCK_SIZE, file);
622         if(ferror(file)) {
623             fmi1_xml_parse_fatal(context, "Error reading from file %s", filename);
624             fclose(file);
625                 fmi1_xml_parse_free_context(context);
626             return -1;
627         }
628         if (!XML_Parse(parser, text, n, feof(file))) {
629              fmi1_xml_parse_fatal(context, "Parse error at line %d:\n%s",
630                          (int)XML_GetCurrentLineNumber(parser),
631                          XML_ErrorString(XML_GetErrorCode(parser)));
632              fclose(file);
633                      fmi1_xml_parse_free_context(context);
634              return -1; /* failure */
635         }
636     }
637     fclose(file);
638     /* done later XML_ParserFree(parser);*/
639     if(!jm_stack_is_empty(int)(&context->elmStack)) {
640         fmi1_xml_parse_fatal(context, "Unexpected end of file (not all elements ended) when parsing %s", filename);
641         fmi1_xml_parse_free_context(context);
642         return -1;
643     }
644
645     /* Check if the 'capabilities' element was parsed in a CS FMU. If not,
646      * md->capabilities == NULL and default values should be set.
647      */
648     if (is_cs_fmu(md) && md->capabilities == NULL) {
649         jm_log_error(md->callbacks, module,
650                      "No \"Capabilities\" element found, using default capabilities.");
651
652         md->capabilities = fmi1_xml_default_capabilities(md->callbacks);
653         if (md->capabilities == NULL) {
654             jm_log_fatal(md->callbacks, module, "Failed to allocate memory");
655             fmi1_xml_parse_free_context(context);
656             return -1;
657         }
658     }
659
660     if (configuration & FMI1_XML_NAME_CHECK) {
661         fmi1_check_variable_naming_conventions(md);
662     }
663
664     md->status = fmi1_xml_model_description_enu_ok;
665     context->modelDescription = 0;
666     fmi1_xml_parse_free_context(context);
667
668     return 0;
669 }
670
671 #define JM_TEMPLATE_INSTANCE_TYPE fmi1_xml_element_handle_map_t
672 #include "JM/jm_vector_template.h"