using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
namespace SCJMapper_V2
{
///
/// should read the default profile - may be replacing the MappingVars once
///
class DProfileReader
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod( ).DeclaringType );
public Boolean ValidContent { get; set; }
private Stack m_nodeNameStack = null; // element name stack - keeping track where we are
// state for the parser
enum EState
{
idle = 0,
inActionMap,
}
private EState m_state = EState.idle;
// an action map and its actions
class Action
{
public String name { get; set; } // the action name
public String input { get; set; } // the input method K,J,X,P
private String m_defBinding = "";
public String defBinding { get { return m_defBinding; } set { m_defBinding = value.Trim( ); } } // need to clean this one, found spaces...
public String keyName
{ get { return input + name; } } // prep for TreView usage - create a key from input+name
}
class ActionMap : List // carries the action list
{
public String name { get; set; } // the map name
};
Dictionary m_aMap = null; // key would be the actionmap name
ActionMap m_currentMap = null;
public DProfileReader( )
{
ValidContent = false; // default
}
///
/// Returns the collected actionmaps as CSV (same format as MappingVars)
/// i.e. one line per actionmap where the first element is the actionmap and following are actions;defaultBinding lead by the input Key in uppercase (JKXP)
///
public String CSVMap
{
get
{
log.Debug( "CSVMap - Entry" );
String buf = "";
foreach ( ActionMap am in m_aMap.Values ) {
buf += am.name + ";";
foreach ( Action a in am ) {
buf += a.keyName + ";" + a.defBinding + ";"; // add default binding to the CSV
}
buf += String.Format( "\n" );
}
return buf;
}
}
///
/// Assumes to be in an action element
/// retrieves the attributes and collects the various control=binding pairs
///
/// An XML reader @ StartElement
private void CollectActions( XmlReader xr, Dictionary attr )
{
// we collect actions for each input ie for K,J,X and P
if ( attr.ContainsKey( "joystick" ) ) {
Action ac = new Action( );
ac.name = attr["name"];
ac.input = "J";
ac.defBinding = attr["joystick"];
if ( !String.IsNullOrEmpty( ac.defBinding ) ) m_currentMap.Add( ac ); // finally add it to the current map if it was bound
}
if ( attr.ContainsKey( "keyboard" ) ) {
Action ac = new Action( );
ac.name = attr["name"];
ac.input = "K";
ac.defBinding = attr["keyboard"];
if ( !String.IsNullOrEmpty( ac.defBinding ) ) m_currentMap.Add( ac ); // finally add it to the current map if it was bound
}
if ( attr.ContainsKey( "xboxpad" ) ) {
Action ac = new Action( );
ac.name = attr["name"];
ac.input = "X";
ac.defBinding = attr["xboxpad"];
if ( !String.IsNullOrEmpty( ac.defBinding ) ) m_currentMap.Add( ac ); // finally add it to the current map if it was bound
}
if ( attr.ContainsKey( "ps3pad" ) ) {
Action ac = new Action( );
ac.name = attr["name"];
ac.input = "P";
ac.defBinding = attr["ps3pad"];
if ( !String.IsNullOrEmpty( ac.defBinding ) ) m_currentMap.Add( ac ); // finally add it to the current map if it was bound
}
}
///
/// Read one 'empty' XML element
///
///
///
///
/// An XML reader @ StartElement
/// True if reading can continue
private Boolean ReadEmptyElement( XmlReader xr )
{
Dictionary attr = new Dictionary( );
String eName = xr.Name;
switch ( xr.NodeType ) {
case XmlNodeType.Element:
//Console.Write( "<{0}", xr.Name );
while ( xr.MoveToNextAttribute( ) ) {
attr.Add( xr.Name, xr.Value ); // save the attributes
//Console.Write( " {0}='{1}'", xr.Name, xr.Value );
}
if ( m_state == EState.inActionMap ) {
// processing a valid action map - collect actions
if ( eName.ToLower( ) == "action" ) {
// this is an action.. - collect it
CollectActions( xr, attr );
}
}// if inmap
//Console.Write( ">\n" );
break;
case XmlNodeType.Text:
//Console.Write( xr.Value );
break;
case XmlNodeType.EndElement:
//Console.Write( "{0}>\n", xr.Name );
break;
}
return true;
}
///
/// Reads an action sub element
///
/// An XML reader @ StartElement
private void ReadActionSub( XmlReader xr, String actionName )
{
//
//
//
//
//or
//
//
//
//
//
Boolean done = false;
do {
xr.Read( ); // get next element
Dictionary attr = new Dictionary( );
String eName = xr.Name;
while ( xr.MoveToNextAttribute( ) ) {
attr.Add( xr.Name, xr.Value ); // save the attributes
//Console.Write( " {0}='{1}'", xr.Name, xr.Value );
}
xr.MoveToElement( ); // backup
Action ac = new Action( );
ac.name = actionName;
// the element name is a control
if ( xr.NodeType == XmlNodeType.EndElement ) {
done = ( xr.Name == "action" );
}
else if ( xr.IsEmptyElement ) {
// an attribute only element
ac.input = ActionCls.DevID( eName );
ac.defBinding = attr["input"];
if ( !String.IsNullOrEmpty( ac.defBinding ) ) m_currentMap.Add( ac ); // finally add it to the current map if it was bound
}
else {
// one with subelements again
xr.Read( );
ac.input = ActionCls.DevID( eName );
ac.defBinding = xr["input"];
if ( !String.IsNullOrEmpty( ac.defBinding ) ) m_currentMap.Add( ac ); // finally add it to the current map if it was bound
}
} while ( !done );
m_nodeNameStack.Pop( ); // action is finished
}
///
/// Read one XML element
///
///
/// [ Xelement ]
///
///
///
/// An XML reader @ StartElement
/// True if reading can continue
private Boolean ReadElement( XmlReader xr )
{
Dictionary attr = new Dictionary( );
String eName = xr.Name;
switch ( xr.NodeType ) {
case XmlNodeType.Element:
//Console.Write( "<{0}", xr.Name );
while ( xr.MoveToNextAttribute( ) ) {
attr.Add( xr.Name, xr.Value ); // save the attributes
//Console.Write( " {0}='{1}'", xr.Name, xr.Value );
}
// now here we could have an actionmap start
if ( m_state == EState.idle ) {
if ( m_nodeNameStack.Peek( ).ToLower( ) == "actionmap" ) {
// check for a valid one
String mapName = attr["name"];
String item = Array.Find( ActionMapsCls.ActionMaps, delegate( String sstr ) {
return sstr == mapName;
} );
if ( !String.IsNullOrEmpty( item ) ) {
// finally.... it is a valid actionmap
m_currentMap = new ActionMap( );
m_currentMap.name = mapName;
m_aMap.Add( mapName, m_currentMap ); // add to our inventory
m_state = EState.inActionMap; // now we are in and processing the map
}
}
}
else if ( m_state == EState.inActionMap ) {
// processing a valid action map - collect actions
if ( eName.ToLower( ) == "action" ) {
// this is an action.. - collect it
CollectActions( xr, attr );
ReadActionSub( xr, attr["name"] ); // a non empty action element may have a sub element
}
}
//Console.Write( ">\n" );
break;
case XmlNodeType.Text:
//Console.Write( xr.Value );
break;
case XmlNodeType.EndElement:
//Console.Write( "{0}>\n", xr.Name );
break;
}
return true;
}
///
/// Read the xml part
///
///
///
private Boolean ReadXML( XmlReader xr )
{
log.Debug( "ReadXML - Entry" );
Boolean retVal = true;
try {
do {
if ( xr.IsStartElement( ) ) {
m_nodeNameStack.Push( xr.Name );
if ( xr.IsEmptyElement ) {
retVal = retVal && ReadEmptyElement( xr );
m_nodeNameStack.Pop( ); // empty ones end inline
}
else {
retVal = retVal && ReadElement( xr );
}
}
else if ( xr.NodeType == XmlNodeType.EndElement ) {
//Console.Write( "{0}>\n", xr.Name );
String exitElement = m_nodeNameStack.Pop( );
if ( m_state == EState.inActionMap )
if ( exitElement.ToLower( ) == "actionmap" ) m_state = EState.idle; // finished
}
} while ( xr.Read( ) );
if ( m_nodeNameStack.Count == 0 )
return retVal && true;
else
return false;
}
catch ( Exception ex ) {
// get any exceptions from reading
log.Error( "ReadXML - unexpected", ex );
return false;
}
}
///
/// Read the defaultProfile.xml - do some sanity check
///
/// the XML action defaultProfile Content
/// True if an action was decoded
public Boolean fromXML( String xml )
{
log.Debug( "fromXML - Entry" );
XmlReaderSettings settings = new XmlReaderSettings( );
settings.ConformanceLevel = ConformanceLevel.Fragment;
settings.IgnoreWhitespace = true;
settings.IgnoreComments = true;
XmlReader reader = XmlReader.Create( new StringReader( xml ), settings );
m_nodeNameStack = new Stack( );
m_aMap = new Dictionary( );
reader.Read( );
ValidContent = ReadXML( reader );
return ValidContent;
}
}
}