]> gerrit.simantics Code Review - simantics/fmil.git/blobdiff - 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
diff --git a/org.simantics.fmil.core/native/FMILibrary/src/XML/src/FMI/fmi_xml_context.c b/org.simantics.fmil.core/native/FMILibrary/src/XML/src/FMI/fmi_xml_context.c
new file mode 100644 (file)
index 0000000..ac6e7d7
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+    Copyright (C) 2012 Modelon AB
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the BSD style license.
+
+     This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    FMILIB_License.txt file for more details.
+
+    You should have received a copy of the FMILIB_License.txt file
+    along with this program. If not, contact Modelon AB <http://www.modelon.com>.
+*/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "fmi_xml_context_impl.h"
+
+static char* MODULE="FMIXML";
+
+fmi_xml_context_t* fmi_xml_allocate_context( jm_callbacks* callbacks) {
+       jm_callbacks* cb;
+       fmi_xml_context_t* c;
+
+       jm_log_debug(callbacks, MODULE, "Allocating context for XML parsing module");
+
+    if(callbacks) {
+        cb = callbacks;
+    }
+    else {
+        cb = jm_get_default_callbacks();
+    }
+    c = cb->malloc(sizeof(fmi_xml_context_t));
+    if(!c) {
+               jm_log_fatal(callbacks, MODULE, "Could not allocate memory");
+               return 0;
+       }
+       c->callbacks = callbacks;
+       c->parser = 0;
+       c->fmi_version = fmi_version_unknown_enu;
+    c->configuration = 0;
+       jm_log_debug(callbacks, MODULE, "Returning allocated context");
+    return c;\r
+}\r
+
+void fmi_xml_free_context(fmi_xml_context_t *context) {
+       jm_log_debug(context->callbacks, MODULE, "Releasing XML parsing module memory");
+    if(!context) return;
+    if(context->parser) {
+        XML_ParserFree(context->parser);
+        context->parser = 0;
+    }
+    context->callbacks->free(context);
+}
+
+void fmi_xml_set_configuration(fmi_xml_context_t *context, int configuration) {
+    context->configuration = configuration;
+}
+
+void fmi_xml_fatal(fmi_xml_context_t *context, const char* fmt, ...) {
+    va_list args;
+
+    va_start (args, fmt);
+
+       jm_log_fatal_v(context->callbacks, MODULE, fmt, args);
+
+    va_end (args);
+
+       XML_StopParser(context->parser,0);
+}
+
+void XMLCALL fmi_xml_parse_element_start(void *c, const char *elm, const char **attr) {
+       fmi_xml_context_t *context = (fmi_xml_context_t*)c;
+       const char* fmiVersion = 0;
+       int i = 0;
+
+       if(strcmp(elm, "fmiModelDescription") != 0) {
+               fmi_xml_fatal(context, "First element in XML must be fmiModelDescription");
+               return;
+       }
+       while(attr[i]) {
+               if(strcmp(attr[i], "fmiVersion") == 0) {
+                       fmiVersion = attr[i+1];
+                       break;
+               }
+               i+=2;
+       }
+       if(!fmiVersion) {
+               fmi_xml_fatal(context, "Could not find fmiVersion attribute in the XML. Cannot proceed.");
+               return;
+       }
+       if( strcmp(fmiVersion, "1.0") == 0 ) {
+               jm_log_verbose(context->callbacks, MODULE, "XML specifies FMI 1.0");
+               context->fmi_version = fmi_version_1_enu;
+               XML_StopParser(context->parser,0);
+               return;
+       }
+       else if( strcmp(fmiVersion, "2.0") == 0 ) {
+               jm_log_verbose(context->callbacks, MODULE, "XML specifies FMI 2.0");
+               context->fmi_version = fmi_version_2_0_enu;
+               XML_StopParser(context->parser,0);
+               return;
+       }
+       else {
+               fmi_xml_fatal(context, "This version of FMI standard is not supported (fmiVersion=%s)", fmiVersion);
+               return;
+       }
+}
+
+void XMLCALL fmi_xml_parse_element_end(void* c, const char *elm) {
+}
+
+void XMLCALL fmi_xml_parse_element_data(void* c, const XML_Char *s, int len) {
+}
+
+fmi_version_enu_t fmi_xml_get_fmi_version(fmi_xml_context_t* context, const char* filename) {
+    XML_Memory_Handling_Suite memsuite;
+    XML_Parser parser = NULL;
+    FILE* file;
+
+       jm_log_verbose(context->callbacks, MODULE, "Parsing XML to detect FMI standard version");
+
+       memsuite.malloc_fcn = context->callbacks->malloc;
+    memsuite.realloc_fcn = context->callbacks->realloc;
+    memsuite.free_fcn = context->callbacks->free;
+    context -> parser = parser = XML_ParserCreate_MM(0, &memsuite, 0);
+
+    if(! parser) {
+        fmi_xml_fatal(context, "Could not initialize XML parsing library.");
+        fmi_xml_free_context(context);
+        return fmi_version_unknown_enu;
+    }
+
+    XML_SetUserData( parser, context);
+
+    XML_SetElementHandler(parser, fmi_xml_parse_element_start, fmi_xml_parse_element_end);
+
+    XML_SetCharacterDataHandler(parser, fmi_xml_parse_element_data);
+
+    file = fopen(filename, "rb");
+    if (file == NULL) {
+        fmi_xml_fatal(context, "Cannot open file '%s' for parsing", filename);
+        return fmi_version_unknown_enu;
+    }
+
+       context->fmi_version = fmi_version_unknown_enu;
+
+#define XML_BLOCK_SIZE 1000
+
+    while (!feof(file)) {
+        char text[XML_BLOCK_SIZE];
+        int n = (int)fread(text, sizeof(char), XML_BLOCK_SIZE, file);
+        if(ferror(file)) {
+            fmi_xml_fatal(context, "Error reading from file %s", filename);
+            fclose(file);
+            return fmi_version_unknown_enu;
+        }
+        if (!XML_Parse(parser, text, n, feof(file)) && (context->fmi_version == fmi_version_unknown_enu)) {
+             fmi_xml_fatal(context, "Parse error at line %d:\n%s",
+                         (int)XML_GetCurrentLineNumber(parser),
+                         XML_ErrorString(XML_GetErrorCode(parser)));
+             fclose(file);
+             return fmi_version_unknown_enu; /* failure */
+        }
+               if(context->fmi_version != fmi_version_unknown_enu) break;
+    }
+    fclose(file);
+
+       if(context->fmi_version == fmi_version_unknown_enu) {
+             fmi_xml_fatal(context, "Could not detect FMI standard version");
+       }
+
+    return context->fmi_version;
+}