Home | History | Annotate | Download | only in xml
      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 
     33 package com.jme3.export.xml;
     34 
     35 import com.jme3.export.InputCapsule;
     36 import com.jme3.export.Savable;
     37 import com.jme3.export.SavableClassUtil;
     38 import com.jme3.util.BufferUtils;
     39 import com.jme3.util.IntMap;
     40 import java.io.IOException;
     41 import java.nio.ByteBuffer;
     42 import java.nio.FloatBuffer;
     43 import java.nio.IntBuffer;
     44 import java.nio.ShortBuffer;
     45 import java.util.*;
     46 import java.util.logging.Logger;
     47 import 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  */
     56 public 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 }