package net.jtank.io;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.io.*;
import java.net.*;
import net.jtank.util.Delegate;
/**
* WXML is a way of storing and transferring data in a hierarchical text format
* It can't yet be technically called XML, as it does not nessesarily accept all
* well-formed XML documents, it does handle most.
*
*
* The WXML class contains some nessesary methods that relate to creating,
* reading and writing the WXML file format. WXML is not XML, but is
* syntactically very similar.
*
*
* @author William Denniss
* @version 1.1 - 3 April 2002
*
* Version History:
* 1.0 - 15 March 2002: Started.
* 1.0 - 17 March 2002: Fully Functional.
* 1.1 - 3 April 2002: TSFS integration added.
*
*
* The tanksoftware package, it's binaries and source code are all licensed
* under the GNU GPL. See the accompanying file COPYING for details.
*
* William Denniss has asserted his right under the Australian Copyright,
* Designs and Patents Act 1988 to be identified as the author of this work.
*/
public class WXML extends WXMLSection {
/**
* Creates an empty WXML object, with no name, and no parent WXMLSection.
*/
public WXML () {
super(null,null);
}
public static final int numTests = 4;
/**
* An example case. The file is read in, and then outputted to the screen.
* Ideally, this output should semantically match the input.
* @param args The arguments parsed into this method.
*/
public static final void main (String [] args) {
int numTests = WXML.numTests;
try {
numTests = Integer.parseInt(args[0]);
} catch (Exception e) {}
for (int i = 1; i < numTests+1; i++) {
try {
System.out.println("loading test " + i);
WXML newX = WXML.loadFile("data/WXML/test" + i + ".wxml");
System.out.println("test " + i + " loaded");
System.out.println("---");
System.out.println(newX.toWXMLString());
System.out.println("---");
System.out.println(newX.toOrderedWXMLString());
System.out.println("|||");
} catch (IOException e) {
System.out.println("IO error reading file");
} catch (Exception e) {
System.out.println("General Exception ---------");
e.printStackTrace();
System.out.println("|-------------|");
}
}
}
/*
public static String toEscape (String unEscaped) {
String toReturn = "";
for (int i = 0; i < unEscaped.length(); i++) {
if (unEscaped.charAt(i) == '=' || // equals
unEscaped.charAt(i) == '\\' || // backslash
unEscaped.charAt(i) == '<' || // less than
unEscaped.charAt(i) == '>') { //greater than
toReturn = toReturn + "\\" + unEscaped.charAt(i);
} else {
toReturn = toReturn + unEscaped.charAt(i);
}
}
return toReturn;
}
public static String fromEscape (String escaped) {
String toReturn = "";
int slash = 0;
for (int i = 0; i < escaped.length(); i++) {
if (escaped.charAt(i) != '\\' || slash > 0) {
toReturn = toReturn + escaped.charAt(i);
if (slash > 0)
slash = 0;
} else {
slash++;
}
}
return toReturn;
}
*/
/**
* Loads a WXML formatted file into a new WXML object.
*
* @param filename The String which points to the name of the file to load.
* @param fileSystem The TSFS file system to use, can be null if none are being
* used.
* @return The WXML Object containing the file data, or null if there was an error.
* @throws IOException If there is an error reading the file.
*/
public static WXML loadFile (String filename) throws IOException {
String contents = "";
/*
* Reads the entire file that is given into a string with no line breaks.
*/
BufferedReader br = null;
FileUtil.getFileSpecificBufferedReader(filename);
String line = br.readLine();
//todo: try putting line + "\n" back in.
while (line != null) {
contents += line + " \n";//" ";
line = br.readLine();
}
return parseString (contents);
}
/**
* Parses a WXML formatted String into a WXML object. It does this by recursivly
* adding the current WXML tag, and parsing the remaining text. A tag which
* contains only text and no other tags is considered an attribute.
*
* @param contents The WXML formatted String to parse.
* @return That String, as loaded into a WXML object.
*/
public static WXML parseString (String contents) {
/*
* Starts off the recursion method which will build the WXML tree.
*/
WXML toAdd = new WXML ();
contents = replaceDoubleChar(contents,'\\','<','�');
contents = replaceDoubleChar(contents,'\\','>','�');
toAdd.addSubSection(parseSection(contents,null));
return toAdd;
}
//given a list of tags, eg asdf9040
// it will recursivly create sections and subsections for the first tag (level), then for all of the rest (balls)
/**
* Recursivly builds a List containing all of the WXMLSections as
* they appear in the parsed text. This text would be in WXML format,
* eg. foobar.
* That String would give 2 WXMLSections in the returned List file, the
* first with a sub-section.
*
* @param toParse The String containing the WXML tags.
* @param parent The parent object to which these tags belong.
* @return A list containing the WXMLSections from the parsed String.
*/
public static List parseSection (String toParse, WXMLSection parent) {
WXMLSection currentSection;
List toReturn = new ArrayList();
String currentTag = "";
String currentTagInlineAttributes = "";
String currentSectionText = "";
int i = 0;
// Skip to the first tag
try {
while (toParse.charAt(i) != '<')
i++;
// There are no further tags, only text ie, it is an attribute
} catch (StringIndexOutOfBoundsException e) {
WXMLSection toAdd = new WXMLSection ("-=attribute=-",parent);
toAdd.text = toParse;
//toAdd.addInOrderSectionTag
toReturn.add(toAdd);
return toReturn;
}
// Gets the text of the first tag
i++;
while (toParse.charAt(i) != ' ' && toParse.charAt(i) != '>') {
currentTag += toParse.charAt(i);
i++;
}
//System.out.println("++" + currentTag);
// gets the inline attributes of the first tag
if (toParse.charAt(i) == ' ') {
while (toParse.charAt(i) != '>') {
currentTagInlineAttributes += toParse.charAt(i);
i++;
}
}
i++;
//System.out.println("++" + currentTagInlineAttributes);
// gets all of the text contined in the tag
try {
while (!toParse.substring(i,currentTag.length() + 3 + i).equalsIgnoreCase("" + currentTag + ">")) {
//System.out.println("=" + toParse.substring(i,currentTag.length() + 3 + i) + "=." + "" + currentTag + ">" + ".=");
currentSectionText += toParse.charAt(i);
i++;
}
//System.out.println("oooo3563456365365ooooooo");
} catch (Exception e) {/*System.out.println("ooooooooooo");*/};
String remainder = "";
// gets all of the text after the tag
try {
remainder = toParse.substring(currentTag.length() + 4 + i, toParse.length());
} catch (Exception e) {/*System.out.println("pppp");*/};
//System.out.println("+++" + currentSectionText);
//System.out.println("++-+" + remainder);
// Create new Section
WXMLSection toAdd = new WXMLSection(currentTag, parent);
toAdd.text = currentSectionText; // Add the text
toAdd.addAttribute(inlineAttributeParser(currentTagInlineAttributes)); // Add attributes
toAdd.addSubSection(parseSection (currentSectionText, parent)); // Add sub-sections
// Add this subsection to the list to be returned
toReturn.add( toAdd);
// Add any other sections that were after this one to the list to be returned
toReturn.addAll(parseSection(remainder, parent));
/*
* NOTE that Sections containing only text and no sub-sections are considered
* attributes, and at some stange need to be converted as such;
*
* todo: attribute resolution for inline and tagged attributes
*/
for (int l = 0; l < toReturn.size(); l++ )
((WXMLSection) toReturn.get(l)).resolveSubSectionAttributes();
return toReturn;
}
public static String replaceChar (String toReplace, char from, char to) {
String toReturn = "";
for (int i = 0; i < toReplace.length(); i++) {
if (toReplace.charAt(i) == from) {
toReturn += to;
} else {
toReturn += toReplace.charAt(i);
}
}
return toReturn;
}
public static String replaceCharDouble (String toReplace, char from, char to1, char to2) {
String toReturn = "";
for (int i = 0; i < toReplace.length(); i++) {
if (toReplace.charAt(i) == from) {
toReturn += to1 + "" + to2;
} else {
toReturn += toReplace.charAt(i);
}
}
return toReturn;
}
public static String replaceDoubleChar (String toReplace, char from1, char from2, char to) {
String toReturn = "";
for (int i = 0; i < toReplace.length()-1; i++) {
if (toReplace.charAt(i) == from1 && toReplace.charAt(i+1) == from2) {
toReturn += to;
i++;
} else {
toReturn += toReplace.charAt(i);
if (i == toReplace.length()-2)
toReturn += toReplace.charAt(i+1);
}
}
return toReturn;
}
/**
* Parses a list of attributes that are embedded in a tag, eg
*
* @param toParse The String to parse for attributes
* @return A List of WXMLAttribute objects which are all of the attributes
* that were found in the tag
*/
public static List inlineAttributeParser (String toParse) {
List toReturn = new ArrayList ();
//System.out.println("1:" + toParse + "<");
toParse = replaceDoubleChar(toParse, '\\','\"','�');
//System.out.println("2:" +toParse + "<");
String spacesInAttribute = "";
// Temporarily remove spaces
int j = 0;
while (j < toParse.length()) {
if (toParse.charAt(j) == '"') {
spacesInAttribute += toParse.charAt(j);
j++; //�
while (toParse.charAt(j) != '"') {
if (toParse.charAt(j) == ' ')
spacesInAttribute += '�';
else if (toParse.charAt(j) == '=')
spacesInAttribute += '�';
else
spacesInAttribute += toParse.charAt(j);
j++;
}
spacesInAttribute += toParse.charAt(j);
j++;
} else {
spacesInAttribute += toParse.charAt(j);
j++;
}
}
String [] attributes = Delegate.stringCarver(spacesInAttribute, " ");
//System.out.println(spacesInAttribute + "========================");
//System.out.println(attributes.length);
for (int i = 0; i < attributes.length; i++) {
String currentAttribute = "";
//insert spaces back in
for (int k = 0; k < attributes[i].length(); k++) {
if (attributes[i].charAt(k) == '�')
currentAttribute += ' '; //re-insert spaces
else if (attributes[i].charAt(k) == '"')
currentAttribute += ""; //cut out "'s
else
currentAttribute += attributes[i].charAt(k);
}
String key = Delegate.carvePos(currentAttribute,0,"=");
String value = Delegate.carvePos(currentAttribute,1,"=");
value = replaceChar(value, '�','\"');
value = replaceChar(value, '�','=');
value = replaceChar(value, '�','<');
value = replaceChar(value, '�','>');
//value = fromEscape(value);
toReturn.add(new WXMLAttribute (key, value, true));
//System.out.println("key:" + key + "value:" + value);
}
return toReturn;
}
}