This repository has been archived on 2022-12-21. You can view files and clone it, but cannot push or open issues or pull requests.
sdm03/src/main/java/com/github/dtschust/zork/parser/ZorkReader.java
2022-11-22 09:55:26 +01:00

220 lines
9.2 KiB
Java

package com.github.dtschust.zork.parser;
import com.github.dtschust.zork.ZorkCondition;
import com.github.dtschust.zork.ZorkGame;
import com.github.dtschust.zork.ZorkTrigger;
import com.github.dtschust.zork.parser.builders.Parsers;
import com.github.dtschust.zork.parser.dom.Elements;
import com.github.dtschust.zork.types.ZorkContainer;
import com.github.dtschust.zork.types.ZorkCreature;
import com.github.dtschust.zork.types.ZorkItem;
import com.github.dtschust.zork.types.ZorkRoom;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.nio.channels.NonReadableChannelException;
import static com.github.dtschust.zork.Zork.Type.*;
public class ZorkReader {
private final String filename;
public ZorkReader(String filename) {
this.filename = filename;
}
private static void addCreature(ZorkGame data, Element element) {
final Set<String> vulnerabilities = new HashSet<>();
final List<ZorkCondition> conditions = new ArrayList<>();
final List<String> prints = new ArrayList<>();
final List<String> actions = new ArrayList<>();
NodeList attacks = element.getElementsByTagName("attack");
for (Element attack : DOMUtils.iterator(attacks)) {
final List<ZorkCondition> conditionsList = Elements.byTagName(attack, "condition").stream()
.map(Parsers.condition::parse)
.collect(Collectors.toList());
conditions.addAll(conditionsList);
for (Element print : DOMUtils.iterator(attack.getElementsByTagName("print"))) {
prints.add(DOMUtils.getInnerText(print));
}
for (Element action : DOMUtils.iterator(attack.getElementsByTagName("action"))) {
actions.add(DOMUtils.getInnerText(action));
}
}
for (Element vuln : DOMUtils.iterator(element.getElementsByTagName("vulnerability"))) {
vulnerabilities.add(DOMUtils.getInnerText(vuln));
}
/* Get all possible creature attributes */
ZorkCreature tempCreature = new ZorkCreature(
DOMUtils.getInnerTextByTagName(element, "name", ""),
DOMUtils.getInnerTextByTagName(element, "description", ""),
vulnerabilities,
conditions,
prints,
actions
);
final List<ZorkTrigger> triggers = Elements.byTagName(element, "trigger").stream()
.map(Parsers.trigger::parse)
.collect(Collectors.toList());
tempCreature.trigger.addAll(triggers);
tempCreature.updateStatus(DOMUtils.getInnerTextByTagName(element, "status", ""));
/* Put each creature in the creatures hashmap, the generic object hashmap, and the objectlookup hashmap*/
data.addObjectThroughLookup(CREATURE, tempCreature);
}
private static void addContainer(ZorkGame data, Element element) {
final ZorkContainer tempCont = Parsers.container.parse(element);
/* Put each container in the containers hashmap, the generic object hashmap, and the objectlookup hashmap*/
data.addObjectThroughLookup(CONTAINER, tempCont);
}
private static void addItem(ZorkGame data, Element element) {
final List<String> prints = new ArrayList<>();
final List<String> actions = new ArrayList<>();
NodeList turnOn = element.getElementsByTagName("turnon");
if (turnOn.getLength() > 0) {
for (Element print : DOMUtils.iterator(element.getElementsByTagName("print"))) {
prints.add(DOMUtils.getInnerText(print));
}
for (Element action : DOMUtils.iterator(element.getElementsByTagName("action"))) {
actions.add(DOMUtils.getInnerText(action));
}
}
/* Get all possible item attributes*/
ZorkItem tempItem = new ZorkItem(
DOMUtils.getInnerTextByTagName(element, "name", ""),
DOMUtils.getInnerTextByTagName(element, "description", ""),
DOMUtils.getInnerTextByTagName(element, "writing", ""),
prints,
actions
);
final List<ZorkTrigger> triggers = Elements.byTagName(element, "trigger").stream()
.map(Parsers.trigger::parse)
.collect(Collectors.toList());
tempItem.trigger.addAll(triggers);
/* Put each item in the items hashmap, the generic objects hashmap, and store its type in object lookup */
data.addObjectThroughLookup(ITEM, tempItem);
tempItem.updateStatus(DOMUtils.getInnerTextByTagName(element, "status", ""));
}
private static void addRoom(ZorkGame data, Element element) {
/*Get all possible Room attributes*/
ZorkRoom tempRoom = new ZorkRoom(
DOMUtils.getInnerTextByTagName(element, "name", ""),
DOMUtils.getInnerTextByTagName(element, "description", ""),
DOMUtils.getInnerTextByTagName(element, "type", "regular")
);
final List<ZorkTrigger> triggers = Elements.byTagName(element, "trigger").stream()
.map(Parsers.trigger::parse)
.collect(Collectors.toList());
tempRoom.trigger.addAll(triggers);
tempRoom.updateStatus(DOMUtils.getInnerTextByTagName(element, "status", ""));
for (Element item : DOMUtils.iterator(element.getElementsByTagName("item"))) {
String itemName = DOMUtils.getInnerText(item);
tempRoom.item.add(itemName);
}
for (Element creature : DOMUtils.iterator(element.getElementsByTagName("creature"))) {
String creatureName = DOMUtils.getInnerText(creature);
tempRoom.creature.add(creatureName);
}
for (Element container : DOMUtils.iterator(element.getElementsByTagName("container"))) {
String containerName = DOMUtils.getInnerText(container);
tempRoom.container.add(containerName);
}
for (Element border : DOMUtils.iterator(element.getElementsByTagName("border"))) {
String borderDirection = DOMUtils.getInnerText((Element) border.getElementsByTagName("direction").item(0));
String borderName = DOMUtils.getInnerText((Element) border.getElementsByTagName("name").item(0));
tempRoom.border.put(borderDirection, borderName);
}
/*Add this room to the rooms hashmap, put it in the generic objects hashmap, and store it's type in the objectlookup hashmap*/
data.addObjectThroughLookup(ROOM, tempRoom);
}
public ZorkGame build() {
ZorkGame data = new ZorkGame();
File file = new File(filename);
if (!file.canRead()) {
System.out.println("Error opening file. Exiting...");
throw new NonReadableChannelException();
}
try {
/* Open the xml file*/
DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();
// Limit XML features to mitigate vulnerabilities
builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
builder.setFeature("http://xml.org/sax/features/external-general-entities", false);
builder.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
Element rootElement = builder.newDocumentBuilder().parse(file).getDocumentElement();
/* Every single first generation child is a room, container, creature, or item. So load them in*/
for (Node node : DOMUtils.iterNodes(rootElement.getChildNodes())) {
Element element;
if (node instanceof Element) {
element = (Element) node;
String tagType = element.getTagName();
switch (tagType) {
/* If it's a room ... */
case "room":
addRoom(data, element);
break;
/* If it's an item... */
case "item":
addItem(data, element);
break;
/* If it's a container... */
case "container":
addContainer(data, element);
break;
/* And finally, if it's a creature...*/
case "creature":
addCreature(data, element);
break;
default:
throw new IllegalStateException("Unexpected value: " + tagType);
}
}
}
} catch (Exception e) {
// e.printStackTrace();
System.out.println("Invalid XML file, exiting");
System.exit(-1);
}
return data;
}
}