1bb9b66c704789717f5eb0bc1b5d5886dbf3d0a5
[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 <cstdio>
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
169 int XMIResource::writePoint(xmlTextWriterPtr writer, double x, double y)
170 {
171     int status;
172
173
174     status = xmlTextWriterStartElement(writer, BAD_CAST("controlPoint"));
175     if (status == -1)
176     {
177         return status;
178     }
179
180     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("x"), BAD_CAST(to_string(x).c_str()));
181     if (status == -1)
182     {
183         return status;
184     }
185
186     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("y"), BAD_CAST(to_string(y).c_str()));
187     if (status == -1)
188     {
189         return status;
190     }
191
192     status = xmlTextWriterEndElement(writer);
193     if (status == -1)
194     {
195         return status;
196     }
197
198     return status;
199 }
200
201 int XMIResource::writeGeometry(xmlTextWriterPtr writer, ScicosID id, kind_t kind)
202 {
203     int status;
204
205     status = xmlTextWriterStartElement(writer, BAD_CAST("geometry"));
206     if (status == -1)
207     {
208         return status;
209     }
210
211     std::vector<double> doubleArrayValue;
212     controller.getObjectProperty(id, kind, GEOMETRY, doubleArrayValue);
213     unsigned int i = 0;
214     if (doubleArrayValue.size() > i && doubleArrayValue[i])
215     {
216         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("x"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
217         if (status == -1)
218         {
219             return status;
220         }
221     }
222
223     i++;
224     if (doubleArrayValue.size() > i && doubleArrayValue[i])
225     {
226         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("y"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
227         if (status == -1)
228         {
229             return status;
230         }
231     }
232
233     i++;
234     if (doubleArrayValue.size() > i && doubleArrayValue[i])
235     {
236         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("width"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
237         if (status == -1)
238         {
239             return status;
240         }
241     }
242
243     i++;
244     if (doubleArrayValue.size() > i && doubleArrayValue[i])
245     {
246         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("height"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
247         if (status == -1)
248         {
249             return status;
250         }
251     }
252
253     status = xmlTextWriterEndElement(writer);
254     if (status == -1)
255     {
256         return status;
257     }
258
259     return status;
260 }
261
262 int XMIResource::writeAbstractLayer(xmlTextWriterPtr writer, ScicosID id, kind_t kind)
263 {
264     int status = 1;
265
266     std::vector<std::string> context;
267     controller.getObjectProperty(id, kind, DIAGRAM_CONTEXT, context);
268     for (const std::string& c : context)
269     {
270         status = xmlTextWriterStartElement(writer, BAD_CAST("context"));
271         if (status == -1)
272         {
273             return status;
274         }
275
276         if (!c.empty())
277         {
278             status = xmlTextWriterWriteCDATA(writer, BAD_CAST(c.c_str()));
279             if (status == -1)
280             {
281                 return status;
282             }
283         }
284
285         status = xmlTextWriterEndElement(writer);
286         if (status == -1)
287         {
288             return status;
289         }
290     }
291
292     std::vector<ScicosID> children;
293     controller.getObjectProperty(id, kind, CHILDREN, children);
294     for (ScicosID child : children)
295     {
296         kind_t kind = controller.getKind(child);
297         switch (kind)
298         {
299             case BLOCK:
300                 status = writeBlock(writer, child);
301                 break;
302             case LINK:
303                 status = writeLink(writer, child);
304                 break;
305             case ANNOTATION:
306                 status = writeAnnotation(writer, child);
307                 break;
308             default:
309                 status =  -1;
310                 break;
311         }
312
313         if (status == -1)
314         {
315             return status;
316         }
317     }
318
319     return status;
320 }
321
322 int XMIResource::writeAbstractBaseObject(xmlTextWriterPtr writer, ScicosID id, kind_t kind)
323 {
324     int status;
325
326     std::string uid;
327     controller.getObjectProperty(id, kind, UID, uid);
328     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("uid"), BAD_CAST(uid.c_str()));
329     if (status == -1)
330     {
331         return status;
332     }
333
334     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("parentDiagram"), BAD_CAST("/"));
335     if (status == -1)
336     {
337         return status;
338     }
339
340     /* parent / child relation is not serialized as this relation is the XML tree */
341     return status;
342 }
343
344 int XMIResource::writeDiagram(xmlTextWriterPtr writer)
345 {
346     int status;
347
348     status = xmlTextWriterStartElementNS(writer, BAD_CAST("xcos"), BAD_CAST("Diagram"), BAD_CAST("org.scilab.modules.xcos"));
349     if (status == -1)
350     {
351         return status;
352     }
353
354     /*
355      * Write default xmlns
356      */
357     status = xmlTextWriterWriteAttributeNS(writer, BAD_CAST("xmi"), BAD_CAST("version"), BAD_CAST("http://www.omg.org/XMI"), BAD_CAST("2.0"));
358     if (status == -1)
359     {
360         return status;
361     }
362     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.xcore#/EPackage"));
363     if (status == -1)
364     {
365         return status;
366     }
367
368     /*
369      * Diagram values
370      */
371     std::string strValue;
372     controller.getObjectProperty(root, DIAGRAM, TITLE, strValue);
373     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("title"), BAD_CAST(strValue.c_str()));
374     if (status == -1)
375     {
376         return status;
377     }
378
379     strValue.clear();
380     controller.getObjectProperty(root, DIAGRAM, PATH, strValue);
381     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("path"), BAD_CAST(strValue.c_str()));
382     if (status == -1)
383     {
384         return status;
385     }
386
387     int intValue;
388     controller.getObjectProperty(root, DIAGRAM, DEBUG_LEVEL, intValue);
389     strValue = to_string(intValue);
390     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("debugLevel"), BAD_CAST(strValue.c_str()));
391     if (status == -1)
392     {
393         return status;
394     }
395
396     strValue.clear();
397     controller.getObjectProperty(root, DIAGRAM, VERSION_NUMBER, strValue);
398     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("version"), BAD_CAST(strValue.c_str()));
399     if (status == -1)
400     {
401         return status;
402     }
403
404     status = writeAbstractLayer(writer, root, DIAGRAM);
405     if (status == -1)
406     {
407         return status;
408     }
409
410     status = writeSimulationConfig(writer, root);
411     if (status == -1)
412     {
413         return status;
414     }
415
416     status = xmlTextWriterEndElement(writer);
417     if (status == -1)
418     {
419         return status;
420     }
421
422     return status;
423 }
424
425 int XMIResource::writeSimulationConfig(xmlTextWriterPtr writer, ScicosID id)
426 {
427     int status;
428
429     status = xmlTextWriterStartElement(writer, BAD_CAST("properties"));
430     if (status == -1)
431     {
432         return status;
433     }
434
435     std::vector<double> doubleArrayValue;
436     controller.getObjectProperty(id, DIAGRAM, PROPERTIES, doubleArrayValue);
437     unsigned int i = 0;
438     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("finalTime"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
439     if (status == -1)
440     {
441         return status;
442     }
443
444     i++;
445     if (i >= doubleArrayValue.size())
446     {
447         return -1;
448     }
449     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("absoluteTime"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
450     if (status == -1)
451     {
452         return status;
453     }
454
455     i++;
456     if (i >= doubleArrayValue.size())
457     {
458         return -1;
459     }
460     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("relativeTolerance"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
461     if (status == -1)
462     {
463         return status;
464     }
465
466     i++;
467     if (i >= doubleArrayValue.size())
468     {
469         return -1;
470     }
471     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("absoluteTolerance"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
472     if (status == -1)
473     {
474         return status;
475     }
476
477     i++;
478     if (i >= doubleArrayValue.size())
479     {
480         return -1;
481     }
482     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("deltaT"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
483     if (status == -1)
484     {
485         return status;
486     }
487
488     i++;
489     if (i >= doubleArrayValue.size())
490     {
491         return -1;
492     }
493     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("realtimeScale"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
494     if (status == -1)
495     {
496         return status;
497     }
498
499     i++;
500     if (i >= doubleArrayValue.size())
501     {
502         return -1;
503     }
504     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("solver"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
505     if (status == -1)
506     {
507         return status;
508     }
509
510     i++;
511     if (i >= doubleArrayValue.size())
512     {
513         return -1;
514     }
515     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("deltaH"), BAD_CAST(to_string(doubleArrayValue[i]).c_str()));
516     if (status == -1)
517     {
518         return status;
519     }
520
521     status = xmlTextWriterEndElement(writer);
522     if (status == -1)
523     {
524         return status;
525     }
526
527     return status;
528 }
529
530 int XMIResource::writeBlock(xmlTextWriterPtr writer, ScicosID id)
531 {
532     int status;
533
534     status = xmlTextWriterStartElement(writer, BAD_CAST("child"));
535     if (status == -1)
536     {
537         return status;
538     }
539
540     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("xsi:type"), BAD_CAST("xcos:Block"));
541     if (status == -1)
542     {
543         return status;
544     }
545
546     status = writeAbstractBaseObject(writer, id, BLOCK);
547     if (status == -1)
548     {
549         return status;
550     }
551
552     std::string strValue;
553     controller.getObjectProperty(id, BLOCK, DESCRIPTION, strValue);
554     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("description"), BAD_CAST(strValue.c_str()));
555     if (status == -1)
556     {
557         return status;
558     }
559
560     strValue.clear();
561     controller.getObjectProperty(id, BLOCK, LABEL, strValue);
562     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("label"), BAD_CAST(strValue.c_str()));
563     if (status == -1)
564     {
565         return status;
566     }
567
568     strValue.clear();
569     controller.getObjectProperty(id, BLOCK, STYLE, strValue);
570     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"), BAD_CAST(strValue.c_str()));
571     if (status == -1)
572     {
573         return status;
574     }
575
576     strValue.clear();
577     controller.getObjectProperty(id, BLOCK, INTERFACE_FUNCTION, strValue);
578     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("interfaceFunction"), BAD_CAST(strValue.c_str()));
579     if (status == -1)
580     {
581         return status;
582     }
583
584     strValue.clear();
585     controller.getObjectProperty(id, BLOCK, SIM_FUNCTION_NAME, strValue);
586     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("functionName"), BAD_CAST(strValue.c_str()));
587     if (status == -1)
588     {
589         return status;
590     }
591
592     int intValue;
593     controller.getObjectProperty(id, BLOCK, SIM_FUNCTION_API, intValue);
594     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("functionAPI"), BAD_CAST(to_string(intValue).c_str()));
595     if (status == -1)
596     {
597         return status;
598     }
599
600     std::vector<int> intArrayValue;
601     controller.getObjectProperty(id, BLOCK, SIM_DEP_UT, intArrayValue);
602     unsigned int i = 0;
603     if (intArrayValue.size() > i && intArrayValue[i])
604     {
605         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("dependsOnU"), BAD_CAST(to_string(intArrayValue[i]).c_str()));
606         if (status == -1)
607         {
608             return status;
609         }
610     }
611     i++;
612     if (intArrayValue.size() > i && intArrayValue[i])
613     {
614         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("dependsOnT"), BAD_CAST(to_string(intArrayValue[i]).c_str()));
615         if (status == -1)
616         {
617             return status;
618         }
619     }
620
621     strValue.clear();
622     controller.getObjectProperty(id, BLOCK, SIM_BLOCKTYPE, strValue);
623     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("blocktype"), BAD_CAST(strValue.c_str()));
624     if (status == -1)
625     {
626         return status;
627     }
628
629     status = writeAbstractLayer(writer, id, BLOCK);
630     if (status == -1)
631     {
632         return status;
633     }
634
635     status = writeGeometry(writer, id, BLOCK);
636     if (status == -1)
637     {
638         return status;
639     }
640
641     std::vector<double> doubleArrayValue;
642     controller.getObjectProperty(id, BLOCK, EXPRS, doubleArrayValue);
643     if (is_empty_matrix(doubleArrayValue))
644     {
645         // we do not serialize the default value
646     }
647     else if (is_string_vector(doubleArrayValue))
648     {
649         // if this is a string the expression is used
650         std::vector<std::string> values = to_string_vector(doubleArrayValue);
651
652         for (const std::string& s : values)
653         {
654             status = xmlTextWriterStartElement(writer, BAD_CAST("expression"));
655             if (status == -1)
656             {
657                 return status;
658             }
659             status = xmlTextWriterWriteCDATA(writer, BAD_CAST(s.c_str()));
660             if (status == -1)
661             {
662                 return status;
663             }
664
665             status = xmlTextWriterEndElement(writer);
666             if (status == -1)
667             {
668                 return status;
669             }
670         }
671     }
672     else
673     {
674         // encode the value as base64 binary
675         status = writeBase64(writer, "exprs", doubleArrayValue);
676         if (status == -1)
677         {
678             return status;
679         }
680     }
681
682     intArrayValue.clear();
683     controller.getObjectProperty(id, BLOCK, NZCROSS, intArrayValue);
684     for (int i : intArrayValue)
685     {
686         status = xmlTextWriterWriteElement(writer, BAD_CAST("nzcross"), BAD_CAST(to_string(i).c_str()));
687         if (status == -1)
688         {
689             return status;
690         }
691     }
692
693     intArrayValue.clear();
694     controller.getObjectProperty(id, BLOCK, NMODE, intArrayValue);
695     for (int i : intArrayValue)
696     {
697         status = xmlTextWriterWriteElement(writer, BAD_CAST("nmode"), BAD_CAST(to_string(i).c_str()));
698         if (status == -1)
699         {
700             return status;
701         }
702     }
703
704     doubleArrayValue.clear();
705     controller.getObjectProperty(id, BLOCK, EQUATIONS, doubleArrayValue);
706     if (!doubleArrayValue.empty() && !is_empty_list(doubleArrayValue))
707     {
708         status = writeBase64(writer, "equations", doubleArrayValue);
709         if (status == -1)
710         {
711             return status;
712         }
713     }
714
715     std::vector<ScicosID> scicosIDArrayValue;
716     controller.getObjectProperty(id, BLOCK, INPUTS, scicosIDArrayValue);
717     for (ScicosID p : scicosIDArrayValue)
718     {
719         status = writePort(writer, INPUTS, p);
720         if (status == -1)
721         {
722             return status;
723         }
724     }
725
726     scicosIDArrayValue.clear();
727     controller.getObjectProperty(id, BLOCK, OUTPUTS, scicosIDArrayValue);
728     for (ScicosID p : scicosIDArrayValue)
729     {
730         status = writePort(writer, OUTPUTS, p);
731         if (status == -1)
732         {
733             return status;
734         }
735     }
736
737     controller.getObjectProperty(id, BLOCK, EVENT_INPUTS, scicosIDArrayValue);
738     for (ScicosID p : scicosIDArrayValue)
739     {
740         status = writePort(writer, EVENT_INPUTS, p);
741         if (status == -1)
742         {
743             return status;
744         }
745     }
746
747     controller.getObjectProperty(id, BLOCK, EVENT_OUTPUTS, scicosIDArrayValue);
748     for (ScicosID p : scicosIDArrayValue)
749     {
750         status = writePort(writer, EVENT_OUTPUTS, p);
751         if (status == -1)
752         {
753             return status;
754         }
755     }
756
757     doubleArrayValue.clear();
758     controller.getObjectProperty(id, BLOCK, RPAR, doubleArrayValue);
759     for (double d : doubleArrayValue)
760     {
761         status = xmlTextWriterWriteElement(writer, BAD_CAST("rpar"), BAD_CAST(to_string(d).c_str()));
762         if (status == -1)
763         {
764             return status;
765         }
766     }
767
768     intArrayValue.clear();
769     controller.getObjectProperty(id, BLOCK, IPAR, intArrayValue);
770     for (int i : intArrayValue)
771     {
772         status = xmlTextWriterWriteElement(writer, BAD_CAST("ipar"), BAD_CAST(to_string(i).c_str()));
773         if (status == -1)
774         {
775             return status;
776         }
777     }
778
779     doubleArrayValue.clear();
780     controller.getObjectProperty(id, BLOCK, OPAR, doubleArrayValue);
781     if (!is_empty_list(doubleArrayValue))
782     {
783         status = writeBase64(writer, "opar", doubleArrayValue);
784         if (status == -1)
785         {
786             return status;
787         }
788     }
789
790     doubleArrayValue.clear();
791     controller.getObjectProperty(id, BLOCK, STATE, doubleArrayValue);
792     for (double d : doubleArrayValue)
793     {
794         status = xmlTextWriterWriteElement(writer, BAD_CAST("state"), BAD_CAST(to_string(d).c_str()));
795         if (status == -1)
796         {
797             return status;
798         }
799     }
800
801     doubleArrayValue.clear();
802     controller.getObjectProperty(id, BLOCK, DSTATE, doubleArrayValue);
803     for (double d : doubleArrayValue)
804     {
805         status = xmlTextWriterWriteElement(writer, BAD_CAST("dstate"), BAD_CAST(to_string(d).c_str()));
806         if (status == -1)
807         {
808             return status;
809         }
810     }
811
812     doubleArrayValue.clear();
813     controller.getObjectProperty(id, BLOCK, ODSTATE, doubleArrayValue);
814     if (!is_empty_list(doubleArrayValue))
815     {
816         status = writeBase64(writer, "odstate", doubleArrayValue);
817         if (status == -1)
818         {
819             return status;
820         }
821     }
822
823     status = xmlTextWriterEndElement(writer);
824     if (status == -1)
825     {
826         return status;
827     }
828
829     return status;
830 }
831
832 int XMIResource::writePort(xmlTextWriterPtr writer, enum object_properties_t container, ScicosID id)
833 {
834     int status;
835
836     std::string element;
837     switch (container)
838     {
839         case INPUTS:
840             element = "in";
841             break;
842         case OUTPUTS:
843             element = "out";
844             break;
845         case EVENT_INPUTS:
846             element = "ein";
847             break;
848         case EVENT_OUTPUTS:
849             element = "eout";
850             break;
851         default:
852             return -1;
853     }
854
855     status = xmlTextWriterStartElement(writer, BAD_CAST(element.c_str()));
856     if (status == -1)
857     {
858         return status;
859     }
860
861     std::string strValue;
862     controller.getObjectProperty(id, PORT, UID, strValue);
863     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("uid"), BAD_CAST(strValue.c_str()));
864     if (status == -1)
865     {
866         return status;
867     }
868
869     ScicosID idValue;
870     controller.getObjectProperty(id, PORT, SOURCE_BLOCK, idValue);
871     controller.getObjectProperty(idValue, BLOCK, UID, strValue);
872     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("sourceBlock"), BAD_CAST(strValue.c_str()));
873     if (status == -1)
874     {
875         return status;
876     }
877
878     const std::vector<std::string> elementName = {"portUndefined", "in", "out", "ein", "eout"};
879     int portKind;
880     controller.getObjectProperty(id, PORT, PORT_KIND, portKind);
881     if (portKind < 0 && elementName.size() <= (unsigned int) portKind)
882     {
883         return -1;
884     }
885     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("kind"), BAD_CAST(elementName[portKind].c_str()));
886     if (status == -1)
887     {
888         return status;
889     }
890
891     controller.getObjectProperty(id, PORT, CONNECTED_SIGNALS, idValue);
892     if (idValue != 0)
893     {
894         strValue.clear();
895         controller.getObjectProperty(idValue, LINK, UID, strValue);
896
897         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("connectedSignal"), BAD_CAST(strValue.c_str()));
898         if (status == -1)
899         {
900             return status;
901         }
902     }
903
904     strValue.clear();
905     controller.getObjectProperty(id, PORT, STYLE, strValue);
906     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"), BAD_CAST(strValue.c_str()));
907     if (status == -1)
908     {
909         return status;
910     }
911
912     strValue.clear();
913     controller.getObjectProperty(id, PORT, LABEL, strValue);
914     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("label"), BAD_CAST(strValue.c_str()));
915     if (status == -1)
916     {
917         return status;
918     }
919
920     std::vector<double> doubleArrayValue;
921     controller.getObjectProperty(id, BLOCK, DATATYPE, doubleArrayValue);
922     for (double d : doubleArrayValue)
923     {
924         status = xmlTextWriterWriteElement(writer, BAD_CAST("datatype"), BAD_CAST(to_string(d).c_str()));
925         if (status == -1)
926         {
927             return status;
928         }
929     }
930
931     status = xmlTextWriterEndElement(writer);
932     if (status == -1)
933     {
934         return status;
935     }
936
937     return status;
938 }
939
940 int XMIResource::writeLink(xmlTextWriterPtr writer, ScicosID id)
941 {
942     int status;
943
944     status = xmlTextWriterStartElement(writer, BAD_CAST("child"));
945     if (status == -1)
946     {
947         return status;
948     }
949
950     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("xsi:type"), BAD_CAST("xcos:Link"));
951     if (status == -1)
952     {
953         return status;
954     }
955
956     status = writeAbstractBaseObject(writer, id, LINK);
957     if (status == -1)
958     {
959         return status;
960     }
961
962     ScicosID idValue;
963     std::string strValue;
964     controller.getObjectProperty(id, LINK, SOURCE_PORT, idValue);
965     if (idValue != 0)
966     {
967         strValue.clear();
968         controller.getObjectProperty(idValue, PORT, UID, strValue);
969
970         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("sourcePort"), BAD_CAST(strValue.c_str()));
971         if (status == -1)
972         {
973             return status;
974         }
975     }
976
977     controller.getObjectProperty(id, LINK, DESTINATION_PORT, idValue);
978     if (idValue != 0)
979     {
980         strValue.clear();
981         controller.getObjectProperty(idValue, PORT, UID, strValue);
982
983         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("destinationPort"), BAD_CAST(strValue.c_str()));
984         if (status == -1)
985         {
986             return status;
987         }
988     }
989
990     strValue.clear();
991     controller.getObjectProperty(id, LINK, STYLE, strValue);
992     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"), BAD_CAST(strValue.c_str()));
993     if (status == -1)
994     {
995         return status;
996     }
997
998     strValue.clear();
999     controller.getObjectProperty(id, LINK, LABEL, strValue);
1000     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("label"), BAD_CAST(strValue.c_str()));
1001     if (status == -1)
1002     {
1003         return status;
1004     }
1005
1006     int intValue;
1007     controller.getObjectProperty(id, LINK, COLOR, intValue);
1008     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("color"), BAD_CAST(to_string(intValue).c_str()));
1009     if (status == -1)
1010     {
1011         return status;
1012     }
1013
1014     std::vector<int> intArrayValue;
1015     controller.getObjectProperty(id, LINK, THICK, intArrayValue);
1016     unsigned int i = 0;
1017     if (i < intArrayValue.size())
1018     {
1019         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("lineWidth"), BAD_CAST(to_string(intArrayValue[i]).c_str()));
1020         if (status == -1)
1021         {
1022             return status;
1023         }
1024     }
1025     i++;
1026     if (i < intArrayValue.size())
1027     {
1028         status = xmlTextWriterWriteAttribute(writer, BAD_CAST("lineHeight"), BAD_CAST(to_string(intArrayValue[i]).c_str()));
1029         if (status == -1)
1030         {
1031             return status;
1032         }
1033     }
1034
1035     status = writeGeometry(writer, id, LINK);
1036     if (status == -1)
1037     {
1038         return status;
1039     }
1040
1041     std::vector<double> dblArrayValue;
1042     controller.getObjectProperty(id, LINK, CONTROL_POINTS, dblArrayValue);
1043     for (unsigned int i = 0; i < dblArrayValue.size(); i += 2)
1044     {
1045         status = writePoint(writer, dblArrayValue[i], dblArrayValue[i + 1]);
1046         if (status == -1)
1047         {
1048             return status;
1049         }
1050     }
1051
1052     status = xmlTextWriterEndElement(writer);
1053     if (status == -1)
1054     {
1055         return status;
1056     }
1057
1058     return status;
1059 }
1060
1061 int XMIResource::writeAnnotation(xmlTextWriterPtr writer, ScicosID id)
1062 {
1063     int status;
1064
1065     status = xmlTextWriterStartElement(writer, BAD_CAST("child"));
1066     if (status == -1)
1067     {
1068         return status;
1069     }
1070
1071     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("xsi:type"), BAD_CAST("xcos:Annotation"));
1072     if (status == -1)
1073     {
1074         return status;
1075     }
1076
1077     status = writeAbstractBaseObject(writer, id, ANNOTATION);
1078     if (status == -1)
1079     {
1080         return status;
1081     }
1082
1083     std::string strValue;
1084     controller.getObjectProperty(id, ANNOTATION, DESCRIPTION, strValue);
1085     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("description"), BAD_CAST(strValue.c_str()));
1086     if (status == -1)
1087     {
1088         return status;
1089     }
1090
1091     strValue.clear();
1092     controller.getObjectProperty(id, ANNOTATION, FONT, strValue);
1093     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("font"), BAD_CAST(strValue.c_str()));
1094     if (status == -1)
1095     {
1096         return status;
1097     }
1098
1099     strValue.clear();
1100     controller.getObjectProperty(id, ANNOTATION, FONT_SIZE, strValue);
1101     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("fontSize"), BAD_CAST(strValue.c_str()));
1102     if (status == -1)
1103     {
1104         return status;
1105     }
1106
1107     strValue.clear();
1108     controller.getObjectProperty(id, ANNOTATION, STYLE, strValue);
1109     status = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"), BAD_CAST(strValue.c_str()));
1110     if (status == -1)
1111     {
1112         return status;
1113     }
1114
1115     status = xmlTextWriterEndElement(writer);
1116     if (status == -1)
1117     {
1118         return status;
1119     }
1120
1121     return status;
1122 }
1123
1124 } /* namespace org_scilab_modules_xcos */