1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package com.jme3.export.xml;
34
35import com.jme3.export.InputCapsule;
36import com.jme3.export.Savable;
37import com.jme3.export.SavableClassUtil;
38import com.jme3.util.BufferUtils;
39import com.jme3.util.IntMap;
40import java.io.IOException;
41import java.nio.ByteBuffer;
42import java.nio.FloatBuffer;
43import java.nio.IntBuffer;
44import java.nio.ShortBuffer;
45import java.util.*;
46import java.util.logging.Logger;
47import org.w3c.dom.*;
48
49/**
50 * Part of the jME XML IO system as introduced in the google code jmexml project.
51 *
52 * @author Kai Rabien (hevee) - original author of the code.google.com jmexml project
53 * @author Doug Daniels (dougnukem) - adjustments for jME 2.0 and Java 1.5
54 * @author blaine
55 */
56public class DOMInputCapsule implements InputCapsule {
57    private static final Logger logger =
58        Logger.getLogger(DOMInputCapsule.class .getName());
59
60    private Document doc;
61    private Element currentElem;
62    private XMLImporter importer;
63    private boolean isAtRoot = true;
64    private Map<String, Savable> referencedSavables = new HashMap<String, Savable>();
65
66    private int[] classHierarchyVersions;
67    private Savable savable;
68
69    public DOMInputCapsule(Document doc, XMLImporter importer) {
70        this.doc = doc;
71        this.importer = importer;
72        currentElem = doc.getDocumentElement();
73
74        String version = currentElem.getAttribute("format_version");
75        importer.formatVersion = version.equals("") ? 0 : Integer.parseInt(version);
76    }
77
78    public int getSavableVersion(Class<? extends Savable> desiredClass) {
79        if (classHierarchyVersions != null){
80            return SavableClassUtil.getSavedSavableVersion(savable, desiredClass,
81                                                        classHierarchyVersions, importer.getFormatVersion());
82        }else{
83            return 0;
84        }
85    }
86
87    private static String decodeString(String s) {
88        if (s == null) {
89            return null;
90        }
91        s = s.replaceAll("\\&quot;", "\"").replaceAll("\\&lt;", "<").replaceAll("\\&amp;", "&");
92        return s;
93    }
94
95    private Element findFirstChildElement(Element parent) {
96        Node ret = parent.getFirstChild();
97        while (ret != null && (!(ret instanceof Element))) {
98            ret = ret.getNextSibling();
99        }
100        return (Element) ret;
101    }
102
103    private Element findChildElement(Element parent, String name) {
104        if (parent == null) {
105            return null;
106        }
107        Node ret = parent.getFirstChild();
108        while (ret != null && (!(ret instanceof Element) || !ret.getNodeName().equals(name))) {
109            ret = ret.getNextSibling();
110        }
111        return (Element) ret;
112    }
113
114    private Element findNextSiblingElement(Element current) {
115        Node ret = current.getNextSibling();
116        while (ret != null) {
117            if (ret instanceof Element) {
118                return (Element) ret;
119            }
120            ret = ret.getNextSibling();
121        }
122        return null;
123    }
124
125    public byte readByte(String name, byte defVal) throws IOException {
126        String tmpString = currentElem.getAttribute(name);
127        if (tmpString == null || tmpString.length() < 1) return defVal;
128        try {
129            return Byte.parseByte(tmpString);
130        } catch (NumberFormatException nfe) {
131            IOException io = new IOException(nfe.toString());
132            io.initCause(nfe);
133            throw io;
134        } catch (DOMException de) {
135            IOException io = new IOException(de.toString());
136            io.initCause(de);
137            throw io;
138        }
139    }
140
141    public byte[] readByteArray(String name, byte[] defVal) throws IOException {
142        try {
143            Element tmpEl;
144            if (name != null) {
145                tmpEl = findChildElement(currentElem, name);
146            } else {
147                tmpEl = currentElem;
148            }
149            if (tmpEl == null) {
150                return defVal;
151            }
152            String sizeString = tmpEl.getAttribute("size");
153            String[] strings = parseTokens(tmpEl.getAttribute("data"));
154            if (sizeString.length() > 0) {
155                int requiredSize = Integer.parseInt(sizeString);
156                if (strings.length != requiredSize)
157                    throw new IOException("Wrong number of bytes for '" + name
158                            + "'.  size says " + requiredSize
159                            + ", data contains "
160                            + strings.length);
161            }
162            byte[] tmp = new byte[strings.length];
163            for (int i = 0; i < strings.length; i++) {
164                tmp[i] = Byte.parseByte(strings[i]);
165            }
166            return tmp;
167        } catch (IOException ioe) {
168            throw ioe;
169        } catch (NumberFormatException nfe) {
170            IOException io = new IOException(nfe.toString());
171            io.initCause(nfe);
172            throw io;
173        } catch (DOMException de) {
174            IOException io = new IOException(de.toString());
175            io.initCause(de);
176            throw io;
177        }
178    }
179
180    public byte[][] readByteArray2D(String name, byte[][] defVal) throws IOException {
181        try {
182            Element tmpEl;
183            if (name != null) {
184                tmpEl = findChildElement(currentElem, name);
185            } else {
186                tmpEl = currentElem;
187            }
188            if (tmpEl == null) {
189                return defVal;
190            }
191
192            String sizeString = tmpEl.getAttribute("size");
193            NodeList nodes = currentElem.getChildNodes();
194            List<byte[]> byteArrays = new ArrayList<byte[]>();
195
196            for (int i = 0; i < nodes.getLength(); i++) {
197                        Node n = nodes.item(i);
198                                if (n instanceof Element && n.getNodeName().contains("array")) {
199                // Very unsafe assumption
200                    byteArrays.add(readByteArray(n.getNodeName(), null));
201                                }
202            }
203            if (sizeString.length() > 0) {
204                int requiredSize = Integer.parseInt(sizeString);
205                if (byteArrays.size() != requiredSize)
206                    throw new IOException(
207                            "String array contains wrong element count.  "
208                            + "Specified size " + requiredSize
209                            + ", data contains " + byteArrays.size());
210            }
211            currentElem = (Element) currentElem.getParentNode();
212            return byteArrays.toArray(new byte[0][]);
213        } catch (IOException ioe) {
214            throw ioe;
215        } catch (NumberFormatException nfe) {
216            IOException io = new IOException(nfe.toString());
217            io.initCause(nfe);
218            throw io;
219        } catch (DOMException de) {
220            IOException io = new IOException(de.toString());
221            io.initCause(de);
222            throw io;
223        }
224    }
225
226    public int readInt(String name, int defVal) throws IOException {
227        String tmpString = currentElem.getAttribute(name);
228        if (tmpString == null || tmpString.length() < 1) return defVal;
229        try {
230            return Integer.parseInt(tmpString);
231        } catch (NumberFormatException nfe) {
232            IOException io = new IOException(nfe.toString());
233            io.initCause(nfe);
234            throw io;
235        } catch (DOMException de) {
236            IOException io = new IOException(de.toString());
237            io.initCause(de);
238            throw io;
239        }
240    }
241
242    public int[] readIntArray(String name, int[] defVal) throws IOException {
243        try {
244            Element tmpEl;
245            if (name != null) {
246                tmpEl = findChildElement(currentElem, name);
247            } else {
248                tmpEl = currentElem;
249            }
250            if (tmpEl == null) {
251                return defVal;
252            }
253            String sizeString = tmpEl.getAttribute("size");
254            String[] strings = parseTokens(tmpEl.getAttribute("data"));
255            if (sizeString.length() > 0) {
256                int requiredSize = Integer.parseInt(sizeString);
257                if (strings.length != requiredSize)
258                    throw new IOException("Wrong number of ints for '" + name
259                            + "'.  size says " + requiredSize
260                            + ", data contains " + strings.length);
261            }
262            int[] tmp = new int[strings.length];
263            for (int i = 0; i < tmp.length; i++) {
264                tmp[i] = Integer.parseInt(strings[i]);
265            }
266            return tmp;
267        } catch (IOException ioe) {
268            throw ioe;
269        } catch (NumberFormatException nfe) {
270            IOException io = new IOException(nfe.toString());
271            io.initCause(nfe);
272            throw io;
273        } catch (DOMException de) {
274            IOException io = new IOException(de.toString());
275            io.initCause(de);
276            throw io;
277        }
278    }
279
280    public int[][] readIntArray2D(String name, int[][] defVal) throws IOException {
281        try {
282            Element tmpEl;
283            if (name != null) {
284                tmpEl = findChildElement(currentElem, name);
285            } else {
286                tmpEl = currentElem;
287            }
288            if (tmpEl == null) {
289                return defVal;
290            }
291            String sizeString = tmpEl.getAttribute("size");
292
293
294
295
296            NodeList nodes = currentElem.getChildNodes();
297            List<int[]> intArrays = new ArrayList<int[]>();
298
299            for (int i = 0; i < nodes.getLength(); i++) {
300                        Node n = nodes.item(i);
301                                if (n instanceof Element && n.getNodeName().contains("array")) {
302                // Very unsafe assumption
303                    intArrays.add(readIntArray(n.getNodeName(), null));
304                                }
305            }
306            if (sizeString.length() > 0) {
307                int requiredSize = Integer.parseInt(sizeString);
308                if (intArrays.size() != requiredSize)
309                    throw new IOException(
310                            "String array contains wrong element count.  "
311                            + "Specified size " + requiredSize
312                            + ", data contains " + intArrays.size());
313            }
314            currentElem = (Element) currentElem.getParentNode();
315            return intArrays.toArray(new int[0][]);
316        } catch (IOException ioe) {
317            throw ioe;
318        } catch (NumberFormatException nfe) {
319            IOException io = new IOException(nfe.toString());
320            io.initCause(nfe);
321            throw io;
322        } catch (DOMException de) {
323            IOException io = new IOException(de.toString());
324            io.initCause(de);
325            throw io;
326        }
327    }
328
329    public float readFloat(String name, float defVal) throws IOException {
330        String tmpString = currentElem.getAttribute(name);
331        if (tmpString == null || tmpString.length() < 1) return defVal;
332        try {
333            return Float.parseFloat(tmpString);
334        } catch (NumberFormatException nfe) {
335            IOException io = new IOException(nfe.toString());
336            io.initCause(nfe);
337            throw io;
338        } catch (DOMException de) {
339            IOException io = new IOException(de.toString());
340            io.initCause(de);
341            throw io;
342        }
343    }
344
345    public float[] readFloatArray(String name, float[] defVal) throws IOException {
346        try {
347            Element tmpEl;
348            if (name != null) {
349                tmpEl = findChildElement(currentElem, name);
350            } else {
351                tmpEl = currentElem;
352            }
353            if (tmpEl == null) {
354                return defVal;
355            }
356            String sizeString = tmpEl.getAttribute("size");
357            String[] strings = parseTokens(tmpEl.getAttribute("data"));
358            if (sizeString.length() > 0) {
359                int requiredSize = Integer.parseInt(sizeString);
360                if (strings.length != requiredSize)
361                    throw new IOException("Wrong number of floats for '" + name
362                            + "'.  size says " + requiredSize
363                            + ", data contains " + strings.length);
364            }
365            float[] tmp = new float[strings.length];
366            for (int i = 0; i < tmp.length; i++) {
367                tmp[i] = Float.parseFloat(strings[i]);
368            }
369            return tmp;
370        } catch (IOException ioe) {
371            throw ioe;
372        } catch (DOMException de) {
373            IOException io = new IOException(de.toString());
374            io.initCause(de);
375            throw io;
376        }
377    }
378
379    public float[][] readFloatArray2D(String name, float[][] defVal) throws IOException {
380        /* Why does this one method ignore the 'size attr.? */
381        try {
382            Element tmpEl;
383            if (name != null) {
384                tmpEl = findChildElement(currentElem, name);
385            } else {
386                tmpEl = currentElem;
387            }
388            if (tmpEl == null) {
389                return defVal;
390            }
391            int size_outer = Integer.parseInt(tmpEl.getAttribute("size_outer"));
392            int size_inner = Integer.parseInt(tmpEl.getAttribute("size_outer"));
393
394            float[][] tmp = new float[size_outer][size_inner];
395
396            String[] strings = parseTokens(tmpEl.getAttribute("data"));
397            for (int i = 0; i < size_outer; i++) {
398                tmp[i] = new float[size_inner];
399                for (int k = 0; k < size_inner; k++) {
400                    tmp[i][k] = Float.parseFloat(strings[i]);
401                }
402            }
403            return tmp;
404        } catch (NumberFormatException nfe) {
405            IOException io = new IOException(nfe.toString());
406            io.initCause(nfe);
407            throw io;
408        } catch (DOMException de) {
409            IOException io = new IOException(de.toString());
410            io.initCause(de);
411            throw io;
412        }
413    }
414
415    public double readDouble(String name, double defVal) throws IOException {
416        String tmpString = currentElem.getAttribute(name);
417        if (tmpString == null || tmpString.length() < 1) return defVal;
418        try {
419            return Double.parseDouble(tmpString);
420        } catch (NumberFormatException nfe) {
421            IOException io = new IOException(nfe.toString());
422            io.initCause(nfe);
423            throw io;
424        } catch (DOMException de) {
425            IOException io = new IOException(de.toString());
426            io.initCause(de);
427            throw io;
428        }
429    }
430
431    public double[] readDoubleArray(String name, double[] defVal) throws IOException {
432        try {
433            Element tmpEl;
434            if (name != null) {
435                tmpEl = findChildElement(currentElem, name);
436            } else {
437                tmpEl = currentElem;
438            }
439            if (tmpEl == null) {
440                return defVal;
441            }
442            String sizeString = tmpEl.getAttribute("size");
443            String[] strings = parseTokens(tmpEl.getAttribute("data"));
444            if (sizeString.length() > 0) {
445                int requiredSize = Integer.parseInt(sizeString);
446                if (strings.length != requiredSize)
447                    throw new IOException("Wrong number of doubles for '"
448                            + name + "'.  size says " + requiredSize
449                            + ", data contains " + strings.length);
450            }
451            double[] tmp = new double[strings.length];
452            for (int i = 0; i < tmp.length; i++) {
453                tmp[i] = Double.parseDouble(strings[i]);
454            }
455            return tmp;
456        } catch (IOException ioe) {
457            throw ioe;
458        } catch (NumberFormatException nfe) {
459            IOException io = new IOException(nfe.toString());
460            io.initCause(nfe);
461            throw io;
462        } catch (DOMException de) {
463            IOException io = new IOException(de.toString());
464            io.initCause(de);
465            throw io;
466        }
467    }
468
469    public double[][] readDoubleArray2D(String name, double[][] defVal) throws IOException {
470        try {
471            Element tmpEl;
472            if (name != null) {
473                tmpEl = findChildElement(currentElem, name);
474            } else {
475                tmpEl = currentElem;
476            }
477            if (tmpEl == null) {
478                return defVal;
479            }
480            String sizeString = tmpEl.getAttribute("size");
481            NodeList nodes = currentElem.getChildNodes();
482            List<double[]> doubleArrays = new ArrayList<double[]>();
483
484            for (int i = 0; i < nodes.getLength(); i++) {
485                        Node n = nodes.item(i);
486                                if (n instanceof Element && n.getNodeName().contains("array")) {
487                // Very unsafe assumption
488                    doubleArrays.add(readDoubleArray(n.getNodeName(), null));
489                                }
490            }
491            if (sizeString.length() > 0) {
492                int requiredSize = Integer.parseInt(sizeString);
493                if (doubleArrays.size() != requiredSize)
494                    throw new IOException(
495                            "String array contains wrong element count.  "
496                            + "Specified size " + requiredSize
497                            + ", data contains " + doubleArrays.size());
498            }
499            currentElem = (Element) currentElem.getParentNode();
500            return doubleArrays.toArray(new double[0][]);
501        } catch (IOException ioe) {
502            throw ioe;
503        } catch (NumberFormatException nfe) {
504            IOException io = new IOException(nfe.toString());
505            io.initCause(nfe);
506            throw io;
507        } catch (DOMException de) {
508            IOException io = new IOException(de.toString());
509            io.initCause(de);
510            throw io;
511        }
512    }
513
514    public long readLong(String name, long defVal) throws IOException {
515        String tmpString = currentElem.getAttribute(name);
516        if (tmpString == null || tmpString.length() < 1) return defVal;
517        try {
518            return Long.parseLong(tmpString);
519        } catch (NumberFormatException nfe) {
520            IOException io = new IOException(nfe.toString());
521            io.initCause(nfe);
522            throw io;
523        } catch (DOMException de) {
524            IOException io = new IOException(de.toString());
525            io.initCause(de);
526            throw io;
527        }
528    }
529
530    public long[] readLongArray(String name, long[] defVal) throws IOException {
531        try {
532            Element tmpEl;
533            if (name != null) {
534                tmpEl = findChildElement(currentElem, name);
535            } else {
536                tmpEl = currentElem;
537            }
538            if (tmpEl == null) {
539                return defVal;
540            }
541            String sizeString = tmpEl.getAttribute("size");
542            String[] strings = parseTokens(tmpEl.getAttribute("data"));
543            if (sizeString.length() > 0) {
544                int requiredSize = Integer.parseInt(sizeString);
545                if (strings.length != requiredSize)
546                    throw new IOException("Wrong number of longs for '" + name
547                            + "'.  size says " + requiredSize
548                            + ", data contains " + strings.length);
549            }
550            long[] tmp = new long[strings.length];
551            for (int i = 0; i < tmp.length; i++) {
552                tmp[i] = Long.parseLong(strings[i]);
553            }
554            return tmp;
555        } catch (IOException ioe) {
556            throw ioe;
557        } catch (NumberFormatException nfe) {
558            IOException io = new IOException(nfe.toString());
559            io.initCause(nfe);
560            throw io;
561        } catch (DOMException de) {
562            IOException io = new IOException(de.toString());
563            io.initCause(de);
564            throw io;
565        }
566    }
567
568    public long[][] readLongArray2D(String name, long[][] defVal) throws IOException {
569        try {
570            Element tmpEl;
571            if (name != null) {
572                tmpEl = findChildElement(currentElem, name);
573            } else {
574                tmpEl = currentElem;
575            }
576            if (tmpEl == null) {
577                return defVal;
578            }
579            String sizeString = tmpEl.getAttribute("size");
580            NodeList nodes = currentElem.getChildNodes();
581            List<long[]> longArrays = new ArrayList<long[]>();
582
583            for (int i = 0; i < nodes.getLength(); i++) {
584                        Node n = nodes.item(i);
585                                if (n instanceof Element && n.getNodeName().contains("array")) {
586                // Very unsafe assumption
587                    longArrays.add(readLongArray(n.getNodeName(), null));
588                                }
589            }
590            if (sizeString.length() > 0) {
591                int requiredSize = Integer.parseInt(sizeString);
592                if (longArrays.size() != requiredSize)
593                    throw new IOException(
594                            "String array contains wrong element count.  "
595                            + "Specified size " + requiredSize
596                            + ", data contains " + longArrays.size());
597            }
598            currentElem = (Element) currentElem.getParentNode();
599            return longArrays.toArray(new long[0][]);
600        } catch (IOException ioe) {
601            throw ioe;
602        } catch (NumberFormatException nfe) {
603            IOException io = new IOException(nfe.toString());
604            io.initCause(nfe);
605            throw io;
606        } catch (DOMException de) {
607            IOException io = new IOException(de.toString());
608            io.initCause(de);
609            throw io;
610        }
611    }
612
613    public short readShort(String name, short defVal) throws IOException {
614        String tmpString = currentElem.getAttribute(name);
615        if (tmpString == null || tmpString.length() < 1) return defVal;
616        try {
617            return Short.parseShort(tmpString);
618        } catch (NumberFormatException nfe) {
619            IOException io = new IOException(nfe.toString());
620            io.initCause(nfe);
621            throw io;
622        } catch (DOMException de) {
623            IOException io = new IOException(de.toString());
624            io.initCause(de);
625            throw io;
626        }
627    }
628
629    public short[] readShortArray(String name, short[] defVal) throws IOException {
630         try {
631             Element tmpEl;
632             if (name != null) {
633                 tmpEl = findChildElement(currentElem, name);
634             } else {
635                 tmpEl = currentElem;
636             }
637             if (tmpEl == null) {
638                 return defVal;
639             }
640            String sizeString = tmpEl.getAttribute("size");
641            String[] strings = parseTokens(tmpEl.getAttribute("data"));
642            if (sizeString.length() > 0) {
643                int requiredSize = Integer.parseInt(sizeString);
644                if (strings.length != requiredSize)
645                    throw new IOException("Wrong number of shorts for '"
646                            + name + "'.  size says " + requiredSize
647                            + ", data contains " + strings.length);
648            }
649            short[] tmp = new short[strings.length];
650            for (int i = 0; i < tmp.length; i++) {
651                tmp[i] = Short.parseShort(strings[i]);
652            }
653            return tmp;
654        } catch (IOException ioe) {
655            throw ioe;
656        } catch (NumberFormatException nfe) {
657            IOException io = new IOException(nfe.toString());
658            io.initCause(nfe);
659            throw io;
660        } catch (DOMException de) {
661            IOException io = new IOException(de.toString());
662            io.initCause(de);
663            throw io;
664        }
665    }
666
667    public short[][] readShortArray2D(String name, short[][] defVal) throws IOException {
668        try {
669            Element tmpEl;
670            if (name != null) {
671                tmpEl = findChildElement(currentElem, name);
672            } else {
673                tmpEl = currentElem;
674            }
675            if (tmpEl == null) {
676                return defVal;
677            }
678
679            String sizeString = tmpEl.getAttribute("size");
680            NodeList nodes = currentElem.getChildNodes();
681            List<short[]> shortArrays = new ArrayList<short[]>();
682
683            for (int i = 0; i < nodes.getLength(); i++) {
684                        Node n = nodes.item(i);
685                                if (n instanceof Element && n.getNodeName().contains("array")) {
686                // Very unsafe assumption
687                    shortArrays.add(readShortArray(n.getNodeName(), null));
688                                }
689            }
690            if (sizeString.length() > 0) {
691                int requiredSize = Integer.parseInt(sizeString);
692                if (shortArrays.size() != requiredSize)
693                    throw new IOException(
694                            "String array contains wrong element count.  "
695                            + "Specified size " + requiredSize
696                            + ", data contains " + shortArrays.size());
697            }
698            currentElem = (Element) currentElem.getParentNode();
699            return shortArrays.toArray(new short[0][]);
700        } catch (IOException ioe) {
701            throw ioe;
702        } catch (NumberFormatException nfe) {
703            IOException io = new IOException(nfe.toString());
704            io.initCause(nfe);
705            throw io;
706        } catch (DOMException de) {
707            IOException io = new IOException(de.toString());
708            io.initCause(de);
709            throw io;
710        }
711    }
712
713    public boolean readBoolean(String name, boolean defVal) throws IOException {
714        String tmpString = currentElem.getAttribute(name);
715        if (tmpString == null || tmpString.length() < 1) return defVal;
716        try {
717            return Boolean.parseBoolean(tmpString);
718        } catch (DOMException de) {
719            IOException io = new IOException(de.toString());
720            io.initCause(de);
721            throw io;
722        }
723    }
724
725    public boolean[] readBooleanArray(String name, boolean[] defVal) throws IOException {
726        try {
727            Element tmpEl;
728            if (name != null) {
729                tmpEl = findChildElement(currentElem, name);
730            } else {
731                tmpEl = currentElem;
732            }
733            if (tmpEl == null) {
734                return defVal;
735            }
736            String sizeString = tmpEl.getAttribute("size");
737            String[] strings = parseTokens(tmpEl.getAttribute("data"));
738            if (sizeString.length() > 0) {
739                int requiredSize = Integer.parseInt(sizeString);
740                if (strings.length != requiredSize)
741                    throw new IOException("Wrong number of bools for '" + name
742                            + "'.  size says " + requiredSize
743                            + ", data contains " + strings.length);
744            }
745            boolean[] tmp = new boolean[strings.length];
746            for (int i = 0; i < tmp.length; i++) {
747                tmp[i] = Boolean.parseBoolean(strings[i]);
748            }
749            return tmp;
750        } catch (IOException ioe) {
751            throw ioe;
752        } catch (DOMException de) {
753            IOException io = new IOException(de.toString());
754            io.initCause(de);
755            throw io;
756        }
757    }
758
759    public boolean[][] readBooleanArray2D(String name, boolean[][] defVal) throws IOException {
760        try {
761            Element tmpEl;
762            if (name != null) {
763                tmpEl = findChildElement(currentElem, name);
764            } else {
765                tmpEl = currentElem;
766            }
767            if (tmpEl == null) {
768                return defVal;
769            }
770            String sizeString = tmpEl.getAttribute("size");
771            NodeList nodes = currentElem.getChildNodes();
772            List<boolean[]> booleanArrays = new ArrayList<boolean[]>();
773
774            for (int i = 0; i < nodes.getLength(); i++) {
775                        Node n = nodes.item(i);
776                                if (n instanceof Element && n.getNodeName().contains("array")) {
777                // Very unsafe assumption
778                    booleanArrays.add(readBooleanArray(n.getNodeName(), null));
779                                }
780            }
781            if (sizeString.length() > 0) {
782                int requiredSize = Integer.parseInt(sizeString);
783                if (booleanArrays.size() != requiredSize)
784                    throw new IOException(
785                            "String array contains wrong element count.  "
786                            + "Specified size " + requiredSize
787                            + ", data contains " + booleanArrays.size());
788            }
789            currentElem = (Element) currentElem.getParentNode();
790            return booleanArrays.toArray(new boolean[0][]);
791        } catch (IOException ioe) {
792            throw ioe;
793        } catch (NumberFormatException nfe) {
794            IOException io = new IOException(nfe.toString());
795            io.initCause(nfe);
796            throw io;
797        } catch (DOMException de) {
798            IOException io = new IOException(de.toString());
799            io.initCause(de);
800            throw io;
801        }
802    }
803
804    public String readString(String name, String defVal) throws IOException {
805        String tmpString = currentElem.getAttribute(name);
806        if (tmpString == null || tmpString.length() < 1) return defVal;
807        try {
808            return decodeString(tmpString);
809        } catch (DOMException de) {
810            IOException io = new IOException(de.toString());
811            io.initCause(de);
812            throw io;
813        }
814    }
815
816    public String[] readStringArray(String name, String[] defVal) throws IOException {
817         try {
818             Element tmpEl;
819             if (name != null) {
820                 tmpEl = findChildElement(currentElem, name);
821             } else {
822                 tmpEl = currentElem;
823             }
824             if (tmpEl == null) {
825                 return defVal;
826             }
827            String sizeString = tmpEl.getAttribute("size");
828            NodeList nodes = tmpEl.getChildNodes();
829            List<String> strings = new ArrayList<String>();
830
831            for (int i = 0; i < nodes.getLength(); i++) {
832                        Node n = nodes.item(i);
833                                if (n instanceof Element && n.getNodeName().contains("String")) {
834                // Very unsafe assumption
835                    strings.add(((Element) n).getAttributeNode("value").getValue());
836                                }
837            }
838            if (sizeString.length() > 0) {
839                int requiredSize = Integer.parseInt(sizeString);
840                if (strings.size() != requiredSize)
841                    throw new IOException(
842                            "String array contains wrong element count.  "
843                            + "Specified size " + requiredSize
844                            + ", data contains " + strings.size());
845            }
846            return strings.toArray(new String[0]);
847        } catch (IOException ioe) {
848            throw ioe;
849        } catch (NumberFormatException nfe) {
850            IOException io = new IOException(nfe.toString());
851            io.initCause(nfe);
852            throw io;
853        } catch (DOMException de) {
854            IOException io = new IOException(de.toString());
855            io.initCause(de);
856            throw io;
857        }
858    }
859
860    public String[][] readStringArray2D(String name, String[][] defVal) throws IOException {
861        try {
862            Element tmpEl;
863            if (name != null) {
864                tmpEl = findChildElement(currentElem, name);
865            } else {
866                tmpEl = currentElem;
867            }
868            if (tmpEl == null) {
869                return defVal;
870            }
871            String sizeString = tmpEl.getAttribute("size");
872            NodeList nodes = currentElem.getChildNodes();
873            List<String[]> stringArrays = new ArrayList<String[]>();
874
875            for (int i = 0; i < nodes.getLength(); i++) {
876                        Node n = nodes.item(i);
877                                if (n instanceof Element && n.getNodeName().contains("array")) {
878                // Very unsafe assumption
879                    stringArrays.add(readStringArray(n.getNodeName(), null));
880                                }
881            }
882            if (sizeString.length() > 0) {
883                int requiredSize = Integer.parseInt(sizeString);
884                if (stringArrays.size() != requiredSize)
885                    throw new IOException(
886                            "String array contains wrong element count.  "
887                            + "Specified size " + requiredSize
888                            + ", data contains " + stringArrays.size());
889            }
890            currentElem = (Element) currentElem.getParentNode();
891            return stringArrays.toArray(new String[0][]);
892        } catch (IOException ioe) {
893            throw ioe;
894        } catch (NumberFormatException nfe) {
895            IOException io = new IOException(nfe.toString());
896            io.initCause(nfe);
897            throw io;
898        } catch (DOMException de) {
899            IOException io = new IOException(de.toString());
900            io.initCause(de);
901            throw io;
902        }
903    }
904
905    public BitSet readBitSet(String name, BitSet defVal) throws IOException {
906        String tmpString = currentElem.getAttribute(name);
907        if (tmpString == null || tmpString.length() < 1) return defVal;
908        try {
909            BitSet set = new BitSet();
910            String[] strings = parseTokens(tmpString);
911            for (int i = 0; i < strings.length; i++) {
912                int isSet = Integer.parseInt(strings[i]);
913                if (isSet == 1) {
914                        set.set(i);
915                }
916            }
917            return set;
918        } catch (NumberFormatException nfe) {
919            IOException io = new IOException(nfe.toString());
920            io.initCause(nfe);
921            throw io;
922        } catch (DOMException de) {
923            IOException io = new IOException(de.toString());
924            io.initCause(de);
925            throw io;
926        }
927    }
928
929    public Savable readSavable(String name, Savable defVal) throws IOException {
930        Savable ret = defVal;
931        if (name != null && name.equals(""))
932            logger.warning("Reading Savable String with name \"\"?");
933        try {
934            Element tmpEl = null;
935            if (name != null) {
936                tmpEl = findChildElement(currentElem, name);
937                if (tmpEl == null) {
938                    return defVal;
939                }
940            } else if (isAtRoot) {
941                tmpEl = doc.getDocumentElement();
942                isAtRoot = false;
943            } else {
944                tmpEl = findFirstChildElement(currentElem);
945            }
946            currentElem = tmpEl;
947            ret = readSavableFromCurrentElem(defVal);
948            if (currentElem.getParentNode() instanceof Element) {
949                currentElem = (Element) currentElem.getParentNode();
950            } else {
951                currentElem = null;
952            }
953        } catch (IOException ioe) {
954            throw ioe;
955        } catch (Exception e) {
956            IOException io = new IOException(e.toString());
957            io.initCause(e);
958            throw io;
959        }
960        return ret;
961    }
962
963    private Savable readSavableFromCurrentElem(Savable defVal) throws
964            InstantiationException, ClassNotFoundException,
965            IOException, IllegalAccessException {
966        Savable ret = defVal;
967        Savable tmp = null;
968
969        if (currentElem == null || currentElem.getNodeName().equals("null")) {
970            return null;
971        }
972        String reference = currentElem.getAttribute("ref");
973        if (reference.length() > 0) {
974            ret = referencedSavables.get(reference);
975        } else {
976            String className = currentElem.getNodeName();
977            if (defVal != null) {
978                className = defVal.getClass().getName();
979            } else if (currentElem.hasAttribute("class")) {
980                className = currentElem.getAttribute("class");
981            }
982            tmp = SavableClassUtil.fromName(className, null);
983
984
985            String versionsStr = currentElem.getAttribute("savable_versions");
986            if (versionsStr != null && !versionsStr.equals("")){
987                String[] versionStr = versionsStr.split(",");
988                classHierarchyVersions = new int[versionStr.length];
989                for (int i = 0; i < classHierarchyVersions.length; i++){
990                    classHierarchyVersions[i] = Integer.parseInt(versionStr[i].trim());
991                }
992            }else{
993                classHierarchyVersions = null;
994            }
995
996            String refID = currentElem.getAttribute("reference_ID");
997            if (refID.length() < 1) refID = currentElem.getAttribute("id");
998            if (refID.length() > 0) referencedSavables.put(refID, tmp);
999            if (tmp != null) {
1000                // Allows reading versions from this savable
1001                savable = tmp;
1002                tmp.read(importer);
1003                ret = tmp;
1004            }
1005        }
1006        return ret;
1007    }
1008
1009    public Savable[] readSavableArray(String name, Savable[] defVal) throws IOException {
1010        Savable[] ret = defVal;
1011        try {
1012            Element tmpEl = findChildElement(currentElem, name);
1013            if (tmpEl == null) {
1014                return defVal;
1015            }
1016
1017            String sizeString = tmpEl.getAttribute("size");
1018            List<Savable> savables = new ArrayList<Savable>();
1019            for (currentElem = findFirstChildElement(tmpEl);
1020                    currentElem != null;
1021                    currentElem = findNextSiblingElement(currentElem)) {
1022                savables.add(readSavableFromCurrentElem(null));
1023            }
1024            if (sizeString.length() > 0) {
1025                int requiredSize = Integer.parseInt(sizeString);
1026                if (savables.size() != requiredSize)
1027                    throw new IOException("Wrong number of Savables for '"
1028                            + name + "'.  size says " + requiredSize
1029                            + ", data contains " + savables.size());
1030            }
1031            ret = savables.toArray(new Savable[0]);
1032            currentElem = (Element) tmpEl.getParentNode();
1033            return ret;
1034        } catch (IOException ioe) {
1035            throw ioe;
1036        } catch (Exception e) {
1037            IOException io = new IOException(e.toString());
1038            io.initCause(e);
1039            throw io;
1040        }
1041    }
1042
1043    public Savable[][] readSavableArray2D(String name, Savable[][] defVal) throws IOException {
1044        Savable[][] ret = defVal;
1045        try {
1046            Element tmpEl = findChildElement(currentElem, name);
1047            if (tmpEl == null) {
1048                return defVal;
1049            }
1050
1051            int size_outer = Integer.parseInt(tmpEl.getAttribute("size_outer"));
1052            int size_inner = Integer.parseInt(tmpEl.getAttribute("size_outer"));
1053
1054            Savable[][] tmp = new Savable[size_outer][size_inner];
1055            currentElem = findFirstChildElement(tmpEl);
1056            for (int i = 0; i < size_outer; i++) {
1057                for (int j = 0; j < size_inner; j++) {
1058                    tmp[i][j] = (readSavableFromCurrentElem(null));
1059                    if (i == size_outer - 1 && j == size_inner - 1) {
1060                        break;
1061                    }
1062                    currentElem = findNextSiblingElement(currentElem);
1063                }
1064            }
1065            ret = tmp;
1066            currentElem = (Element) tmpEl.getParentNode();
1067            return ret;
1068        } catch (IOException ioe) {
1069            throw ioe;
1070        } catch (Exception e) {
1071            IOException io = new IOException(e.toString());
1072            io.initCause(e);
1073            throw io;
1074        }
1075    }
1076
1077    public ArrayList<Savable> readSavableArrayList(String name, ArrayList defVal) throws IOException {
1078        try {
1079            Element tmpEl = findChildElement(currentElem, name);
1080            if (tmpEl == null) {
1081                return defVal;
1082            }
1083
1084            String sizeString = tmpEl.getAttribute("size");
1085            ArrayList<Savable> savables = new ArrayList<Savable>();
1086            for (currentElem = findFirstChildElement(tmpEl);
1087                    currentElem != null;
1088                    currentElem = findNextSiblingElement(currentElem)) {
1089                savables.add(readSavableFromCurrentElem(null));
1090            }
1091            if (sizeString.length() > 0) {
1092                int requiredSize = Integer.parseInt(sizeString);
1093                if (savables.size() != requiredSize)
1094                    throw new IOException(
1095                            "Wrong number of Savable arrays for '" + name
1096                            + "'.  size says " + requiredSize
1097                            + ", data contains " + savables.size());
1098            }
1099            currentElem = (Element) tmpEl.getParentNode();
1100            return savables;
1101        } catch (IOException ioe) {
1102            throw ioe;
1103        } catch (Exception e) {
1104            IOException io = new IOException(e.toString());
1105            io.initCause(e);
1106            throw io;
1107        }
1108    }
1109
1110    public ArrayList<Savable>[] readSavableArrayListArray(
1111            String name, ArrayList[] defVal) throws IOException {
1112        try {
1113            Element tmpEl = findChildElement(currentElem, name);
1114            if (tmpEl == null) {
1115                return defVal;
1116            }
1117            currentElem = tmpEl;
1118
1119            String sizeString = tmpEl.getAttribute("size");
1120            int requiredSize = (sizeString.length() > 0)
1121                             ? Integer.parseInt(sizeString)
1122                             : -1;
1123
1124            ArrayList<Savable> sal;
1125            List<ArrayList<Savable>> savableArrayLists =
1126                    new ArrayList<ArrayList<Savable>>();
1127            int i = -1;
1128            while (true) {
1129                sal = readSavableArrayList("SavableArrayList_" + ++i, null);
1130                if (sal == null && savableArrayLists.size() >= requiredSize)
1131                    break;
1132                savableArrayLists.add(sal);
1133            }
1134
1135            if (requiredSize > -1 && savableArrayLists.size() != requiredSize)
1136                throw new IOException(
1137                        "String array contains wrong element count.  "
1138                        + "Specified size " + requiredSize
1139                        + ", data contains " + savableArrayLists.size());
1140            currentElem = (Element) tmpEl.getParentNode();
1141            return savableArrayLists.toArray(new ArrayList[0]);
1142        } catch (IOException ioe) {
1143            throw ioe;
1144        } catch (NumberFormatException nfe) {
1145            IOException io = new IOException(nfe.toString());
1146            io.initCause(nfe);
1147            throw io;
1148        } catch (DOMException de) {
1149            IOException io = new IOException(de.toString());
1150            io.initCause(de);
1151            throw io;
1152        }
1153    }
1154
1155    public ArrayList<Savable>[][] readSavableArrayListArray2D(String name, ArrayList[][] defVal) throws IOException {
1156        try {
1157            Element tmpEl = findChildElement(currentElem, name);
1158            if (tmpEl == null) {
1159                return defVal;
1160            }
1161            currentElem = tmpEl;
1162            String sizeString = tmpEl.getAttribute("size");
1163
1164            ArrayList<Savable>[] arr;
1165            List<ArrayList<Savable>[]> sall = new ArrayList<ArrayList<Savable>[]>();
1166            int i = -1;
1167            while ((arr = readSavableArrayListArray(
1168                    "SavableArrayListArray_" + ++i, null)) != null) sall.add(arr);
1169            if (sizeString.length() > 0) {
1170                int requiredSize = Integer.parseInt(sizeString);
1171                if (sall.size() != requiredSize)
1172                    throw new IOException(
1173                            "String array contains wrong element count.  "
1174                            + "Specified size " + requiredSize
1175                            + ", data contains " + sall.size());
1176            }
1177            currentElem = (Element) tmpEl.getParentNode();
1178            return sall.toArray(new ArrayList[0][]);
1179        } catch (IOException ioe) {
1180            throw ioe;
1181        } catch (Exception e) {
1182            IOException io = new IOException(e.toString());
1183            io.initCause(e);
1184            throw io;
1185        }
1186    }
1187
1188    public ArrayList<FloatBuffer> readFloatBufferArrayList(
1189            String name, ArrayList<FloatBuffer> defVal) throws IOException {
1190        try {
1191            Element tmpEl = findChildElement(currentElem, name);
1192            if (tmpEl == null) {
1193                return defVal;
1194            }
1195
1196            String sizeString = tmpEl.getAttribute("size");
1197            ArrayList<FloatBuffer> tmp = new ArrayList<FloatBuffer>();
1198            for (currentElem = findFirstChildElement(tmpEl);
1199                    currentElem != null;
1200                    currentElem = findNextSiblingElement(currentElem)) {
1201                tmp.add(readFloatBuffer(null, null));
1202            }
1203            if (sizeString.length() > 0) {
1204                int requiredSize = Integer.parseInt(sizeString);
1205                if (tmp.size() != requiredSize)
1206                    throw new IOException(
1207                            "String array contains wrong element count.  "
1208                            + "Specified size " + requiredSize
1209                            + ", data contains " + tmp.size());
1210            }
1211            currentElem = (Element) tmpEl.getParentNode();
1212            return tmp;
1213        } catch (IOException ioe) {
1214            throw ioe;
1215        } catch (NumberFormatException nfe) {
1216            IOException io = new IOException(nfe.toString());
1217            io.initCause(nfe);
1218            throw io;
1219        } catch (DOMException de) {
1220            IOException io = new IOException(de.toString());
1221            io.initCause(de);
1222            throw io;
1223        }
1224    }
1225
1226    public Map<? extends Savable, ? extends Savable> readSavableMap(String name, Map<? extends Savable, ? extends Savable> defVal) throws IOException {
1227        Map<Savable, Savable> ret;
1228        Element tempEl;
1229
1230        if (name != null) {
1231                tempEl = findChildElement(currentElem, name);
1232        } else {
1233                tempEl = currentElem;
1234        }
1235        ret = new HashMap<Savable, Savable>();
1236
1237        NodeList nodes = tempEl.getChildNodes();
1238        for (int i = 0; i < nodes.getLength(); i++) {
1239                Node n = nodes.item(i);
1240            if (n instanceof Element && n.getNodeName().equals("MapEntry")) {
1241                Element elem = (Element) n;
1242                        currentElem = elem;
1243                        Savable key = readSavable(XMLExporter.ELEMENT_KEY, null);
1244                        Savable val = readSavable(XMLExporter.ELEMENT_VALUE, null);
1245                        ret.put(key, val);
1246                }
1247        }
1248        currentElem = (Element) tempEl.getParentNode();
1249        return ret;
1250    }
1251
1252    public Map<String, ? extends Savable> readStringSavableMap(String name, Map<String, ? extends Savable> defVal) throws IOException {
1253        Map<String, Savable> ret = null;
1254        Element tempEl;
1255
1256        if (name != null) {
1257                tempEl = findChildElement(currentElem, name);
1258        } else {
1259                tempEl = currentElem;
1260        }
1261        if (tempEl != null) {
1262                ret = new HashMap<String, Savable>();
1263
1264                NodeList nodes = tempEl.getChildNodes();
1265                    for (int i = 0; i < nodes.getLength(); i++) {
1266                                Node n = nodes.item(i);
1267                                if (n instanceof Element && n.getNodeName().equals("MapEntry")) {
1268                                        Element elem = (Element) n;
1269                                        currentElem = elem;
1270                                        String key = currentElem.getAttribute("key");
1271                                        Savable val = readSavable("Savable", null);
1272                                        ret.put(key, val);
1273                                }
1274                        }
1275        } else {
1276                return defVal;
1277            }
1278        currentElem = (Element) tempEl.getParentNode();
1279        return ret;
1280    }
1281
1282    public IntMap<? extends Savable> readIntSavableMap(String name, IntMap<? extends Savable> defVal) throws IOException {
1283        IntMap<Savable> ret = null;
1284        Element tempEl;
1285
1286        if (name != null) {
1287                tempEl = findChildElement(currentElem, name);
1288        } else {
1289                tempEl = currentElem;
1290        }
1291        if (tempEl != null) {
1292                ret = new IntMap<Savable>();
1293
1294                NodeList nodes = tempEl.getChildNodes();
1295                    for (int i = 0; i < nodes.getLength(); i++) {
1296                                Node n = nodes.item(i);
1297                                if (n instanceof Element && n.getNodeName().equals("MapEntry")) {
1298                                        Element elem = (Element) n;
1299                                        currentElem = elem;
1300                                        int key = Integer.parseInt(currentElem.getAttribute("key"));
1301                                        Savable val = readSavable("Savable", null);
1302                                        ret.put(key, val);
1303                                }
1304                        }
1305        } else {
1306                return defVal;
1307            }
1308        currentElem = (Element) tempEl.getParentNode();
1309        return ret;
1310    }
1311
1312    /**
1313     * reads from currentElem if name is null
1314     */
1315    public FloatBuffer readFloatBuffer(String name, FloatBuffer defVal) throws IOException {
1316        try {
1317            Element tmpEl;
1318            if (name != null) {
1319                tmpEl = findChildElement(currentElem, name);
1320            } else {
1321                tmpEl = currentElem;
1322            }
1323            if (tmpEl == null) {
1324                return defVal;
1325            }
1326            String sizeString = tmpEl.getAttribute("size");
1327            String[] strings = parseTokens(tmpEl.getAttribute("data"));
1328            if (sizeString.length() > 0) {
1329                int requiredSize = Integer.parseInt(sizeString);
1330                if (strings.length != requiredSize)
1331                    throw new IOException("Wrong number of float buffers for '"
1332                            + name + "'.  size says " + requiredSize
1333                            + ", data contains " + strings.length);
1334            }
1335            FloatBuffer tmp = BufferUtils.createFloatBuffer(strings.length);
1336            for (String s : strings) tmp.put(Float.parseFloat(s));
1337            tmp.flip();
1338            return tmp;
1339        } catch (IOException ioe) {
1340            throw ioe;
1341        } catch (NumberFormatException nfe) {
1342            IOException io = new IOException(nfe.toString());
1343            io.initCause(nfe);
1344            throw io;
1345        } catch (DOMException de) {
1346            IOException io = new IOException(de.toString());
1347            io.initCause(de);
1348            throw io;
1349        }
1350    }
1351
1352    public IntBuffer readIntBuffer(String name, IntBuffer defVal) throws IOException {
1353        try {
1354            Element tmpEl = findChildElement(currentElem, name);
1355            if (tmpEl == null) {
1356                return defVal;
1357            }
1358
1359            String sizeString = tmpEl.getAttribute("size");
1360            String[] strings = parseTokens(tmpEl.getAttribute("data"));
1361            if (sizeString.length() > 0) {
1362                int requiredSize = Integer.parseInt(sizeString);
1363                if (strings.length != requiredSize)
1364                    throw new IOException("Wrong number of int buffers for '"
1365                            + name + "'.  size says " + requiredSize
1366                            + ", data contains " + strings.length);
1367            }
1368            IntBuffer tmp = BufferUtils.createIntBuffer(strings.length);
1369            for (String s : strings) tmp.put(Integer.parseInt(s));
1370            tmp.flip();
1371            return tmp;
1372        } catch (IOException ioe) {
1373            throw ioe;
1374        } catch (NumberFormatException nfe) {
1375            IOException io = new IOException(nfe.toString());
1376            io.initCause(nfe);
1377            throw io;
1378        } catch (DOMException de) {
1379            IOException io = new IOException(de.toString());
1380            io.initCause(de);
1381            throw io;
1382        }
1383    }
1384
1385    public ByteBuffer readByteBuffer(String name, ByteBuffer defVal) throws IOException {
1386        try {
1387            Element tmpEl = findChildElement(currentElem, name);
1388            if (tmpEl == null) {
1389                return defVal;
1390            }
1391
1392            String sizeString = tmpEl.getAttribute("size");
1393            String[] strings = parseTokens(tmpEl.getAttribute("data"));
1394            if (sizeString.length() > 0) {
1395                int requiredSize = Integer.parseInt(sizeString);
1396                if (strings.length != requiredSize)
1397                    throw new IOException("Wrong number of byte buffers for '"
1398                            + name + "'.  size says " + requiredSize
1399                            + ", data contains " + strings.length);
1400            }
1401            ByteBuffer tmp = BufferUtils.createByteBuffer(strings.length);
1402            for (String s : strings) tmp.put(Byte.valueOf(s));
1403            tmp.flip();
1404            return tmp;
1405        } catch (IOException ioe) {
1406            throw ioe;
1407        } catch (NumberFormatException nfe) {
1408            IOException io = new IOException(nfe.toString());
1409            io.initCause(nfe);
1410            throw io;
1411        } catch (DOMException de) {
1412            IOException io = new IOException(de.toString());
1413            io.initCause(de);
1414            throw io;
1415        }
1416    }
1417
1418    public ShortBuffer readShortBuffer(String name, ShortBuffer defVal) throws IOException {
1419        try {
1420            Element tmpEl = findChildElement(currentElem, name);
1421            if (tmpEl == null) {
1422                return defVal;
1423            }
1424
1425            String sizeString = tmpEl.getAttribute("size");
1426            String[] strings = parseTokens(tmpEl.getAttribute("data"));
1427            if (sizeString.length() > 0) {
1428                int requiredSize = Integer.parseInt(sizeString);
1429                if (strings.length != requiredSize)
1430                    throw new IOException("Wrong number of short buffers for '"
1431                            + name + "'.  size says " + requiredSize
1432                            + ", data contains " + strings.length);
1433            }
1434            ShortBuffer tmp = BufferUtils.createShortBuffer(strings.length);
1435            for (String s : strings) tmp.put(Short.valueOf(s));
1436            tmp.flip();
1437            return tmp;
1438        } catch (IOException ioe) {
1439            throw ioe;
1440        } catch (NumberFormatException nfe) {
1441            IOException io = new IOException(nfe.toString());
1442            io.initCause(nfe);
1443            throw io;
1444        } catch (DOMException de) {
1445            IOException io = new IOException(de.toString());
1446            io.initCause(de);
1447            throw io;
1448        }
1449    }
1450
1451        public ArrayList<ByteBuffer> readByteBufferArrayList(String name, ArrayList<ByteBuffer> defVal) throws IOException {
1452        try {
1453            Element tmpEl = findChildElement(currentElem, name);
1454            if (tmpEl == null) {
1455                return defVal;
1456            }
1457
1458            String sizeString = tmpEl.getAttribute("size");
1459            ArrayList<ByteBuffer> tmp = new ArrayList<ByteBuffer>();
1460            for (currentElem = findFirstChildElement(tmpEl);
1461                    currentElem != null;
1462                    currentElem = findNextSiblingElement(currentElem)) {
1463                tmp.add(readByteBuffer(null, null));
1464            }
1465            if (sizeString.length() > 0) {
1466                int requiredSize = Integer.parseInt(sizeString);
1467                if (tmp.size() != requiredSize)
1468                    throw new IOException("Wrong number of short buffers for '"
1469                            + name + "'.  size says " + requiredSize
1470                            + ", data contains " + tmp.size());
1471            }
1472            currentElem = (Element) tmpEl.getParentNode();
1473            return tmp;
1474        } catch (IOException ioe) {
1475            throw ioe;
1476        } catch (NumberFormatException nfe) {
1477            IOException io = new IOException(nfe.toString());
1478            io.initCause(nfe);
1479            throw io;
1480        } catch (DOMException de) {
1481            IOException io = new IOException(de.toString());
1482            io.initCause(de);
1483            throw io;
1484        }
1485        }
1486
1487        public <T extends Enum<T>> T readEnum(String name, Class<T> enumType,
1488                        T defVal) throws IOException {
1489        T ret = defVal;
1490        try {
1491            String eVal = currentElem.getAttribute(name);
1492            if (eVal != null && eVal.length() > 0) {
1493                ret = Enum.valueOf(enumType, eVal);
1494            }
1495        } catch (Exception e) {
1496            IOException io = new IOException(e.toString());
1497            io.initCause(e);
1498            throw io;
1499        }
1500        return ret;
1501        }
1502
1503    private static final String[] zeroStrings = new String[0];
1504
1505    protected String[] parseTokens(String inString) {
1506        String[] outStrings = inString.split("\\s+");
1507        return (outStrings.length == 1 && outStrings[0].length() == 0)
1508               ? zeroStrings
1509               : outStrings;
1510    }
1511}