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