/*
* This file is part of the OdinMS Maple Story Server Copyright (C) 2008 ~ 2010
* Patrick Huy <patrick.huy@frz.cc> Matthias Butz <matze@odinms.de> Jan
* Christian Meyer <vimes@odinms.de>
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation. You may not use, modify or distribute this
* program under any other version of the GNU Affero General Public License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package javastory.xml;
import java.awt.Point;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javastory.wz.WzData;
import javastory.wz.WzDataEntity;
import javastory.wz.WzDataType;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class XmlDomWzData implements WzData, Serializable {
/**
*
*/
private static final long serialVersionUID = 523068040190693685L;
private Node node;
private File imageDataDir;
private XmlDomWzData(final Node node) {
this.node = node;
}
public XmlDomWzData(final FileInputStream fis, final File imageDataDir) {
try {
final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
final Document document = documentBuilder.parse(fis);
this.node = document.getFirstChild();
} catch (final ParserConfigurationException e) {
throw new RuntimeException(e);
} catch (final SAXException e) {
throw new RuntimeException(e);
} catch (final IOException e) {
throw new RuntimeException(e);
}
this.imageDataDir = imageDataDir;
}
@Override
public WzData getChildByPath(final String path) {
final String pathSegments[] = path.split("/");
if (pathSegments[0].equals("..")) {
return ((WzData) this.getParent()).getChildByPath(path.substring(path.indexOf("/") + 1));
}
Node current = this.node;
for (final String pathSegment : pathSegments) {
final NodeList children = current.getChildNodes();
boolean foundChild = false;
for (int i = 0; i < children.getLength(); i++) {
final Node child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE
&& child.getAttributes().getNamedItem("name").getNodeValue().equals(pathSegment)) {
current = child;
foundChild = true;
break;
}
}
if (!foundChild) {
return null;
}
}
final XmlDomWzData ret = new XmlDomWzData(current);
ret.imageDataDir = new File(this.imageDataDir, this.getName() + "/" + path).getParentFile();
return ret;
}
public boolean hasChildAtPath(final String path) {
final String pathSegments[] = path.split("/");
if (pathSegments[0].equals("..")) {
return ((WzData) this.getParent()).hasChildAtPath(path.substring(path.indexOf("/") + 1));
}
Node current = this.node;
for (final String pathSegment : pathSegments) {
final NodeList children = current.getChildNodes();
boolean foundChild = false;
for (int i = 0; i < children.getLength(); i ++) {
final Node child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE
&& child.getAttributes().getNamedItem("name").getNodeValue().equals(pathSegment)) {
current = child;
foundChild = true;
break;
}
}
if (!foundChild) {
return false;
}
}
return true;
}
@Override
public List<WzData> getChildren() {
final List<WzData> ret = new ArrayList<WzData>();
final NodeList childNodes = this.node.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
final Node childNode = childNodes.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
final XmlDomWzData child = new XmlDomWzData(childNode);
child.imageDataDir = new File(this.imageDataDir, this.getName());
ret.add(child);
}
}
return ret;
}
@Override
public Object getData() {
final NamedNodeMap attributes = this.node.getAttributes();
final WzDataType type = this.getType();
switch (type) {
case DOUBLE:
final double doubleValue = Double.parseDouble(attributes.getNamedItem("value").getNodeValue());
return Double.valueOf(doubleValue);
case FLOAT:
final float floatValue = Float.parseFloat(attributes.getNamedItem("value").getNodeValue());
return Float.valueOf(floatValue);
case INT:
final int intValue = Integer.parseInt(attributes.getNamedItem("value").getNodeValue());
return Integer.valueOf(intValue);
case SHORT:
final short shortValue = Short.parseShort(attributes.getNamedItem("value").getNodeValue());
return Short.valueOf(shortValue);
case STRING:
case UOL:
return attributes.getNamedItem("value").getNodeValue();
case VECTOR:
final String xNode = attributes.getNamedItem("x").getNodeValue();
final String yNode = attributes.getNamedItem("y").getNodeValue();
final int x = Integer.parseInt(xNode);
final int y = Integer.parseInt(yNode);
return new Point(x, y);
case CANVAS:
final String widthNode = attributes.getNamedItem("width").getNodeValue();
final String heightNode = attributes.getNamedItem("height").getNodeValue();
final int width = Integer.parseInt(widthNode);
final int height = Integer.parseInt(heightNode);
final File file = new File(this.imageDataDir, this.getName() + ".png");
return new FileStoredPngWzCanvas(width, height, file);
}
return null;
}
@Override
public final WzDataType getType() {
final String nodeName = this.node.getNodeName();
switch (nodeName) {
case "imgdir":
return WzDataType.PROPERTY;
case "canvas":
return WzDataType.CANVAS;
case "convex":
return WzDataType.CONVEX;
case "sound":
return WzDataType.SOUND;
case "uol":
return WzDataType.UOL;
case "double":
return WzDataType.DOUBLE;
case "float":
return WzDataType.FLOAT;
case "int":
return WzDataType.INT;
case "short":
return WzDataType.SHORT;
case "string":
return WzDataType.STRING;
case "vector":
return WzDataType.VECTOR;
case "null":
return WzDataType.IMG_0x00;
default:
return null;
}
}
@Override
public WzDataEntity getParent() {
final Node parentNode = this.node.getParentNode();
if (parentNode.getNodeType() == Node.DOCUMENT_NODE) {
return null;
// can't traverse outside the img file
// TODO is this a problem?
}
final XmlDomWzData parentData = new XmlDomWzData(parentNode);
parentData.imageDataDir = this.imageDataDir.getParentFile();
return parentData;
}
@Override
public String getName() {
return this.node.getAttributes().getNamedItem("name").getNodeValue();
}
@Override
public Iterator<WzData> iterator() {
return this.getChildren().iterator();
}
}