* Bug #15024 fixed : Xcos labels were not preserved .
[scilab.git] / scilab / modules / scicos / src / cpp / XMIResource_load.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2016-2016 - Scilab Enterprises - Clement DAVID
4  * Copyright (C) 2017 - ESI Group - Clement DAVID
5  *
6  * This file is hereby licensed under the terms of the GNU GPL v2.0,
7  * pursuant to article 5.3.4 of the CeCILL v.2.1.
8  * This file was originally licensed under the terms of the CeCILL v2.1,
9  * and continues to be available under such terms.
10  * For more information, see the COPYING file which you should have received
11  * along with this program.
12  */
13
14 #include "XMIResource.hxx"
15 #include "base64.hxx"
16
17 #include <cassert>
18 #include <string>
19 #include <vector>
20 #include <algorithm>
21 #include <cstdlib> // for atoi and atof
22 #include <cstring> // for strcmp and strchr
23
24 extern "C"
25 {
26 #include <libxml/tree.h>
27 #include <libxml/parser.h>
28 #include <libxml/xmlerror.h>
29 #include <libxml/xmlreader.h>
30
31 #include "sci_types.h"
32 #include "sciprint.h"
33 }
34
35 namespace org_scilab_modules_scicos
36 {
37
38 /**
39  * Display on the Scilab console
40  */
41 void console_print(void *, const char *msg, ...) LIBXML_ATTR_FORMAT(2, 3);
42 void console_print(void *, const char *msg, ...)
43 {
44     //print the message
45     va_list ap;
46     va_start(ap, msg);
47     scivprint(msg, ap);
48     va_end(ap);
49 }
50
51 /**
52  * Helper class to set / reset the XML parser state
53  */
54 struct LibXML2State
55 {
56     LibXML2State()
57     {
58         xmlGenericErrorFunc f = &console_print;
59         initGenericErrorDefaultFunc(&f);
60     }
61     ~LibXML2State()
62     {
63         initGenericErrorDefaultFunc(nullptr);
64     }
65 };
66
67 int XMIResource::load(const char* uri)
68 {
69     int ret;
70
71     LibXML2State state;
72
73     /*
74      * Allocate the reader object, this API is used as it is simpler to use than SAX2 :
75      *  * we have direct access to a node object
76      *  * Strings are interned by libxml2
77      *  * partial SAX2 callbacks are not supported by libxml2
78      */
79     xmlTextReaderPtr reader;
80     /* resolve xinclude and intern strings */
81     reader = xmlReaderForFile(uri, NULL, XML_PARSE_XINCLUDE | XML_PARSE_COMPACT);
82
83     /*
84      * Intern strings to speedup comparaison, this table can be generated using XPath on xcos.ecore .
85      */
86     constXcosNames[e_Annotation] = xmlTextReaderConstString(reader, BAD_CAST ("Annotation"));
87     constXcosNames[e_BaseObject] = xmlTextReaderConstString(reader, BAD_CAST ("BaseObject"));
88     constXcosNames[e_Block] = xmlTextReaderConstString(reader, BAD_CAST ("Block"));
89     constXcosNames[e_CompiledRepresentation] = xmlTextReaderConstString(reader, BAD_CAST ("CompiledRepresentation"));
90     constXcosNames[e_Diagram] = xmlTextReaderConstString(reader, BAD_CAST ("Diagram"));
91     constXcosNames[e_Geometry] = xmlTextReaderConstString(reader, BAD_CAST ("Geometry"));
92     constXcosNames[e_Layer] = xmlTextReaderConstString(reader, BAD_CAST ("Layer"));
93     constXcosNames[e_Link] = xmlTextReaderConstString(reader, BAD_CAST ("Link"));
94     constXcosNames[e_Point] = xmlTextReaderConstString(reader, BAD_CAST ("Point"));
95     constXcosNames[e_Port] = xmlTextReaderConstString(reader, BAD_CAST ("Port"));
96     constXcosNames[e_PortKind] = xmlTextReaderConstString(reader, BAD_CAST ("PortKind"));
97     constXcosNames[e_SimulationConfig] = xmlTextReaderConstString(reader, BAD_CAST ("SimulationConfig"));
98     constXcosNames[e_absoluteTolerance] = xmlTextReaderConstString(reader, BAD_CAST ("absoluteTolerance"));
99     constXcosNames[e_base64] = xmlTextReaderConstString(reader, BAD_CAST ("base64"));
100     constXcosNames[e_blocktype] = xmlTextReaderConstString(reader, BAD_CAST ("blocktype"));
101     constXcosNames[e_child] = xmlTextReaderConstString(reader, BAD_CAST ("child"));
102     constXcosNames[e_color] = xmlTextReaderConstString(reader, BAD_CAST ("color"));
103     constXcosNames[e_columns] = xmlTextReaderConstString(reader, BAD_CAST ("columns"));
104     constXcosNames[e_connectedSignal] = xmlTextReaderConstString(reader, BAD_CAST ("connectedSignal"));
105     constXcosNames[e_context] = xmlTextReaderConstString(reader, BAD_CAST ("context"));
106     constXcosNames[e_controlPoint] = xmlTextReaderConstString(reader, BAD_CAST ("controlPoint"));
107     constXcosNames[e_datatype] = xmlTextReaderConstString(reader, BAD_CAST ("datatype"));
108     constXcosNames[e_debugLevel] = xmlTextReaderConstString(reader, BAD_CAST ("debugLevel"));
109     constXcosNames[e_deltaH] = xmlTextReaderConstString(reader, BAD_CAST ("deltaH"));
110     constXcosNames[e_deltaT] = xmlTextReaderConstString(reader, BAD_CAST ("deltaT"));
111     constXcosNames[e_dependsOnT] = xmlTextReaderConstString(reader, BAD_CAST ("dependsOnT"));
112     constXcosNames[e_dependsOnU] = xmlTextReaderConstString(reader, BAD_CAST ("dependsOnU"));
113     constXcosNames[e_description] = xmlTextReaderConstString(reader, BAD_CAST ("description"));
114     constXcosNames[e_destinationPort] = xmlTextReaderConstString(reader, BAD_CAST ("destinationPort"));
115     constXcosNames[e_dstate] = xmlTextReaderConstString(reader, BAD_CAST ("dstate"));
116     constXcosNames[e_ein] = xmlTextReaderConstString(reader, BAD_CAST ("ein"));
117     constXcosNames[e_eout] = xmlTextReaderConstString(reader, BAD_CAST ("eout"));
118     constXcosNames[e_equations] = xmlTextReaderConstString(reader, BAD_CAST ("equations"));
119     constXcosNames[e_expression] = xmlTextReaderConstString(reader, BAD_CAST ("expression"));
120     constXcosNames[e_exprs] = xmlTextReaderConstString(reader, BAD_CAST ("exprs"));
121     constXcosNames[e_finalTime] = xmlTextReaderConstString(reader, BAD_CAST ("finalTime"));
122     constXcosNames[e_firing] = xmlTextReaderConstString(reader, BAD_CAST ("firing"));
123     constXcosNames[e_font] = xmlTextReaderConstString(reader, BAD_CAST ("font"));
124     constXcosNames[e_fontSize] = xmlTextReaderConstString(reader, BAD_CAST ("fontSize"));
125     constXcosNames[e_functionAPI] = xmlTextReaderConstString(reader, BAD_CAST ("functionAPI"));
126     constXcosNames[e_functionName] = xmlTextReaderConstString(reader, BAD_CAST ("functionName"));
127     constXcosNames[e_geometry] = xmlTextReaderConstString(reader, BAD_CAST ("geometry"));
128     constXcosNames[e_height] = xmlTextReaderConstString(reader, BAD_CAST ("height"));
129     constXcosNames[e_implicit] = xmlTextReaderConstString(reader, BAD_CAST ("implicit"));
130     constXcosNames[e_in] = xmlTextReaderConstString(reader, BAD_CAST ("in"));
131     constXcosNames[e_interfaceFunction] = xmlTextReaderConstString(reader, BAD_CAST ("interfaceFunction"));
132     constXcosNames[e_ipar] = xmlTextReaderConstString(reader, BAD_CAST ("ipar"));
133     constXcosNames[e_kind] = xmlTextReaderConstString(reader, BAD_CAST ("kind"));
134     constXcosNames[e_label] = xmlTextReaderConstString(reader, BAD_CAST ("label"));
135     constXcosNames[e_lineHeight] = xmlTextReaderConstString(reader, BAD_CAST ("lineHeight"));
136     constXcosNames[e_lineWidth] = xmlTextReaderConstString(reader, BAD_CAST ("lineWidth"));
137     constXcosNames[e_nmode] = xmlTextReaderConstString(reader, BAD_CAST ("nmode"));
138     constXcosNames[e_nzcross] = xmlTextReaderConstString(reader, BAD_CAST ("nzcross"));
139     constXcosNames[e_odstate] = xmlTextReaderConstString(reader, BAD_CAST ("odstate"));
140     constXcosNames[e_opar] = xmlTextReaderConstString(reader, BAD_CAST ("opar"));
141     constXcosNames[e_out] = xmlTextReaderConstString(reader, BAD_CAST ("out"));
142     constXcosNames[e_parent] = xmlTextReaderConstString(reader, BAD_CAST ("parent"));
143     constXcosNames[e_parentDiagram] = xmlTextReaderConstString(reader, BAD_CAST ("parentDiagram"));
144     constXcosNames[e_path] = xmlTextReaderConstString(reader, BAD_CAST ("path"));
145     constXcosNames[e_properties] = xmlTextReaderConstString(reader, BAD_CAST ("properties"));
146     constXcosNames[e_realtimeScale] = xmlTextReaderConstString(reader, BAD_CAST ("realtimeScale"));
147     constXcosNames[e_relativeTolerance] = xmlTextReaderConstString(reader, BAD_CAST ("relativeTolerance"));
148     constXcosNames[e_rows] = xmlTextReaderConstString(reader, BAD_CAST ("rows"));
149     constXcosNames[e_rpar] = xmlTextReaderConstString(reader, BAD_CAST ("rpar"));
150     constXcosNames[e_solver] = xmlTextReaderConstString(reader, BAD_CAST ("solver"));
151     constXcosNames[e_sourceBlock] = xmlTextReaderConstString(reader, BAD_CAST ("sourceBlock"));
152     constXcosNames[e_sourcePort] = xmlTextReaderConstString(reader, BAD_CAST ("sourcePort"));
153     constXcosNames[e_state] = xmlTextReaderConstString(reader, BAD_CAST ("state"));
154     constXcosNames[e_style] = xmlTextReaderConstString(reader, BAD_CAST ("style"));
155     constXcosNames[e_timeTolerance] = xmlTextReaderConstString(reader, BAD_CAST ("timeTolerance"));
156     constXcosNames[e_title] = xmlTextReaderConstString(reader, BAD_CAST ("title"));
157     constXcosNames[e_type] = xmlTextReaderConstString(reader, BAD_CAST ("type"));
158     constXcosNames[e_uid] = xmlTextReaderConstString(reader, BAD_CAST ("uid"));
159     constXcosNames[e_version] = xmlTextReaderConstString(reader, BAD_CAST ("version"));
160     constXcosNames[e_width] = xmlTextReaderConstString(reader, BAD_CAST ("width"));
161     constXcosNames[e_x] = xmlTextReaderConstString(reader, BAD_CAST ("x"));
162     constXcosNames[e_xcos] = xmlTextReaderConstString(reader, BAD_CAST ("xcos"));
163     constXcosNames[e_y] = xmlTextReaderConstString(reader, BAD_CAST ("y"));
164
165     xcosNamespaceUri = xmlTextReaderConstString(reader, BAD_CAST ("org.scilab.modules.xcos"));
166     xsiNamespaceUri = xmlTextReaderConstString(reader, BAD_CAST ("http://www.w3.org/2001/XMLSchema-instance"));
167
168     unresolved.clear();
169
170     /*
171      * Process the document
172      */
173     if (reader != NULL)
174     {
175         ret = xmlTextReaderRead(reader);
176         while (ret == 1)
177         {
178             ret = processNode(reader);
179             if (ret == 1)
180             {
181                 ret = xmlTextReaderRead(reader);
182             }
183         }
184         /*
185          * Once the document has been fully parsed check the validation results
186          */
187         if (xmlTextReaderIsValid(reader) < 0)
188         {
189             sciprint("Document %s does not validate\n", uri);
190         }
191         xmlFreeTextReader(reader);
192         if (ret < 0)
193         {
194             sciprint("%s : failed to parse\n", uri);
195             return ret;
196         }
197     }
198     else
199     {
200         sciprint("Unable to open %s\n", uri);
201         return -1;
202     }
203
204     /*
205      * After loading the XML file, resolve all references
206      */
207     for (const unresolvedReference& ref : unresolved)
208     {
209         auto it = references.find(ref.m_uid);
210         if (it != references.end())
211         {
212             controller.setObjectProperty(ref.m_id, ref.m_kind, ref.m_prop, it->second);
213
214             // change the link kind on re-connection
215             if (ref.m_kind == LINK)
216             {
217                 if (ref.m_prop == SOURCE_PORT || ref.m_prop == DESTINATION_PORT)
218                 {
219                     int kind;
220                     controller.getObjectProperty(it->second, PORT, PORT_KIND, kind);
221
222                     if (kind == PORT_EIN || kind == PORT_EOUT)
223                     {
224                         // this should be an event link
225                         controller.setObjectProperty(ref.m_id, LINK, COLOR, 5);
226                         controller.setObjectProperty(ref.m_id, LINK, KIND, -1);
227                     }
228                     else
229                     {
230                         bool isImplicit;
231                         controller.getObjectProperty(it->second, PORT, IMPLICIT, isImplicit);
232
233                         if (isImplicit)
234                         {
235                             // this should be a modelica link
236                             controller.setObjectProperty(ref.m_id, LINK, KIND, 2);
237                         }
238                     }
239                     // otherwise this should be a regular link
240                 }
241             }
242         }
243         else
244         {
245             sciprint("Unable to resolve %s\n", ref.m_uid.c_str());
246             return -1;
247         }
248     }
249
250     return ret;
251 }
252
253 /*
254  * Convert an XML UTF-8 string to a model string
255  */
256 std::string to_string(const xmlChar* xmlStr)
257 {
258     if (xmlStr == nullptr)
259     {
260         return "";
261     }
262
263     // the strings in the model are stored as UTF-8 as in libxml2
264     return std::string((const char*) xmlStr);
265 }
266
267 /*
268  * Convert an XML UTF-8 string to a model int
269  */
270 int to_int(const xmlChar* xmlStr)
271 {
272     if (xmlStr == nullptr)
273     {
274         return 0;
275     }
276
277     return std::atoi((const char*) xmlStr);
278 }
279
280 /*
281  * Convert an XML UTF-8 string to a model boolean
282  */
283 bool to_boolean(const xmlChar* xmlStr)
284 {
285     if (xmlStr == nullptr)
286     {
287         return 0;
288     }
289
290     return std::strcmp((const char*) xmlStr, "true") == 0;
291 }
292
293 /*
294  * Convert an XML UTF-8 string to a model double
295  */
296 double to_double(const xmlChar* xmlStr)
297 {
298     if (xmlStr == nullptr)
299     {
300         return 0.0;
301     }
302
303     return std::atof((const char*) xmlStr);
304 }
305
306 int XMIResource::loadDoubleArray(xmlTextReaderPtr reader, enum object_properties_t property, const model::BaseObject& o)
307 {
308     std::vector<double> v;
309     controller.getObjectProperty(o.id(), o.kind(), property, v);
310
311     v.push_back(to_double(xmlTextReaderConstValue(reader)));
312
313     controller.setObjectProperty(o.id(), o.kind(), property, v);
314     return 1;
315 }
316
317 int XMIResource::loadIntArray(xmlTextReaderPtr reader, enum object_properties_t property, const model::BaseObject& o)
318 {
319     std::vector<int> v;
320     controller.getObjectProperty(o.id(), o.kind(), property, v);
321
322     v.push_back(to_int(xmlTextReaderConstValue(reader)));
323
324     controller.setObjectProperty(o.id(), o.kind(), property, v);
325     return 1;
326 }
327
328 int XMIResource::loadStringArray(xmlTextReaderPtr reader, enum object_properties_t property, const model::BaseObject& o)
329 {
330     std::vector<std::string> v;
331     controller.getObjectProperty(o.id(), o.kind(), property, v);
332
333     v.push_back(to_string(xmlTextReaderConstValue(reader)));
334
335     controller.setObjectProperty(o.id(), o.kind(), property, v);
336     return 1;
337 }
338
339 /* helper function to encode simple string */
340 static std::vector<double> encode_string_vector(const std::vector<std::string>& v)
341 {
342     std::vector<double> ret;
343
344     // header
345     ret.push_back(sci_strings);
346
347     // serialize as a Scilab vector
348     ret.push_back(2); // MxN
349     ret.push_back(v.size()); // M
350     if (v.size() > 0)
351     {
352         ret.push_back(1);    // N
353     }
354     else
355     {
356         ret.push_back(0);
357     }
358
359     // reserve some space to store the length of each string (including the null terminating character)
360     ret.resize(ret.size() + v.size());
361
362     // store the index and the null terminated UTF-8 strings
363     size_t stringOffset = 0;
364     for (size_t i = 0; i < v.size(); ++i)
365     {
366         const std::string& str = v[i];
367         // length as a 64bit index (as we store on a double vector)
368         size_t len = ((str.size() + 1) * sizeof(char) + sizeof(double) - 1) / sizeof(double);
369
370         // insert the offset
371         auto it = ret.begin() + 4 + i;
372         stringOffset += len;
373         *it = stringOffset;
374
375         // reserve some space for the string
376         size_t size = ret.size();
377         ret.resize(size + len);
378
379         // copy the UTF-8 encoded values (\0 terminated thanks to the resize)
380         std::memcpy(ret.data() + size, str.data(), str.size());
381     }
382
383     return ret;
384 }
385
386 /* helper function to decode simple string */
387 static std::vector<std::string> decode_string_vector(const std::vector<double>& v)
388 {
389     std::vector<std::string> exprs;
390
391     if (v.size() < 3)
392     {
393         return exprs;
394     }
395
396     // decode header
397     int type = v[0];
398     int iDims = v[1];
399     if (type != sci_strings )
400     {
401         return exprs;
402     }
403     if (iDims < 2)
404     {
405         return exprs;
406     }
407
408     // number of elements (setup the first one)
409     int iElements = v[2];
410     for (int i = 1; i < iDims; ++i)
411     {
412         iElements *= v[2 + i];
413     }
414
415     if (iElements == 0)
416     {
417         return exprs;
418     }
419
420     // decode UTF-8 strings
421     char* pString = (char*) (v.data() + 2 + iDims + iElements);
422     size_t len = static_cast<size_t>(v[2 + iDims]);
423     for (int i = 1; i < iElements; i++)
424     {
425         exprs.emplace_back(pString);
426
427         pString = (char*) (v.data() + 2 + iDims + iElements + len);
428         len = static_cast<size_t>(v[2 + iDims + i]);
429     }
430     exprs.emplace_back(pString);
431
432     return exprs;
433 }
434
435 int XMIResource::loadEncodedStringArray(xmlTextReaderPtr reader, enum object_properties_t property, const model::BaseObject& o)
436 {
437     std::vector<double> v;
438     controller.getObjectProperty(o.id(), o.kind(), property, v);
439
440     std::vector<std::string> exprsAsString = decode_string_vector(v);
441     exprsAsString.push_back(to_string(xmlTextReaderConstValue(reader)));
442
443     controller.setObjectProperty(o.id(), o.kind(), property, encode_string_vector(exprsAsString));
444     return 1;
445 }
446
447 int XMIResource::loadBase64(xmlTextReaderPtr reader, enum object_properties_t property, const model::BaseObject& o)
448 {
449     // iterate on attributes
450     for (int rc = xmlTextReaderMoveToFirstAttribute(reader); rc > 0; rc = xmlTextReaderMoveToNextAttribute(reader))
451     {
452         auto found = std::find(constXcosNames.begin(), constXcosNames.end(), xmlTextReaderConstName(reader));
453         enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
454
455         switch (current)
456         {
457             case e_base64:
458             {
459                 const xmlChar* base64 = xmlTextReaderConstValue(reader);
460                 std::vector<double> v = base64::decode<std::vector<double> >(to_string(base64));
461                 controller.setObjectProperty(o.id(), o.kind(), property, v);
462                 break;
463             }
464             default:
465                 // ignore other parameters
466                 // TODO: Does other metamodels might be managed there ?
467                 break;
468         }
469     }
470
471     return 1;
472 }
473
474 int XMIResource::loadDatatype(xmlTextReaderPtr reader, const model::BaseObject& o)
475 {
476     assert(o.kind() == PORT);
477
478     std::vector<int> datatype;
479     controller.getObjectProperty(o.id(), o.kind(), DATATYPE, datatype);
480
481     // iterate on attributes
482     for (int rc = xmlTextReaderMoveToFirstAttribute(reader); rc > 0; rc = xmlTextReaderMoveToNextAttribute(reader))
483     {
484         auto found = std::find(constXcosNames.begin(), constXcosNames.end(), xmlTextReaderConstName(reader));
485         enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
486         switch (current)
487         {
488             case e_type:
489                 datatype[2]  = to_double(xmlTextReaderConstValue(reader));
490                 break;
491             case e_rows:
492                 datatype[0]  = to_double(xmlTextReaderConstValue(reader));
493                 break;
494             case e_columns:
495                 datatype[1]  = to_double(xmlTextReaderConstValue(reader));
496                 break;
497             default:
498                 // ignore other parameters
499                 // TODO: Does other metamodels might be managed there ?
500                 break;
501         }
502     }
503
504     controller.setObjectProperty(o.id(), o.kind(), DATATYPE, datatype);
505     return 1;
506 }
507
508 int XMIResource::loadPoint(xmlTextReaderPtr reader, const model::BaseObject& o)
509 {
510     assert(o.kind() == LINK);
511
512     std::vector<double> points;
513     controller.getObjectProperty(o.id(), o.kind(), CONTROL_POINTS, points);
514
515     // iterate on attributes
516     for (int rc = xmlTextReaderMoveToFirstAttribute(reader); rc > 0; rc = xmlTextReaderMoveToNextAttribute(reader))
517     {
518         auto found = std::find(constXcosNames.begin(), constXcosNames.end(), xmlTextReaderConstName(reader));
519         enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
520         switch (current)
521         {
522             case e_x:
523                 points.push_back(to_double(xmlTextReaderConstValue(reader)));
524                 break;
525             case e_y:
526                 points.push_back(to_double(xmlTextReaderConstValue(reader)));
527                 break;
528             default:
529                 // ignore other parameters
530                 // TODO: Does other metamodels might be managed there ?
531                 break;
532         }
533     }
534
535     controller.setObjectProperty(o.id(), o.kind(), CONTROL_POINTS, points);
536     return 1;
537 }
538
539 int XMIResource::loadGeometry(xmlTextReaderPtr reader, const model::BaseObject& o)
540 {
541     assert(o.kind() == BLOCK || o.kind() == ANNOTATION || o.kind() == LINK);
542
543     std::vector<double> geom;
544     controller.getObjectProperty(o.id(), o.kind(), GEOMETRY, geom);
545     geom.resize(4);
546
547     // iterate on attributes
548     for (int rc = xmlTextReaderMoveToFirstAttribute(reader); rc > 0; rc = xmlTextReaderMoveToNextAttribute(reader))
549     {
550         auto found = std::find(constXcosNames.begin(), constXcosNames.end(), xmlTextReaderConstName(reader));
551         enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
552         switch (current)
553         {
554             case e_x:
555                 geom[0] = to_double(xmlTextReaderConstValue(reader));
556                 break;
557             case e_y:
558                 geom[1] = to_double(xmlTextReaderConstValue(reader));
559                 break;
560             case e_width:
561                 geom[2] = to_double(xmlTextReaderConstValue(reader));
562                 break;
563             case e_height:
564                 geom[3] = to_double(xmlTextReaderConstValue(reader));
565                 break;
566             default:
567                 // ignore other parameters
568                 // TODO: Does other metamodels might be managed there ?
569                 break;
570         }
571     }
572
573     controller.setObjectProperty(o.id(), o.kind(), GEOMETRY, geom);
574     return 1;
575 }
576
577 int XMIResource::loadAbstractBaseObject(xmlTextReaderPtr reader, const model::BaseObject& o)
578 {
579     assert(o.kind() == BLOCK || o.kind() == ANNOTATION || o.kind() == LINK);
580
581     // abstract Layer is not decoded there as it has no attribute
582
583     // iterate on attributes
584     for (int rc = xmlTextReaderMoveToFirstAttribute(reader); rc > 0; rc = xmlTextReaderMoveToNextAttribute(reader))
585     {
586         auto found = std::find(constXcosNames.begin(), constXcosNames.end(), xmlTextReaderConstName(reader));
587         enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
588         switch (current)
589         {
590             case e_uid:
591             {
592                 std::string uid = to_string(xmlTextReaderConstValue(reader));
593                 controller.setObjectProperty(o.id(), o.kind(), UID, uid);
594                 references.insert(std::make_pair(uid, o.id()));
595                 break;
596             }
597             case e_parentDiagram:
598             {
599                 // not lookup needed ; only one diagram is serialized at a time
600                 controller.setObjectProperty(o.id(), o.kind(), PARENT_DIAGRAM, root);
601                 break;
602             }
603             case e_parent:
604             {
605                 // not lookup needed thanks to the XML hierarchy
606                 const model::BaseObject& parent = *(processed.end() - 2);
607                 controller.setObjectProperty(o.id(), o.kind(), PARENT_BLOCK, parent.id());
608                 break;
609             }
610             default:
611                 // ignore other parameters
612                 // TODO: Does other metamodels might be managed there ?
613                 break;
614         }
615     }
616
617     return 1;
618 }
619
620 int XMIResource::loadDiagram(xmlTextReaderPtr reader, const model::BaseObject& o)
621 {
622     assert(o.kind() == DIAGRAM);
623
624     // abstract Layer is not decoded there as it has no attribute
625
626     // iterate on attributes
627     for (int rc = xmlTextReaderMoveToFirstAttribute(reader); rc > 0; rc = xmlTextReaderMoveToNextAttribute(reader))
628     {
629         auto found = std::find(constXcosNames.begin(), constXcosNames.end(), xmlTextReaderConstName(reader));
630         enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
631         switch (current)
632         {
633             case e_title:
634                 controller.setObjectProperty(o.id(), o.kind(), TITLE, to_string(xmlTextReaderConstValue(reader)));
635                 break;
636             case e_path:
637                 controller.setObjectProperty(o.id(), o.kind(), PATH, to_string(xmlTextReaderConstValue(reader)));
638                 break;
639             case e_debugLevel:
640                 controller.setObjectProperty(o.id(), o.kind(), DEBUG_LEVEL, to_int(xmlTextReaderConstValue(reader)));
641                 break;
642             case e_version:
643                 controller.setObjectProperty(o.id(), o.kind(), VERSION_NUMBER, to_string(xmlTextReaderConstValue(reader)));
644                 break;
645             default:
646                 // ignore other parameters
647                 // TODO: Does other metamodels might be managed there ?
648                 break;
649         }
650     }
651
652     return 1;
653 }
654
655 int XMIResource::loadSimulationConfig(xmlTextReaderPtr reader, const model::BaseObject& o)
656 {
657     assert(o.kind() == DIAGRAM);
658
659     std::vector<double> properties;
660     controller.getObjectProperty(o.id(), o.kind(), PROPERTIES, properties);
661     properties.resize(8);
662
663     // iterate on attributes
664     for (int rc = xmlTextReaderMoveToFirstAttribute(reader); rc > 0; rc = xmlTextReaderMoveToNextAttribute(reader))
665     {
666         auto found = std::find(constXcosNames.begin(), constXcosNames.end(), xmlTextReaderConstName(reader));
667         enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
668         switch (current)
669         {
670             case e_finalTime:
671                 properties[0] = to_double(xmlTextReaderConstValue(reader));
672                 break;
673             case e_absoluteTolerance:
674                 properties[1] = to_double(xmlTextReaderConstValue(reader));
675                 break;
676             case e_relativeTolerance:
677                 properties[2] = to_double(xmlTextReaderConstValue(reader));
678                 break;
679             case e_timeTolerance:
680                 properties[3] = to_double(xmlTextReaderConstValue(reader));
681                 break;
682             case e_deltaT:
683                 properties[4] = to_double(xmlTextReaderConstValue(reader));
684                 break;
685             case e_realtimeScale:
686                 properties[5] = to_double(xmlTextReaderConstValue(reader));
687                 break;
688             case e_solver:
689                 properties[6] = to_double(xmlTextReaderConstValue(reader));
690                 break;
691             case e_deltaH:
692                 properties[7] = to_double(xmlTextReaderConstValue(reader));
693                 break;
694             default:
695                 // ignore other parameters
696                 // TODO: Does other metamodels might be managed there ?
697                 break;
698         }
699     }
700
701     controller.setObjectProperty(o.id(), o.kind(), PROPERTIES, properties);
702     return 1;
703 }
704
705 int XMIResource::loadBlock(xmlTextReaderPtr reader, const model::BaseObject& o)
706 {
707     assert(o.kind() == BLOCK);
708
709     // load the base class
710     int ret = loadAbstractBaseObject(reader, o);
711     if (ret != 1)
712     {
713         return ret;
714     }
715
716     // Layer has no attribute so there is no need to decode it there
717     // Geometry is handled as an element
718     // Label is handled as an element
719
720     // iterate on attributes
721     for (int rc = xmlTextReaderMoveToFirstAttribute(reader); rc > 0; rc = xmlTextReaderMoveToNextAttribute(reader))
722     {
723         auto found = std::find(constXcosNames.begin(), constXcosNames.end(), xmlTextReaderConstName(reader));
724         enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
725         switch (current)
726         {
727             case e_description:
728                 controller.setObjectProperty(o.id(), o.kind(), DESCRIPTION, to_string(xmlTextReaderConstValue(reader)));
729                 break;
730             case e_style:
731                 controller.setObjectProperty(o.id(), o.kind(), STYLE, to_string(xmlTextReaderConstValue(reader)));
732                 break;
733             case e_interfaceFunction:
734                 controller.setObjectProperty(o.id(), o.kind(), INTERFACE_FUNCTION, to_string(xmlTextReaderConstValue(reader)));
735                 break;
736             case e_functionName:
737                 controller.setObjectProperty(o.id(), o.kind(), SIM_FUNCTION_NAME, to_string(xmlTextReaderConstValue(reader)));
738                 break;
739             case e_functionAPI:
740                 controller.setObjectProperty(o.id(), o.kind(), SIM_FUNCTION_API, to_int(xmlTextReaderConstValue(reader)));
741                 break;
742             case e_dependsOnT:
743             {
744                 std::vector<int> dep_ut;
745                 controller.getObjectProperty(o.id(), o.kind(), SIM_DEP_UT, dep_ut);
746                 dep_ut.resize(2);
747
748                 dep_ut[1] = to_int(xmlTextReaderConstValue(reader));
749                 controller.setObjectProperty(o.id(), o.kind(), SIM_DEP_UT, dep_ut);
750                 break;
751             }
752             case e_dependsOnU:
753             {
754                 std::vector<int> dep_ut;
755                 controller.getObjectProperty(o.id(), o.kind(), SIM_DEP_UT, dep_ut);
756                 dep_ut.resize(2);
757
758                 dep_ut[0] = to_int(xmlTextReaderConstValue(reader));
759                 controller.setObjectProperty(o.id(), o.kind(), SIM_DEP_UT, dep_ut);
760                 break;
761             }
762             case e_blocktype:
763                 controller.setObjectProperty(o.id(), o.kind(), SIM_BLOCKTYPE, to_string(xmlTextReaderConstValue(reader)));
764                 break;
765             default:
766                 // ignore other parameters
767                 // TODO: Does other metamodels might be managed there ?
768                 break;
769         }
770     }
771
772     /*
773      * Reset some properties loaded as array and initialized with non-empty value
774      */
775     std::vector<int> empty_int_array;
776     controller.setObjectProperty(o.id(), o.kind(), NZCROSS, empty_int_array);
777     controller.setObjectProperty(o.id(), o.kind(), NMODE, empty_int_array);
778
779     return 1;
780 }
781
782 int XMIResource::loadPort(xmlTextReaderPtr reader, const model::BaseObject& o)
783 {
784     assert(o.kind() == PORT);
785
786     // ignore datatype as it is managed as an XML node
787
788     // iterate on attributes
789     for (int rc = xmlTextReaderMoveToFirstAttribute(reader); rc > 0; rc = xmlTextReaderMoveToNextAttribute(reader))
790     {
791         auto found = std::find(constXcosNames.begin(), constXcosNames.end(), xmlTextReaderConstName(reader));
792         enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
793         switch (current)
794         {
795             case e_uid:
796             {
797                 std::string uid = to_string(xmlTextReaderConstValue(reader));
798                 controller.setObjectProperty(o.id(), o.kind(), UID, uid);
799                 references.insert(std::make_pair(uid, o.id()));
800                 break;
801             }
802             case e_firing:
803                 controller.setObjectProperty(o.id(), o.kind(), FIRING, to_double(xmlTextReaderConstValue(reader)));
804                 break;
805             case e_sourceBlock:
806             {
807                 // not lookup needed thanks to the XML hierarchy
808                 break;
809             }
810             case e_kind:
811             {
812                 std::string portKindStr = to_string(xmlTextReaderConstValue(reader));
813                 int k;
814                 if ("in" == portKindStr)
815                 {
816                     k = PORT_IN;
817                 }
818                 else if ("out" == portKindStr)
819                 {
820                     k = PORT_OUT;
821                 }
822                 else if ("ein" == portKindStr)
823                 {
824                     k = PORT_EIN;
825                 }
826                 else if ("eout" == portKindStr)
827                 {
828                     k = PORT_EOUT;
829                 }
830                 else
831                 {
832                     k = PORT_UNDEF;
833                 }
834                 controller.setObjectProperty(o.id(), o.kind(), PORT_KIND, k);
835                 break;
836             }
837             case e_implicit:
838                 controller.setObjectProperty(o.id(), o.kind(), IMPLICIT, to_boolean(xmlTextReaderConstValue(reader)));
839                 break;
840             case e_connectedSignal:
841                 // will be resolved later
842                 unresolved.push_back(
843                     unresolvedReference(o.id(), o.kind(), CONNECTED_SIGNALS,
844                                         to_string(xmlTextReaderConstValue(reader))));
845                 break;
846             case e_style:
847                 controller.setObjectProperty(o.id(), o.kind(), STYLE, to_string(xmlTextReaderConstValue(reader)));
848                 break;
849             case e_label:
850                 controller.setObjectProperty(o.id(), o.kind(), LABEL, to_string(xmlTextReaderConstValue(reader)));
851                 break;
852             default:
853                 // ignore other parameters
854                 // TODO: Does other metamodels might be managed there ?
855                 break;
856         }
857     }
858
859     return 1;
860 }
861
862 int XMIResource::loadLink(xmlTextReaderPtr reader, const model::BaseObject& o)
863 {
864     assert(o.kind() == LINK);
865
866     // load the base class
867     int ret = loadAbstractBaseObject(reader, o);
868     if (ret != 1)
869     {
870         return ret;
871     }
872
873     // geometry is handled as in independent node
874     // controlPoint is handled as in independent node
875     // Label is handled as an element
876
877     // iterate on attributes
878     for (int rc = xmlTextReaderMoveToFirstAttribute(reader); rc > 0; rc = xmlTextReaderMoveToNextAttribute(reader))
879     {
880         auto found = std::find(constXcosNames.begin(), constXcosNames.end(), xmlTextReaderConstName(reader));
881         enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
882         switch (current)
883         {
884             case e_description:
885                 controller.setObjectProperty(o.id(), o.kind(), DESCRIPTION, to_string(xmlTextReaderConstValue(reader)));
886                 break;
887             case e_uid:
888             {
889                 std::string uid = to_string(xmlTextReaderConstValue(reader));
890                 controller.setObjectProperty(o.id(), o.kind(), UID, uid);
891                 references.insert(std::make_pair(uid, o.id()));
892                 break;
893             }
894             case e_sourcePort:
895                 // will be resolved later
896                 unresolved.push_back(
897                     unresolvedReference(o.id(), o.kind(), SOURCE_PORT, to_string(xmlTextReaderConstValue(reader))));
898                 break;
899             case e_destinationPort:
900                 // will be resolved later
901                 unresolved.push_back(
902                     unresolvedReference(o.id(), o.kind(), DESTINATION_PORT,
903                                         to_string(xmlTextReaderConstValue(reader))));
904                 break;
905             case e_style:
906                 controller.setObjectProperty(o.id(), o.kind(), STYLE, to_string(xmlTextReaderConstValue(reader)));
907                 break;
908             case e_lineWidth:
909             {
910                 std::vector<double> thick;
911                 controller.getObjectProperty(o.id(), o.kind(), THICK, thick);
912                 thick[0] = to_double(xmlTextReaderConstValue(reader));
913                 controller.setObjectProperty(o.id(), o.kind(), THICK, thick);
914                 break;
915             }
916             case e_lineHeight:
917             {
918                 std::vector<double> thick;
919                 controller.getObjectProperty(o.id(), o.kind(), THICK, thick);
920                 thick[1] = to_double(xmlTextReaderConstValue(reader));
921                 controller.setObjectProperty(o.id(), o.kind(), THICK, thick);
922                 break;
923             }
924             case e_color:
925                 controller.setObjectProperty(o.id(), o.kind(), COLOR, to_int(xmlTextReaderConstValue(reader)));
926                 break;
927             default:
928                 // ignore other parameters
929                 // TODO: Does other metamodels might be managed there ?
930                 break;
931         }
932     }
933
934     return ret;
935 }
936
937 int XMIResource::loadAnnotation(xmlTextReaderPtr reader, const model::BaseObject& o)
938 {
939     assert(o.kind() == ANNOTATION);
940
941     // load the base class
942     int ret = loadAbstractBaseObject(reader, o);
943     if (ret != 1)
944     {
945         return ret;
946     }
947
948     // geometry is handled as a node
949
950     // iterate on attributes
951     for (int rc = xmlTextReaderMoveToFirstAttribute(reader); rc > 0; rc = xmlTextReaderMoveToNextAttribute(reader))
952     {
953         auto found = std::find(constXcosNames.begin(), constXcosNames.end(), xmlTextReaderConstName(reader));
954         enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
955         switch (current)
956         {
957             case e_description:
958                 controller.setObjectProperty(o.id(), o.kind(), DESCRIPTION, to_string(xmlTextReaderConstValue(reader)));
959                 break;
960             case e_font:
961                 controller.setObjectProperty(o.id(), o.kind(), FONT, to_string(xmlTextReaderConstValue(reader)));
962                 break;
963             case e_fontSize:
964                 controller.setObjectProperty(o.id(), o.kind(), FONT_SIZE, to_string(xmlTextReaderConstValue(reader)));
965                 break;
966             case e_style:
967                 controller.setObjectProperty(o.id(), o.kind(), STYLE, to_string(xmlTextReaderConstValue(reader)));
968                 break;
969             default:
970                 // ignore other parameters
971                 // TODO: Does other metamodels might be managed there ?
972                 break;
973         }
974     }
975
976     return ret;
977 }
978
979 int XMIResource::processNode(xmlTextReaderPtr reader)
980 {
981     // manage only xcos related XML nodes
982     const xmlChar* nsURI = xmlTextReaderConstNamespaceUri(reader);
983     if (nsURI == xcosNamespaceUri || nsURI == nullptr)
984     {
985         xmlReaderTypes nodeType = (xmlReaderTypes) xmlTextReaderNodeType(reader);
986         switch (nodeType)
987         {
988             case XML_READER_TYPE_NONE:
989                 return 1;
990             case XML_READER_TYPE_ELEMENT:
991                 return processElement(reader);
992             case XML_READER_TYPE_ATTRIBUTE:
993                 sciprint("xmlReader attributes node not supported\n");
994                 return -1;
995             case XML_READER_TYPE_TEXT:
996                 return processText(reader);
997             case XML_READER_TYPE_CDATA:
998                 return processText(reader);
999             case XML_READER_TYPE_ENTITY_REFERENCE:
1000                 sciprint("xmlReader entity reference not supported\n");
1001                 return -1;
1002             case XML_READER_TYPE_ENTITY:
1003                 sciprint("xmlReader entity not supported\n");
1004                 return -1;
1005             case XML_READER_TYPE_PROCESSING_INSTRUCTION:
1006                 sciprint("xmlReader processing instruction not supported\n");
1007                 return -1;
1008             case XML_READER_TYPE_COMMENT:
1009                 return 1;
1010             case XML_READER_TYPE_DOCUMENT:
1011                 return 1;
1012             case XML_READER_TYPE_DOCUMENT_TYPE:
1013                 sciprint("xmlReader document type not supported\n");
1014                 return -1;
1015             case XML_READER_TYPE_DOCUMENT_FRAGMENT:
1016                 sciprint("xmlReader document fragment not supported\n");
1017                 return -1;
1018             case XML_READER_TYPE_NOTATION:
1019                 sciprint("xmlReader notation not supported\n");
1020                 return -1;
1021             case XML_READER_TYPE_WHITESPACE:
1022                 sciprint("xmlReader whitespace not supported\n");
1023                 return -1;
1024             case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
1025                 return 1; // ignore indent or end-of-line
1026             case XML_READER_TYPE_END_ELEMENT:
1027                 return processEndElement(reader);
1028             case XML_READER_TYPE_END_ENTITY:
1029                 sciprint("xmlReader end entity not supported\n");
1030                 return -1;
1031             case XML_READER_TYPE_XML_DECLARATION:
1032                 sciprint("xmlReader XML declaration not supported\n");
1033                 return -1;
1034         }
1035     }
1036     else
1037     {
1038         // TODO mixed model should be preserved in some way and restored back on XMIResource_save.cpp .
1039     }
1040     sciprint("unable to process node\n");
1041     return -1;
1042 }
1043
1044 int XMIResource::processElement(xmlTextReaderPtr reader)
1045 {
1046     const xmlChar *name = xmlTextReaderConstLocalName(reader);
1047     parent = NB_XCOS_NAMES;
1048
1049     // lookup for known node names
1050     // thanks to the string intern-ing, the pointer comparison could be used
1051     auto found = std::find(constXcosNames.begin(), constXcosNames.end(), name);
1052     enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
1053     switch (current)
1054     {
1055         case e_Diagram:
1056         {
1057             // the root diagram should be decoded
1058             model::BaseObject o(root, DIAGRAM);
1059
1060             processed.push_back(o);
1061             return loadDiagram(reader, o);
1062         }
1063         case e_child:
1064         {
1065             // this is a child of a diagram, resolve the type and call the loaders
1066             // iterate on attributes to lookup for EMF type
1067
1068             // iterate on attributes
1069             for (int rc = xmlTextReaderMoveToFirstAttribute(reader); rc > 0; rc = xmlTextReaderMoveToNextAttribute(reader))
1070             {
1071                 const xmlChar* nsURI  = xmlTextReaderConstNamespaceUri(reader);
1072                 if (nsURI != xsiNamespaceUri)
1073                 {
1074                     continue;
1075                 }
1076
1077                 auto foundName = std::find(constXcosNames.begin(), constXcosNames.end(), xmlTextReaderConstLocalName(reader));
1078                 enum xcosNames currentName = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), foundName));
1079                 if (currentName != e_type)
1080                 {
1081                     continue;
1082                 }
1083
1084                 const xmlChar* value = xmlTextReaderConstValue(reader);
1085                 const xmlChar* valueWithoutPrefix = BAD_CAST(std::strchr((const char*) value, ':'));
1086                 if (valueWithoutPrefix == nullptr)
1087                 {
1088                     valueWithoutPrefix = value;
1089                 }
1090                 else
1091                 {
1092                     // remove the leading ':'
1093                     valueWithoutPrefix = valueWithoutPrefix + 1;
1094                 }
1095                 const xmlChar* interned = xmlTextReaderConstString(reader, valueWithoutPrefix);
1096
1097                 auto found = std::find(constXcosNames.begin(), constXcosNames.end(), interned);
1098                 enum xcosNames current = static_cast<enum xcosNames>(std::distance(constXcosNames.begin(), found));
1099                 switch (current)
1100                 {
1101                     case e_Block:
1102                     {
1103                         ScicosID o = controller.createObject(BLOCK);
1104
1105                         // assign the child
1106                         model::BaseObject parent = processed.back();
1107
1108                         controller.referenceObject(o);
1109                         controller.setObjectProperty(o, BLOCK, PARENT_DIAGRAM, root);
1110                         if (parent.kind() == BLOCK)
1111                         {
1112                             controller.setObjectProperty(o, BLOCK, PARENT_BLOCK, parent.id());
1113                         }
1114                         std::vector<ScicosID> children;
1115                         controller.getObjectProperty(parent.id(), parent.kind(), CHILDREN, children);
1116                         children.push_back(o);
1117                         controller.setObjectProperty(parent.id(), parent.kind(), CHILDREN, children);
1118
1119                         model::BaseObject child(o, BLOCK);
1120                         processed.push_back(child);
1121                         return loadBlock(reader, child);
1122                     }
1123                     case e_Link:
1124                     {
1125                         ScicosID o = controller.createObject(LINK);
1126
1127                         // assign the child
1128                         model::BaseObject parent = processed.back();
1129
1130                         controller.referenceObject(o);
1131                         controller.setObjectProperty(o, LINK, PARENT_DIAGRAM, root);
1132                         if (parent.kind() == BLOCK)
1133                         {
1134                             controller.setObjectProperty(o, LINK, PARENT_BLOCK, parent.id());
1135                         }
1136                         std::vector<ScicosID> children;
1137                         controller.getObjectProperty(parent.id(), parent.kind(), CHILDREN, children);
1138                         children.push_back(o);
1139                         controller.setObjectProperty(parent.id(), parent.kind(), CHILDREN, children);
1140
1141                         model::BaseObject child(o, LINK);
1142                         processed.push_back(child);
1143                         return loadLink(reader, child);
1144                     }
1145                     case e_Annotation:
1146                     {
1147                         ScicosID o = controller.createObject(ANNOTATION);
1148
1149                         // assign the child
1150                         model::BaseObject parent = processed.back();
1151
1152                         controller.referenceObject(o);
1153                         controller.setObjectProperty(o, ANNOTATION, PARENT_DIAGRAM, root);
1154                         if (parent.kind() == BLOCK)
1155                         {
1156                             controller.setObjectProperty(o, ANNOTATION, PARENT_BLOCK, parent.id());
1157                         }
1158                         std::vector<ScicosID> children;
1159                         controller.getObjectProperty(parent.id(), parent.kind(), CHILDREN, children);
1160                         children.push_back(o);
1161                         controller.setObjectProperty(parent.id(), parent.kind(), CHILDREN, children);
1162
1163                         model::BaseObject child(o, ANNOTATION);
1164                         return loadAnnotation(reader, child);
1165                     }
1166                     default:
1167                         sciprint("Not handled child type=%s at line %d\n", *found,
1168                                  xmlTextReaderGetParserLineNumber(reader) - 1);
1169                         return -1;
1170                 }
1171             }
1172             break;
1173         }
1174         case e_in: // no break on purpose
1175         case e_out: // no break on purpose
1176         case e_ein: // no break on purpose
1177         case e_eout:
1178         {
1179             ScicosID o = controller.createObject(PORT);
1180
1181             enum object_properties_t p;
1182             switch (current)
1183             {
1184                 case e_in:
1185                     p = INPUTS;
1186                     break;
1187                 case e_out:
1188                     p = OUTPUTS;
1189                     break;
1190                 case e_ein:
1191                     p = EVENT_INPUTS;
1192                     break;
1193                 case e_eout:
1194                     p = EVENT_OUTPUTS;
1195                     break;
1196                 default:
1197                     return -1;
1198             }
1199
1200             model::BaseObject parent = processed.back();
1201             // add the port them to the parent
1202             controller.setObjectProperty(o, PORT, SOURCE_BLOCK, parent.id());
1203
1204             std::vector<ScicosID> ports;
1205             controller.getObjectProperty(parent.id(), parent.kind(), p, ports);
1206             ports.push_back(o);
1207             controller.setObjectProperty(parent.id(), parent.kind(), p, ports);
1208
1209             // decode content
1210             model::BaseObject child(o, PORT);
1211             processed.push_back(child);
1212             return loadPort(reader, child);
1213         }
1214         case e_geometry:
1215             // geometry is used for rectangle coordinates of its parent
1216             return loadGeometry(reader, processed.back());
1217         case e_nzcross:
1218             // nzcross is a Block property
1219             if (!xmlTextReaderIsEmptyElement(reader))
1220             {
1221                 parent = current;
1222             }
1223             return 1;
1224         case e_nmode:
1225             // nmode is a Block property
1226             if (!xmlTextReaderIsEmptyElement(reader))
1227             {
1228                 parent = current;
1229             }
1230             return 1;
1231         case e_rpar:
1232             // rpar is a Block property
1233             if (!xmlTextReaderIsEmptyElement(reader))
1234             {
1235                 parent = current;
1236             }
1237             return 1;
1238         case e_ipar:
1239             // ipar is a Block property
1240             if (!xmlTextReaderIsEmptyElement(reader))
1241             {
1242                 parent = current;
1243             }
1244             return 1;
1245         case e_label:
1246         {
1247             // label is used for attaching an Annotation to its parent
1248             ScicosID o = controller.createObject(ANNOTATION);
1249
1250             // assign the child
1251             model::BaseObject parent = processed.back();
1252
1253             controller.setObjectProperty(o, ANNOTATION, RELATED_TO, parent.id());
1254             controller.setObjectProperty(parent.id(), parent.kind(), LABEL, o);
1255
1256             model::BaseObject child(o, ANNOTATION);
1257             processed.push_back(child);
1258             return loadAnnotation(reader, child);
1259         }
1260         case e_opar:
1261             // ipar is a Block property
1262             return loadBase64(reader, OPAR, processed.back());
1263         case e_state:
1264             // state is a Block property
1265             if (!xmlTextReaderIsEmptyElement(reader))
1266             {
1267                 parent = current;
1268             }
1269             return 1;
1270         case e_dstate:
1271             // dstate is a Block property
1272             if (!xmlTextReaderIsEmptyElement(reader))
1273             {
1274                 parent = current;
1275             }
1276             return 1;
1277         case e_odstate:
1278             // odstate is a Block property
1279             return loadBase64(reader, ODSTATE, processed.back());
1280         case e_equations:
1281             // equation is a Block property
1282             return loadBase64(reader, EQUATIONS, processed.back());
1283         case e_expression:
1284             // expression is a Block property
1285             if (!xmlTextReaderIsEmptyElement(reader))
1286             {
1287                 parent = current;
1288             }
1289             return 1;
1290         case e_exprs:
1291             // exprs is a Block property
1292             return loadBase64(reader, EXPRS, processed.back());
1293         case e_controlPoint:
1294             // controlPoint is a link property
1295             return loadPoint(reader, processed.back());
1296         case e_context:
1297             // context is a Layer property
1298             if (!xmlTextReaderIsEmptyElement(reader))
1299             {
1300                 parent = current;
1301             }
1302             return 1;
1303         case e_properties:
1304             // properties is a Diagram property
1305             return loadSimulationConfig(reader, processed.back());
1306         case e_datatype:
1307             // datatype is a Port property
1308             return loadDatatype(reader, processed.back());
1309         default:
1310             sciprint("Unknown \"%s\" element name at line %d\n", name, xmlTextReaderGetParserLineNumber(reader) - 1);
1311             return -1;
1312     }
1313
1314     return 1;
1315 }
1316
1317 int XMIResource::processText(xmlTextReaderPtr reader)
1318 {
1319     int ret;
1320
1321     switch (parent)
1322     {
1323         case e_nzcross:
1324             // nzcross is a Block property
1325             ret = loadIntArray(reader, NZCROSS, processed.back());
1326             break;
1327         case e_nmode:
1328             // nmode is a Block property
1329             ret = loadIntArray(reader, NMODE, processed.back());
1330             break;
1331         case e_rpar:
1332             // rpar is a Block property
1333             ret = loadDoubleArray(reader, RPAR, processed.back());
1334             break;
1335         case e_ipar:
1336             // ipar is a Block property
1337             ret = loadIntArray(reader, IPAR, processed.back());
1338             break;
1339         case e_state:
1340             // state is a Block property
1341             ret = loadDoubleArray(reader, STATE, processed.back());
1342             break;
1343         case e_dstate:
1344             // dstate is a Block property
1345             ret = loadDoubleArray(reader, DSTATE, processed.back());
1346             break;
1347         case e_expression:
1348             // expression is a Block property
1349             ret = loadEncodedStringArray(reader, EXPRS, processed.back());
1350             break;
1351         case e_context:
1352             // context is a Layer property
1353             ret = loadStringArray(reader, DIAGRAM_CONTEXT, processed.back());
1354             break;
1355         case e_datatype:
1356             // datatype is a port property
1357             ret = loadIntArray(reader, DATATYPE, processed.back());
1358             break;
1359         default:
1360             sciprint("Unable to decode text value at line %d\n", xmlTextReaderGetParserLineNumber(reader) - 1);
1361             ret = -1;
1362             break;
1363     }
1364
1365     return ret;
1366 }
1367
1368 int XMIResource::processEndElement(xmlTextReaderPtr)
1369 {
1370     if (parent == NB_XCOS_NAMES)
1371     {
1372         processed.pop_back();
1373     }
1374     else
1375     {
1376         parent = NB_XCOS_NAMES;
1377     }
1378
1379     return 1;
1380 }
1381
1382 } /* namespace org_scilab_modules_xcos */