/* * EquipmentTableParser.java * Copyright 2006 (C) Aaron Divinsky <boomer70@yahoo.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Current Ver: $Revision$ */ package pcgen.core.npcgen; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import pcgen.core.Equipment; import pcgen.core.GameMode; import pcgen.core.Globals; import pcgen.core.SystemCollections; import pcgen.util.Logging; /** * Parse a equipment table (random treasure) data file. * * @author boomer70 <boomer70@yahoo.com> * */ public class EquipmentTableParser { private SAXParser theParser; private GameMode theMode; private HashMap<EquipmentItem, String> theLinkTable = new HashMap<>(); private HashMap<EqmodItem, String> theEqmodLinkTable = new HashMap<>(); /** * Creates a new <tt>EquipmentTableParser</tt> for the specified game mode. * * @param aMode The game mode to parse equipment tables for. * * @throws ParserConfigurationException * @throws SAXException */ public EquipmentTableParser(final GameMode aMode) throws ParserConfigurationException, SAXException { theMode = aMode; final SAXParserFactory parserFactory = SAXParserFactory.newInstance(); parserFactory.setValidating(true); theParser = parserFactory.newSAXParser(); } /** * Parses an XML equipment table file. * * @param aFileList An array of files to process * * @return A <tt>List</tt> of <tt>EquipmentTable</tt> objects representing * the tables in the file. * * @throws SAXException * @throws IOException */ public List<EquipmentTable> parse( final File[] aFileList ) throws SAXException, IOException { final List<EquipmentTable> ret = new ArrayList<>(); for ( final File fileName : aFileList ) { try { theParser.parse(fileName, new EquipmentTableHandler(theMode, ret)); } catch (IllegalArgumentException ex ) { // Do nothing, means we weren't the right game mode for this file. } } // Resolve all links now that all tables should have been read in. for ( final EquipmentItem item : theLinkTable.keySet() ) { final EquipmentTable table = EquipmentTable.get(theLinkTable.get(item)); if ( table == null ) { Logging.errorPrint("Could not find linked table " + theLinkTable.get(item) + " for " + item); continue; } item.setLookup(table); } for ( final EqmodItem item : theEqmodLinkTable.keySet() ) { final EqmodTable table = EqmodTable.get(theEqmodLinkTable.get(item)); if ( table == null ) { Logging.errorPrint("Could not find linked table " + theEqmodLinkTable.get(item) + " for " + item); continue; } item.setLookup(table); } return ret; } /** An enum for the current state in the state machine the parser is in */ private enum ParserState { /** The initial state of the parser */ INIT, EQTABLEDATA, EQMODTABLEDATA, ENTRYDATA, EQUIPMENT } /** * This is the parsing event handler class. The methods in this class are * called by the SAX parser as it finds various elements in the XML file. * * @author boomer70 <boomer70@yahoo.com> * */ class EquipmentTableHandler extends DefaultHandler { private List<EquipmentTable> theList; private GameMode theGameMode = null; private boolean theValidFlag = false; private ParserState theState = ParserState.INIT; private Table theCurrentData = null; private TableEntry theCurrentEntry = null; private EquipmentItem theCurrentItem = null; /** * Constructs the handler * * @param aMode The game mode to expect the file to be for. * @param aList The list of <tt>ClassData</tt> objects to fill */ public EquipmentTableHandler( final GameMode aMode, final List<EquipmentTable> aList ) { theGameMode = aMode; theList = aList; } /** * @throws SAXException * @throws IllegalArgumentException if the file being processed is not the * same GameMode as requested. * * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) */ @Override public void startElement( final String uri, final String localName, final String aName, final Attributes anAttrs) throws SAXException { if ( theState == ParserState.INIT && "equipment_tables".equals(aName) ) //$NON-NLS-1$ { if ( anAttrs != null ) { final String gm = anAttrs.getValue("game_mode"); //$NON-NLS-1$ if ( ! SystemCollections.getGameModeNamed(gm).equals(theGameMode) ) { throw new IllegalArgumentException("Incorrect game mode"); //$NON-NLS-1$ } theValidFlag = true; } return; } if (!theValidFlag ) { throw new SAXException("Generators.Equipment.InvalidFileFormat"); //$NON-NLS-1$ } if ( theState == ParserState.INIT ) { if ( "table".equals(aName) ) //$NON-NLS-1$ { if ( anAttrs != null ) { final String name = anAttrs.getValue("name"); //$NON-NLS-1$ final String id = anAttrs.getValue("id"); //$NON-NLS-1$ // See if this table already exists EquipmentTable table = EquipmentTable.get(id); if ( table == null ) { // This is not an existing table, so create one. table = new EquipmentTable(id); table.setName( name ); EquipmentTable.addTable( table ); theList.add( table ); } theCurrentData = table; theState = ParserState.EQTABLEDATA; } } else if ( "eqmod_table".equals(aName) ) { if ( anAttrs != null ) { final String name = anAttrs.getValue("name"); //$NON-NLS-1$ final String id = anAttrs.getValue("id"); //$NON-NLS-1$ // See if this table already exists EqmodTable table = EqmodTable.get(id); if ( table == null ) { // This is not an existing table, so create one. table = new EqmodTable(id); table.setName( name ); EqmodTable.addTable( table ); } theCurrentData = table; theState = ParserState.EQMODTABLEDATA; } } } else if ( theState == ParserState.EQTABLEDATA ) { if ( "entry".equals(aName) ) { // Found an entry for the table if ( anAttrs != null ) { final String entryName = anAttrs.getValue("name"); if ( entryName != null ) { final TableEntry te = new EquipmentTableEntry( entryName ); theCurrentEntry = te; theState = ParserState.ENTRYDATA; final int weight = getWeight( anAttrs ); theCurrentData.add( weight, te ); } } } } else if ( theState == ParserState.EQMODTABLEDATA ) { if ( "entry".equals(aName) ) { // Found an entry for the table if ( anAttrs != null ) { final String entryName = anAttrs.getValue("name"); if ( entryName != null ) { final TableEntry te = new EqmodTableEntry( entryName ); theCurrentEntry = te; theState = ParserState.ENTRYDATA; final int weight = getWeight( anAttrs ); theCurrentData.add( weight, te ); } } } } else if ( theState == ParserState.ENTRYDATA ) { if ( "equipment".equals(aName) ) { if ( anAttrs != null ) { theCurrentItem = new EquipmentItem(); final String rolls = anAttrs.getValue( "rolls" ); if ( rolls != null ) { theCurrentItem.setTimes( rolls ); } final String linkLoc = anAttrs.getValue( "link" ); if ( linkLoc != null ) { // This entry contains a lookup final EquipmentTable table = EquipmentTable.get( linkLoc ); if ( table == null ) { // Store the lookup in a Hashtable until it the end // so we can resolve all the references. theLinkTable.put( theCurrentItem, linkLoc ); } else { theCurrentItem.setLookup( table ); } } else { final String choiceStr = anAttrs.getValue( "choose" ); if ( choiceStr != null ) { String[] choices = choiceStr.split( "\\|" ); theCurrentItem.setVariableEquipment( anAttrs.getValue( "value" ), Arrays.asList(choices) ); } else { final String val = anAttrs.getValue( "value" ); if ( val != null ) { final Equipment eq = Globals.getContext().getReferenceContext().silentlyGetConstructedCDOMObject( Equipment.class, val ); if ( eq == null ) { Logging.errorPrint("Could not find equipment named: " + val ); } theCurrentItem.setEquipment(eq); } final String qty = anAttrs.getValue( "quantity" ); theCurrentItem.setQuantity( qty ); } } theCurrentEntry.addData( theCurrentItem ); } theState = ParserState.EQUIPMENT; } } else if ( theState == ParserState.EQUIPMENT ) { if ( "eqmod".equals(aName) ) //$NON-NLS-1$ { if ( anAttrs != null ) { final EqmodItem eqmodItem = new EqmodItem(); final String link = anAttrs.getValue( "link" ); //$NON-NLS-1$ if ( link != null ) { final EqmodTable table = EqmodTable.get( link ); if ( table == null ) { theEqmodLinkTable.put( eqmodItem, link ); } else { eqmodItem.setLookup( table ); } } else { final String rollStr = anAttrs.getValue( "roll" ); if ( rollStr != null ) { eqmodItem.setRollString( rollStr ); } final String val = anAttrs.getValue( "value" ); //$NON-NLS-1$ if ( val != null ) { eqmodItem.setEqmod( val ); } } theCurrentItem.addEqMod( eqmodItem ); } } } } /** * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String) */ @Override public void endElement(final String uri, final String localName, final String qName) { if ( "equipment_tables".equals(qName) ) //$NON-NLS-1$ { theState = ParserState.INIT; } else if ( "table".equals(qName) ) //$NON-NLS-1$ { theState = ParserState.INIT; TreasureGenerator.addTable( theGameMode, (EquipmentTable)theCurrentData ); } else if ( "eqmod_table".equals(qName) ) //$NON-NLS-1$ { theState = ParserState.INIT; } else if ( "entry".equals(qName) ) //$NON-NLS-1$ { if ( theCurrentData instanceof EquipmentTable ) { theState = ParserState.EQTABLEDATA; } else if ( theCurrentData instanceof EqmodTable ) { theState = ParserState.EQMODTABLEDATA; } } else if ( "equipment".equals(qName) ) //$NON-NLS-1$ { theState = ParserState.ENTRYDATA; } else if ( "eqmod".equals(qName) ) //$NON-NLS-1$ { ; } } private int getWeight( final Attributes anAttrs ) { int weight = 1; final String wtStr = anAttrs.getValue("weight"); //$NON-NLS-1$ if ( wtStr != null ) { weight = Integer.parseInt(wtStr.trim()); } return weight; } } }