Cleaned up XML parsing to store temporary info more cleanly. Initial

work on scene group parser.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@271 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Walter Korman
2001-08-16 20:14:06 +00:00
parent a99829818f
commit 722073eca6
3 changed files with 329 additions and 93 deletions
@@ -1,5 +1,5 @@
// //
// $Id: XMLTileSetParser.java,v 1.11 2001/08/13 19:54:39 shaper Exp $ // $Id: XMLTileSetParser.java,v 1.12 2001/08/16 20:14:06 shaper Exp $
package com.threerings.miso.tile; package com.threerings.miso.tile;
@@ -39,45 +39,50 @@ public class XMLTileSetParser extends DefaultHandler
String str = _chars.toString(); String str = _chars.toString();
if (qName.equals("name")) { if (qName.equals("name")) {
_tsName = str.trim(); _info.name = str.trim();
} else if (qName.equals("tsid")) { } else if (qName.equals("tsid")) {
try { try {
_tsTsid = Integer.parseInt(str); _info.tsid = Integer.parseInt(str);
} catch (NumberFormatException nfe) { } catch (NumberFormatException nfe) {
Log.warning("Malformed integer tilesetid [str=" + str + "]."); Log.warning("Malformed integer tilesetid [str=" + str + "].");
_tsTsid = -1; _info.tsid = -1;
} }
} else if (qName.equals("imagefile")) { } else if (qName.equals("imagefile")) {
_tsImgFile = str; _info.imgfile = str;
} else if (qName.equals("rowwidth")) { } else if (qName.equals("rowwidth")) {
_tsRowWidth = StringUtil.parseIntArray(str); _info.rowwidth = StringUtil.parseIntArray(str);
} else if (qName.equals("rowheight")) { } else if (qName.equals("rowheight")) {
_tsRowHeight = StringUtil.parseIntArray(str); _info.rowheight = StringUtil.parseIntArray(str);
} else if (qName.equals("tilecount")) { } else if (qName.equals("tilecount")) {
_tsTileCount = StringUtil.parseIntArray(str); _info.tilecount = StringUtil.parseIntArray(str);
// calculate the total number of tiles in the tileset // calculate the total number of tiles in the tileset
for (int ii = 0; ii < _tsTileCount.length; ii++) { for (int ii = 0; ii < _info.tilecount.length; ii++) {
_tsNumTiles += _tsTileCount[ii]; _info.numtiles += _info.tilecount[ii];
} }
} else if (qName.equals("passable")) { } else if (qName.equals("passable")) {
_tsPassable = StringUtil.parseIntArray(str); _info.passable = StringUtil.parseIntArray(str);
} else if (qName.equals("offsetpos")) { } else if (qName.equals("offsetpos")) {
getPoint(str, _tsOffsetPos); getPoint(str, _info.offsetpos);
} else if (qName.equals("gapdist")) { } else if (qName.equals("gapdist")) {
getPoint(str, _tsGapDist); getPoint(str, _info.gapdist);
} else if (qName.equals("tileset")) { } else if (qName.equals("tileset")) {
constructTileSet(); // construct the tileset on tag close and add it to the
} // list of tilesets constructed thus far
_tilesets.add(_info.constructTileSet());
// prepare to read another tileset object
init();
}
// note that we're not within a tag to avoid considering any // note that we're not within a tag to avoid considering any
// characters during this quiescent time // characters during this quiescent time
@@ -87,28 +92,6 @@ public class XMLTileSetParser extends DefaultHandler
_chars = new StringBuffer(); _chars = new StringBuffer();
} }
protected void constructTileSet ()
{
// if passability is unspecified, default to all passable
if (_tsPassable == null) {
_tsPassable = new int[_tsNumTiles];
for (int ii = 0; ii < _tsNumTiles; ii++) {
_tsPassable[ii] = 1;
}
}
// construct the tileset object on tag close
TileSet tset = new TileSet(
_tsName, _tsTsid, _tsImgFile,
_tsRowWidth, _tsRowHeight, _tsTileCount, _tsPassable,
_tsOffsetPos, _tsGapDist);
_tilesets.add(tset);
// prepare to read another tileset object
init();
}
public void characters (char ch[], int start, int length) public void characters (char ch[], int start, int length)
{ {
// bail if we're not within a meaningful tag // bail if we're not within a meaningful tag
@@ -123,9 +106,11 @@ public class XMLTileSetParser extends DefaultHandler
InputStream tis = ConfigUtil.getStream(fname); InputStream tis = ConfigUtil.getStream(fname);
if (tis == null) { if (tis == null) {
Log.warning("Couldn't find file [fname=" + fname + "]."); Log.warning("Couldn't find file [fname=" + fname + "].");
return _tilesets; return null;
} }
_tilesets = new ArrayList();
// prepare to read a new tileset // prepare to read a new tileset
init(); init();
@@ -148,11 +133,8 @@ public class XMLTileSetParser extends DefaultHandler
*/ */
protected void init () protected void init ()
{ {
_tsOffsetPos = new Point();
_tsGapDist = new Point();
_tsPassable = null;
_tsNumTiles = 0;
_chars = new StringBuffer(); _chars = new StringBuffer();
_info = new TileSetInfo();
} }
/** /**
@@ -175,12 +157,67 @@ public class XMLTileSetParser extends DefaultHandler
/** The tilesets constructed thus far. */ /** The tilesets constructed thus far. */
protected ArrayList _tilesets = new ArrayList(); protected ArrayList _tilesets = new ArrayList();
/** Temporary storage of tileset object values. */ /** Temporary storage of character data while parsing. */
protected StringBuffer _chars; protected StringBuffer _chars;
protected String _tsName;
protected int _tsTsid; /** Temporary storage of tileset info while parsing. */
protected String _tsImgFile; protected TileSetInfo _info;
protected int[] _tsRowWidth, _tsRowHeight, _tsTileCount, _tsPassable;
protected int _tsNumTiles; /**
protected Point _tsOffsetPos, _tsGapDist; * A class to hold temporary information on a tileset.
*/
class TileSetInfo
{
/** The tileset name. */
public String name;
/** The tileset id. */
public int tsid;
/** The tileset full image file path. */
public String imgfile;
/** The width of the tiles in each row. */
public int[] rowwidth;
/** The height of the tiles in each row. */
public int[] rowheight;
/** The number of tiles in each row. */
public int[] tilecount;
/** The passability of each tile. */
public int[] passable;
/** The number of tiles in the tileset. */
public int numtiles;
/** The offset position at which tiles begin in the tile image. */
public Point offsetpos;
/** The gap distance between each tile in the tile image. */
public Point gapdist;
public TileSetInfo ()
{
offsetpos = new Point();
gapdist = new Point();
}
public TileSet constructTileSet ()
{
// if passability is unspecified, default to all passable
if (passable == null) {
passable = new int[numtiles];
for (int ii = 0; ii < numtiles; ii++) {
passable[ii] = 1;
}
}
// construct a tileset object using all gathered data
return new TileSet(
name, tsid, imgfile, rowwidth, rowheight, tilecount,
passable, offsetpos, gapdist);
}
}
} }
@@ -0,0 +1,164 @@
//
// $Id: XMLSceneGroupParser.java,v 1.1 2001/08/16 20:14:06 shaper Exp $
package com.threerings.miso.scene.xml;
import java.io.*;
import java.util.*;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import com.samskivert.util.*;
import com.samskivert.xml.XMLUtil;
import com.threerings.miso.Log;
import com.threerings.miso.scene.*;
/**
* Parses an XML scene group description file, loads the referenced
* scenes into the runtime scene repository, and creates bindings
* between the portals in the scenes.
*
* <p> Does not currently perform validation on the input XML stream,
* though the parsing code assumes the XML document is well-formed.
*/
public class XMLSceneGroupParser extends DefaultHandler
{
public void startElement (String uri, String localName,
String qName, Attributes attributes)
{
_tag = qName;
}
public void endElement (String uri, String localName, String qName)
{
// we know we've received the entirety of the character data
// for the elements we're tracking at this point, so proceed
// with saving off element data for later use.
// note that we're not within a tag to avoid considering any
// characters during this quiescent time
_tag = null;
// and clear out the character data we're gathering
_chars = new StringBuffer();
}
public void characters (char ch[], int start, int length)
{
// bail if we're not within a meaningful tag
if (_tag == null) return;
_chars.append(ch, start, length);
}
/**
* Parse the specified XML file and return a list of miso scene
* objects that have been fully bound and loaded into the scene
* repository.
*
* @param fname the file name.
*
* @return the list of scene objects, or null if an error occurred.
*/
public List loadSceneGroup (String fname) throws IOException
{
_fname = fname;
try {
// get the file input stream
FileInputStream fis = new FileInputStream(fname);
BufferedInputStream bis = new BufferedInputStream(fis);
// prepare temporary data storage for parsing
_chars = new StringBuffer();
// read the XML input stream and construct all scene objects
XMLUtil.parse(this, bis);
// return the final list of scene objects
return _info.scenes;
} catch (ParserConfigurationException pce) {
throw new IOException(pce.toString());
} catch (SAXException saxe) {
throw new IOException(saxe.toString());
}
}
/** The file currently being processed. */
protected String _fname;
/** The XML element tag currently being processed. */
protected String _tag;
/** Temporary storage of scene group values and data. */
protected StringBuffer _chars;
/** The scene group info gathered while parsing. */
protected SceneGroupInfo _info;
/**
* A class to hold information on the overall scene group while
* parsing, as well as the resulting list of scene objects
* produced when finished.
*/
class SceneGroupInfo
{
/** The list of scenes constructed once parsing is complete. */
public ArrayList scenes;
/** The scene info for all scenes described in the group. */
public ArrayList sceneinfo;
/** The current scene info. */
public SceneInfo curscene;
}
/**
* A class to hold information on a single scene's bindings.
*/
class SceneInfo
{
/** The logical scene name. */
public String name;
/** The scene description file path. */
public String src;
/** The default scene entrance. */
public String entrance;
/** The list of portal info objects describing portal bindings. */
public ArrayList portals;
public SceneInfo (String src)
{
this.src = src;
}
}
/**
* A class to hold information on a single portal's bindings.
*/
class PortalInfo
{
/** The source portal name. */
public String src;
/** The destination portal name within the destination scene. */
public String dest;
/** The logical destination scene name. */
public String destScene;
public PortalInfo (String src, String destScene, String dest)
{
this.src = src;
this.destScene = destScene;
this.dest = dest;
}
}
}
@@ -1,5 +1,5 @@
// //
// $Id: XMLSceneParser.java,v 1.12 2001/08/16 18:05:17 shaper Exp $ // $Id: XMLSceneParser.java,v 1.13 2001/08/16 20:14:06 shaper Exp $
package com.threerings.miso.scene.xml; package com.threerings.miso.scene.xml;
@@ -36,14 +36,14 @@ public class XMLSceneParser extends DefaultHandler
{ {
_tag = qName; _tag = qName;
if (_tag.equals("layer")) { if (_tag.equals("layer")) {
_scLnum = getInt(attributes.getValue("lnum")); _info.lnum = getInt(attributes.getValue("lnum"));
} else if (_tag.equals("row")) { } else if (_tag.equals("row")) {
_scRownum = getInt(attributes.getValue("rownum")); _info.rownum = getInt(attributes.getValue("rownum"));
// get the column start value if present // get the column start value if present
String strcs = attributes.getValue("colstart"); String strcs = attributes.getValue("colstart");
if (strcs != null) _scColstart = getInt(strcs); if (strcs != null) _info.colstart = getInt(strcs);
} }
} }
@@ -54,7 +54,7 @@ public class XMLSceneParser extends DefaultHandler
// with saving off element values for use when we construct // with saving off element values for use when we construct
// the scene object. // the scene object.
if (qName.equals("name")) { if (qName.equals("name")) {
_scName = _chars.toString().trim(); _info.name = _chars.toString().trim();
} else if (qName.equals("version")) { } else if (qName.equals("version")) {
int version = getInt(_chars.toString()); int version = getInt(_chars.toString());
@@ -68,30 +68,26 @@ public class XMLSceneParser extends DefaultHandler
} else if (qName.equals("locations")) { } else if (qName.equals("locations")) {
int vals[] = StringUtil.parseIntArray(_chars.toString()); int vals[] = StringUtil.parseIntArray(_chars.toString());
_scLocations = toLocationsList(vals); _info.locations = toLocationsList(vals);
} else if (qName.equals("cluster")) { } else if (qName.equals("cluster")) {
int vals[] = StringUtil.parseIntArray(_chars.toString()); int vals[] = StringUtil.parseIntArray(_chars.toString());
_scClusters.add(toCluster(_scLocations, vals)); _info.clusters.add(toCluster(_info.locations, vals));
} else if (qName.equals("portals")) { } else if (qName.equals("portals")) {
String vals[] = StringUtil.parseStringArray(_chars.toString()); String vals[] = StringUtil.parseStringArray(_chars.toString());
_scPortals = toPortalList(_scLocations, vals); _info.portals = toPortalList(_info.locations, vals);
} else if (qName.equals("row")) { } else if (qName.equals("row")) {
if (_scLnum == MisoScene.LAYER_BASE) { if (_info.lnum == MisoScene.LAYER_BASE) {
readRowData(_chars.toString()); readRowData(_info, _chars.toString());
} else { } else {
readSparseRowData(_chars.toString()); readSparseRowData(_info, _chars.toString());
} }
} else if (qName.equals("scene")) { } else if (qName.equals("scene")) {
// construct the scene object on tag close // construct the scene object on tag close
_scene = new MisoScene( _info.constructScene(_tilemgr);
_tilemgr, _scName, _scLocations, _scClusters,
_scPortals, _scTiles);
Log.info("Constructed parsed scene [scene=" + _scene + "].");
} }
// note that we're not within a tag to avoid considering any // note that we're not within a tag to avoid considering any
@@ -112,12 +108,12 @@ public class XMLSceneParser extends DefaultHandler
/** /**
* Given a string of comma-delimited tuples as (tileset id, tile * Given a string of comma-delimited tuples as (tileset id, tile
* id), populate the <code>_scTiles</code> tile array with tiles * id), populate the scene info tile array with tiles to suit.
* to suit.
* *
* @param info the scene info.
* @param data the tile data. * @param data the tile data.
*/ */
protected void readRowData (String data) protected void readRowData (SceneInfo info, String data)
{ {
int[] vals = StringUtil.parseIntArray(data); int[] vals = StringUtil.parseIntArray(data);
@@ -126,7 +122,7 @@ public class XMLSceneParser extends DefaultHandler
if (vals.length != validLen) { if (vals.length != validLen) {
Log.warning( Log.warning(
"Invalid number of tiles in full row data set, skipping set " + "Invalid number of tiles in full row data set, skipping set " +
"[rownum=" + _scRownum + ", len=" + vals.length + "[rownum=" + info.rownum + ", len=" + vals.length +
", valid_len=" + validLen + ", data=" + data + "]."); ", valid_len=" + validLen + ", data=" + data + "].");
return; return;
} }
@@ -134,21 +130,22 @@ public class XMLSceneParser extends DefaultHandler
// create the tile objects in the tile array // create the tile objects in the tile array
for (int xx = 0; xx < vals.length; xx += 2) { for (int xx = 0; xx < vals.length; xx += 2) {
Tile tile = _tilemgr.getTile(vals[xx], vals[xx + 1]); Tile tile = _tilemgr.getTile(vals[xx], vals[xx + 1]);
_scTiles[xx / 2][_scRownum][_scLnum] = tile; info.tiles[xx / 2][info.rownum][info.lnum] = tile;
} }
} }
/** /**
* Given a string of comma-delimited tuples as (tileset id, tile * Given a string of comma-delimited tuples as (tileset id, tile
* id) and having previously set up the <code>_scRownum</code> and * id) and having previously set up the scene info object's
* <code>_scColstart</code> member data by retrieving the * <code>rownum</code> and <code>colstart</code> member data by
* attribute values when the <code>row</code> element tag was * retrieving the attribute values when the <code>row</code>
* noted, this method then proceeds to populate the * element tag was noted, this method then proceeds to populate
* <code>_scTiles</code> tile array with tiles to suit. * the info object's tile array with tiles to suit.
* *
* @param info the scene info.
* @param data the tile data. * @param data the tile data.
*/ */
protected void readSparseRowData (String data) protected void readSparseRowData (SceneInfo info, String data)
{ {
int[] vals = StringUtil.parseIntArray(data); int[] vals = StringUtil.parseIntArray(data);
@@ -156,7 +153,7 @@ public class XMLSceneParser extends DefaultHandler
if ((vals.length % 2) == 1) { if ((vals.length % 2) == 1) {
Log.warning( Log.warning(
"Odd number of tiles in sparse row data set, skipping set " + "Odd number of tiles in sparse row data set, skipping set " +
"[rownum=" + _scRownum + ", colstart=" + _scColstart + "[rownum=" + info.rownum + ", colstart=" + info.colstart +
", len=" + vals.length + "]."); ", len=" + vals.length + "].");
return; return;
} }
@@ -164,7 +161,8 @@ public class XMLSceneParser extends DefaultHandler
// create the tile objects in the tile array // create the tile objects in the tile array
for (int xx = 0; xx < vals.length; xx += 2) { for (int xx = 0; xx < vals.length; xx += 2) {
Tile tile = _tilemgr.getTile(vals[xx], vals[xx + 1]); Tile tile = _tilemgr.getTile(vals[xx], vals[xx + 1]);
_scTiles[_scColstart + (xx / 2)][_scRownum][_scLnum] = tile; int xidx = info.colstart + (xx / 2);
info.tiles[xidx][info.rownum][info.lnum] = tile;
} }
} }
@@ -269,12 +267,7 @@ public class XMLSceneParser extends DefaultHandler
protected void init () protected void init ()
{ {
_chars = new StringBuffer(); _chars = new StringBuffer();
_scene = null; _info = new SceneInfo();
int width = MisoScene.TILE_WIDTH, height = MisoScene.TILE_HEIGHT;
_scTiles = new Tile[width][height][MisoScene.NUM_LAYERS];
_scLocations = null;
_scPortals = null;
_scClusters = new ArrayList();
} }
/** /**
@@ -301,7 +294,7 @@ public class XMLSceneParser extends DefaultHandler
XMLUtil.parse(this, bis); XMLUtil.parse(this, bis);
// return the final scene object // return the final scene object
return _scene; return _info.scene;
} catch (ParserConfigurationException pce) { } catch (ParserConfigurationException pce) {
throw new IOException(pce.toString()); throw new IOException(pce.toString());
@@ -317,16 +310,58 @@ public class XMLSceneParser extends DefaultHandler
/** The XML element tag currently being processed. */ /** The XML element tag currently being processed. */
protected String _tag; protected String _tag;
/** The scene object constructed as each scene file is read. */
protected MisoScene _scene;
/** The tile manager object for use in constructing scenes. */ /** The tile manager object for use in constructing scenes. */
protected TileManager _tilemgr; protected TileManager _tilemgr;
/** Temporary storage of scene object values and data. */ /** Temporary storage of character data while parsing. */
protected StringBuffer _chars; protected StringBuffer _chars;
protected String _scName;
protected ArrayList _scLocations, _scPortals, _scClusters; /** Temporary storage of scene info while parsing. */
protected Tile[][][] _scTiles; protected SceneInfo _info;
protected int _scLnum, _scRownum, _scColstart;
/**
* A class to hold temporary information on a scene.
*/
class SceneInfo
{
/** The scene name. */
public String name;
/** The location list. */
public ArrayList locations;
/** The portal list. */
public ArrayList portals;
/** The cluster list. */
public ArrayList clusters;
/** The tile array. */
public Tile[][][] tiles;
/** The current layer number being processed. */
public int lnum;
/** The current row number being processed. */
public int rownum;
/** The column at which the current row data begins. */
public int colstart;
/** The scene object constructed once all scene info is parsed. */
public MisoScene scene;
public SceneInfo ()
{
int width = MisoScene.TILE_WIDTH, height = MisoScene.TILE_HEIGHT;
tiles = new Tile[width][height][MisoScene.NUM_LAYERS];
clusters = new ArrayList();
}
public void constructScene (TileManager tilemgr)
{
scene = new MisoScene(
tilemgr, name, locations, clusters, portals, tiles);
}
}
} }