Xcos I/O: decode more properties and store them
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / io / writer / RawDataWriter.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2015-2015 - Scilab Enterprises - Clement DAVID
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12 package org.scilab.modules.xcos.io.writer;
13
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.Map.Entry;
18 import java.util.logging.Level;
19
20 import javax.xml.stream.XMLStreamException;
21
22 import org.scilab.modules.types.ScilabBoolean;
23 import org.scilab.modules.types.ScilabDouble;
24 import org.scilab.modules.types.ScilabInteger;
25 import org.scilab.modules.types.ScilabString;
26 import org.scilab.modules.types.ScilabType;
27 import org.scilab.modules.types.ScilabTypeEnum;
28 import org.scilab.modules.xcos.Kind;
29 import org.scilab.modules.xcos.ObjectProperties;
30 import org.scilab.modules.xcos.VectorOfDouble;
31 import org.scilab.modules.xcos.VectorOfInt;
32 import org.scilab.modules.xcos.VectorOfString;
33 import org.scilab.modules.xcos.io.ScilabTypeCoder;
34
35 public class RawDataWriter extends ScilabWriter {
36
37     /*
38      * Shared map information used to avoid duplicated entry on the dictionary
39      */
40     private final HashMap<ScilabType, Integer> dictionaryMap;
41
42     public RawDataWriter(XcosWriter writer) {
43         super(writer);
44
45         dictionaryMap = new HashMap<>();
46     }
47
48     /**
49      * Fill the shared dictinary with the encoded mapping
50      */
51     public void fillSharedDictionary() {
52         if (shared.dictionary == null) {
53             return;
54         }
55
56         // reserve the size with null values
57         shared.dictionary.addAll(Collections.nCopies(dictionaryMap.size(), new ScilabDouble()));
58
59         // push all the values
60         for (Entry<ScilabType, Integer> entry : dictionaryMap.entrySet()) {
61             shared.dictionary.set(entry.getValue(), entry.getKey());
62         }
63     }
64
65     @Override
66     public void write(long uid, Kind kind) throws XMLStreamException {
67
68         switch (kind) {
69             case BLOCK:
70                 writeBlock(uid, kind);
71                 break;
72             case DIAGRAM:
73                 writeContext(uid, kind);
74                 break;
75             case LINK: // no break on purpose
76             case ANNOTATION:  // no break on purpose
77             default:
78                 break;
79         }
80     }
81
82     private void writeContext(long uid, Kind kind) throws XMLStreamException {
83         VectorOfString context = new VectorOfString();
84         shared.controller.getObjectProperty(uid, kind, ObjectProperties.DIAGRAM_CONTEXT, context);
85
86         String[] value = new String[context.size()];
87         for (int i = 0; i < value.length; i++) {
88             value[i] = context.get(i);
89         }
90         write(value, "context");
91     }
92
93     private void writeBlock(long uid, Kind kind) throws XMLStreamException {
94         VectorOfDouble vDouble = new VectorOfDouble();
95         VectorOfInt vInt = new VectorOfInt();
96
97         shared.controller.getObjectProperty(uid, kind, ObjectProperties.EXPRS, vDouble);
98         write(new ScilabTypeCoder().vec2var(vDouble), "exprs");
99
100         shared.controller.getObjectProperty(uid, kind, ObjectProperties.RPAR, vDouble);
101         write(vDouble, "realParameters");
102
103         shared.controller.getObjectProperty(uid, kind, ObjectProperties.IPAR, vInt);
104         write(vInt, "integerParameters");
105
106         shared.controller.getObjectProperty(uid, kind, ObjectProperties.OPAR, vDouble);
107         write(new ScilabTypeCoder().vec2var(vDouble), "objectsParameters");
108
109         shared.controller.getObjectProperty(uid, kind, ObjectProperties.NZCROSS, vInt);
110         write(vInt, "nbZerosCrossing");
111
112         shared.controller.getObjectProperty(uid, kind, ObjectProperties.NMODE, vInt);
113         write(vInt, "nmode");
114
115         shared.controller.getObjectProperty(uid, kind, ObjectProperties.STATE, vDouble);
116         write(vDouble, "state");
117
118         shared.controller.getObjectProperty(uid, kind, ObjectProperties.DSTATE, vDouble);
119         write(vDouble, "dState");
120
121         shared.controller.getObjectProperty(uid, kind, ObjectProperties.ODSTATE, vDouble);
122         write(new ScilabTypeCoder().vec2var(vDouble), "oDState");
123
124         shared.controller.getObjectProperty(uid, kind, ObjectProperties.EQUATIONS, vDouble);
125         write(new ScilabTypeCoder().vec2var(vDouble), "equations");
126     }
127
128     /*
129      * Low-level serialization methods
130      */
131
132     private void write(String[] value, String as) throws XMLStreamException {
133         shared.stream.writeStartElement("Array");
134         shared.stream.writeAttribute("as", as);
135         shared.stream.writeAttribute("scilabClass", "String[]");
136
137         for (String v : value) {
138             shared.stream.writeEmptyElement("add");
139             shared.stream.writeAttribute("value", v);
140         }
141
142         shared.stream.writeEndElement(); // Array
143     }
144
145     private void write(ScilabType value, String as) throws XMLStreamException {
146         if (shared.dictionary == null) {
147             writeAsXml(value, as);
148         } else {
149             writeAsBinary(value, as);
150         }
151     }
152
153     private void writeAsXml(ScilabType value, String as) throws XMLStreamException {
154         ScilabTypeEnum type = value.getType();
155         final String localName;
156         final String scilabClass;
157         final String intPrecision;
158
159         /*
160          * Get the right descriptor
161          */
162         switch (type) {
163             case sci_boolean:
164                 localName = "ScilabBoolean";
165                 scilabClass = null;
166                 intPrecision = null;
167                 break;
168             case sci_ints:
169                 localName = "ScilabInteger";
170                 scilabClass = null;
171                 intPrecision = ((ScilabInteger) value).getPrec().name();
172                 break;
173             case sci_matrix:
174                 localName = "ScilabDouble";
175                 scilabClass = null;
176                 intPrecision = null;
177                 break;
178             case sci_strings:
179                 localName = "ScilabString";
180                 scilabClass = null;
181                 intPrecision = null;
182                 break;
183             case sci_list:
184                 localName = "Array";
185                 scilabClass = "ScilabList";
186                 intPrecision = null;
187                 break;
188             case sci_mlist:
189                 localName = "Array";
190                 scilabClass = "ScilabMList";
191                 intPrecision = null;
192                 break;
193             case sci_tlist:
194                 localName = "Array";
195                 scilabClass = "ScilabTList";
196                 intPrecision = null;
197                 break;
198             default:
199                 throw new XMLStreamException("Not handled ScilabType : " + type.name());
200         }
201
202         /*
203          * Emit the elements
204          */
205         final int len = value.getHeight() * value.getWidth();
206         if (len > 0) {
207             shared.stream.writeStartElement(localName);
208         } else {
209             shared.stream.writeEmptyElement(localName);
210         }
211         if (as != null) {
212             shared.stream.writeAttribute("as", as);
213         }
214
215         if (value instanceof ArrayList) {
216             writeList(value, scilabClass);
217         } else {
218             writeMatrix(value, type, intPrecision);
219         }
220
221         if (len > 0) {
222             shared.stream.writeEndElement();
223         }
224     }
225
226     private void writeList(ScilabType value, final String scilabClass) throws XMLStreamException {
227         shared.stream.writeAttribute("scilabClass", scilabClass);
228
229         @SuppressWarnings("unchecked")
230         ArrayList<ScilabType> values = (ArrayList<ScilabType>) value;
231         for (ScilabType subValue : values) {
232             write(subValue, null);
233         }
234     }
235
236     @SuppressWarnings("incomplete-switch")
237     private void writeMatrix(ScilabType value, ScilabTypeEnum type, final String intPrecision) throws XMLStreamException {
238         shared.stream.writeAttribute("height", Integer.toString(value.getHeight()));
239         shared.stream.writeAttribute("width", Integer.toString(value.getWidth()));
240         if (intPrecision != null) {
241             shared.stream.writeAttribute("intPrecision", intPrecision);
242         }
243
244         for (int i = 0; i < value.getHeight(); i++) {
245             for (int j = 0; j < value.getWidth(); j++) {
246                 shared.stream.writeEmptyElement("data");
247                 shared.stream.writeAttribute("column", Integer.toString(i));
248                 shared.stream.writeAttribute("line", Integer.toString(j));
249
250                 switch (type) {
251                     case sci_boolean:
252                         boolean bValue = ((ScilabBoolean)value).getElement(i, j);
253                         shared.stream.writeAttribute("value", Boolean.toString(bValue));
254                         break;
255                     case sci_ints:
256                         long lValue = ((ScilabInteger) value).getElement(i, j);
257                         shared.stream.writeAttribute("value", Long.toString(lValue));
258                         break;
259                     case sci_matrix:
260                         double dValue = ((ScilabDouble) value).getRealElement(i, j);
261                         shared.stream.writeAttribute("realPart", Double.toString(dValue));
262                         if (!((ScilabDouble) value).isReal()) {
263                             dValue  = ((ScilabDouble) value).getImaginaryElement(i, j);
264                             shared.stream.writeAttribute("imaginaryPart", Double.toString(dValue));
265                         }
266                         break;
267                     case sci_strings:
268                         String strValue = ((ScilabString) value).getData()[i][j];
269                         shared.stream.writeAttribute("value", strValue);
270                         break;
271                 }
272             }
273         }
274     }
275
276     private void writeAsBinary(ScilabType value, String as) throws XMLStreamException {
277         ScilabTypeEnum type = value.getType();
278         final String localName;
279
280         /*
281          * Get the right descriptor
282          */
283         switch (type) {
284             case sci_boolean:
285                 localName = "ScilabBoolean";
286                 break;
287             case sci_ints:
288                 localName = "ScilabInteger";
289                 break;
290             case sci_matrix:
291                 localName = "ScilabDouble";
292                 break;
293             case sci_strings:
294                 localName = "ScilabString";
295                 break;
296             case sci_list: // no break on purpose
297             case sci_mlist: // no break on purpose
298             case sci_tlist:
299                 localName = "Array";
300                 break;
301             default:
302                 throw new XMLStreamException("Not handled ScilabType : " + type.name());
303         }
304
305         /*
306          * Emit the elements
307          */
308
309         // if the value has not been mapped, then use the next position (map.size())
310         // else re-use the same position
311         Integer expectedPosition = dictionaryMap.size();
312         Integer position = dictionaryMap.putIfAbsent(value, expectedPosition);
313         if (position == null) {
314             position = expectedPosition;
315         }
316
317         if (XcosWriter.LOG.isLoggable(Level.FINE)) {
318             XcosWriter.LOG.fine("put:" + value.toString() + ":" + position.toString());
319         }
320
321         shared.stream.writeEmptyElement(localName);
322         shared.stream.writeAttribute("as", as);
323         shared.stream.writeAttribute("binary", "true");
324         shared.stream.writeAttribute("position", position.toString());
325     }
326
327     private void write(VectorOfDouble value, String as) throws XMLStreamException {
328         // recreate a ScilabDouble for the encoding
329         final int length = value.size();
330         if (length > 0) {
331             double[][] data = new double[1][length];
332             value.asByteBuffer(0, length).asDoubleBuffer().get(data[0]);
333             write(new ScilabDouble(data), as);
334         } else {
335             write(new ScilabDouble(), as);
336         }
337     }
338
339     private void write(VectorOfInt value, String as) throws XMLStreamException {
340         // recreate a ScilabInteger for the encoding
341         final int length = value.size();
342         if (length > 0) {
343             int[][] data = new int[1][length];
344             value.asByteBuffer(0, length).asIntBuffer().get(data[0]);
345             write(new ScilabInteger(data, false), as);
346         } else {
347             write(new ScilabDouble(), as);
348         }
349     }
350 }