diff options
author | Scott Barta <sbarta@google.com> | 2012-03-01 12:35:35 -0800 |
---|---|---|
committer | Scott Barta <sbarta@google.com> | 2012-03-01 12:40:08 -0800 |
commit | 59b2e6871c65f58fdad78cd7229c292f6a177578 (patch) | |
tree | 2d4e7bfc05b93f40b34675d77e403dd1c25efafd /engine/src/xml | |
parent | f9b30489e75ac1eabc365064959804e99534f7ab (diff) | |
download | jmonkeyengine-59b2e6871c65f58fdad78cd7229c292f6a177578.tar.gz |
Adds the jMonkeyEngine library to the build.
Adds the jMonkeyEngine open source 3D game engine to the build. This
is built as a static library and is only used by the Finsky client.
Change-Id: I06a3f054df7b8a67757267d884854f70c5a16ca0
Diffstat (limited to 'engine/src/xml')
-rw-r--r-- | engine/src/xml/com/jme3/export/xml/DOMInputCapsule.java | 1511 | ||||
-rw-r--r-- | engine/src/xml/com/jme3/export/xml/DOMOutputCapsule.java | 825 | ||||
-rw-r--r-- | engine/src/xml/com/jme3/export/xml/DOMSerializer.java | 237 | ||||
-rw-r--r-- | engine/src/xml/com/jme3/export/xml/XMLExporter.java | 92 | ||||
-rw-r--r-- | engine/src/xml/com/jme3/export/xml/XMLImporter.java | 116 |
5 files changed, 2781 insertions, 0 deletions
diff --git a/engine/src/xml/com/jme3/export/xml/DOMInputCapsule.java b/engine/src/xml/com/jme3/export/xml/DOMInputCapsule.java new file mode 100644 index 0000000..c3be20a --- /dev/null +++ b/engine/src/xml/com/jme3/export/xml/DOMInputCapsule.java @@ -0,0 +1,1511 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.export.xml; + +import com.jme3.export.InputCapsule; +import com.jme3.export.Savable; +import com.jme3.export.SavableClassUtil; +import com.jme3.util.BufferUtils; +import com.jme3.util.IntMap; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.util.*; +import java.util.logging.Logger; +import org.w3c.dom.*; + +/** + * Part of the jME XML IO system as introduced in the google code jmexml project. + * + * @author Kai Rabien (hevee) - original author of the code.google.com jmexml project + * @author Doug Daniels (dougnukem) - adjustments for jME 2.0 and Java 1.5 + * @author blaine + */ +public class DOMInputCapsule implements InputCapsule { + private static final Logger logger = + Logger.getLogger(DOMInputCapsule.class .getName()); + + private Document doc; + private Element currentElem; + private XMLImporter importer; + private boolean isAtRoot = true; + private Map<String, Savable> referencedSavables = new HashMap<String, Savable>(); + + private int[] classHierarchyVersions; + private Savable savable; + + public DOMInputCapsule(Document doc, XMLImporter importer) { + this.doc = doc; + this.importer = importer; + currentElem = doc.getDocumentElement(); + + String version = currentElem.getAttribute("format_version"); + importer.formatVersion = version.equals("") ? 0 : Integer.parseInt(version); + } + + public int getSavableVersion(Class<? extends Savable> desiredClass) { + if (classHierarchyVersions != null){ + return SavableClassUtil.getSavedSavableVersion(savable, desiredClass, + classHierarchyVersions, importer.getFormatVersion()); + }else{ + return 0; + } + } + + private static String decodeString(String s) { + if (s == null) { + return null; + } + s = s.replaceAll("\\"", "\"").replaceAll("\\<", "<").replaceAll("\\&", "&"); + return s; + } + + private Element findFirstChildElement(Element parent) { + Node ret = parent.getFirstChild(); + while (ret != null && (!(ret instanceof Element))) { + ret = ret.getNextSibling(); + } + return (Element) ret; + } + + private Element findChildElement(Element parent, String name) { + if (parent == null) { + return null; + } + Node ret = parent.getFirstChild(); + while (ret != null && (!(ret instanceof Element) || !ret.getNodeName().equals(name))) { + ret = ret.getNextSibling(); + } + return (Element) ret; + } + + private Element findNextSiblingElement(Element current) { + Node ret = current.getNextSibling(); + while (ret != null) { + if (ret instanceof Element) { + return (Element) ret; + } + ret = ret.getNextSibling(); + } + return null; + } + + public byte readByte(String name, byte defVal) throws IOException { + String tmpString = currentElem.getAttribute(name); + if (tmpString == null || tmpString.length() < 1) return defVal; + try { + return Byte.parseByte(tmpString); + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public byte[] readByteArray(String name, byte[] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + String[] strings = parseTokens(tmpEl.getAttribute("data")); + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (strings.length != requiredSize) + throw new IOException("Wrong number of bytes for '" + name + + "'. size says " + requiredSize + + ", data contains " + + strings.length); + } + byte[] tmp = new byte[strings.length]; + for (int i = 0; i < strings.length; i++) { + tmp[i] = Byte.parseByte(strings[i]); + } + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public byte[][] readByteArray2D(String name, byte[][] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + + String sizeString = tmpEl.getAttribute("size"); + NodeList nodes = currentElem.getChildNodes(); + List<byte[]> byteArrays = new ArrayList<byte[]>(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.item(i); + if (n instanceof Element && n.getNodeName().contains("array")) { + // Very unsafe assumption + byteArrays.add(readByteArray(n.getNodeName(), null)); + } + } + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (byteArrays.size() != requiredSize) + throw new IOException( + "String array contains wrong element count. " + + "Specified size " + requiredSize + + ", data contains " + byteArrays.size()); + } + currentElem = (Element) currentElem.getParentNode(); + return byteArrays.toArray(new byte[0][]); + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public int readInt(String name, int defVal) throws IOException { + String tmpString = currentElem.getAttribute(name); + if (tmpString == null || tmpString.length() < 1) return defVal; + try { + return Integer.parseInt(tmpString); + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public int[] readIntArray(String name, int[] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + String[] strings = parseTokens(tmpEl.getAttribute("data")); + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (strings.length != requiredSize) + throw new IOException("Wrong number of ints for '" + name + + "'. size says " + requiredSize + + ", data contains " + strings.length); + } + int[] tmp = new int[strings.length]; + for (int i = 0; i < tmp.length; i++) { + tmp[i] = Integer.parseInt(strings[i]); + } + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public int[][] readIntArray2D(String name, int[][] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + + + + + NodeList nodes = currentElem.getChildNodes(); + List<int[]> intArrays = new ArrayList<int[]>(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.item(i); + if (n instanceof Element && n.getNodeName().contains("array")) { + // Very unsafe assumption + intArrays.add(readIntArray(n.getNodeName(), null)); + } + } + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (intArrays.size() != requiredSize) + throw new IOException( + "String array contains wrong element count. " + + "Specified size " + requiredSize + + ", data contains " + intArrays.size()); + } + currentElem = (Element) currentElem.getParentNode(); + return intArrays.toArray(new int[0][]); + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public float readFloat(String name, float defVal) throws IOException { + String tmpString = currentElem.getAttribute(name); + if (tmpString == null || tmpString.length() < 1) return defVal; + try { + return Float.parseFloat(tmpString); + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public float[] readFloatArray(String name, float[] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + String[] strings = parseTokens(tmpEl.getAttribute("data")); + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (strings.length != requiredSize) + throw new IOException("Wrong number of floats for '" + name + + "'. size says " + requiredSize + + ", data contains " + strings.length); + } + float[] tmp = new float[strings.length]; + for (int i = 0; i < tmp.length; i++) { + tmp[i] = Float.parseFloat(strings[i]); + } + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public float[][] readFloatArray2D(String name, float[][] defVal) throws IOException { + /* Why does this one method ignore the 'size attr.? */ + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + int size_outer = Integer.parseInt(tmpEl.getAttribute("size_outer")); + int size_inner = Integer.parseInt(tmpEl.getAttribute("size_outer")); + + float[][] tmp = new float[size_outer][size_inner]; + + String[] strings = parseTokens(tmpEl.getAttribute("data")); + for (int i = 0; i < size_outer; i++) { + tmp[i] = new float[size_inner]; + for (int k = 0; k < size_inner; k++) { + tmp[i][k] = Float.parseFloat(strings[i]); + } + } + return tmp; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public double readDouble(String name, double defVal) throws IOException { + String tmpString = currentElem.getAttribute(name); + if (tmpString == null || tmpString.length() < 1) return defVal; + try { + return Double.parseDouble(tmpString); + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public double[] readDoubleArray(String name, double[] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + String[] strings = parseTokens(tmpEl.getAttribute("data")); + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (strings.length != requiredSize) + throw new IOException("Wrong number of doubles for '" + + name + "'. size says " + requiredSize + + ", data contains " + strings.length); + } + double[] tmp = new double[strings.length]; + for (int i = 0; i < tmp.length; i++) { + tmp[i] = Double.parseDouble(strings[i]); + } + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public double[][] readDoubleArray2D(String name, double[][] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + NodeList nodes = currentElem.getChildNodes(); + List<double[]> doubleArrays = new ArrayList<double[]>(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.item(i); + if (n instanceof Element && n.getNodeName().contains("array")) { + // Very unsafe assumption + doubleArrays.add(readDoubleArray(n.getNodeName(), null)); + } + } + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (doubleArrays.size() != requiredSize) + throw new IOException( + "String array contains wrong element count. " + + "Specified size " + requiredSize + + ", data contains " + doubleArrays.size()); + } + currentElem = (Element) currentElem.getParentNode(); + return doubleArrays.toArray(new double[0][]); + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public long readLong(String name, long defVal) throws IOException { + String tmpString = currentElem.getAttribute(name); + if (tmpString == null || tmpString.length() < 1) return defVal; + try { + return Long.parseLong(tmpString); + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public long[] readLongArray(String name, long[] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + String[] strings = parseTokens(tmpEl.getAttribute("data")); + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (strings.length != requiredSize) + throw new IOException("Wrong number of longs for '" + name + + "'. size says " + requiredSize + + ", data contains " + strings.length); + } + long[] tmp = new long[strings.length]; + for (int i = 0; i < tmp.length; i++) { + tmp[i] = Long.parseLong(strings[i]); + } + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public long[][] readLongArray2D(String name, long[][] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + NodeList nodes = currentElem.getChildNodes(); + List<long[]> longArrays = new ArrayList<long[]>(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.item(i); + if (n instanceof Element && n.getNodeName().contains("array")) { + // Very unsafe assumption + longArrays.add(readLongArray(n.getNodeName(), null)); + } + } + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (longArrays.size() != requiredSize) + throw new IOException( + "String array contains wrong element count. " + + "Specified size " + requiredSize + + ", data contains " + longArrays.size()); + } + currentElem = (Element) currentElem.getParentNode(); + return longArrays.toArray(new long[0][]); + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public short readShort(String name, short defVal) throws IOException { + String tmpString = currentElem.getAttribute(name); + if (tmpString == null || tmpString.length() < 1) return defVal; + try { + return Short.parseShort(tmpString); + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public short[] readShortArray(String name, short[] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + String[] strings = parseTokens(tmpEl.getAttribute("data")); + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (strings.length != requiredSize) + throw new IOException("Wrong number of shorts for '" + + name + "'. size says " + requiredSize + + ", data contains " + strings.length); + } + short[] tmp = new short[strings.length]; + for (int i = 0; i < tmp.length; i++) { + tmp[i] = Short.parseShort(strings[i]); + } + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public short[][] readShortArray2D(String name, short[][] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + + String sizeString = tmpEl.getAttribute("size"); + NodeList nodes = currentElem.getChildNodes(); + List<short[]> shortArrays = new ArrayList<short[]>(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.item(i); + if (n instanceof Element && n.getNodeName().contains("array")) { + // Very unsafe assumption + shortArrays.add(readShortArray(n.getNodeName(), null)); + } + } + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (shortArrays.size() != requiredSize) + throw new IOException( + "String array contains wrong element count. " + + "Specified size " + requiredSize + + ", data contains " + shortArrays.size()); + } + currentElem = (Element) currentElem.getParentNode(); + return shortArrays.toArray(new short[0][]); + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public boolean readBoolean(String name, boolean defVal) throws IOException { + String tmpString = currentElem.getAttribute(name); + if (tmpString == null || tmpString.length() < 1) return defVal; + try { + return Boolean.parseBoolean(tmpString); + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public boolean[] readBooleanArray(String name, boolean[] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + String[] strings = parseTokens(tmpEl.getAttribute("data")); + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (strings.length != requiredSize) + throw new IOException("Wrong number of bools for '" + name + + "'. size says " + requiredSize + + ", data contains " + strings.length); + } + boolean[] tmp = new boolean[strings.length]; + for (int i = 0; i < tmp.length; i++) { + tmp[i] = Boolean.parseBoolean(strings[i]); + } + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public boolean[][] readBooleanArray2D(String name, boolean[][] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + NodeList nodes = currentElem.getChildNodes(); + List<boolean[]> booleanArrays = new ArrayList<boolean[]>(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.item(i); + if (n instanceof Element && n.getNodeName().contains("array")) { + // Very unsafe assumption + booleanArrays.add(readBooleanArray(n.getNodeName(), null)); + } + } + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (booleanArrays.size() != requiredSize) + throw new IOException( + "String array contains wrong element count. " + + "Specified size " + requiredSize + + ", data contains " + booleanArrays.size()); + } + currentElem = (Element) currentElem.getParentNode(); + return booleanArrays.toArray(new boolean[0][]); + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public String readString(String name, String defVal) throws IOException { + String tmpString = currentElem.getAttribute(name); + if (tmpString == null || tmpString.length() < 1) return defVal; + try { + return decodeString(tmpString); + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public String[] readStringArray(String name, String[] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + NodeList nodes = tmpEl.getChildNodes(); + List<String> strings = new ArrayList<String>(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.item(i); + if (n instanceof Element && n.getNodeName().contains("String")) { + // Very unsafe assumption + strings.add(((Element) n).getAttributeNode("value").getValue()); + } + } + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (strings.size() != requiredSize) + throw new IOException( + "String array contains wrong element count. " + + "Specified size " + requiredSize + + ", data contains " + strings.size()); + } + return strings.toArray(new String[0]); + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public String[][] readStringArray2D(String name, String[][] defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + NodeList nodes = currentElem.getChildNodes(); + List<String[]> stringArrays = new ArrayList<String[]>(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.item(i); + if (n instanceof Element && n.getNodeName().contains("array")) { + // Very unsafe assumption + stringArrays.add(readStringArray(n.getNodeName(), null)); + } + } + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (stringArrays.size() != requiredSize) + throw new IOException( + "String array contains wrong element count. " + + "Specified size " + requiredSize + + ", data contains " + stringArrays.size()); + } + currentElem = (Element) currentElem.getParentNode(); + return stringArrays.toArray(new String[0][]); + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public BitSet readBitSet(String name, BitSet defVal) throws IOException { + String tmpString = currentElem.getAttribute(name); + if (tmpString == null || tmpString.length() < 1) return defVal; + try { + BitSet set = new BitSet(); + String[] strings = parseTokens(tmpString); + for (int i = 0; i < strings.length; i++) { + int isSet = Integer.parseInt(strings[i]); + if (isSet == 1) { + set.set(i); + } + } + return set; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public Savable readSavable(String name, Savable defVal) throws IOException { + Savable ret = defVal; + if (name != null && name.equals("")) + logger.warning("Reading Savable String with name \"\"?"); + try { + Element tmpEl = null; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + if (tmpEl == null) { + return defVal; + } + } else if (isAtRoot) { + tmpEl = doc.getDocumentElement(); + isAtRoot = false; + } else { + tmpEl = findFirstChildElement(currentElem); + } + currentElem = tmpEl; + ret = readSavableFromCurrentElem(defVal); + if (currentElem.getParentNode() instanceof Element) { + currentElem = (Element) currentElem.getParentNode(); + } else { + currentElem = null; + } + } catch (IOException ioe) { + throw ioe; + } catch (Exception e) { + IOException io = new IOException(e.toString()); + io.initCause(e); + throw io; + } + return ret; + } + + private Savable readSavableFromCurrentElem(Savable defVal) throws + InstantiationException, ClassNotFoundException, + IOException, IllegalAccessException { + Savable ret = defVal; + Savable tmp = null; + + if (currentElem == null || currentElem.getNodeName().equals("null")) { + return null; + } + String reference = currentElem.getAttribute("ref"); + if (reference.length() > 0) { + ret = referencedSavables.get(reference); + } else { + String className = currentElem.getNodeName(); + if (defVal != null) { + className = defVal.getClass().getName(); + } else if (currentElem.hasAttribute("class")) { + className = currentElem.getAttribute("class"); + } + tmp = SavableClassUtil.fromName(className, null); + + + String versionsStr = currentElem.getAttribute("savable_versions"); + if (versionsStr != null && !versionsStr.equals("")){ + String[] versionStr = versionsStr.split(","); + classHierarchyVersions = new int[versionStr.length]; + for (int i = 0; i < classHierarchyVersions.length; i++){ + classHierarchyVersions[i] = Integer.parseInt(versionStr[i].trim()); + } + }else{ + classHierarchyVersions = null; + } + + String refID = currentElem.getAttribute("reference_ID"); + if (refID.length() < 1) refID = currentElem.getAttribute("id"); + if (refID.length() > 0) referencedSavables.put(refID, tmp); + if (tmp != null) { + // Allows reading versions from this savable + savable = tmp; + tmp.read(importer); + ret = tmp; + } + } + return ret; + } + + public Savable[] readSavableArray(String name, Savable[] defVal) throws IOException { + Savable[] ret = defVal; + try { + Element tmpEl = findChildElement(currentElem, name); + if (tmpEl == null) { + return defVal; + } + + String sizeString = tmpEl.getAttribute("size"); + List<Savable> savables = new ArrayList<Savable>(); + for (currentElem = findFirstChildElement(tmpEl); + currentElem != null; + currentElem = findNextSiblingElement(currentElem)) { + savables.add(readSavableFromCurrentElem(null)); + } + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (savables.size() != requiredSize) + throw new IOException("Wrong number of Savables for '" + + name + "'. size says " + requiredSize + + ", data contains " + savables.size()); + } + ret = savables.toArray(new Savable[0]); + currentElem = (Element) tmpEl.getParentNode(); + return ret; + } catch (IOException ioe) { + throw ioe; + } catch (Exception e) { + IOException io = new IOException(e.toString()); + io.initCause(e); + throw io; + } + } + + public Savable[][] readSavableArray2D(String name, Savable[][] defVal) throws IOException { + Savable[][] ret = defVal; + try { + Element tmpEl = findChildElement(currentElem, name); + if (tmpEl == null) { + return defVal; + } + + int size_outer = Integer.parseInt(tmpEl.getAttribute("size_outer")); + int size_inner = Integer.parseInt(tmpEl.getAttribute("size_outer")); + + Savable[][] tmp = new Savable[size_outer][size_inner]; + currentElem = findFirstChildElement(tmpEl); + for (int i = 0; i < size_outer; i++) { + for (int j = 0; j < size_inner; j++) { + tmp[i][j] = (readSavableFromCurrentElem(null)); + if (i == size_outer - 1 && j == size_inner - 1) { + break; + } + currentElem = findNextSiblingElement(currentElem); + } + } + ret = tmp; + currentElem = (Element) tmpEl.getParentNode(); + return ret; + } catch (IOException ioe) { + throw ioe; + } catch (Exception e) { + IOException io = new IOException(e.toString()); + io.initCause(e); + throw io; + } + } + + public ArrayList<Savable> readSavableArrayList(String name, ArrayList defVal) throws IOException { + try { + Element tmpEl = findChildElement(currentElem, name); + if (tmpEl == null) { + return defVal; + } + + String sizeString = tmpEl.getAttribute("size"); + ArrayList<Savable> savables = new ArrayList<Savable>(); + for (currentElem = findFirstChildElement(tmpEl); + currentElem != null; + currentElem = findNextSiblingElement(currentElem)) { + savables.add(readSavableFromCurrentElem(null)); + } + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (savables.size() != requiredSize) + throw new IOException( + "Wrong number of Savable arrays for '" + name + + "'. size says " + requiredSize + + ", data contains " + savables.size()); + } + currentElem = (Element) tmpEl.getParentNode(); + return savables; + } catch (IOException ioe) { + throw ioe; + } catch (Exception e) { + IOException io = new IOException(e.toString()); + io.initCause(e); + throw io; + } + } + + public ArrayList<Savable>[] readSavableArrayListArray( + String name, ArrayList[] defVal) throws IOException { + try { + Element tmpEl = findChildElement(currentElem, name); + if (tmpEl == null) { + return defVal; + } + currentElem = tmpEl; + + String sizeString = tmpEl.getAttribute("size"); + int requiredSize = (sizeString.length() > 0) + ? Integer.parseInt(sizeString) + : -1; + + ArrayList<Savable> sal; + List<ArrayList<Savable>> savableArrayLists = + new ArrayList<ArrayList<Savable>>(); + int i = -1; + while (true) { + sal = readSavableArrayList("SavableArrayList_" + ++i, null); + if (sal == null && savableArrayLists.size() >= requiredSize) + break; + savableArrayLists.add(sal); + } + + if (requiredSize > -1 && savableArrayLists.size() != requiredSize) + throw new IOException( + "String array contains wrong element count. " + + "Specified size " + requiredSize + + ", data contains " + savableArrayLists.size()); + currentElem = (Element) tmpEl.getParentNode(); + return savableArrayLists.toArray(new ArrayList[0]); + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public ArrayList<Savable>[][] readSavableArrayListArray2D(String name, ArrayList[][] defVal) throws IOException { + try { + Element tmpEl = findChildElement(currentElem, name); + if (tmpEl == null) { + return defVal; + } + currentElem = tmpEl; + String sizeString = tmpEl.getAttribute("size"); + + ArrayList<Savable>[] arr; + List<ArrayList<Savable>[]> sall = new ArrayList<ArrayList<Savable>[]>(); + int i = -1; + while ((arr = readSavableArrayListArray( + "SavableArrayListArray_" + ++i, null)) != null) sall.add(arr); + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (sall.size() != requiredSize) + throw new IOException( + "String array contains wrong element count. " + + "Specified size " + requiredSize + + ", data contains " + sall.size()); + } + currentElem = (Element) tmpEl.getParentNode(); + return sall.toArray(new ArrayList[0][]); + } catch (IOException ioe) { + throw ioe; + } catch (Exception e) { + IOException io = new IOException(e.toString()); + io.initCause(e); + throw io; + } + } + + public ArrayList<FloatBuffer> readFloatBufferArrayList( + String name, ArrayList<FloatBuffer> defVal) throws IOException { + try { + Element tmpEl = findChildElement(currentElem, name); + if (tmpEl == null) { + return defVal; + } + + String sizeString = tmpEl.getAttribute("size"); + ArrayList<FloatBuffer> tmp = new ArrayList<FloatBuffer>(); + for (currentElem = findFirstChildElement(tmpEl); + currentElem != null; + currentElem = findNextSiblingElement(currentElem)) { + tmp.add(readFloatBuffer(null, null)); + } + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (tmp.size() != requiredSize) + throw new IOException( + "String array contains wrong element count. " + + "Specified size " + requiredSize + + ", data contains " + tmp.size()); + } + currentElem = (Element) tmpEl.getParentNode(); + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public Map<? extends Savable, ? extends Savable> readSavableMap(String name, Map<? extends Savable, ? extends Savable> defVal) throws IOException { + Map<Savable, Savable> ret; + Element tempEl; + + if (name != null) { + tempEl = findChildElement(currentElem, name); + } else { + tempEl = currentElem; + } + ret = new HashMap<Savable, Savable>(); + + NodeList nodes = tempEl.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.item(i); + if (n instanceof Element && n.getNodeName().equals("MapEntry")) { + Element elem = (Element) n; + currentElem = elem; + Savable key = readSavable(XMLExporter.ELEMENT_KEY, null); + Savable val = readSavable(XMLExporter.ELEMENT_VALUE, null); + ret.put(key, val); + } + } + currentElem = (Element) tempEl.getParentNode(); + return ret; + } + + public Map<String, ? extends Savable> readStringSavableMap(String name, Map<String, ? extends Savable> defVal) throws IOException { + Map<String, Savable> ret = null; + Element tempEl; + + if (name != null) { + tempEl = findChildElement(currentElem, name); + } else { + tempEl = currentElem; + } + if (tempEl != null) { + ret = new HashMap<String, Savable>(); + + NodeList nodes = tempEl.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.item(i); + if (n instanceof Element && n.getNodeName().equals("MapEntry")) { + Element elem = (Element) n; + currentElem = elem; + String key = currentElem.getAttribute("key"); + Savable val = readSavable("Savable", null); + ret.put(key, val); + } + } + } else { + return defVal; + } + currentElem = (Element) tempEl.getParentNode(); + return ret; + } + + public IntMap<? extends Savable> readIntSavableMap(String name, IntMap<? extends Savable> defVal) throws IOException { + IntMap<Savable> ret = null; + Element tempEl; + + if (name != null) { + tempEl = findChildElement(currentElem, name); + } else { + tempEl = currentElem; + } + if (tempEl != null) { + ret = new IntMap<Savable>(); + + NodeList nodes = tempEl.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.item(i); + if (n instanceof Element && n.getNodeName().equals("MapEntry")) { + Element elem = (Element) n; + currentElem = elem; + int key = Integer.parseInt(currentElem.getAttribute("key")); + Savable val = readSavable("Savable", null); + ret.put(key, val); + } + } + } else { + return defVal; + } + currentElem = (Element) tempEl.getParentNode(); + return ret; + } + + /** + * reads from currentElem if name is null + */ + public FloatBuffer readFloatBuffer(String name, FloatBuffer defVal) throws IOException { + try { + Element tmpEl; + if (name != null) { + tmpEl = findChildElement(currentElem, name); + } else { + tmpEl = currentElem; + } + if (tmpEl == null) { + return defVal; + } + String sizeString = tmpEl.getAttribute("size"); + String[] strings = parseTokens(tmpEl.getAttribute("data")); + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (strings.length != requiredSize) + throw new IOException("Wrong number of float buffers for '" + + name + "'. size says " + requiredSize + + ", data contains " + strings.length); + } + FloatBuffer tmp = BufferUtils.createFloatBuffer(strings.length); + for (String s : strings) tmp.put(Float.parseFloat(s)); + tmp.flip(); + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public IntBuffer readIntBuffer(String name, IntBuffer defVal) throws IOException { + try { + Element tmpEl = findChildElement(currentElem, name); + if (tmpEl == null) { + return defVal; + } + + String sizeString = tmpEl.getAttribute("size"); + String[] strings = parseTokens(tmpEl.getAttribute("data")); + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (strings.length != requiredSize) + throw new IOException("Wrong number of int buffers for '" + + name + "'. size says " + requiredSize + + ", data contains " + strings.length); + } + IntBuffer tmp = BufferUtils.createIntBuffer(strings.length); + for (String s : strings) tmp.put(Integer.parseInt(s)); + tmp.flip(); + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public ByteBuffer readByteBuffer(String name, ByteBuffer defVal) throws IOException { + try { + Element tmpEl = findChildElement(currentElem, name); + if (tmpEl == null) { + return defVal; + } + + String sizeString = tmpEl.getAttribute("size"); + String[] strings = parseTokens(tmpEl.getAttribute("data")); + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (strings.length != requiredSize) + throw new IOException("Wrong number of byte buffers for '" + + name + "'. size says " + requiredSize + + ", data contains " + strings.length); + } + ByteBuffer tmp = BufferUtils.createByteBuffer(strings.length); + for (String s : strings) tmp.put(Byte.valueOf(s)); + tmp.flip(); + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public ShortBuffer readShortBuffer(String name, ShortBuffer defVal) throws IOException { + try { + Element tmpEl = findChildElement(currentElem, name); + if (tmpEl == null) { + return defVal; + } + + String sizeString = tmpEl.getAttribute("size"); + String[] strings = parseTokens(tmpEl.getAttribute("data")); + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (strings.length != requiredSize) + throw new IOException("Wrong number of short buffers for '" + + name + "'. size says " + requiredSize + + ", data contains " + strings.length); + } + ShortBuffer tmp = BufferUtils.createShortBuffer(strings.length); + for (String s : strings) tmp.put(Short.valueOf(s)); + tmp.flip(); + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public ArrayList<ByteBuffer> readByteBufferArrayList(String name, ArrayList<ByteBuffer> defVal) throws IOException { + try { + Element tmpEl = findChildElement(currentElem, name); + if (tmpEl == null) { + return defVal; + } + + String sizeString = tmpEl.getAttribute("size"); + ArrayList<ByteBuffer> tmp = new ArrayList<ByteBuffer>(); + for (currentElem = findFirstChildElement(tmpEl); + currentElem != null; + currentElem = findNextSiblingElement(currentElem)) { + tmp.add(readByteBuffer(null, null)); + } + if (sizeString.length() > 0) { + int requiredSize = Integer.parseInt(sizeString); + if (tmp.size() != requiredSize) + throw new IOException("Wrong number of short buffers for '" + + name + "'. size says " + requiredSize + + ", data contains " + tmp.size()); + } + currentElem = (Element) tmpEl.getParentNode(); + return tmp; + } catch (IOException ioe) { + throw ioe; + } catch (NumberFormatException nfe) { + IOException io = new IOException(nfe.toString()); + io.initCause(nfe); + throw io; + } catch (DOMException de) { + IOException io = new IOException(de.toString()); + io.initCause(de); + throw io; + } + } + + public <T extends Enum<T>> T readEnum(String name, Class<T> enumType, + T defVal) throws IOException { + T ret = defVal; + try { + String eVal = currentElem.getAttribute(name); + if (eVal != null && eVal.length() > 0) { + ret = Enum.valueOf(enumType, eVal); + } + } catch (Exception e) { + IOException io = new IOException(e.toString()); + io.initCause(e); + throw io; + } + return ret; + } + + private static final String[] zeroStrings = new String[0]; + + protected String[] parseTokens(String inString) { + String[] outStrings = inString.split("\\s+"); + return (outStrings.length == 1 && outStrings[0].length() == 0) + ? zeroStrings + : outStrings; + } +}
\ No newline at end of file diff --git a/engine/src/xml/com/jme3/export/xml/DOMOutputCapsule.java b/engine/src/xml/com/jme3/export/xml/DOMOutputCapsule.java new file mode 100644 index 0000000..2baef1f --- /dev/null +++ b/engine/src/xml/com/jme3/export/xml/DOMOutputCapsule.java @@ -0,0 +1,825 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.export.xml; + +import com.jme3.export.FormatVersion; +import com.jme3.export.JmeExporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import com.jme3.export.SavableClassUtil; +import com.jme3.util.IntMap; +import com.jme3.util.IntMap.Entry; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.util.*; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Part of the jME XML IO system as introduced in the google code jmexml project. + * + * @author Kai Rabien (hevee) - original author of the code.google.com jmexml project + * @author Doug Daniels (dougnukem) - adjustments for jME 2.0 and Java 1.5 + */ +public class DOMOutputCapsule implements OutputCapsule { + + private static final String dataAttributeName = "data"; + private Document doc; + private Element currentElement; + private JmeExporter exporter; + private Map<Savable, Element> writtenSavables = new IdentityHashMap<Savable, Element>(); + + public DOMOutputCapsule(Document doc, JmeExporter exporter) { + this.doc = doc; + this.exporter = exporter; + currentElement = null; + } + + public Document getDoc() { + return doc; + } + + /** + * appends a new Element with the given name to currentElement, sets + * currentElement to be new Element, and returns the new Element as well + */ + private Element appendElement(String name) { + Element ret = doc.createElement(name); + if (currentElement == null) { + ret.setAttribute("format_version", Integer.toString(FormatVersion.VERSION)); + doc.appendChild(ret); + } else { + currentElement.appendChild(ret); + } + currentElement = ret; + return ret; + } + + private static String encodeString(String s) { + if (s == null) { + return null; + } + s = s.replaceAll("\\&", "&") + .replaceAll("\\\"", """) + .replaceAll("\\<", "<"); + return s; + } + + public void write(byte value, String name, byte defVal) throws IOException { + if (value == defVal) { + return; + } + currentElement.setAttribute(name, String.valueOf(value)); + } + + public void write(byte[] value, String name, byte[] defVal) throws IOException { + StringBuilder buf = new StringBuilder(); + if (value == null) { + value = defVal; + } + for (byte b : value) { + buf.append(b); + buf.append(" "); + } + //remove last space + buf.setLength(buf.length() - 1); + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.length)); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) currentElement.getParentNode(); + } + + public void write(byte[][] value, String name, byte[][] defVal) throws IOException { + StringBuilder buf = new StringBuilder(); + if (value == null) { + value = defVal; + } + for (byte[] bs : value) { + for (byte b : bs) { + buf.append(b); + buf.append(" "); + } + buf.append(" "); + } + //remove last spaces + buf.setLength(buf.length() - 2); + + Element el = appendElement(name); + el.setAttribute("size_outer", String.valueOf(value.length)); + el.setAttribute("size_inner", String.valueOf(value[0].length)); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) currentElement.getParentNode(); + } + + public void write(int value, String name, int defVal) throws IOException { + if (value == defVal) { + return; + } + currentElement.setAttribute(name, String.valueOf(value)); + } + + public void write(int[] value, String name, int[] defVal) throws IOException { + StringBuilder buf = new StringBuilder(); + if (value == null) { return; } + if (Arrays.equals(value, defVal)) { return; } + + for (int b : value) { + buf.append(b); + buf.append(" "); + } + //remove last space + buf.setLength(Math.max(0, buf.length() - 1)); + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.length)); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) currentElement.getParentNode(); + } + + public void write(int[][] value, String name, int[][] defVal) throws IOException { + if (value == null) return; + if(Arrays.deepEquals(value, defVal)) return; + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.length)); + + for (int i=0; i<value.length; i++) { + int[] array = value[i]; + write(array, "array_"+i, defVal==null?null:defVal[i]); + } + currentElement = (Element) el.getParentNode(); + } + + public void write(float value, String name, float defVal) throws IOException { + if (value == defVal) { + return; + } + currentElement.setAttribute(name, String.valueOf(value)); + } + + public void write(float[] value, String name, float[] defVal) throws IOException { + StringBuilder buf = new StringBuilder(); + if (value == null) { + value = defVal; + } + if (value != null) { + for (float b : value) { + buf.append(b); + buf.append(" "); + } + //remove last space + buf.setLength(buf.length() - 1); + } + + Element el = appendElement(name); + el.setAttribute("size", value == null ? "0" : String.valueOf(value.length)); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) currentElement.getParentNode(); + } + + public void write(float[][] value, String name, float[][] defVal) throws IOException { + StringBuilder buf = new StringBuilder(); + if (value == null) return; + if(Arrays.deepEquals(value, defVal)) return; + + for (float[] bs : value) { + for(float b : bs){ + buf.append(b); + buf.append(" "); + } + } + //remove last space + buf.setLength(buf.length() - 1); + + Element el = appendElement(name); + el.setAttribute("size_outer", String.valueOf(value.length)); + el.setAttribute("size_inner", String.valueOf(value[0].length)); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) currentElement.getParentNode(); + } + + public void write(double value, String name, double defVal) throws IOException { + if (value == defVal) { + return; + } + currentElement.setAttribute(name, String.valueOf(value)); + } + + public void write(double[] value, String name, double[] defVal) throws IOException { + StringBuilder buf = new StringBuilder(); + if (value == null) { + value = defVal; + } + for (double b : value) { + buf.append(b); + buf.append(" "); + } + //remove last space + buf.setLength(buf.length() - 1); + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.length)); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) currentElement.getParentNode(); + } + + public void write(double[][] value, String name, double[][] defVal) throws IOException { + if (value == null) return; + if(Arrays.deepEquals(value, defVal)) return; + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.length)); + + for (int i=0; i<value.length; i++) { + double[] array = value[i]; + write(array, "array_"+i, defVal==null?null:defVal[i]); + } + currentElement = (Element) el.getParentNode(); + } + + public void write(long value, String name, long defVal) throws IOException { + if (value == defVal) { + return; + } + currentElement.setAttribute(name, String.valueOf(value)); + } + + public void write(long[] value, String name, long[] defVal) throws IOException { + StringBuilder buf = new StringBuilder(); + if (value == null) { + value = defVal; + } + for (long b : value) { + buf.append(b); + buf.append(" "); + } + //remove last space + buf.setLength(buf.length() - 1); + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.length)); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) currentElement.getParentNode(); + } + + public void write(long[][] value, String name, long[][] defVal) throws IOException { + if (value == null) return; + if(Arrays.deepEquals(value, defVal)) return; + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.length)); + + for (int i=0; i<value.length; i++) { + long[] array = value[i]; + write(array, "array_"+i, defVal==null?null:defVal[i]); + } + currentElement = (Element) el.getParentNode(); + } + + public void write(short value, String name, short defVal) throws IOException { + if (value == defVal) { + return; + } + currentElement.setAttribute(name, String.valueOf(value)); + } + + public void write(short[] value, String name, short[] defVal) throws IOException { + StringBuilder buf = new StringBuilder(); + if (value == null) { + value = defVal; + } + for (short b : value) { + buf.append(b); + buf.append(" "); + } + //remove last space + buf.setLength(buf.length() - 1); + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.length)); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) currentElement.getParentNode(); + } + + public void write(short[][] value, String name, short[][] defVal) throws IOException { + if (value == null) return; + if(Arrays.deepEquals(value, defVal)) return; + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.length)); + + for (int i=0; i<value.length; i++) { + short[] array = value[i]; + write(array, "array_"+i, defVal==null?null:defVal[i]); + } + currentElement = (Element) el.getParentNode(); + } + + public void write(boolean value, String name, boolean defVal) throws IOException { + if (value == defVal) { + return; + } + currentElement.setAttribute(name, String.valueOf(value)); + } + + public void write(boolean[] value, String name, boolean[] defVal) throws IOException { + StringBuilder buf = new StringBuilder(); + if (value == null) { + value = defVal; + } + for (boolean b : value) { + buf.append(b); + buf.append(" "); + } + //remove last space + buf.setLength(Math.max(0, buf.length() - 1)); + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.length)); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) currentElement.getParentNode(); + } + + public void write(boolean[][] value, String name, boolean[][] defVal) throws IOException { + if (value == null) return; + if(Arrays.deepEquals(value, defVal)) return; + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.length)); + + for (int i=0; i<value.length; i++) { + boolean[] array = value[i]; + write(array, "array_"+i, defVal==null?null:defVal[i]); + } + currentElement = (Element) el.getParentNode(); + } + + public void write(String value, String name, String defVal) throws IOException { + if (value == null || value.equals(defVal)) { + return; + } + currentElement.setAttribute(name, encodeString(value)); + } + + public void write(String[] value, String name, String[] defVal) throws IOException { + Element el = appendElement(name); + + if (value == null) { + value = defVal; + } + + el.setAttribute("size", String.valueOf(value.length)); + + for (int i=0; i<value.length; i++) { + String b = value[i]; + appendElement("String_"+i); + String val = encodeString(b); + currentElement.setAttribute("value", val); + currentElement = el; + } + currentElement = (Element) currentElement.getParentNode(); + } + + public void write(String[][] value, String name, String[][] defVal) throws IOException { + if (value == null) return; + if(Arrays.deepEquals(value, defVal)) return; + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.length)); + + for (int i=0; i<value.length; i++) { + String[] array = value[i]; + write(array, "array_"+i, defVal==null?null:defVal[i]); + } + currentElement = (Element) el.getParentNode(); + } + + public void write(BitSet value, String name, BitSet defVal) throws IOException { + if (value == null || value.equals(defVal)) { + return; + } + StringBuilder buf = new StringBuilder(); + for (int i = value.nextSetBit(0); i >= 0; i = value.nextSetBit(i + 1)) { + buf.append(i); + buf.append(" "); + } + buf.setLength(Math.max(0, buf.length() - 1)); + currentElement.setAttribute(name, buf.toString()); + + } + + public void write(Savable object, String name, Savable defVal) throws IOException { + if (object == null) { + return; + } + if (object.equals(defVal)) { + return; + } + + Element old = currentElement; + Element el = writtenSavables.get(object); + + String className = null; + if(!object.getClass().getName().equals(name)){ + className = object.getClass().getName(); + } + try { + doc.createElement(name); + } catch (DOMException e) { + // Ridiculous fallback behavior. + // Would be far better to throw than to totally disregard the + // specified "name" and write a class name instead! + // (Besides the fact we are clobbering the managed .getClassTag()). + name = "Object"; + className = object.getClass().getName(); + } + + if (el != null) { + String refID = el.getAttribute("reference_ID"); + if (refID.length() == 0) { + refID = object.getClass().getName() + "@" + object.hashCode(); + el.setAttribute("reference_ID", refID); + } + el = appendElement(name); + el.setAttribute("ref", refID); + } else { + el = appendElement(name); + + // jME3 NEW: Append version number(s) + int[] versions = SavableClassUtil.getSavableVersions(object.getClass()); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < versions.length; i++){ + sb.append(versions[i]); + if (i != versions.length - 1){ + sb.append(", "); + } + } + el.setAttribute("savable_versions", sb.toString()); + + writtenSavables.put(object, el); + object.write(exporter); + } + if(className != null){ + el.setAttribute("class", className); + } + + currentElement = old; + } + + public void write(Savable[] objects, String name, Savable[] defVal) throws IOException { + if (objects == null) { + return; + } + if (Arrays.equals(objects, defVal)) { + return; + } + + Element old = currentElement; + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(objects.length)); + for (int i = 0; i < objects.length; i++) { + Savable o = objects[i]; + if(o == null){ + //renderStateList has special loading code, so we can leave out the null values + if(!name.equals("renderStateList")){ + Element before = currentElement; + appendElement("null"); + currentElement = before; + } + }else{ + write(o, o.getClass().getName(), null); + } + } + currentElement = old; + } + + public void write(Savable[][] value, String name, Savable[][] defVal) throws IOException { + if (value == null) return; + if(Arrays.deepEquals(value, defVal)) return; + + Element el = appendElement(name); + el.setAttribute("size_outer", String.valueOf(value.length)); + el.setAttribute("size_inner", String.valueOf(value[0].length)); + for (Savable[] bs : value) { + for(Savable b : bs){ + write(b, b.getClass().getSimpleName(), null); + } + } + currentElement = (Element) currentElement.getParentNode(); + } + + public void writeSavableArrayList(ArrayList array, String name, ArrayList defVal) throws IOException { + if (array == null) { + return; + } + if (array.equals(defVal)) { + return; + } + Element old = currentElement; + Element el = appendElement(name); + currentElement = el; + el.setAttribute(XMLExporter.ATTRIBUTE_SIZE, String.valueOf(array.size())); + for (Object o : array) { + if(o == null) { + continue; + } + else if (o instanceof Savable) { + Savable s = (Savable) o; + write(s, s.getClass().getName(), null); + } else { + throw new ClassCastException("Not a Savable instance: " + o); + } + } + currentElement = old; + } + + public void writeSavableArrayListArray(ArrayList[] objects, String name, ArrayList[] defVal) throws IOException { + if (objects == null) {return;} + if (Arrays.equals(objects, defVal)) {return;} + + Element old = currentElement; + Element el = appendElement(name); + el.setAttribute(XMLExporter.ATTRIBUTE_SIZE, String.valueOf(objects.length)); + for (int i = 0; i < objects.length; i++) { + ArrayList o = objects[i]; + if(o == null){ + Element before = currentElement; + appendElement("null"); + currentElement = before; + }else{ + StringBuilder buf = new StringBuilder("SavableArrayList_"); + buf.append(i); + writeSavableArrayList(o, buf.toString(), null); + } + } + currentElement = old; + } + + public void writeSavableArrayListArray2D(ArrayList[][] value, String name, ArrayList[][] defVal) throws IOException { + if (value == null) return; + if(Arrays.deepEquals(value, defVal)) return; + + Element el = appendElement(name); + int size = value.length; + el.setAttribute(XMLExporter.ATTRIBUTE_SIZE, String.valueOf(size)); + + for (int i=0; i< size; i++) { + ArrayList[] vi = value[i]; + writeSavableArrayListArray(vi, "SavableArrayListArray_"+i, null); + } + currentElement = (Element) el.getParentNode(); + } + + public void writeFloatBufferArrayList(ArrayList<FloatBuffer> array, String name, ArrayList<FloatBuffer> defVal) throws IOException { + if (array == null) { + return; + } + if (array.equals(defVal)) { + return; + } + Element el = appendElement(name); + el.setAttribute(XMLExporter.ATTRIBUTE_SIZE, String.valueOf(array.size())); + for (FloatBuffer o : array) { + write(o, XMLExporter.ELEMENT_FLOATBUFFER, null); + } + currentElement = (Element) el.getParentNode(); + } + + public void writeSavableMap(Map<? extends Savable, ? extends Savable> map, String name, Map<? extends Savable, ? extends Savable> defVal) throws IOException { + if (map == null) { + return; + } + if (map.equals(defVal)) { + return; + } + Element stringMap = appendElement(name); + + Iterator<? extends Savable> keyIterator = map.keySet().iterator(); + while(keyIterator.hasNext()) { + Savable key = keyIterator.next(); + Element mapEntry = appendElement(XMLExporter.ELEMENT_MAPENTRY); + write(key, XMLExporter.ELEMENT_KEY, null); + Savable value = map.get(key); + write(value, XMLExporter.ELEMENT_VALUE, null); + currentElement = stringMap; + } + + currentElement = (Element) stringMap.getParentNode(); + } + + public void writeStringSavableMap(Map<String, ? extends Savable> map, String name, Map<String, ? extends Savable> defVal) throws IOException { + if (map == null) { + return; + } + if (map.equals(defVal)) { + return; + } + Element stringMap = appendElement(name); + + Iterator<String> keyIterator = map.keySet().iterator(); + while(keyIterator.hasNext()) { + String key = keyIterator.next(); + Element mapEntry = appendElement("MapEntry"); + mapEntry.setAttribute("key", key); + Savable s = map.get(key); + write(s, "Savable", null); + currentElement = stringMap; + } + + currentElement = (Element) stringMap.getParentNode(); + } + + public void writeIntSavableMap(IntMap<? extends Savable> map, String name, IntMap<? extends Savable> defVal) throws IOException { + if (map == null) { + return; + } + if (map.equals(defVal)) { + return; + } + Element stringMap = appendElement(name); + + for(Entry<? extends Savable> entry : map) { + int key = entry.getKey(); + Element mapEntry = appendElement("MapEntry"); + mapEntry.setAttribute("key", Integer.toString(key)); + Savable s = entry.getValue(); + write(s, "Savable", null); + currentElement = stringMap; + } + + currentElement = (Element) stringMap.getParentNode(); + } + + public void write(FloatBuffer value, String name, FloatBuffer defVal) throws IOException { + if (value == null) { + return; + } + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.limit())); + StringBuilder buf = new StringBuilder(); + int pos = value.position(); + value.rewind(); + int ctr = 0; + while (value.hasRemaining()) { + ctr++; + buf.append(value.get()); + buf.append(" "); + } + if (ctr != value.limit()) + throw new IOException("'" + name + + "' buffer contention resulted in write data consistency. " + + ctr + " values written when should have written " + + value.limit()); + buf.setLength(Math.max(0, buf.length() - 1)); + value.position(pos); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) el.getParentNode(); + } + + public void write(IntBuffer value, String name, IntBuffer defVal) throws IOException { + if (value == null) { + return; + } + if (value.equals(defVal)) { + return; + } + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.limit())); + StringBuilder buf = new StringBuilder(); + int pos = value.position(); + value.rewind(); + int ctr = 0; + while (value.hasRemaining()) { + ctr++; + buf.append(value.get()); + buf.append(" "); + } + if (ctr != value.limit()) + throw new IOException("'" + name + + "' buffer contention resulted in write data consistency. " + + ctr + " values written when should have written " + + value.limit()); + buf.setLength(buf.length() - 1); + value.position(pos); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) el.getParentNode(); + } + + public void write(ByteBuffer value, String name, ByteBuffer defVal) throws IOException { + if (value == null) return; + if (value.equals(defVal)) return; + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.limit())); + StringBuilder buf = new StringBuilder(); + int pos = value.position(); + value.rewind(); + int ctr = 0; + while (value.hasRemaining()) { + ctr++; + buf.append(value.get()); + buf.append(" "); + } + if (ctr != value.limit()) + throw new IOException("'" + name + + "' buffer contention resulted in write data consistency. " + + ctr + " values written when should have written " + + value.limit()); + buf.setLength(buf.length() - 1); + value.position(pos); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) el.getParentNode(); + } + + public void write(ShortBuffer value, String name, ShortBuffer defVal) throws IOException { + if (value == null) { + return; + } + if (value.equals(defVal)) { + return; + } + + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(value.limit())); + StringBuilder buf = new StringBuilder(); + int pos = value.position(); + value.rewind(); + int ctr = 0; + while (value.hasRemaining()) { + ctr++; + buf.append(value.get()); + buf.append(" "); + } + if (ctr != value.limit()) + throw new IOException("'" + name + + "' buffer contention resulted in write data consistency. " + + ctr + " values written when should have written " + + value.limit()); + buf.setLength(buf.length() - 1); + value.position(pos); + el.setAttribute(dataAttributeName, buf.toString()); + currentElement = (Element) el.getParentNode(); + } + + public void write(Enum value, String name, Enum defVal) throws IOException { + if (value == defVal) { + return; + } + currentElement.setAttribute(name, String.valueOf(value)); + + } + + public void writeByteBufferArrayList(ArrayList<ByteBuffer> array, + String name, ArrayList<ByteBuffer> defVal) throws IOException { + if (array == null) { + return; + } + if (array.equals(defVal)) { + return; + } + Element el = appendElement(name); + el.setAttribute("size", String.valueOf(array.size())); + for (ByteBuffer o : array) { + write(o, "ByteBuffer", null); + } + currentElement = (Element) el.getParentNode(); + + } +}
\ No newline at end of file diff --git a/engine/src/xml/com/jme3/export/xml/DOMSerializer.java b/engine/src/xml/com/jme3/export/xml/DOMSerializer.java new file mode 100644 index 0000000..b30ba19 --- /dev/null +++ b/engine/src/xml/com/jme3/export/xml/DOMSerializer.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.export.xml; + +import java.io.*; +import java.nio.charset.Charset; +import org.w3c.dom.*; + +/** + * The DOMSerializer was based primarily off the DOMSerializer.java class from the + * "Java and XML" 3rd Edition book by Brett McLaughlin, and Justin Edelson. Some + * modifications were made to support formatting of elements and attributes. + * + * @author Brett McLaughlin, Justin Edelson - Original creation for "Java and XML" book. + * @author Doug Daniels (dougnukem) - adjustments for XML formatting + * @version $Revision: 4207 $, $Date: 2009-03-29 11:19:16 -0400 (Sun, 29 Mar 2009) $ + */ +public class DOMSerializer { + + /** The encoding to use for output (default is UTF-8) */ + private Charset encoding = Charset.forName("utf-8"); + + /** The amount of indentation to use (default is 4 spaces). */ + private int indent = 4; + + /** The line separator to use (default is the based on the current system settings). */ + private String lineSeparator = System.getProperty("line.separator", "\n"); + + private void escape(Writer writer, String s) throws IOException { + if (s == null) { return; } + for (int i = 0, len = s.length(); i < len; i++) { + char c = s.charAt(i); + switch (c) { + case '<': + writer.write("<"); + break; + case '>': + writer.write(">"); + break; + case '&': + writer.write("&"); + break; + case '\r': + writer.write("
"); + break; + default: + writer.write(c); + } + } + } + + /** + * Serialize {@code doc} to {@code out} + * + * @param doc the document to serialize. + * @param file the file to serialize to. + * @throws IOException + */ + public void serialize(Document doc, File file) throws IOException { + serialize(doc, new FileOutputStream(file)); + } + + /** + * Serialize {@code doc} to {@code out} + * + * @param doc the document to serialize. + * @param out the stream to serialize to. + * @throws IOException + */ + public void serialize(Document doc, OutputStream out) throws IOException { + Writer writer = new OutputStreamWriter(out, encoding); + write(doc, writer, 0); + writer.flush(); + } + + /** + * Set the encoding used by this serializer. + * + * @param encoding the encoding to use, passing in {@code null} results in the + * default encoding (UTF-8) being set. + * @throws IllegalCharsetNameException if the given charset name is illegal. + * @throws UnsupportedCharsetException if the given charset is not supported by the + * current JVM. + */ + public void setEncoding(String encoding) { + this.encoding = Charset.forName(encoding); + } + + /** + * Set the number of spaces to use for indentation. + * <p> + * The default is to use 4 spaces. + * + * @param indent the number of spaces to use for indentation, values less than or + * equal to zero result in no indentation being used. + */ + public void setIndent(int indent) { + this.indent = indent >= 0 ? indent : 0; + } + + /** + * Set the line separator that will be used when serializing documents. + * <p> + * If this is not called then the serializer uses a default based on the + * {@code line.separator} system property. + * + * @param lineSeparator the line separator to set. + */ + public void setLineSeparator(String lineSeparator) { + this.lineSeparator = lineSeparator; + } + + private void write(Node node, Writer writer, int depth) throws IOException { + switch (node.getNodeType()) { + case Node.DOCUMENT_NODE: + writeDocument((Document) node, writer); + break; + case Node.ELEMENT_NODE: + writeElement((Element) node, writer, depth); + break; + case Node.TEXT_NODE: + escape(writer, node.getNodeValue()); + break; + case Node.CDATA_SECTION_NODE: + writer.write("<![CDATA["); + escape(writer, node.getNodeValue()); + writer.write("]]>"); + break; + case Node.COMMENT_NODE: + for (int i = 0; i < depth; ++i) { writer.append(' '); } + writer.append("<!-- ").append(node.getNodeValue()).append(" -->").append(lineSeparator); + break; + case Node.PROCESSING_INSTRUCTION_NODE: + String n = node.getNodeName(); + String v = node.getNodeValue(); + for (int i = 0; i < depth; ++i) { writer.append(' '); } + writer.append("<?").append(n).append(' ').append(v).append("?>").append(lineSeparator); + break; + case Node.ENTITY_REFERENCE_NODE: + writer.append('&').append(node.getNodeName()).append(';'); + break; + case Node.DOCUMENT_TYPE_NODE: + writeDocumentType((DocumentType) node, writer, depth); + break; + } + } + + private void writeDocument(Document document, Writer writer) throws IOException { + String v = document.getXmlVersion(); + + writer.append("<?xml "); + writer.append(" version='").append(v == null ? "1.0" : v).append("'"); + writer.append(" encoding='").append(encoding.name()).append("'"); + if (document.getXmlStandalone()) { + writer.append(" standalone='yes'"); + } + writer.append("?>").append(lineSeparator); + + NodeList nodes = document.getChildNodes(); + for (int i = 0, imax = nodes.getLength(); i < imax; ++i) { + write(nodes.item(i), writer, 0); + } + } + + private void writeDocumentType(DocumentType docType, Writer writer, int depth) throws IOException { + String publicId = docType.getPublicId(); + String internalSubset = docType.getInternalSubset(); + + for (int i = 0; i < depth; ++i) { writer.append(' '); } + writer.append("<!DOCTYPE ").append(docType.getName()); + if (publicId != null) { + writer.append(" PUBLIC '").append(publicId).append("' "); + } else { + writer.write(" SYSTEM "); + } + writer.append("'").append(docType.getSystemId()).append("'"); + if (internalSubset != null) { + writer.append(" [").append(internalSubset).append("]"); + } + writer.append('>').append(lineSeparator); + } + + private void writeElement(Element element, Writer writer, int depth) throws IOException { + for (int i = 0; i < depth; ++i) { writer.append(' '); } + writer.append('<').append(element.getTagName()); + NamedNodeMap attrs = element.getAttributes(); + for (int i = 0, imax = attrs.getLength(); i < imax; ++i) { + Attr attr = (Attr) attrs.item(i); + writer.append(' ').append(attr.getName()).append("='").append(attr.getValue()).append("'"); + } + NodeList nodes = element.getChildNodes(); + if (nodes.getLength() == 0) { + // no children, so just close off the element and return + writer.append("/>").append(lineSeparator); + return; + } + writer.append('>').append(lineSeparator); + for (int i = 0, imax = nodes.getLength(); i < imax; ++i) { + Node n = nodes.item(i); + if (n.getNodeType() == Node.ATTRIBUTE_NODE) { continue; } + write(n, writer, depth + indent); + } + for (int i = 0; i < depth; ++i) { writer.append(' '); } + writer.append("</").append(element.getTagName()).append('>').append(lineSeparator); + } + +} diff --git a/engine/src/xml/com/jme3/export/xml/XMLExporter.java b/engine/src/xml/com/jme3/export/xml/XMLExporter.java new file mode 100644 index 0000000..6e7c395 --- /dev/null +++ b/engine/src/xml/com/jme3/export/xml/XMLExporter.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.export.xml; + +import com.jme3.export.JmeExporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import javax.xml.parsers.DocumentBuilderFactory; + +/** + * Part of the jME XML IO system as introduced in the google code jmexml project. + * + * @author Kai Rabien (hevee) - original author of the code.google.com jmexml project + * @author Doug Daniels (dougnukem) - adjustments for jME 2.0 and Java 1.5 + */ +public class XMLExporter implements JmeExporter { + + public static final String ELEMENT_MAPENTRY = "MapEntry"; + public static final String ELEMENT_KEY = "Key"; + public static final String ELEMENT_VALUE = "Value"; + public static final String ELEMENT_FLOATBUFFER = "FloatBuffer"; + public static final String ATTRIBUTE_SIZE = "size"; + + private DOMOutputCapsule domOut; + + public XMLExporter() { + + } + + public boolean save(Savable object, OutputStream f) throws IOException { + try { + //Initialize Document when saving so we don't retain state of previous exports + this.domOut = new DOMOutputCapsule(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(), this); + domOut.write(object, object.getClass().getName(), null); + DOMSerializer serializer = new DOMSerializer(); + serializer.serialize(domOut.getDoc(), f); + f.flush(); + return true; + } catch (Exception ex) { + IOException e = new IOException(); + e.initCause(ex); + throw e; + } + } + + public boolean save(Savable object, File f) throws IOException { + return save(object, new FileOutputStream(f)); + } + + public OutputCapsule getCapsule(Savable object) { + return domOut; + } + + public static XMLExporter getInstance() { + return new XMLExporter(); + } + +} diff --git a/engine/src/xml/com/jme3/export/xml/XMLImporter.java b/engine/src/xml/com/jme3/export/xml/XMLImporter.java new file mode 100644 index 0000000..7a46b17 --- /dev/null +++ b/engine/src/xml/com/jme3/export/xml/XMLImporter.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.export.xml; + +import com.jme3.asset.AssetInfo; +import com.jme3.asset.AssetManager; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeImporter; +import com.jme3.export.Savable; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.xml.sax.SAXException; + +/** + * Part of the jME XML IO system as introduced in the google code jmexml project. + * @author Kai Rabien (hevee) - original author of the code.google.com jmexml project + * @author Doug Daniels (dougnukem) - adjustments for jME 2.0 and Java 1.5 + */ +public class XMLImporter implements JmeImporter { + + private AssetManager assetManager; + private DOMInputCapsule domIn; + int formatVersion = 0; + + public XMLImporter() { + } + + public int getFormatVersion() { + return formatVersion; + } + + public AssetManager getAssetManager(){ + return assetManager; + } + + public void setAssetManager(AssetManager assetManager){ + this.assetManager = assetManager; + } + + public Object load(AssetInfo info) throws IOException{ + assetManager = info.getManager(); + InputStream in = info.openStream(); + Savable obj = load(in); + in.close(); + return obj; + } + + public Savable load(File f) throws IOException { + FileInputStream fis = null; + try { + fis = new FileInputStream(f); + Savable sav = load(fis); + return sav; + } finally { + if (fis != null) fis.close(); + } + } + + public Savable load(InputStream f) throws IOException { + try { + domIn = new DOMInputCapsule(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(f), this); + return domIn.readSavable(null, null); + } catch (SAXException e) { + IOException ex = new IOException(); + ex.initCause(e); + throw ex; + } catch (ParserConfigurationException e) { + IOException ex = new IOException(); + ex.initCause(e); + throw ex; + } + } + + public InputCapsule getCapsule(Savable id) { + return domIn; + } + + public static XMLImporter getInstance() { + return new XMLImporter(); + } + +} |