Xcos ecore: fix datatype definition
[scilab.git] / scilab / modules / scicos / src / cpp / XMIResource_save.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2016-2016 - Scilab Enterprises - Clement DAVID
4  *
5  * This file is hereby licensed under the terms of the GNU GPL v2.0,
6  * pursuant to article 5.3.4 of the CeCILL v.2.1.
7  * This file was originally licensed under the terms of the CeCILL v2.1,
8  * and continues to be available under such terms.
9  * For more information, see the COPYING file which you should have received
10  * along with this program.
11  */
12
13 #include "XMIResource.hxx"
14 #include "base64.hxx"
15
16 #include <string>
17 #include <sstream>
18 #include <vector>
19 #include <cmath> // for trunc
20
21 extern "C" {
22 #include "sci_types.h"
23
24 #include <libxml/xmlwriter.h>
25 }
26
27 namespace org_scilab_modules_scicos
28 {
29
30 int XMIResource::save(const char* uri)
31 {
32     int status;
33
34     xmlTextWriterPtr writer = xmlNewTextWriterFilename(uri, 0);
35     if (writer == NULL)
36     {
37         return -1;
38     }
39
40     status = xmlTextWriterSetIndent(writer, 1);
41     if (status == -1)
42     {
43         xmlFreeTextWriter(writer);
44         return status;
45     }
46
47     status = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
48     if (status == -1)
49     {
50         xmlFreeTextWriter(writer);
51         return status;
52     }
53
54     status = writeDiagram(writer);
55     if (status == -1)
56     {
57         xmlFreeTextWriter(writer);
58         return status;
59     }
60
61     status = xmlTextWriterEndDocument(writer);
62     xmlFreeTextWriter(writer);
63     return status;
64 }
65
66 static bool is_empty_matrix(const std::vector<double>& v)
67 {
68     // v == {1, 2, 0, 0, 0}
69     return v.size() == 5 && v[0] == sci_matrix && v[1] == 2. && v[2] == 0. && v[3] == 0. && v[4] == 0.;
70 }
71
72 static bool is_empty_list(const std::vector<double>& v)
73 {
74     // v == {15, 0}
75     return v.size() == 2 && v[0] == sci_list && v[1] == 0.;
76 }
77
78 static bool is_string_vector(const std::vector<double>& v)
79 {
80     return v.size() > 2 && v[0] == sci_strings && v[1] != 0;
81 }
82
83 static std::string to_string(int v)
84 {
85     return std::to_string(v);
86 }
87
88 static std::string to_string(double v)
89 {
90     if (std::trunc(v) == v)
91     {
92         return to_string((int) v);
93     }
94
95     std::string str(15, '\0');
96     // std::snprintf(const_cast<char*>(str.data()), str.size(), "%.6E", v);
97     std::sprintf(const_cast<char*>(str.data()), "%.6E", v);
98     return str;
99 }
100
101 /* helper function to decode simple string EXPRS */
102 static std::vector<std::string> to_string_vector(const std::vector<double>& v)
103 {
104     std::vector<std::string> ret;
105     std::vector<double>::const_iterator it = v.begin();
106
107     int strHeader = *it++;
108     if (strHeader != sci_strings)
109     {
110         return ret;
111     }
112     unsigned int iDims = *it++;
113
114     // manage multi-dimensional arrays (will be serialized as a vector)
115     unsigned int iElements = 1;
116     for (unsigned int i = 0; i < iDims; ++i)
117     {
118         iElements *= static_cast<unsigned int>(*it++);
119     }
120
121     // retrieve the length of each encoded string, stored as a stack
122     std::vector<unsigned int> stringsLength;
123     stringsLength.reserve(iElements + 1);
124     stringsLength.push_back(0);
125     for (unsigned int i = 0; i < iElements; ++i)
126     {
127         stringsLength.push_back(*it++);
128     }
129
130     // Retrieving the pointers (already UTF-8 encoded char*) and store them as strings
131     ret.reserve(ret.size() + iElements);
132     for (unsigned int i = 0; i < iElements; ++i)
133     {
134         // push the data
135         const double* strData = &(*(it + stringsLength[i]));
136         ret.emplace_back((char*) strData);
137     }
138
139     return ret;
140 }
141
142
143 static int writeBase64(xmlTextWriterPtr writer, const char* name, const std::vector<double>& v)
144 {
145     int status;
146
147     // convert values as big endian (network endianess)
148     // convert the big endian value to Base64
149     std::string content = base64::encode(v);
150
151     // write the XML data
152     status = xmlTextWriterStartElement(writer, BAD_CAST(name));
153     if (status == -1)
154     {
155         return status;
156     }
157
158     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("base64"), BAD_CAST(content.data()));
159     if (status == -1)
160     {
161         return status;
162     }
163
164     status = xmlTextWriterEndElement(writer);
165     return status;
166 }
167
168 int XMIResource::writeDatatype(xmlTextWriterPtr writer, const std::vector<int>& datatype)
169 {
170     int status;
171
172     status = xmlTextWriterStartElement(writer, BAD_CAST("datatype"));
173     if (status == -1)
174     {
175         return status;
176     }
177
178     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("type"), BAD_CAST(to_string(datatype[2]).c_str()));
179     if (status == -1)
180     {
181         return status;
182     }
183
184     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("rows"), BAD_CAST(to_string(datatype[0]).c_str()));
185     if (status == -1)
186     {
187         return status;
188     }
189
190     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("columns"), BAD_CAST(to_string(datatype[1]).c_str()));
191     if (status == -1)
192     {
193         return status;
194     }
195
196     status = xmlTextWriterEndElement(writer);
197     if (status == -1)
198     {
199         return status;
200     }
201
202     return status;
203 }
204
205 int XMIResource::writePoint(xmlTextWriterPtr writer, double x, double y)
206 {
207     int status;
208
209     status = xmlTextWriterStartElement(writer, BAD_CAST("controlPoint"));
210     if (status == -1)
211     {
212         return status;
213     }
214
215     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("x"), BAD_CAST(to_string(x).c_str()));
216     if (status == -1)
217     {
218         return status;
219     }
220
221     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("y"), BAD_CAST(to_string(y).c_str()));
222     if (status == -1)
223     {
224         return status;
225     }
226
227     status = xmlTextWriterEndElement(writer);
228     if (status == -1)
229     {
230         return status;
231     }
232
233     return status;
234 }
235
236 int XMIResource::writeGeometry(xmlTextWriterPtr writer, ScicosID id, kind_t kind)
237 {
238     int status;
239
240     status = xmlTextWriterStartElement(writer, BAD_CAST("geometry"));
241     if (status == -1)
242     {
243         return status;
244     }
245
246     std::vector<double> doubleArrayValue;
247     controller.getObjectProperty(id, kind, GEOMETRY, doubleArrayValue);
248     unsigned int i = 0;
249     if (doubleArrayValue.size() > i && doubleArrayValue[i])
250     {
251         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("x"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
252         if (status == -1)
253         {
254             return status;
255         }
256     }
257
258     i++;
259     if (doubleArrayValue.size() > i && doubleArrayValue[i])
260     {
261         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("y"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
262         if (status == -1)
263         {
264             return status;
265         }
266     }
267
268     i++;
269     if (doubleArrayValue.size() > i && doubleArrayValue[i])
270     {
271         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("width"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
272         if (status == -1)
273         {
274             return status;
275         }
276     }
277
278     i++;
279     if (doubleArrayValue.size() > i && doubleArrayValue[i])
280     {
281         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("height"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
282         if (status == -1)
283         {
284             return status;
285         }
286     }
287
288     status = xmlTextWriterEndElement(writer);
289     if (status == -1)
290     {
291         return status;
292     }
293
294     return status;
295 }
296
297 int XMIResource::writeAbstractLayer(xmlTextWriterPtr writer, ScicosID id, kind_t kind)
298 {
299     int status = 1;
300
301     std::vector<std::string> context;
302     controller.getObjectProperty(id, kind, DIAGRAM_CONTEXT, context);
303     for (const std::string& c : context)
304     {
305         status = xmlTextWriterStartElement(writer, BAD_CAST("context"));
306         if (status == -1)
307         {
308             return status;
309         }
310
311         if (!c.empty())
312         {
313             status = xmlTextWriterWriteCDATA(writer, BAD_CAST(c.c_str()));
314             if (status == -1)
315             {
316                 return status;
317             }
318         }
319
320         status = xmlTextWriterEndElement(writer);
321         if (status == -1)
322         {
323             return status;
324         }
325     }
326
327     std::vector<ScicosID> children;
328     controller.getObjectProperty(id, kind, CHILDREN, children);
329     for (ScicosID child : children)
330     {
331         kind_t kind = controller.getKind(child);
332         switch (kind)
333         {
334             case BLOCK:
335                 status = writeBlock(writer, child);
336                 break;
337             case LINK:
338                 status = writeLink(writer, child);
339                 break;
340             case ANNOTATION:
341                 status = writeAnnotation(writer, child);
342                 break;
343             default:
344                 status =  -1;
345                 break;
346         }
347
348         if (status == -1)
349         {
350             return status;
351         }
352     }
353
354     return status;
355 }
356
357 int XMIResource::writeAbstractBaseObject(xmlTextWriterPtr writer, ScicosID id, kind_t kind)
358 {
359     int status;
360
361     std::string uid;
362     controller.getObjectProperty(id, kind, UID, uid);
363     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("uid"), BAD_CAST(uid.c_str()));
364     if (status == -1)
365     {
366         return status;
367     }
368
369     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("parentDiagram"), BAD_CAST("/"));
370     if (status == -1)
371     {
372         return status;
373     }
374
375     /* parent / child relation is not serialized as this relation is the XML tree */
376     return status;
377 }
378
379 int XMIResource::writeDiagram(xmlTextWriterPtr writer)
380 {
381     int status;
382
383     status = xmlTextWriterStartElementNS(writer, BAD_CAST("xcos"), BAD_CAST("Diagram"), BAD_CAST("org.scilab.modules.xcos"));
384     if (status == -1)
385     {
386         return status;
387     }
388
389     /*
390      * Write default xmlns
391      */
392     status = xmlTextWriterWriteAttributeNS(writer, BAD_CAST("xmi"), BAD_CAST("version"), BAD_CAST("http://www.omg.org/XMI"), BAD_CAST("2.0"));
393     if (status == -1)
394     {
395         return status;
396     }
397     status = xmlTextWriterWriteAttributeNS(writer, BAD_CAST("xsi"), BAD_CAST("schemaLocation"), BAD_CAST("http://www.w3.org/2001/XMLSchema-instance"), BAD_CAST("org.scilab.modules.xcos xcos.ecore"));
398     if (status == -1)
399     {
400         return status;
401     }
402
403     /*
404      * Diagram values
405      */
406     std::string strValue;
407     controller.getObjectProperty(root, DIAGRAM, TITLE, strValue);
408     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("title"), BAD_CAST(strValue.c_str()));
409     if (status == -1)
410     {
411         return status;
412     }
413
414     strValue.clear();
415     controller.getObjectProperty(root, DIAGRAM, PATH, strValue);
416     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("path"), BAD_CAST(strValue.c_str()));
417     if (status == -1)
418     {
419         return status;
420     }
421
422     int intValue;
423     controller.getObjectProperty(root, DIAGRAM, DEBUG_LEVEL, intValue);
424     strValue = to_string(intValue);
425     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("debugLevel"), BAD_CAST(strValue.c_str()));
426     if (status == -1)
427     {
428         return status;
429     }
430
431     strValue.clear();
432     controller.getObjectProperty(root, DIAGRAM, VERSION_NUMBER, strValue);
433     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("version"), BAD_CAST(strValue.c_str()));
434     if (status == -1)
435     {
436         return status;
437     }
438
439     status = writeAbstractLayer(writer, root, DIAGRAM);
440     if (status == -1)
441     {
442         return status;
443     }
444
445     status = writeSimulationConfig(writer, root);
446     if (status == -1)
447     {
448         return status;
449     }
450
451     status = xmlTextWriterEndElement(writer);
452     if (status == -1)
453     {
454         return status;
455     }
456
457     return status;
458 }
459
460 int XMIResource::writeSimulationConfig(xmlTextWriterPtr writer, ScicosID id)
461 {
462     int status;
463
464     status = xmlTextWriterStartElement(writer, BAD_CAST("properties"));
465     if (status == -1)
466     {
467         return status;
468     }
469
470     std::vector<double> doubleArrayValue;
471     controller.getObjectProperty(id, DIAGRAM, PROPERTIES, doubleArrayValue);
472     unsigned int i = 0;
473     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("finalTime"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
474     if (status == -1)
475     {
476         return status;
477     }
478
479     i++;
480     if (i >= doubleArrayValue.size())
481     {
482         return -1;
483     }
484     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("absoluteTime"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
485     if (status == -1)
486     {
487         return status;
488     }
489
490     i++;
491     if (i >= doubleArrayValue.size())
492     {
493         return -1;
494     }
495     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("relativeTolerance"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
496     if (status == -1)
497     {
498         return status;
499     }
500
501     i++;
502     if (i >= doubleArrayValue.size())
503     {
504         return -1;
505     }
506     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("absoluteTolerance"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
507     if (status == -1)
508     {
509         return status;
510     }
511
512     i++;
513     if (i >= doubleArrayValue.size())
514     {
515         return -1;
516     }
517     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("deltaT"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
518     if (status == -1)
519     {
520         return status;
521     }
522
523     i++;
524     if (i >= doubleArrayValue.size())
525     {
526         return -1;
527     }
528     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("realtimeScale"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
529     if (status == -1)
530     {
531         return status;
532     }
533
534     i++;
535     if (i >= doubleArrayValue.size())
536     {
537         return -1;
538     }
539     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("solver"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
540     if (status == -1)
541     {
542         return status;
543     }
544
545     i++;
546     if (i >= doubleArrayValue.size())
547     {
548         return -1;
549     }
550     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("deltaH"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
551     if (status == -1)
552     {
553         return status;
554     }
555
556     status = xmlTextWriterEndElement(writer);
557     if (status == -1)
558     {
559         return status;
560     }
561
562     return status;
563 }
564
565 int XMIResource::writeBlock(xmlTextWriterPtr writer, ScicosID id)
566 {
567     int status;
568
569     status = xmlTextWriterStartElement(writer, BAD_CAST("child"));
570     if (status == -1)
571     {
572         return status;
573     }
574
575     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("xsi:type"), BAD_CAST("xcos:Block"));
576     if (status == -1)
577     {
578         return status;
579     }
580
581     status = writeAbstractBaseObject(writer, id, BLOCK);
582     if (status == -1)
583     {
584         return status;
585     }
586
587     std::string strValue;
588     controller.getObjectProperty(id, BLOCK, DESCRIPTION, strValue);
589     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("description"), BAD_CAST(strValue.c_str()));
590     if (status == -1)
591     {
592         return status;
593     }
594
595     strValue.clear();
596     controller.getObjectProperty(id, BLOCK, LABEL, strValue);
597     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("label"), BAD_CAST(strValue.c_str()));
598     if (status == -1)
599     {
600         return status;
601     }
602
603     strValue.clear();
604     controller.getObjectProperty(id, BLOCK, STYLE, strValue);
605     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"), BAD_CAST(strValue.c_str()));
606     if (status == -1)
607     {
608         return status;
609     }
610
611     strValue.clear();
612     controller.getObjectProperty(id, BLOCK, INTERFACE_FUNCTION, strValue);
613     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("interfaceFunction"), BAD_CAST(strValue.c_str()));
614     if (status == -1)
615     {
616         return status;
617     }
618
619     strValue.clear();
620     controller.getObjectProperty(id, BLOCK, SIM_FUNCTION_NAME, strValue);
621     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("functionName"), BAD_CAST(strValue.c_str()));
622     if (status == -1)
623     {
624         return status;
625     }
626
627     int intValue;
628     controller.getObjectProperty(id, BLOCK, SIM_FUNCTION_API, intValue);
629     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("functionAPI"), BAD_CAST(to_string(intValue).c_str()));
630     if (status == -1)
631     {
632         return status;
633     }
634
635     std::vector<int> intArrayValue;
636     controller.getObjectProperty(id, BLOCK, SIM_DEP_UT, intArrayValue);
637     unsigned int i = 0;
638     if (intArrayValue.size() > i && intArrayValue[i])
639     {
640         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("dependsOnU"), BAD_CAST(to_string(intArrayValue[i]).c_str()));
641         if (status == -1)
642         {
643             return status;
644         }
645     }
646     i++;
647     if (intArrayValue.size() > i && intArrayValue[i])
648     {
649         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("dependsOnT"), BAD_CAST(to_string(intArrayValue[i]).c_str()));
650         if (status == -1)
651         {
652             return status;
653         }
654     }
655
656     strValue.clear();
657     controller.getObjectProperty(id, BLOCK, SIM_BLOCKTYPE, strValue);
658     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("blocktype"), BAD_CAST(strValue.c_str()));
659     if (status == -1)
660     {
661         return status;
662     }
663
664     status = writeAbstractLayer(writer, id, BLOCK);
665     if (status == -1)
666     {
667         return status;
668     }
669
670     status = writeGeometry(writer, id, BLOCK);
671     if (status == -1)
672     {
673         return status;
674     }
675
676     std::vector<double> doubleArrayValue;
677     controller.getObjectProperty(id, BLOCK, EXPRS, doubleArrayValue);
678     if (is_empty_matrix(doubleArrayValue))
679     {
680         // we do not serialize the default value
681     }
682     else if (is_string_vector(doubleArrayValue))
683     {
684         // if this is a string the expression is used
685         std::vector<std::string> values = to_string_vector(doubleArrayValue);
686
687         for (const std::string& s : values)
688         {
689             status = xmlTextWriterStartElement(writer, BAD_CAST("expression"));
690             if (status == -1)
691             {
692                 return status;
693             }
694             status = xmlTextWriterWriteCDATA(writer, BAD_CAST(s.c_str()));
695             if (status == -1)
696             {
697                 return status;
698             }
699
700             status = xmlTextWriterEndElement(writer);
701             if (status == -1)
702             {
703                 return status;
704             }
705         }
706     }
707     else
708     {
709         // encode the value as base64 binary
710         status = writeBase64(writer, "exprs", doubleArrayValue);
711         if (status == -1)
712         {
713             return status;
714         }
715     }
716
717     intArrayValue.clear();
718     controller.getObjectProperty(id, BLOCK, NZCROSS, intArrayValue);
719     for (int i : intArrayValue)
720     {
721         status = xmlTextWriterWriteElement(writer, BAD_CAST("nzcross"), BAD_CAST(to_string(i).c_str()));
722         if (status == -1)
723         {
724             return status;
725         }
726     }
727
728     intArrayValue.clear();
729     controller.getObjectProperty(id, BLOCK, NMODE, intArrayValue);
730     for (int i : intArrayValue)
731     {
732         status = xmlTextWriterWriteElement(writer, BAD_CAST("nmode"), BAD_CAST(to_string(i).c_str()));
733         if (status == -1)
734         {
735             return status;
736         }
737     }
738
739     doubleArrayValue.clear();
740     controller.getObjectProperty(id, BLOCK, EQUATIONS, doubleArrayValue);
741     if (!doubleArrayValue.empty() && !is_empty_list(doubleArrayValue))
742     {
743         status = writeBase64(writer, "equations", doubleArrayValue);
744         if (status == -1)
745         {
746             return status;
747         }
748     }
749
750     std::vector<ScicosID> scicosIDArrayValue;
751     controller.getObjectProperty(id, BLOCK, INPUTS, scicosIDArrayValue);
752     for (ScicosID p : scicosIDArrayValue)
753     {
754         status = writePort(writer, INPUTS, p);
755         if (status == -1)
756         {
757             return status;
758         }
759     }
760
761     scicosIDArrayValue.clear();
762     controller.getObjectProperty(id, BLOCK, OUTPUTS, scicosIDArrayValue);
763     for (ScicosID p : scicosIDArrayValue)
764     {
765         status = writePort(writer, OUTPUTS, p);
766         if (status == -1)
767         {
768             return status;
769         }
770     }
771
772     controller.getObjectProperty(id, BLOCK, EVENT_INPUTS, scicosIDArrayValue);
773     for (ScicosID p : scicosIDArrayValue)
774     {
775         status = writePort(writer, EVENT_INPUTS, p);
776         if (status == -1)
777         {
778             return status;
779         }
780     }
781
782     controller.getObjectProperty(id, BLOCK, EVENT_OUTPUTS, scicosIDArrayValue);
783     for (ScicosID p : scicosIDArrayValue)
784     {
785         status = writePort(writer, EVENT_OUTPUTS, p);
786         if (status == -1)
787         {
788             return status;
789         }
790     }
791
792     doubleArrayValue.clear();
793     controller.getObjectProperty(id, BLOCK, RPAR, doubleArrayValue);
794     for (double d : doubleArrayValue)
795     {
796         status = xmlTextWriterWriteElement(writer, BAD_CAST("rpar"), BAD_CAST(to_string(d).c_str()));
797         if (status == -1)
798         {
799             return status;
800         }
801     }
802
803     intArrayValue.clear();
804     controller.getObjectProperty(id, BLOCK, IPAR, intArrayValue);
805     for (int i : intArrayValue)
806     {
807         status = xmlTextWriterWriteElement(writer, BAD_CAST("ipar"), BAD_CAST(to_string(i).c_str()));
808         if (status == -1)
809         {
810             return status;
811         }
812     }
813
814     doubleArrayValue.clear();
815     controller.getObjectProperty(id, BLOCK, OPAR, doubleArrayValue);
816     if (!is_empty_list(doubleArrayValue))
817     {
818         status = writeBase64(writer, "opar", doubleArrayValue);
819         if (status == -1)
820         {
821             return status;
822         }
823     }
824
825     doubleArrayValue.clear();
826     controller.getObjectProperty(id, BLOCK, STATE, doubleArrayValue);
827     for (double d : doubleArrayValue)
828     {
829         status = xmlTextWriterWriteElement(writer, BAD_CAST("state"), BAD_CAST(to_string(d).c_str()));
830         if (status == -1)
831         {
832             return status;
833         }
834     }
835
836     doubleArrayValue.clear();
837     controller.getObjectProperty(id, BLOCK, DSTATE, doubleArrayValue);
838     for (double d : doubleArrayValue)
839     {
840         status = xmlTextWriterWriteElement(writer, BAD_CAST("dstate"), BAD_CAST(to_string(d).c_str()));
841         if (status == -1)
842         {
843             return status;
844         }
845     }
846
847     doubleArrayValue.clear();
848     controller.getObjectProperty(id, BLOCK, ODSTATE, doubleArrayValue);
849     if (!is_empty_list(doubleArrayValue))
850     {
851         status = writeBase64(writer, "odstate", doubleArrayValue);
852         if (status == -1)
853         {
854             return status;
855         }
856     }
857
858     status = xmlTextWriterEndElement(writer);
859     if (status == -1)
860     {
861         return status;
862     }
863
864     return status;
865 }
866
867 int XMIResource::writePort(xmlTextWriterPtr writer, enum object_properties_t container, ScicosID id)
868 {
869     int status;
870
871     std::string element;
872     switch (container)
873     {
874         case INPUTS:
875             element = "in";
876             break;
877         case OUTPUTS:
878             element = "out";
879             break;
880         case EVENT_INPUTS:
881             element = "ein";
882             break;
883         case EVENT_OUTPUTS:
884             element = "eout";
885             break;
886         default:
887             return -1;
888     }
889
890     status = xmlTextWriterStartElement(writer, BAD_CAST(element.c_str()));
891     if (status == -1)
892     {
893         return status;
894     }
895
896     std::string strValue;
897     controller.getObjectProperty(id, PORT, UID, strValue);
898     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("uid"), BAD_CAST(strValue.c_str()));
899     if (status == -1)
900     {
901         return status;
902     }
903
904     ScicosID idValue;
905     controller.getObjectProperty(id, PORT, SOURCE_BLOCK, idValue);
906     controller.getObjectProperty(idValue, BLOCK, UID, strValue);
907     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("sourceBlock"), BAD_CAST(strValue.c_str()));
908     if (status == -1)
909     {
910         return status;
911     }
912
913     const std::vector<std::string> elementName = {"portUndefined", "in", "out", "ein", "eout"};
914     int portKind;
915     controller.getObjectProperty(id, PORT, PORT_KIND, portKind);
916     if (portKind < 0 && elementName.size() <= (unsigned int) portKind)
917     {
918         return -1;
919     }
920     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("kind"), BAD_CAST(elementName[portKind].c_str()));
921     if (status == -1)
922     {
923         return status;
924     }
925
926     controller.getObjectProperty(id, PORT, CONNECTED_SIGNALS, idValue);
927     if (idValue != 0)
928     {
929         strValue.clear();
930         controller.getObjectProperty(idValue, LINK, UID, strValue);
931
932         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("connectedSignal"), BAD_CAST(strValue.c_str()));
933         if (status == -1)
934         {
935             return status;
936         }
937     }
938
939     strValue.clear();
940     controller.getObjectProperty(id, PORT, STYLE, strValue);
941     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"), BAD_CAST(strValue.c_str()));
942     if (status == -1)
943     {
944         return status;
945     }
946
947     strValue.clear();
948     controller.getObjectProperty(id, PORT, LABEL, strValue);
949     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("label"), BAD_CAST(strValue.c_str()));
950     if (status == -1)
951     {
952         return status;
953     }
954
955     std::vector<int> intArrayValue;
956     controller.getObjectProperty(id, PORT, DATATYPE, intArrayValue);
957     status = writeDatatype(writer, intArrayValue);
958
959     status = xmlTextWriterEndElement(writer);
960     if (status == -1)
961     {
962         return status;
963     }
964
965     return status;
966 }
967
968 int XMIResource::writeLink(xmlTextWriterPtr writer, ScicosID id)
969 {
970     int status;
971
972     status = xmlTextWriterStartElement(writer, BAD_CAST("child"));
973     if (status == -1)
974     {
975         return status;
976     }
977
978     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("xsi:type"), BAD_CAST("xcos:Link"));
979     if (status == -1)
980     {
981         return status;
982     }
983
984     status = writeAbstractBaseObject(writer, id, LINK);
985     if (status == -1)
986     {
987         return status;
988     }
989
990     ScicosID idValue;
991     std::string strValue;
992     controller.getObjectProperty(id, LINK, SOURCE_PORT, idValue);
993     if (idValue != 0)
994     {
995         strValue.clear();
996         controller.getObjectProperty(idValue, PORT, UID, strValue);
997
998         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("sourcePort"), BAD_CAST(strValue.c_str()));
999         if (status == -1)
1000         {
1001             return status;
1002         }
1003     }
1004
1005     controller.getObjectProperty(id, LINK, DESTINATION_PORT, idValue);
1006     if (idValue != 0)
1007     {
1008         strValue.clear();
1009         controller.getObjectProperty(idValue, PORT, UID, strValue);
1010
1011         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("destinationPort"), BAD_CAST(strValue.c_str()));
1012         if (status == -1)
1013         {
1014             return status;
1015         }
1016     }
1017
1018     strValue.clear();
1019     controller.getObjectProperty(id, LINK, STYLE, strValue);
1020     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"), BAD_CAST(strValue.c_str()));
1021     if (status == -1)
1022     {
1023         return status;
1024     }
1025
1026     strValue.clear();
1027     controller.getObjectProperty(id, LINK, LABEL, strValue);
1028     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("label"), BAD_CAST(strValue.c_str()));
1029     if (status == -1)
1030     {
1031         return status;
1032     }
1033
1034     int intValue;
1035     controller.getObjectProperty(id, LINK, COLOR, intValue);
1036     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("color"), BAD_CAST(to_string(intValue).c_str()));
1037     if (status == -1)
1038     {
1039         return status;
1040     }
1041
1042     std::vector<int> intArrayValue;
1043     controller.getObjectProperty(id, LINK, THICK, intArrayValue);
1044     unsigned int i = 0;
1045     if (i < intArrayValue.size())
1046     {
1047         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("lineWidth"), BAD_CAST(to_string(intArrayValue[i]).c_str()));
1048         if (status == -1)
1049         {
1050             return status;
1051         }
1052     }
1053     i++;
1054     if (i < intArrayValue.size())
1055     {
1056         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("lineHeight"), BAD_CAST(to_string(intArrayValue[i]).c_str()));
1057         if (status == -1)
1058         {
1059             return status;
1060         }
1061     }
1062
1063     status = writeGeometry(writer, id, LINK);
1064     if (status == -1)
1065     {
1066         return status;
1067     }
1068
1069     std::vector<double> dblArrayValue;
1070     controller.getObjectProperty(id, LINK, CONTROL_POINTS, dblArrayValue);
1071     for (unsigned int i = 0; i < dblArrayValue.size(); i += 2)
1072     {
1073         status = writePoint(writer, dblArrayValue[i], dblArrayValue[i + 1]);
1074         if (status == -1)
1075         {
1076             return status;
1077         }
1078     }
1079
1080     status = xmlTextWriterEndElement(writer);
1081     if (status == -1)
1082     {
1083         return status;
1084     }
1085
1086     return status;
1087 }
1088
1089 int XMIResource::writeAnnotation(xmlTextWriterPtr writer, ScicosID id)
1090 {
1091     int status;
1092
1093     status = xmlTextWriterStartElement(writer, BAD_CAST("child"));
1094     if (status == -1)
1095     {
1096         return status;
1097     }
1098
1099     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("xsi:type"), BAD_CAST("xcos:Annotation"));
1100     if (status == -1)
1101     {
1102         return status;
1103     }
1104
1105     status = writeAbstractBaseObject(writer, id, ANNOTATION);
1106     if (status == -1)
1107     {
1108         return status;
1109     }
1110
1111     std::string strValue;
1112     controller.getObjectProperty(id, ANNOTATION, DESCRIPTION, strValue);
1113     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("description"), BAD_CAST(strValue.c_str()));
1114     if (status == -1)
1115     {
1116         return status;
1117     }
1118
1119     strValue.clear();
1120     controller.getObjectProperty(id, ANNOTATION, FONT, strValue);
1121     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("font"), BAD_CAST(strValue.c_str()));
1122     if (status == -1)
1123     {
1124         return status;
1125     }
1126
1127     strValue.clear();
1128     controller.getObjectProperty(id, ANNOTATION, FONT_SIZE, strValue);
1129     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("fontSize"), BAD_CAST(strValue.c_str()));
1130     if (status == -1)
1131     {
1132         return status;
1133     }
1134
1135     strValue.clear();
1136     controller.getObjectProperty(id, ANNOTATION, STYLE, strValue);
1137     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"), BAD_CAST(strValue.c_str()));
1138     if (status == -1)
1139     {
1140         return status;
1141     }
1142
1143     status = xmlTextWriterEndElement(writer);
1144     if (status == -1)
1145     {
1146         return status;
1147     }
1148
1149     return status;
1150 }
1151
1152 } /* namespace org_scilab_modules_xcos */