Xcos vec2var: fix String and TList / MList
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / io / sax / RawDataHandler.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
13 package org.scilab.modules.xcos.io.sax;
14
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.Map;
19
20 import org.scilab.modules.types.ScilabBoolean;
21 import org.scilab.modules.types.ScilabDouble;
22 import org.scilab.modules.types.ScilabInteger;
23 import org.scilab.modules.types.ScilabIntegerTypeEnum;
24 import org.scilab.modules.types.ScilabList;
25 import org.scilab.modules.types.ScilabMList;
26 import org.scilab.modules.types.ScilabString;
27 import org.scilab.modules.types.ScilabTList;
28 import org.scilab.modules.types.ScilabType;
29 import org.scilab.modules.xcos.ObjectProperties;
30 import org.scilab.modules.xcos.VectorOfDouble;
31 import org.scilab.modules.xcos.VectorOfString;
32 import org.scilab.modules.xcos.graph.XcosDiagram;
33 import org.scilab.modules.xcos.graph.model.ScicosObjectOwner;
34 import org.scilab.modules.xcos.graph.model.XcosCell;
35 import org.scilab.modules.xcos.io.HandledElement;
36 import org.scilab.modules.xcos.io.ScilabTypeCoder;
37 import org.scilab.modules.xcos.io.scicos.DiagramElement;
38 import org.scilab.modules.xcos.io.scicos.ScicosFormatException;
39 import org.xml.sax.Attributes;
40
41 import com.mxgraph.model.mxGeometry;
42 import com.mxgraph.util.mxPoint;
43 import org.scilab.modules.xcos.VectorOfInt;
44
45 class RawDataHandler implements ScilabHandler {
46
47     static class RawDataDescriptor {
48         final ObjectProperties as;
49         final HandledElement found;
50         final String scilabClass;
51         final Object value;
52
53         public RawDataDescriptor(ObjectProperties as, HandledElement found, String scilabClass, Object container) {
54             this.as = as;
55             this.found = found;
56             this.scilabClass = scilabClass;
57             this.value = container;
58         }
59     }
60
61     private final XcosSAXHandler saxHandler;
62     private final Map<String, ObjectProperties> propertyMap;
63
64     /**
65      * Default constructor
66      *
67      * @param saxHandler
68      *            the shared sax handler
69      */
70     RawDataHandler(XcosSAXHandler saxHandler) {
71         this.saxHandler = saxHandler;
72
73         Map<String, ObjectProperties> localPropertyMap = new HashMap<>();
74         localPropertyMap.put("context", ObjectProperties.DIAGRAM_CONTEXT);
75         localPropertyMap.put("exprs", ObjectProperties.EXPRS);
76         localPropertyMap.put("realParameters", ObjectProperties.RPAR);
77         localPropertyMap.put("integerParameters", ObjectProperties.IPAR);
78         localPropertyMap.put("objectsParameters", ObjectProperties.OPAR);
79         localPropertyMap.put("nbZerosCrossing", ObjectProperties.NZCROSS);
80         localPropertyMap.put("nmode", ObjectProperties.NMODE);
81         localPropertyMap.put("state", ObjectProperties.STATE);
82         localPropertyMap.put("dState", ObjectProperties.DSTATE);
83         localPropertyMap.put("oDState", ObjectProperties.ODSTATE);
84         localPropertyMap.put("equations", ObjectProperties.EQUATIONS);
85         localPropertyMap.put("points", ObjectProperties.CONTROL_POINTS);
86         propertyMap = Collections.unmodifiableMap(localPropertyMap);
87     }
88
89     /*
90      * Implement the ScilabHandler interface to decode the data
91      */
92
93     @Override
94     public Object startElement(HandledElement found, Attributes atts) {
95         String v;
96
97         switch (found) {
98             case ScilabBoolean:
99             // no break on purpose
100             case ScilabDouble:
101             // no break on purpose
102             case ScilabInteger:
103             // no break on purpose
104             case ScilabString:
105             // no break on purpose
106             case Array: {
107                 String as = atts.getValue("as");
108
109                 /*
110                  * first : try to retrieve the already decoded binary data
111                  */
112                 boolean binary = false;
113                 int position = -1;
114
115                 v = atts.getValue("binary");
116                 if (v != null) {
117                     binary = Boolean.valueOf(v);
118                 }
119                 v = atts.getValue("position");
120                 if (v != null) {
121                     position = Integer.valueOf(v);
122                 }
123
124                 if (binary &&
125                         saxHandler.dictionary != null &&
126                         (0 <= position && position < saxHandler.dictionary.size())) {
127                     final ObjectProperties asProp = propertyMap.get(as);
128                     return new RawDataDescriptor(asProp, found, null, saxHandler.dictionary.get(position));
129                 }
130
131                 /*
132                  * otherwise : this is not a binary, decode it
133                  */
134                 int height = 0;
135                 int width = 0;
136                 String scilabClass = "ScilabDouble";
137
138                 v = atts.getValue("height");
139                 if (v != null) {
140                     height = Integer.valueOf(v);
141                 }
142                 v = atts.getValue("width");
143                 if (v != null) {
144                     width = Integer.valueOf(v);
145                 }
146                 v = atts.getValue("scilabClass");
147                 if (v != null) {
148                     scilabClass = v;
149                 }
150
151                 // allocate the right class and push it to a descriptor
152                 final Object container = allocateDataType(found, atts, height, width, scilabClass);
153                 final ObjectProperties asProp = propertyMap.get(as);
154                 return new RawDataDescriptor(asProp, found, scilabClass, container);
155             }
156             case add: {
157                 // defensive programming
158                 if (!(saxHandler.parents.peek() instanceof RawDataDescriptor)) {
159                     return null;
160                 }
161                 RawDataDescriptor fieldValue = (RawDataDescriptor) saxHandler.parents.peek();
162
163                 switch (fieldValue.as) {
164                     case DIAGRAM_CONTEXT: {
165                         @SuppressWarnings("unchecked")
166                         ArrayList<String> container = ((ArrayList<String>) fieldValue.value);
167                         container.add(atts.getValue("value"));
168                         break;
169                     }
170                     default:
171                         break;
172                 }
173                 break;
174             }
175             case data: {
176                 // defensive programming
177                 if (!(saxHandler.parents.peek() instanceof RawDataDescriptor)) {
178                     return null;
179                 }
180                 RawDataDescriptor fieldValue = (RawDataDescriptor) saxHandler.parents.peek();
181
182                 /*
183                  * Decode the position and then switch per container klass
184                  */
185
186                 int column = 0;
187                 int line = 0;
188
189                 v = atts.getValue("column");
190                 if (v != null) {
191                     column = Integer.valueOf(v);
192                 }
193                 v = atts.getValue("line");
194                 if (v != null) {
195                     line = Integer.valueOf(v);
196                 }
197
198                 switch (fieldValue.found) {
199                     case ScilabBoolean: {
200                         ScilabBoolean localScilabValue = ((ScilabBoolean) fieldValue.value);
201                         boolean[][] data = localScilabValue.getData();
202
203                         v = atts.getValue("value");
204                         if (v != null) {
205                             data[line][column] = Boolean.valueOf(v);
206                         }
207                         break;
208                     }
209                     case ScilabDouble: {
210                         ScilabDouble localScilabValue = ((ScilabDouble) fieldValue.value);
211                         double[][] realPartData = localScilabValue.getRealPart();
212                         double[][] imaginaryPartData = localScilabValue.getImaginaryPart();
213
214                         v = atts.getValue("realPart");
215                         if (v != null) {
216                             realPartData[line][column] = Double.valueOf(v);
217                         }
218
219                         v = atts.getValue("imaginaryPart");
220                         if (v != null) {
221                             // allocate the imaginary part on demand
222                             if (imaginaryPartData == null) {
223                                 imaginaryPartData = new double[localScilabValue.getHeight()][localScilabValue.getWidth()];
224                                 localScilabValue.setImaginaryPart(imaginaryPartData);
225                             }
226
227                             imaginaryPartData[line][column] = Double.valueOf(v);
228                         }
229                         break;
230                     }
231                     case ScilabInteger: {
232                         ScilabInteger localScilabValue = ((ScilabInteger) fieldValue.value);
233                         ScilabIntegerTypeEnum precision = localScilabValue.getPrec();
234
235                         v = atts.getValue("value");
236                         if (v != null) {
237                             switch (precision) {
238                                 case sci_int8:
239                                 case sci_uint8:
240                                     localScilabValue.getDataAsByte()[line][column] = Byte.valueOf(v);
241                                     break;
242                                 case sci_int16:
243                                 case sci_uint16:
244                                     localScilabValue.getDataAsShort()[line][column] = Short.valueOf(v);
245                                     break;
246                                 case sci_int32:
247                                 case sci_uint32:
248                                     localScilabValue.getDataAsInt()[line][column] = Integer.valueOf(v);
249                                     break;
250                                 case sci_int64:
251                                 case sci_uint64:
252                                     localScilabValue.getDataAsLong()[line][column] = Long.valueOf(v);
253                                     break;
254                             }
255                         }
256                         break;
257                     }
258                     case ScilabString: {
259                         ScilabString localScilabValue = ((ScilabString) fieldValue.value);
260                         String[][] data = localScilabValue.getData();
261                         data[line][column] = atts.getValue("value");
262                         break;
263                     }
264                     default:
265                         break;
266                 }
267                 break;
268             }
269             default:
270                 throw new IllegalArgumentException();
271         }
272
273         return null;
274     }
275
276     /**
277      * Allocate a {@link ScilabType} datatype accordingly to the decoded descriptors
278      *
279      * @param found
280      *            the decoded element
281      * @param atts
282      *            the attributes of the element
283      * @param height
284      *            decoded height
285      * @param width
286      *            decoded width
287      * @param scilabClass
288      *            decoded scilabClass
289      * @return the container
290      */
291     @SuppressWarnings("fallthrough")
292     private Object allocateDataType(HandledElement found, Attributes atts, int height, int width, String scilabClass) {
293         String v;
294         final Object container;
295         switch (found) {
296             case ScilabBoolean:
297                 container = new ScilabBoolean(new boolean[height][width]);
298                 break;
299             case ScilabDouble:
300                 container = new ScilabDouble(new double[height][width]);
301                 break;
302             case ScilabInteger:
303                 v = atts.getValue("intPrecision");
304                 if (v != null) {
305                     boolean unsigned = true;
306                     switch (ScilabIntegerTypeEnum.valueOf(v)) {
307                         case sci_int8:
308                             unsigned = false;
309                         // no break on purpose
310                         case sci_uint8:
311                             container = new ScilabInteger(new byte[height][width], unsigned);
312                             break;
313                         case sci_int16:
314                             unsigned = false;
315                         // no break on purpose
316                         case sci_uint16:
317                             container = new ScilabInteger(new short[height][width], unsigned);
318                             break;
319                         case sci_int32:
320                             unsigned = false;
321                         // no break on purpose
322                         case sci_uint32:
323                             container = new ScilabInteger(new int[height][width], unsigned);
324                             break;
325                         case sci_int64:
326                             unsigned = false;
327                         // no break on purpose
328                         case sci_uint64:
329                             container = new ScilabInteger(new long[height][width], unsigned);
330                             break;
331                         default:
332                             container = new ScilabInteger(new long[height][width], false);
333                             break;
334                     }
335                 } else {
336                     container = new ScilabInteger(new long[height][width], false);
337                 }
338                 break;
339             case ScilabString:
340                 container = new ScilabString(new String[height][width]);
341                 break;
342             default: // case Array
343                 if ("ScilabMList".equals(scilabClass)) {
344                     container = new ScilabMList();
345                 } else if ("ScilabTList".equals(scilabClass)) {
346                     container = new ScilabTList();
347                 } else if ("ScilabList".equals(scilabClass)) {
348                     container = new ScilabList();
349                 } else {
350                     container = new ArrayList<>();
351                 }
352                 break;
353         }
354         return container;
355     }
356
357     @Override
358     public void endElement(HandledElement found) {
359         switch (found) {
360             case Array:
361             // no break on purpose
362             case ScilabBoolean:
363             // no break on purpose
364             case ScilabDouble:
365             // no break on purpose
366             case ScilabInteger:
367             // no break on purpose
368             case ScilabString: {
369                 // defensive programming
370                 if (!(saxHandler.parents.peek() instanceof RawDataDescriptor)) {
371                     return;
372                 }
373                 RawDataDescriptor fieldValue = (RawDataDescriptor) saxHandler.parents.peek();
374                 Object parent = saxHandler.parents.peek(1);
375
376                 // when we are decoding data into a list "as" is null
377                 if (fieldValue.as == null) {
378                     if (!(parent instanceof RawDataDescriptor)) {
379                         return;
380                     }
381
382                     ArrayList<Object> parentList = (ArrayList<Object>) ((RawDataDescriptor) parent).value;
383                     parentList.add(fieldValue.value);
384                     return;
385                 }
386
387                 switch (fieldValue.as) {
388                     case CONTROL_POINTS: {
389                         // defensive programming
390                         if (!(parent instanceof mxGeometry)) {
391                             return;
392                         }
393                         mxGeometry geom = (mxGeometry) parent;
394
395                         @SuppressWarnings("unchecked")
396                         ArrayList<mxPoint> value = (ArrayList<mxPoint>) fieldValue.value;
397                         geom.setPoints(value);
398                         break;
399                     }
400                     case DIAGRAM_CONTEXT: {
401                         // defensive programming
402                         if (!(parent instanceof ScicosObjectOwner)) {
403                             return;
404                         }
405                         ScicosObjectOwner diagram = (ScicosObjectOwner) parent;
406
407                         @SuppressWarnings("unchecked")
408                         ArrayList<String> value = (ArrayList<String>) fieldValue.value;
409                         VectorOfString ctx = new VectorOfString(value.size());
410                         for (int i = 0; i < value.size(); i++) {
411                             ctx.set(i, value.get(i));
412                         }
413                         saxHandler.controller.setObjectProperty(diagram.getUID(), diagram.getKind(), ObjectProperties.DIAGRAM_CONTEXT, ctx);
414                         break;
415                     }
416                     case STATE:
417                     case DSTATE:
418                     case RPAR: {
419                         // defensive programming
420                         if (!(parent instanceof XcosCell)) {
421                             return;
422                         }
423                         XcosCell cell = (XcosCell) parent;
424                         if (fieldValue.as == ObjectProperties.RPAR && fieldValue.value instanceof ScilabMList) {
425                             // CORNER CASE for partially decoded sub-diagram hierarchy
426                             // decode the rpar as a subdiagram using the legacy decoders
427                             try {
428                                 new DiagramElement(saxHandler.controller).decode((ScilabMList) fieldValue.value, new XcosDiagram(cell.getUID(), cell.getKind()));
429                             } catch (ScicosFormatException e) {
430                             }
431                             return;
432                         }
433
434                         VectorOfDouble vec;
435                         if (fieldValue.value instanceof ScilabDouble) {
436                             // defensive programming against old schema
437                             ScilabDouble value = (ScilabDouble) fieldValue.value;
438
439                             vec = new VectorOfDouble(value.getHeight());
440                             for (int i = 0; i < value.getHeight(); i++) {
441                                 vec.set(i, value.getRealElement(i, 0));
442                             }
443
444                             saxHandler.controller.setObjectProperty(cell.getUID(), cell.getKind(), fieldValue.as, vec);
445                         }
446                         break;
447                     }
448                     case NZCROSS:
449                     case NMODE:
450                     case IPAR: {
451                         // defensive programming
452                         if (!(parent instanceof XcosCell)) {
453                             return;
454                         }
455                         XcosCell cell = (XcosCell) parent;
456
457                         VectorOfInt vec = null;
458                         if (fieldValue.value instanceof ScilabDouble) {
459                             // defensive programming against old schema
460                             ScilabDouble value = (ScilabDouble) fieldValue.value;
461
462                             vec = new VectorOfInt(value.getHeight());
463                             for (int i = 0; i < value.getHeight(); i++) {
464                                 vec.set(i, (int) value.getRealElement(i, 0));
465                             }
466                         } else if (fieldValue.value instanceof ScilabInteger) {
467                             // defensive programming against old schema
468                             ScilabInteger value = (ScilabInteger) fieldValue.value;
469
470                             vec = new VectorOfInt(value.getHeight());
471                             for (int i = 0; i < value.getHeight(); i++) {
472                                 switch (value.getPrec()) {
473                                     case sci_int8:
474                                     case sci_uint8:
475                                         vec.set(i, value.getByteElement(i, 0));
476                                         break;
477                                     case sci_int16:
478                                     case sci_uint16:
479                                         vec.set(i, value.getShortElement(i, 0));
480                                         break;
481                                     case sci_int32:
482                                     case sci_uint32:
483                                         vec.set(i, value.getIntElement(i, 0));
484                                         break;
485                                     case sci_int64:
486                                     case sci_uint64:
487                                         vec.set(i, (int) value.getLongElement(i, 0));
488                                         break;
489                                 }
490                             }
491                         }
492                         if (vec != null) {
493                             saxHandler.controller.setObjectProperty(cell.getUID(), cell.getKind(), fieldValue.as, vec);
494                         }
495                         break;
496
497                     }
498                     case EXPRS:
499                     case EQUATIONS:
500                     case OPAR:
501                     case ODSTATE: {
502                         // defensive programming
503                         if (!(parent instanceof XcosCell)) {
504                             return;
505                         }
506                         XcosCell cell = (XcosCell) parent;
507                         ScilabType value = (ScilabType) fieldValue.value;
508
509                         VectorOfDouble vec = new ScilabTypeCoder().var2vec(value);
510                         saxHandler.controller.setObjectProperty(cell.getUID(), cell.getKind(), fieldValue.as, vec);
511                         break;
512                     }
513                     default:
514                         XcosSAXHandler.LOG.warning("RawDataHandler not handled: " + fieldValue.as);
515                         break;
516                 }
517                 break;
518             }
519             case add:
520                 break;
521             case data:
522                 break;
523             default:
524                 throw new IllegalArgumentException();
525         }
526     }
527 }