xml_parser.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  1. /*
  2. * Copyright QTronic GmbH. All rights reserved.
  3. */
  4. /* -------------------------------------------------------------------------
  5. * xml_Parser.c
  6. * A parser for file modelVariables.xml of an FMU.
  7. * The parser creates an AST (abstract syntax tree) for a given XML file.
  8. * The root node of the AST is of type ModelDescription.
  9. * Validation already performed by this parser
  10. * - check for match of open/close elements (performed by Expat)
  11. * - check element, attribute and enum value names, all case sensitive
  12. * - check for each element that is has the expected parent element
  13. * - check for correct sequence of elements
  14. * - check for each attribute value that it is of the expected type
  15. * - check that all declaredType values reference an existing Type
  16. * Validation to be performed by this parser
  17. * - check that required attributes are present
  18. * - check that dependencies are only declared for outputs and
  19. * refer only to inputs
  20. * Author: Jakob Mauss, January 2010.
  21. * -------------------------------------------------------------------------*/
  22. #include <assert.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #ifdef STANDALONE_XML_PARSER
  27. #define logThis(n, ...) printf(__VA_ARGS__);printf("\n")
  28. #else
  29. #include "GlobalIncludes.h"
  30. #include "logging.h" // logThis
  31. #endif // STANDALONE_XML_PARSER
  32. #include "xml_parser.h"
  33. const char *elmNames[SIZEOF_ELM] = {
  34. "fmiModelDescription","UnitDefinitions","BaseUnit","DisplayUnitDefinition","TypeDefinitions",
  35. "Type","RealType","IntegerType","BooleanType","StringType","EnumerationType","Item",
  36. "DefaultExperiment","VendorAnnotations","Tool","Annotation", "ModelVariables","ScalarVariable",
  37. "DirectDependency", "Name", "Real","Integer","Boolean","String","Enumeration",
  38. "Implementation","CoSimulation_StandAlone","CoSimulation_Tool","Model","File","Capabilities"
  39. };
  40. const char *attNames[SIZEOF_ATT] = {
  41. "fmiVersion","displayUnit","gain","offset","unit","name","description","quantity", "relativeQuantity",
  42. "min","max","nominal","declaredType","start","fixed","startTime","stopTime","tolerance","value",
  43. "valueReference","variability","causality","alias", "modelName","modelIdentifier","guid","author",
  44. "version","generationTool","generationDateAndTime","variableNamingConvention","numberOfContinuousStates",
  45. "numberOfEventIndicators","input",
  46. "canHandleVariableCommunicationStepSize","canHandleEvents","canRejectSteps","canInterpolateInputs",
  47. "maxOutputDerivativeOrder","canRunAsynchronuously","canSignalEvents","canBeInstantiatedOnlyOncePerProcess",
  48. "canNotUseMemoryManagementFunctions","file","entryPoint","manualStart","type"
  49. };
  50. const char *enuNames[SIZEOF_ENU] = {
  51. "flat","structured","constant","parameter","discrete","continuous",
  52. "input","output", "internal","none","noAlias","alias","negatedAlias"
  53. };
  54. #define XMLBUFSIZE 1024
  55. char text[XMLBUFSIZE]; // XML file is parsed in chunks of length XMLBUFZIZE
  56. XML_Parser parser = NULL; // non-NULL during parsing
  57. Stack* stack = NULL; // the parser stack
  58. char* data = NULL; // buffer that holds element content, see handleData
  59. int skipData=0; // 1 to ignore element content, 0 when recording content
  60. // -------------------------------------------------------------------------
  61. // Low-level functions for inspecting the model description
  62. const char* getString(void* element, Att a){
  63. Element* e = (Element*)element;
  64. const char** attr = e->attributes;
  65. int i;
  66. for (i=0; i<e->n; i+=2)
  67. if (attr[i]==attNames[a]) return attr[i+1];
  68. return NULL;
  69. }
  70. double getDouble(void* element, Att a, ValueStatus* vs){
  71. double d = 0;
  72. const char* value = getString(element, a);
  73. if (!value) { *vs=valueMissing; return d; }
  74. *vs = (1==sscanf(value, "%lf", &d)) ? valueDefined : valueIllegal;
  75. return d;
  76. }
  77. // getInt() is also used to retrieve Enumeration values from XML,
  78. // e.g. the start value for a variable of user-defined enumeration type.
  79. int getInt(void* element, Att a, ValueStatus* vs){
  80. int n = 0;
  81. const char* value = getString(element, a);
  82. if (!value) { *vs=valueMissing; return n; }
  83. *vs = (1==sscanf(value, "%d", &n)) ? valueDefined : valueIllegal;
  84. return n;
  85. }
  86. unsigned int getUInt(void* element, Att a, ValueStatus* vs){
  87. unsigned int u = -1;
  88. const char* value = getString(element, a);
  89. if (!value) { *vs=valueMissing; return u; }
  90. *vs = (1==sscanf(value, "%u", &u)) ? valueDefined : valueIllegal;
  91. return u;
  92. }
  93. char getBoolean(void* element, Att a, ValueStatus* vs){
  94. const char* value = getString(element, a);
  95. if (!value) { *vs=valueMissing; return 0; };
  96. *vs = valueDefined;
  97. if (!strcmp(value, "true")) return 1;
  98. if (!strcmp(value, "false")) return 0;
  99. *vs = valueIllegal;
  100. return 0;
  101. }
  102. static Enu checkEnumValue(const char* enu);
  103. // Retrieve the value of the given built-in enum attribute.
  104. // If the value is missing, this is marked in the ValueStatus
  105. // and the corresponding default is returned.
  106. // Returns enu_BAD_DEFINED or a globally unique id for the value such that
  107. // enuNames[id] is the string representation of the enum value.
  108. Enu getEnumValue(void* element, Att a, ValueStatus* vs) {
  109. const char* value = getString(element, a);
  110. Enu id;
  111. *vs = valueDefined;
  112. if (!value) {
  113. *vs = valueMissing;
  114. switch (a) {
  115. case att_variableNamingConvention: return enu_flat;
  116. case att_variability: return enu_continuous;
  117. case att_causality: return enu_internal;
  118. case att_alias: return enu_noAlias;
  119. default: return enu_BAD_DEFINED;
  120. }
  121. }
  122. id = checkEnumValue(value);
  123. if (id == enu_BAD_DEFINED) *vs = valueIllegal;
  124. return id;
  125. }
  126. // -------------------------------------------------------------------------
  127. // Convenience methods for accessing the model description.
  128. // Use is only safe after the ast has been successfully validated.
  129. const char* getModelIdentifier(ModelDescription* md) {
  130. const char* modelId = getString(md, att_modelIdentifier);
  131. assert(modelId); // this is a required attribute
  132. return modelId;
  133. }
  134. int getNumberOfStates(ModelDescription* md) {
  135. ValueStatus vs;
  136. int n = getUInt(md, att_numberOfContinuousStates, &vs);
  137. assert(vs==valueDefined); // this is a required attribute
  138. return n;
  139. }
  140. int getNumberOfEventIndicators(ModelDescription* md) {
  141. ValueStatus vs;
  142. int n = getInt(md, att_numberOfEventIndicators, &vs);
  143. assert(vs==valueDefined); // this is a required attribute
  144. return n;
  145. }
  146. // name is a required attribute of ScalarVariable, Type, Item, Annotation, and Tool
  147. const char* getName(void* element) {
  148. const char* name = getString(element, att_name);
  149. assert(name); // this is a required attribute
  150. return name;
  151. }
  152. // returns one of: input, output, internal, none
  153. // if value is missing, the default internal is returned
  154. Enu getCausality(void* scalarVariable) {
  155. ValueStatus vs;
  156. return getEnumValue(scalarVariable, att_causality, &vs);
  157. }
  158. // returns one of constant, parameter, discrete, continuous
  159. // if value is missing, the default continuous is returned
  160. Enu getVariability(void* scalarVariable) {
  161. ValueStatus vs;
  162. return getEnumValue(scalarVariable, att_variability, &vs);
  163. }
  164. // returns one of noAlias, alias, negatedAlias
  165. // if value is missing, the default noAlias is returned
  166. Enu getAlias(void* scalarVariable) {
  167. ValueStatus vs;
  168. return getEnumValue(scalarVariable, att_alias, &vs);
  169. }
  170. // the vr is unique only for one of the 4 base data types r,i,b,s and
  171. // may also be fmiUndefinedValueReference = 4294967295 = 0xFFFFFFFF
  172. // here, i means integer or enumeration
  173. fmiValueReference getValueReference(void* scalarVariable) {
  174. ValueStatus vs;
  175. fmiValueReference vr = getUInt(scalarVariable, att_valueReference, &vs);
  176. assert(((Element*)scalarVariable)->type == elm_ScalarVariable);
  177. assert(vs==valueDefined); // this is a required attribute
  178. return vr;
  179. }
  180. // the name is unique within a fmu
  181. ScalarVariable* getVariableByName(ModelDescription* md, const char* name) {
  182. int i;
  183. if (md->modelVariables) {
  184. for (i=0; md->modelVariables[i]; i++){
  185. ScalarVariable* sv = (ScalarVariable*)md->modelVariables[i];
  186. if (!strcmp(getName(sv), name)) return sv;
  187. }
  188. }
  189. return NULL;
  190. }
  191. // Enumeration and Integer have the same base type while
  192. // Real, String, Boolean define own base types.
  193. int sameBaseType(Elm t1, Elm t2){
  194. return t1==t2 ||
  195. t1==elm_Enumeration && t2==elm_Integer ||
  196. t2==elm_Enumeration && t1==elm_Integer;
  197. }
  198. // returns NULL if variable not found or vr==fmiUndefinedValueReference
  199. // problem: vr/type in not a unique key, may return alias
  200. ScalarVariable* getVariable(ModelDescription* md, fmiValueReference vr, Elm type){
  201. int i;
  202. if (md->modelVariables && vr!=fmiUndefinedValueReference)
  203. for (i=0; md->modelVariables[i]; i++){
  204. ScalarVariable* sv = (ScalarVariable*)md->modelVariables[i];
  205. if (sameBaseType(type, sv->typeSpec->type) && getValueReference(sv) == vr)
  206. return sv;
  207. }
  208. return NULL;
  209. }
  210. // returns NULL if variable not found or vr==fmiUndefinedValueReference
  211. // problem: vr/type in not a unique key, return just the non alias variable
  212. ScalarVariable* getNonAliasVariable(ModelDescription* md, fmiValueReference vr, Elm type){
  213. int i;
  214. if (md->modelVariables && vr!=fmiUndefinedValueReference)
  215. for (i=0; md->modelVariables[i]; i++){
  216. ScalarVariable* sv = (ScalarVariable*)md->modelVariables[i];
  217. if (sameBaseType(type, sv->typeSpec->type) && getValueReference(sv) == vr && getAlias(sv) == enu_noAlias)
  218. return sv;
  219. }
  220. return NULL;
  221. }
  222. Type* getDeclaredType(ModelDescription* md, const char* declaredType){
  223. int i;
  224. if (declaredType && md->typeDefinitions)
  225. for (i=0; md->typeDefinitions[i]; i++){
  226. Type* tp = (Type*)md->typeDefinitions[i];
  227. if (!strcmp(declaredType, getName(tp))) return tp;
  228. }
  229. return NULL;
  230. }
  231. // Get attribute value from variable or from declared type, or NULL.
  232. const char* getString2(ModelDescription* md, void* tp, Att a) {
  233. Type* type;
  234. const char* value = getString(tp, a);
  235. if (value) return value; // found
  236. // search declared type, if any
  237. type = getDeclaredType(md, getString(tp, att_declaredType));
  238. return type ? getString(type->typeSpec, a) : NULL;
  239. }
  240. // Get description from variable or from declared type, or NULL.
  241. const char * getDescription(ModelDescription* md, ScalarVariable* sv){
  242. const char* value = getString(sv, att_description);
  243. Type* type;
  244. if (value) return value; // found
  245. // search declared type, if any
  246. type = getDeclaredType(md, getString(sv->typeSpec, att_declaredType));
  247. return type ? getString(type, att_description) : NULL;
  248. }
  249. // Get attribute value from scalar variable given by vr and type,
  250. // incl. default value provided by declared type, if any.
  251. const char *getVariableAttributeString(ModelDescription* md,
  252. fmiValueReference vr, Elm type, Att a) {
  253. const char* value;
  254. Type* tp;
  255. ScalarVariable* sv = getVariable(md, vr, type);
  256. if (!sv) return NULL;
  257. value = getString(sv->typeSpec, a);
  258. if (value) return value; // found
  259. // search declared type, if any
  260. tp = getDeclaredType(md, getString(sv->typeSpec, att_declaredType));
  261. return tp ? getString(tp->typeSpec, a) : NULL;
  262. }
  263. // Get attribute value from scalar variable given by vr and type,
  264. // incl. default value provided by declared type, if any.
  265. double getVariableAttributeDouble(ModelDescription* md,
  266. fmiValueReference vr, Elm type, Att a, ValueStatus* vs){
  267. double d = 0;
  268. const char* value = getVariableAttributeString(md, vr, type, a);
  269. if (!value) { *vs = valueMissing; return d; }
  270. *vs = (1==sscanf(value, "%lf", &d)) ? valueDefined : valueIllegal;
  271. return d;
  272. }
  273. // Get nominal value from real variable or its declared type.
  274. // Return 1, if no nominal value is defined.
  275. double getNominal(ModelDescription* md, fmiValueReference vr){
  276. ValueStatus vs;
  277. double nominal = getVariableAttributeDouble(md, vr, elm_Real, att_nominal, &vs);
  278. return vs==valueDefined ? nominal : 1.0;
  279. }
  280. // -------------------------------------------------------------------------
  281. // Various checks that log an error and stop the parser
  282. // Returns 0 to indicate error
  283. static int checkPointer(const void* ptr){
  284. if (! ptr) {
  285. logThis(ERROR_FATAL, "Out of memory");
  286. if (parser) XML_StopParser(parser, XML_FALSE);
  287. return 0; // error
  288. }
  289. return 1; // success
  290. }
  291. static int checkName(const char* name, const char* kind, const char* array[], int n){
  292. int i;
  293. for (i=0; i<n; i++) {
  294. if (!strcmp(name, array[i])) return i;
  295. }
  296. logThis(ERROR_FATAL, "Illegal %s %s", kind, name);
  297. XML_StopParser(parser, XML_FALSE);
  298. return -1;
  299. }
  300. // Returns elm_BAD_DEFINED to indicate error
  301. static Elm checkElement(const char* elm){
  302. return (Elm)checkName(elm, "element", elmNames, SIZEOF_ELM);
  303. }
  304. // Returns att_BAD_DEFINED to indicate error
  305. static Att checkAttribute(const char* att){
  306. return (Att)checkName(att, "attribute", attNames, SIZEOF_ATT);
  307. }
  308. // Returns enu_BAD_DEFINED to indicate error
  309. static Enu checkEnumValue(const char* enu){
  310. return (Enu)checkName(enu, "enum value", enuNames, SIZEOF_ENU);
  311. }
  312. static void logFatalTypeError(const char* expected, Elm found) {
  313. logThis(ERROR_FATAL, "Wrong element type, expected %s, found %s",
  314. expected, elmNames[found]);
  315. XML_StopParser(parser, XML_FALSE);
  316. }
  317. // Returns 0 to indicate error
  318. // Verify that Element elm is of the given type
  319. static int checkElementType(void* element, Elm e) {
  320. Element* elm = (Element* )element;
  321. if (elm->type == e) return 1; // success
  322. logFatalTypeError(elmNames[e], elm->type);
  323. return 0; // error
  324. }
  325. // Returns 0 to indicate error
  326. // Verify that the next stack element exists and is of the given type
  327. // If e==elm_BAD_DEFINED, the type check is omitted
  328. static int checkPeek(Elm e) {
  329. if (stackIsEmpty(stack)) {
  330. logThis(ERROR_FATAL, "Illegal document structure, expected %s",
  331. e==elm_BAD_DEFINED ? "xml element" : elmNames[e]);
  332. XML_StopParser(parser, XML_FALSE);
  333. return 0; // error
  334. }
  335. return e==elm_BAD_DEFINED ? 1 : checkElementType(stackPeek(stack), e);
  336. }
  337. // Returns NULL to indicate error
  338. // Get the next stack element, it is of the given type.
  339. // If e==elm_BAD_DEFINED, the type check is omitted
  340. static void* checkPop(Elm e){
  341. return checkPeek(e) ? stackPop(stack) : NULL;
  342. }
  343. // -------------------------------------------------------------------------
  344. // Helper
  345. AstNodeType getAstNodeType(Elm e){
  346. switch (e) {
  347. case elm_fmiModelDescription:
  348. return astModelDescription;
  349. case elm_Type:
  350. return astType;
  351. case elm_ScalarVariable:
  352. return astScalarVariable;
  353. case elm_CoSimulation_StandAlone:
  354. case elm_CoSimulation_Tool:
  355. return astCoSimulation;
  356. case elm_BaseUnit:
  357. case elm_EnumerationType:
  358. case elm_Tool:
  359. case elm_UnitDefinitions:
  360. case elm_TypeDefinitions:
  361. case elm_VendorAnnotations:
  362. case elm_ModelVariables:
  363. case elm_DirectDependency:
  364. case elm_Model:
  365. return astListElement;
  366. default:
  367. return astElement;
  368. }
  369. }
  370. // Returns 0 to indicate error
  371. // Copies the attr array and all values.
  372. // Replaces all attribute names by constant literal strings.
  373. // Converts the null-terminated array into an array of known size n.
  374. int addAttributes(Element* el, const char** attr) {
  375. int n;
  376. Att a;
  377. const char** att = NULL;
  378. for (n=0; attr[n]; n+=2);
  379. if (n>0) {
  380. att = (const char **)calloc(n, sizeof(char*));
  381. if (!checkPointer(att)) return 0;
  382. }
  383. for (n=0; attr[n]; n+=2) {
  384. char* value = strdup(attr[n+1]);
  385. if (!checkPointer(value)) {
  386. free((void *)att);
  387. return 0;
  388. }
  389. a = checkAttribute(attr[n]);
  390. if (a == att_BAD_DEFINED) {
  391. free(value);
  392. free((void *)att);
  393. return 0; // illegal attribute error
  394. }
  395. att[n ] = attNames[a]; // no heap memory
  396. att[n+1] = value; // heap memory
  397. }
  398. el->attributes = att; // NULL if n=0
  399. el->n = n;
  400. return 1; // success
  401. }
  402. // Returns NULL to indicate error
  403. Element* newElement(Elm type, int size, const char** attr) {
  404. Element* e = (Element*)calloc(1, size);
  405. if (!checkPointer(e)) return NULL;
  406. e->type = type;
  407. e->attributes = NULL;
  408. e->n=0;
  409. if (!addAttributes(e, attr)) {
  410. free(e);
  411. return NULL;
  412. }
  413. return e;
  414. }
  415. // -------------------------------------------------------------------------
  416. // callback functions called by the XML parser
  417. // Create and push a new element node
  418. static void XMLCALL startElement(void *context, const char *elm, const char **attr) {
  419. Elm el;
  420. void* e;
  421. int size;
  422. //logThis(ERROR_INFO, "start %s", elm);
  423. el = checkElement(elm);
  424. if (el==elm_BAD_DEFINED) return; // error
  425. skipData = (el != elm_Name); // skip element content for all elements but Name
  426. switch(getAstNodeType(el)){
  427. case astElement: size = sizeof(Element); break;
  428. case astListElement: size = sizeof(ListElement); break;
  429. case astType: size = sizeof(Type); break;
  430. case astScalarVariable: size = sizeof(ScalarVariable); break;
  431. case astCoSimulation: size = sizeof(CoSimulation); break;
  432. case astModelDescription: size = sizeof(ModelDescription); break;
  433. default: assert(0);
  434. }
  435. e = newElement(el, size, attr);
  436. if (checkPointer(e)) stackPush(stack, e);
  437. }
  438. // Pop all elements of the given type from stack and
  439. // add it to the ListElement that follows.
  440. // The ListElement remains on the stack.
  441. static void popList(Elm e) {
  442. int n = 0;
  443. Element** array;
  444. Element* elm = (Element *)stackPop(stack);
  445. while (elm->type == e) {
  446. elm = (Element *)stackPop(stack);
  447. n++;
  448. }
  449. stackPush(stack, elm); // push ListElement back to stack
  450. array = (Element**)stackLastPopedAsArray0(stack, n); // NULL terminated list
  451. if (getAstNodeType(elm->type)!=astListElement) {
  452. free(array);
  453. return; // failure
  454. }
  455. ((ListElement*)elm)->list = array;
  456. return; // success only if list!=NULL
  457. }
  458. // Pop the children from the stack and
  459. // check for correct type and sequence of children
  460. static void XMLCALL endElement(void *context, const char *elm) {
  461. Elm el;
  462. //logThis(ERROR_INFO, " end %s", elm);
  463. el = checkElement(elm);
  464. switch(el) {
  465. case elm_fmiModelDescription:
  466. {
  467. ModelDescription* md;
  468. ListElement** ud = NULL; // NULL or list of BaseUnits
  469. Type** td = NULL; // NULL or list of Types
  470. Element* de = NULL; // NULL or DefaultExperiment
  471. ListElement** va = NULL; // NULL or list of Tools
  472. ScalarVariable** mv = NULL; // NULL or list of ScalarVariable
  473. CoSimulation *cs = NULL; // NULL or CoSimulation
  474. ListElement* child;
  475. child = (ListElement *)checkPop(elm_BAD_DEFINED);
  476. if (child->type == elm_CoSimulation_StandAlone || child->type == elm_CoSimulation_Tool) {
  477. cs = (CoSimulation*)child;
  478. child = (ListElement *)checkPop(elm_BAD_DEFINED);
  479. if (!child) return;
  480. }
  481. if (child->type == elm_ModelVariables){
  482. mv = (ScalarVariable**)child->list;
  483. free(child);
  484. child = (ListElement *)checkPop(elm_BAD_DEFINED);
  485. if (!child) return;
  486. }
  487. if (child->type == elm_VendorAnnotations){
  488. va = (ListElement**)child->list;
  489. free(child);
  490. child = (ListElement *)checkPop(elm_BAD_DEFINED);
  491. if (!child) return;
  492. }
  493. if (child->type == elm_DefaultExperiment){
  494. de = (Element*)child;
  495. child = (ListElement *)checkPop(elm_BAD_DEFINED);
  496. if (!child) return;
  497. }
  498. if (child->type == elm_TypeDefinitions){
  499. td = (Type**)child->list;
  500. free(child);
  501. child = (ListElement *)checkPop(elm_BAD_DEFINED);
  502. if (!child) return;
  503. }
  504. if (child->type == elm_UnitDefinitions){
  505. ud = (ListElement**)child->list;
  506. free(child);
  507. child = (ListElement *)checkPop(elm_BAD_DEFINED);
  508. if (!child) return;
  509. }
  510. // work around bug of SimulationX 3.x which places Implementation at wrong location
  511. if (!cs && (child->type == elm_CoSimulation_StandAlone || child->type == elm_CoSimulation_Tool)) {
  512. cs = (CoSimulation*)child;
  513. child = (ListElement *)checkPop(elm_BAD_DEFINED);
  514. if (!child) return;
  515. }
  516. if (!checkElementType(child, elm_fmiModelDescription)) return;
  517. md = (ModelDescription*)child;
  518. md->modelVariables = mv;
  519. md->vendorAnnotations = va;
  520. md->defaultExperiment = de;
  521. md->typeDefinitions = td;
  522. md->unitDefinitions = ud;
  523. md->cosimulation = cs;
  524. stackPush(stack, md);
  525. break;
  526. }
  527. case elm_Implementation:
  528. {
  529. // replace Implementation element
  530. void* cs = checkPop(elm_BAD_DEFINED);
  531. void* im = checkPop(elm_Implementation);
  532. if (!cs || !im) return;
  533. stackPush(stack, cs);
  534. //printf("im=%x att=%x\n",im,((Element*)im)->attributes);
  535. free(im);
  536. el = ((Element*)cs)->type;
  537. break;
  538. }
  539. case elm_CoSimulation_StandAlone:
  540. {
  541. Element* ca = (Element *)checkPop(elm_Capabilities);
  542. CoSimulation* cs = (CoSimulation *)checkPop(elm_CoSimulation_StandAlone);
  543. if (!ca || !cs) return;
  544. cs->capabilities = ca;
  545. stackPush(stack, cs);
  546. break;
  547. }
  548. case elm_CoSimulation_Tool:
  549. {
  550. ListElement* mo = (ListElement *)checkPop(elm_Model);
  551. Element* ca = (Element *)checkPop(elm_Capabilities);
  552. CoSimulation* cs = (CoSimulation *)checkPop(elm_CoSimulation_Tool);
  553. if (!ca || !mo || !cs) return;
  554. cs->capabilities = ca;
  555. cs->model = mo;
  556. stackPush(stack, cs);
  557. break;
  558. }
  559. case elm_Type:
  560. {
  561. Type* tp;
  562. Element* ts = (Element *)checkPop(elm_BAD_DEFINED);
  563. if (!ts) return;
  564. if (!checkPeek(elm_Type)) return;
  565. tp = (Type*)stackPeek(stack);
  566. switch (ts->type) {
  567. case elm_RealType:
  568. case elm_IntegerType:
  569. case elm_BooleanType:
  570. case elm_StringType:
  571. case elm_EnumerationType:
  572. break;
  573. default:
  574. logFatalTypeError("RealType or similar", ts->type);
  575. return;
  576. }
  577. tp->typeSpec = ts;
  578. break;
  579. }
  580. case elm_ScalarVariable:
  581. {
  582. ScalarVariable* sv;
  583. Element** list = NULL;
  584. Element* child = (Element *)checkPop(elm_BAD_DEFINED);
  585. if (!child) return;
  586. if (child->type==elm_DirectDependency){
  587. list = ((ListElement*)child)->list;
  588. free(child);
  589. child = (Element *)checkPop(elm_BAD_DEFINED);
  590. if (!child) return;
  591. }
  592. if (!checkPeek(elm_ScalarVariable)) return;
  593. sv = (ScalarVariable*)stackPeek(stack);
  594. switch (child->type) {
  595. case elm_Real:
  596. case elm_Integer:
  597. case elm_Boolean:
  598. case elm_String:
  599. case elm_Enumeration:
  600. break;
  601. default:
  602. logFatalTypeError("Real or similar", child->type);
  603. return;
  604. }
  605. sv->directDependencies = list;
  606. sv->typeSpec = child;
  607. break;
  608. }
  609. case elm_ModelVariables: popList(elm_ScalarVariable); break;
  610. case elm_VendorAnnotations: popList(elm_Tool);break;
  611. case elm_Tool: popList(elm_Annotation); break;
  612. case elm_TypeDefinitions: popList(elm_Type); break;
  613. case elm_EnumerationType: popList(elm_Item); break;
  614. case elm_UnitDefinitions: popList(elm_BaseUnit); break;
  615. case elm_BaseUnit: popList(elm_DisplayUnitDefinition); break;
  616. case elm_DirectDependency: popList(elm_Name); break;
  617. case elm_Model: popList(elm_File); break;
  618. case elm_Name:
  619. {
  620. // Exception: the name value is represented as element content.
  621. // All other values of the XML file are represented using attributes.
  622. Element* name = (Element *)checkPop(elm_Name);
  623. if (!name) return;
  624. name->n = 2;
  625. name->attributes = (const char **)malloc(2*sizeof(char*));
  626. name->attributes[0] = attNames[att_input];
  627. name->attributes[1] = data;
  628. data = NULL;
  629. skipData = 1; // stop recording element content
  630. stackPush(stack, name);
  631. break;
  632. }
  633. case elm_BAD_DEFINED: return; // illegal element error
  634. default: // must be a leaf Element
  635. assert(getAstNodeType(el)==astElement);
  636. break;
  637. }
  638. // All children of el removed from the stack.
  639. // The top element must be of type el now.
  640. checkPeek(el);
  641. }
  642. // Called to handle element data, e.g. "xy" in <Name>xy</Name>
  643. // Can be called many times, e.g. with "x" and then with "y" in the example above.
  644. // Feature in expat:
  645. // For some reason, if the element data is the empty string (Eg. <a></a>)
  646. // instead of an empty string with len == 0 we get "\n". The workaround is
  647. // to replace this with the empty string whenever we encounter "\n".
  648. void XMLCALL handleData(void *context, const XML_Char *s, int len) {
  649. int n;
  650. if (skipData) return;
  651. if (!data) {
  652. // start a new data string
  653. if (len == 1 && s[0] == '\n') {
  654. data = strdup("");
  655. } else {
  656. data = (char *)malloc(len + 1);
  657. strncpy(data, s, len);
  658. data[len] = '\0';
  659. }
  660. }
  661. else {
  662. // continue existing string
  663. n = strlen(data) + len;
  664. data = (char *)realloc(data, n+1);
  665. strncat(data, s, len);
  666. data[n] = '\0';
  667. }
  668. return;
  669. }
  670. #ifdef STANDALONE_XML_PARSER
  671. // -------------------------------------------------------------------------
  672. // printing
  673. static void printList(int indent, void** list);
  674. void printElement(int indent, void* element){
  675. int i;
  676. Element* e = (Element*)element;
  677. if (!e) return;
  678. // print attributes
  679. for (i=0; i<indent; i++) printf(" ");
  680. printf("%s", elmNames[e->type]);
  681. for (i=0; i<e->n; i+=2)
  682. printf(" %s=%s", e->attributes[i], e->attributes[i+1]);
  683. printf("\n");
  684. // print child nodes
  685. indent += 2;
  686. switch (getAstNodeType(e->type)) {
  687. case astElement:
  688. // we already printed the attributes
  689. break;
  690. case astListElement:
  691. printList(indent, (void **)((ListElement*)e)->list);
  692. break;
  693. case astScalarVariable:
  694. printElement(indent, ((Type*)e)->typeSpec);
  695. printList(indent, (void **)((ScalarVariable*)e)->directDependencies);
  696. break;
  697. case astType:
  698. printElement(indent, ((Type*)e)->typeSpec);
  699. break;
  700. case astCoSimulation: {
  701. CoSimulation* cs = (CoSimulation*)e;
  702. printElement(indent, cs->capabilities);
  703. printElement(indent, cs->model);
  704. break;
  705. }
  706. case astModelDescription: {
  707. ModelDescription *md = (ModelDescription*)e;
  708. printList(indent, (void **)md->unitDefinitions);
  709. printList(indent, (void **)md->typeDefinitions);
  710. printElement(indent, md->defaultExperiment);
  711. printList(indent, (void **)md->vendorAnnotations);
  712. printList(indent, (void **)md->modelVariables);
  713. printElement(indent, md->cosimulation);
  714. break;
  715. }
  716. }
  717. }
  718. static void printList(int indent, void** list){
  719. int i;
  720. if (list) for (i=0; list[i]; i++)
  721. printElement(indent, list[i]);
  722. }
  723. #endif // STANDALONE_XML_PARSER
  724. // -------------------------------------------------------------------------
  725. // free memory of the AST
  726. static void freeList(void** list);
  727. void freeElement(void* element){
  728. int i;
  729. Element* e = (Element *)element;
  730. if (!e) return;
  731. // free attributes
  732. for (i=0; i<e->n; i+=2)
  733. free((void *)e->attributes[i+1]);
  734. if (e->attributes) free((void *)e->attributes);
  735. // free child nodes
  736. switch (getAstNodeType(e->type)) {
  737. case astElement:
  738. // we already freed the attributes
  739. break;
  740. case astListElement:
  741. freeList((void **)((ListElement*)e)->list);
  742. break;
  743. case astScalarVariable:
  744. freeList((void **)((ScalarVariable*)e)->directDependencies);
  745. case astType:
  746. freeElement(((Type*)e)->typeSpec);
  747. break;
  748. case astCoSimulation: {
  749. CoSimulation* cs = (CoSimulation*)e;
  750. freeElement(cs->capabilities);
  751. freeElement(cs->model);
  752. break;
  753. }
  754. case astModelDescription: {
  755. ModelDescription* md = (ModelDescription*)e;
  756. freeList((void **)md->unitDefinitions);
  757. freeList((void **)md->typeDefinitions);
  758. freeElement(md->defaultExperiment);
  759. freeList((void **)md->vendorAnnotations);
  760. freeList((void **)md->modelVariables);
  761. freeElement(md->cosimulation);
  762. break;
  763. }
  764. }
  765. // free the struct
  766. free(e);
  767. }
  768. static void freeList(void** list){
  769. int i;
  770. if (!list) return;
  771. for (i=0; list[i]; i++)
  772. freeElement(list[i]);
  773. free(list);
  774. }
  775. // -------------------------------------------------------------------------
  776. // Validation - done after parsing to report all errors
  777. ModelDescription* validate(ModelDescription* md) {
  778. int error = 0;
  779. int i;
  780. if (md->modelVariables)
  781. for (i=0; md->modelVariables[i]; i++){
  782. ScalarVariable* sv = (ScalarVariable*)md->modelVariables[i];
  783. const char* declaredType = getString(sv->typeSpec, att_declaredType);
  784. Type* declType = getDeclaredType(md, declaredType);
  785. if (declaredType && declType==NULL) {
  786. logThis(ERROR_WARNING, "Declared type %s of variable %s not found in modelDescription.xml", declaredType, getName(sv));
  787. error++;
  788. }
  789. }
  790. if (error) {
  791. logThis(ERROR_ERROR, "Found %d error in modelDescription.xml", error);
  792. return NULL;
  793. }
  794. return md;
  795. }
  796. // -------------------------------------------------------------------------
  797. // Entry function parse() of the XML parser
  798. static void cleanup(FILE *file) {
  799. stackFree(stack);
  800. stack = NULL;
  801. XML_ParserFree(parser);
  802. parser = NULL;
  803. fclose(file);
  804. }
  805. // Returns NULL to indicate failure
  806. // Otherwise, return the root node md of the AST.
  807. // The receiver must call freeElement(md) to release AST memory.
  808. ModelDescription* parse(const char* xmlPath) {
  809. ModelDescription* md = NULL;
  810. FILE *file;
  811. int done = 0;
  812. stack = stackNew(100, 10);
  813. if (!checkPointer(stack)) return NULL; // failure
  814. parser = XML_ParserCreate(NULL);
  815. if (!checkPointer(parser)) return NULL; // failure
  816. XML_SetElementHandler(parser, startElement, endElement);
  817. XML_SetCharacterDataHandler(parser, handleData);
  818. file = fopen(xmlPath, "rb");
  819. if (file == NULL) {
  820. logThis(ERROR_ERROR, "Cannot open file '%s'", xmlPath);
  821. XML_ParserFree(parser);
  822. return NULL; // failure
  823. }
  824. logThis(ERROR_INFO, "parse %s", xmlPath);
  825. while (!done) {
  826. int n = fread(text, sizeof(char), XMLBUFSIZE, file);
  827. if (n != XMLBUFSIZE) done = 1;
  828. if (!XML_Parse(parser, text, n, done)){
  829. logThis(ERROR_ERROR, "Parse error in file %s at line %d:\n%s\n",
  830. xmlPath,
  831. XML_GetCurrentLineNumber(parser),
  832. XML_ErrorString(XML_GetErrorCode(parser)));
  833. while (!stackIsEmpty(stack)) md = (ModelDescription *)stackPop(stack);
  834. if (md) freeElement(md);
  835. cleanup(file);
  836. return NULL; // failure
  837. }
  838. }
  839. md = (ModelDescription *)stackPop(stack);
  840. assert(stackIsEmpty(stack));
  841. cleanup(file);
  842. //printElement(1, md); // debug
  843. return validate(md); // success if all refs are valid
  844. }
  845. // #define TEST
  846. #ifdef TEST
  847. int main(int argc, char**argv) {
  848. ModelDescription* md;
  849. // { char c='c'; while(c!='g') scanf("%c", &c); } // to debug: wait for the g key
  850. if (argc!=2) {
  851. printf("usage: xml_parser <filename>");
  852. return;
  853. }
  854. logThis(ERROR_INFO, "Parsing %s ...\n", argv[1]);
  855. md = parse(argv[1]);
  856. if (md) {
  857. printf("Successfully parsed %s\n", argv[1]);
  858. printElement(1, md);
  859. freeElement(md);
  860. }
  861. dumpMemoryLeaks();
  862. }
  863. #endif // TEST