[dasher: 1/43] Introduce AbstractXMLParser with code common to ColourIO, AlphIO, TrainingHelper



commit c167cebe2629bee45f7f6d47b2acf32f2ad26665
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Thu Mar 17 14:00:47 2011 +0000

    Introduce AbstractXMLParser with code common to ColourIO, AlphIO, TrainingHelper
    
    Pretty minimal, but removes duplication of ParseFile, and wraps void* callback
     into C++ virtual methods => Remove "Me->" from everything in {Alph,Colour}IO!
    
    Update MacOS+iPhone project files, Makefile.am
    
    Rm what's left of TrainingHelper (not a lot!) by combining into Trainer

 Src/DasherCore/AbstractXMLParser.cpp        |   93 ++++++++++
 Src/DasherCore/AbstractXMLParser.h          |   53 ++++++
 Src/DasherCore/Alphabet/AlphIO.cpp          |  259 +++++++++-----------------
 Src/DasherCore/Alphabet/AlphIO.h            |   19 +--
 Src/DasherCore/ColourIO.cpp                 |  105 ++----------
 Src/DasherCore/ColourIO.h                   |   19 +--
 Src/DasherCore/Makefile.am                  |    4 +-
 Src/DasherCore/Trainer.cpp                  |   59 ++++++-
 Src/DasherCore/Trainer.h                    |   17 ++-
 Src/DasherCore/TrainingHelper.cpp           |  166 -----------------
 Src/DasherCore/TrainingHelper.h             |   59 ------
 Src/MacOSX/Dasher.xcodeproj/project.pbxproj |   16 +-
 Src/iPhone/Dasher.xcodeproj/project.pbxproj |   12 +-
 13 files changed, 350 insertions(+), 531 deletions(-)
---
diff --git a/Src/DasherCore/AbstractXMLParser.cpp b/Src/DasherCore/AbstractXMLParser.cpp
new file mode 100644
index 0000000..b9acdd5
--- /dev/null
+++ b/Src/DasherCore/AbstractXMLParser.cpp
@@ -0,0 +1,93 @@
+/*
+ *  AbstractXMLParser.cpp
+ *  Dasher
+ *
+ *  Created by Alan Lawrence on 17/03/2011.
+ *  Copyright 2011 Cavendish Laboratory. All rights reserved.
+ *
+ */
+
+#include "AbstractXMLParser.h"
+
+bool AbstractXMLParser::ParseFile(const std::string &strFilename) {
+  FILE *Input;
+  if((Input = fopen(strFilename.c_str(), "r")) == (FILE *) 0) {
+    // could not open file
+    return false;
+  }
+
+  XML_Parser Parser = XML_ParserCreate(NULL);
+
+  // Members passed as callbacks must be static, so don't have a "this" pointer.
+  // We give them one through horrible casting so they can effect changes.
+  XML_SetUserData(Parser, this);
+
+  XML_SetElementHandler(Parser, XML_StartElement, XML_EndElement);
+  XML_SetCharacterDataHandler(Parser, XML_CharacterData);
+
+  char Buffer[1024];
+  int Done;
+  do {
+    size_t len = fread(Buffer, 1, sizeof(Buffer), Input);
+    Done = len < sizeof(Buffer);
+    if(XML_Parse(Parser, Buffer, len, Done) == XML_STATUS_ERROR) {
+      //TODO, should we make sure we return false, if this happens?
+      break;
+    }
+  } while (!Done);
+
+  XML_ParserFree(Parser);
+  fclose(Input);
+  return true;
+}
+
+void AbstractXMLParser::XmlCData(const XML_Char *str, int len) {
+  DASHER_ASSERT(false);
+}
+
+void AbstractXMLParser::XML_Escape(std::string &Input, bool Attribute) {
+  // The XML "W3C Recommendation" is here: http://www.w3.org/TR/REC-xml
+  
+  for(unsigned int i = 0; i < Input.size(); i++) {
+    // & and < need escaping in XML. In one rare circumstance >
+    // needs escaping too. I'll always do it, as I'm allowed to.
+    if(Input[i] == '&') {
+      Input.replace(i, 1, "&amp;");
+      continue;
+    }
+    if(Input[i] == '<') {
+      Input.replace(i, 1, "&lt;");
+      continue;
+    }
+    if(Input[i] == '>') {
+      Input.replace(i, 1, "&gt;");
+      continue;
+    }
+    // " and ' might need escaping inside attributes, I'll do them all.
+    if(Attribute == false)
+      continue;
+    
+    if(Input[i] == '\'') {
+      Input.replace(i, 1, "&apos;");
+      continue;
+    }
+    if(Input[i] == '"') {
+      Input.replace(i, 1, "&quot;");
+      continue;
+    }
+  }
+}
+
+
+//Actual callbacks for expat. void*, here we come!
+void AbstractXMLParser::XML_StartElement(void *userData, const XML_Char * name, const XML_Char ** atts) {
+  static_cast<AbstractXMLParser*>(userData)->XmlStartHandler(name, atts);
+}
+
+void AbstractXMLParser::XML_EndElement(void *userData, const XML_Char * name) {
+  static_cast<AbstractXMLParser*>(userData)->XmlEndHandler(name);
+}
+
+void AbstractXMLParser::XML_CharacterData(void *userData, const XML_Char * s, int len) {
+  static_cast<AbstractXMLParser*>(userData)->XmlCData(s,len);
+}
diff --git a/Src/DasherCore/AbstractXMLParser.h b/Src/DasherCore/AbstractXMLParser.h
new file mode 100644
index 0000000..0a80c3a
--- /dev/null
+++ b/Src/DasherCore/AbstractXMLParser.h
@@ -0,0 +1,53 @@
+/*
+ *  AbstractXMLParser.h
+ *  Dasher
+ *
+ *  Created by Alan Lawrence on 17/03/2011.
+ *  Copyright 2011 Cavendish Laboratory. All rights reserved.
+ *
+ */
+
+#ifndef __ABSTRACT_XML_PARSER_H__
+#define __ABSTRACT_XML_PARSER_H__
+
+#include "../Common/Common.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string>
+#include <expat.h>
+
+///Basic wrapper over (Expat) XML Parser, handling file IO and wrapping C++
+/// virtual methods over C callbacks. Subclasses must implement methods to
+/// handle actual tags.
+class AbstractXMLParser {
+public:
+  ///Parse (the whole) file - done in chunks to avoid loading the whole thing into memory.
+  /// \return true if the file was opened+parsed; false if not (i.e. filename did not exist)
+  bool ParseFile(const std::string &strFilename);
+protected:
+  ///Subclass should override to handle a start tag
+  virtual void XmlStartHandler(const XML_Char *name, const XML_Char **atts)=0;
+  ///Subclass should override to handle an end tag
+  virtual void XmlEndHandler(const XML_Char *name)=0;
+  ///Subclass may override to handle character data;
+  /// Default implementation asserts false, and ignores.
+  ///\param str pointer to string data, note is NOT null-terminated
+  ///\param len number of bytes to read from pointer
+  virtual void XmlCData(const XML_Char *str, int len);
+  
+  ///Utility function provided for subclasses wishing to perform XML _output_.
+  // & to &amp;  < to &lt; and > to &gt;  and if (Attribute) ' to &apos; and " to &quot;
+  /// \param Input string to escape, will be updated in-place.
+  void XML_Escape(std::string &Input, bool Attribute);
+private:
+  /// The actual callbacks passed to the expat library.
+  /// These just convert the void* we passed to the library back into
+  /// an instance pointer, to get a C++ class to work with a plain C library.
+  static void XML_StartElement(void *userData, const XML_Char * name, const XML_Char ** atts);
+  static void XML_EndElement(void *userData, const XML_Char * name);
+  static void XML_CharacterData(void *userData, const XML_Char * s, int len);
+};
+
+#endif
\ No newline at end of file
diff --git a/Src/DasherCore/Alphabet/AlphIO.cpp b/Src/DasherCore/Alphabet/AlphIO.cpp
index 9f360d4..d52b772 100644
--- a/Src/DasherCore/Alphabet/AlphIO.cpp
+++ b/Src/DasherCore/Alphabet/AlphIO.cpp
@@ -78,37 +78,6 @@ CAlphIO::CAlphIO(std::string SystemLocation, std::string UserLocation, std::vect
   }
 }
 
-void CAlphIO::ParseFile(std::string Filename) {
-  FILE *Input;
-  if((Input = fopen(Filename.c_str(), "r")) == (FILE *) 0) {
-    // could not open file
-    return;
-  }
-
-  XML_Parser Parser = XML_ParserCreate(NULL);
-
-  // Members passed as callbacks must be static, so don't have a "this" pointer.
-  // We give them one through horrible casting so they can effect changes.
-  XML_SetUserData(Parser, this);
-
-  XML_SetElementHandler(Parser, XML_StartElement, XML_EndElement);
-  XML_SetCharacterDataHandler(Parser, XML_CharacterData);
-
-  const unsigned int BufferSize = 1024;
-  char Buffer[BufferSize];
-  int Done;
-  do {
-    size_t len = fread(Buffer, 1, sizeof(Buffer), Input);
-    Done = len < sizeof(Buffer);
-    if(XML_Parse(Parser, Buffer, len, Done) == XML_STATUS_ERROR) {
-      break;
-    }
-  } while(!Done);
-
-  XML_ParserFree(Parser);
-  fclose(Input);
-}
-
 void CAlphIO::GetAlphabets(std::vector <std::string >*AlphabetList) const {
   AlphabetList->clear();
 
@@ -192,7 +161,7 @@ void CAlphIO::Save(const std::string &AlphID) {
       continue;
 
     fwrite("<alphabet name=\"", sizeof(char), 16, Output);
-    XML_Escape(&Info.AlphID, true);
+    XML_Escape(Info.AlphID, true);
     fwrite(Info.AlphID.c_str(), sizeof(char), Info.AlphID.size(), Output);
     fwrite("\">\n", sizeof(char), 3, Output);
 
@@ -221,17 +190,17 @@ void CAlphIO::Save(const std::string &AlphID) {
     fwrite("\"/>\n", sizeof(char), 4, Output);
 
     fwrite("<palette>", sizeof(char), 9, Output);
-    XML_Escape(&Info.PreferredColours, false);
+    XML_Escape(Info.PreferredColours, false);
     fwrite(Info.PreferredColours.c_str(), sizeof(char), Info.PreferredColours.size(), Output);
     fwrite("</palette>\n", sizeof(char), 11, Output);
 
     fwrite("<train>", sizeof(char), 7, Output);
-    XML_Escape(&Info.TrainingFile, false);
+    XML_Escape(Info.TrainingFile, false);
     fwrite(Info.TrainingFile.c_str(), sizeof(char), Info.TrainingFile.size(), Output);
     fwrite("</train>\n", sizeof(char), 9, Output);
 
     fwrite("<gamemode>", sizeof(char), 10, Output);
-    XML_Escape(&Info.GameModeFile, false);
+    XML_Escape(Info.GameModeFile, false);
     fwrite(Info.GameModeFile.c_str(), sizeof(char), Info.GameModeFile.size(), Output);
     fwrite("</gamemode>\n", sizeof(char), 12, Output);
 
@@ -242,10 +211,10 @@ void CAlphIO::Save(const std::string &AlphID) {
     if (Info.iSpaceCharacter!=0) {
       CAlphInfo::character &spC(Info.m_vCharacters[Info.iSpaceCharacter]);
       fwrite("<space d=\"", sizeof(char), 10, Output);
-      XML_Escape(&spC.Display, true);
+      XML_Escape(spC.Display, true);
       fwrite(spC.Display.c_str(), sizeof(char), spC.Display.size(), Output);
       fwrite("\" t=\"", sizeof(char), 5, Output);
-      XML_Escape(&spC.Text, true);
+      XML_Escape(spC.Text, true);
       fwrite(spC.Text.c_str(), sizeof(char), spC.Text.size(), Output);
       fwrite("\" b=\"", sizeof(char), 5, Output);
       sprintf(Number, "%d", spC.Colour);
@@ -257,10 +226,10 @@ void CAlphIO::Save(const std::string &AlphID) {
     if (Info.iParagraphCharacter!=-1) {
       CAlphInfo::character para(Info.m_vCharacters[Info.iParagraphCharacter]);
       fwrite("<paragraph d=\"", sizeof(char), 14, Output);
-      XML_Escape(&para.Display, true);
+      XML_Escape(para.Display, true);
       fwrite(para.Display.c_str(), sizeof(char), para.Display.size(), Output);
       fwrite("\" t=\"", sizeof(char), 5, Output);
-      XML_Escape(&para.Text, true);
+      XML_Escape(para.Text, true);
       fwrite(para.Text.c_str(), sizeof(char), para.Text.size(), Output);
       fwrite("\" b=\"", sizeof(char), 5, Output);
       sprintf(Number, "%d", para.Colour);
@@ -271,10 +240,10 @@ void CAlphIO::Save(const std::string &AlphID) {
     // Write out the control character
     if (Info.ControlCharacter) {
       fwrite("<control d=\"", sizeof(char), 12, Output);
-      XML_Escape(&Info.ControlCharacter->Display, true);
+      XML_Escape(Info.ControlCharacter->Display, true);
       fwrite(Info.ControlCharacter->Display.c_str(), sizeof(char), Info.ControlCharacter->Display.size(), Output);
       fwrite("\" t=\"", sizeof(char), 5, Output);
-      XML_Escape(&Info.ControlCharacter->Text, true);
+      XML_Escape(Info.ControlCharacter->Text, true);
       fwrite(Info.ControlCharacter->Text.c_str(), sizeof(char), Info.ControlCharacter->Text.size(), Output);
       fwrite("\" b=\"", sizeof(char), 5, Output);
       sprintf(Number, "%d", Info.ControlCharacter->Colour);
@@ -286,7 +255,7 @@ void CAlphIO::Save(const std::string &AlphID) {
 //     gi LG = Info.Groups.end();
 //     for(gi CG = Info.Groups.begin(); CG != LG; CG++) {
 //       fwrite("<group name=\"", sizeof(char), 13, Output);
-//       XML_Escape(&CG->Description, true);
+//       XML_Escape(CG->Description, true);
 //       fwrite(CG->Description.c_str(), sizeof(char), CG->Description.size(), Output);
 //       fwrite("\" b=\"", sizeof(char), 5, Output);
 //       sprintf(Number, "%d", CG->Colour);
@@ -298,10 +267,10 @@ void CAlphIO::Save(const std::string &AlphID) {
 //       ci LC = CG->Characters.end();
 //       for(ci CC = CG->Characters.begin(); CC != LC; CC++) {
 //         fwrite("<s d=\"", sizeof(char), 6, Output);
-//         XML_Escape(&CC->Display, true);
+//         XML_Escape(CC->Display, true);
 //         fwrite(CC->Display.c_str(), sizeof(char), CC->Display.size(), Output);
 //         fwrite("\" t=\"", sizeof(char), 5, Output);
-//         XML_Escape(&CC->Text, true);
+//         XML_Escape(CC->Text, true);
 //         fwrite(CC->Text.c_str(), sizeof(char), CC->Text.size(), Output);
 //         fwrite("\" b=\"", sizeof(char), 5, Output);
 //         sprintf(Number, "%d", CC->Colour);
@@ -382,88 +351,48 @@ CAlphInfo *CAlphIO::CreateDefault() {
   return &Default;
 }
 
-void CAlphIO::XML_Escape(std::string *Text, bool Attribute) {
-  // The XML "W3C Recommendation" is here: http://www.w3.org/TR/REC-xml
-
-  std::string & Input = *Text;       // Makes syntax less fiddly below
-
-  for(unsigned int i = 0; i < Text->size(); i++) {
-    // & and < need escaping in XML. In one rare circumstance >
-    // needs escaping too. I'll always do it, as I'm allowed to.
-    if(Input[i] == '&') {
-      Input.replace(i, 1, "&amp;");
-      continue;
-    }
-    if(Input[i] == '<') {
-      Input.replace(i, 1, "&lt;");
-      continue;
-    }
-    if(Input[i] == '>') {
-      Input.replace(i, 1, "&gt;");
-      continue;
-    }
-    // " and ' might need escaping inside attributes, I'll do them all.
-    if(Attribute == false)
-      continue;
-
-    if(Input[i] == '\'') {
-      Input.replace(i, 1, "&apos;");
-      continue;
-    }
-    if(Input[i] == '"') {
-      Input.replace(i, 1, "&quot;");
-      continue;
-    }
-  }
-}
-
 // Below here handlers for the Expat XML input library
 ////////////////////////////////////////////////////////////////////////////////////
 
-void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_Char **atts) {
-  CAlphIO *Me = (CAlphIO *) userData;
+void CAlphIO::XmlStartHandler(const XML_Char *name, const XML_Char **atts) {
 
-  Me->CData = "";
+  CData = "";
 
   if(strcmp(name, "alphabet") == 0) {
-    Me->InputInfo = new CAlphInfo();
-    Me->InputInfo->Mutable = Me->LoadMutable;
-    Me->ParagraphCharacter = NULL;
-    Me->SpaceCharacter = NULL;
-    Me->bFirstGroup = true;
-    Me->iGroupIdx = 0;
+    InputInfo = new CAlphInfo();
+    InputInfo->Mutable = LoadMutable;
+    ParagraphCharacter = NULL;
+    SpaceCharacter = NULL;
+    bFirstGroup = true;
+    iGroupIdx = 0;
     while(*atts != 0) {
       if(strcmp(*atts, "name") == 0) {
-        atts++;
-        Me->InputInfo->AlphID = *atts;
-        atts--;
+        InputInfo->AlphID = *(atts+1);
       } else if (strcmp(*atts, "hidden") == 0) {
-        Me->InputInfo->m_bHidden = (strcmp(*(atts+1), "yes")==0);
+        InputInfo->m_bHidden = (strcmp(*(atts+1), "yes")==0);
       } else if (strcmp(*atts, "escape") == 0) {
-        Me->InputInfo->m_strCtxChar = *(atts+1);
+        InputInfo->m_strCtxChar = *(atts+1);
       }
       atts += 2;
     }
-    Me->m_vGroups.clear();
+    m_vGroups.clear();
     return;
   }
 
   if(strcmp(name, "orientation") == 0) {
     while(*atts != 0) {
       if(!strcmp(*atts, "type")) {
-        atts++;
-        if(!strcmp(*atts, "RL")) {
-          Me->InputInfo->Orientation = Opts::RightToLeft;
+        if(!strcmp(*(atts+1), "RL")) {
+          InputInfo->Orientation = Opts::RightToLeft;
         }
-        else if(!strcmp(*atts, "TB")) {
-          Me->InputInfo->Orientation = Opts::TopToBottom;
+        else if(!strcmp(*(atts+1), "TB")) {
+          InputInfo->Orientation = Opts::TopToBottom;
         }
-        else if(!strcmp(*atts, "BT")) {
-          Me->InputInfo->Orientation = Opts::BottomToTop;
+        else if(!strcmp(*(atts+1), "BT")) {
+          InputInfo->Orientation = Opts::BottomToTop;
         }
         else
-          Me->InputInfo->Orientation = Opts::LeftToRight;
-        atts--;
+          InputInfo->Orientation = Opts::LeftToRight;
       }
       atts += 2;
     }
@@ -473,9 +402,7 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
   if(strcmp(name, "encoding") == 0) {
     while(*atts != 0) {
       if(strcmp(*atts, "type") == 0) {
-        atts++;
-        Me->InputInfo->Type = Me->StoT[*atts];
-        atts--;
+        InputInfo->Type = StoT[*(atts+1)];
       }
       atts += 2;
     }
@@ -483,36 +410,36 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
   }
 
   if(strcmp(name, "space") == 0) {
-    if (!Me->SpaceCharacter) Me->SpaceCharacter = new CAlphInfo::character();
-    Me->ReadCharAtts(atts,*(Me->SpaceCharacter));
+    if (!SpaceCharacter) SpaceCharacter = new CAlphInfo::character();
+    ReadCharAtts(atts,*SpaceCharacter);
     return;
   }
   if(strcmp(name, "paragraph") == 0) {
-    if (!Me->ParagraphCharacter) Me->ParagraphCharacter=new CAlphInfo::character();
-    Me->ReadCharAtts(atts,*(Me->ParagraphCharacter));
+    if (!ParagraphCharacter) ParagraphCharacter=new CAlphInfo::character();
+    ReadCharAtts(atts,*ParagraphCharacter);
 #ifdef WIN32
-        Me->ParagraphCharacter->Text = "\r\n";
+        ParagraphCharacter->Text = "\r\n";
 #else
-        Me->ParagraphCharacter->Text = "\n";
+        ParagraphCharacter->Text = "\n";
 #endif
     return;
   }
   if(strcmp(name, "control") == 0) {
-    if (!Me->InputInfo->ControlCharacter) Me->InputInfo->ControlCharacter = new CAlphInfo::character();
-    Me->ReadCharAtts(atts, *(Me->InputInfo->ControlCharacter));
+    if (!InputInfo->ControlCharacter) InputInfo->ControlCharacter = new CAlphInfo::character();
+    ReadCharAtts(atts, *(InputInfo->ControlCharacter));
     return;
   }
 
   if(strcmp(name, "group") == 0) {
     SGroupInfo *pNewGroup(new SGroupInfo);
     pNewGroup->iNumChildNodes=0;
-    pNewGroup->iColour = (Me->iGroupIdx % 3) + 110;
-    ++Me->iGroupIdx;
-    if (Me->m_vGroups.empty()) Me->InputInfo->iNumChildNodes++; else Me->m_vGroups.back()->iNumChildNodes++;
+    pNewGroup->iColour = (iGroupIdx % 3) + 110;
+    ++iGroupIdx;
+    if (m_vGroups.empty()) InputInfo->iNumChildNodes++; else m_vGroups.back()->iNumChildNodes++;
 
-    if(Me->bFirstGroup) {
+    if(bFirstGroup) {
       pNewGroup->bVisible = false;
-      Me->bFirstGroup = false;
+      bFirstGroup = false;
     }
     else {
       pNewGroup->bVisible = true;
@@ -523,7 +450,7 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
 	// TODO: Fix this, or remove if names aren't needed
 
 //         atts++;
-//         Me->InputInfo->Groups.back().Description = *atts;
+//         InputInfo->Groups.back().Description = *atts;
 //         atts--;
       }
       if(strcmp(*atts, "b") == 0) {
@@ -547,21 +474,21 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
       atts += 2;
     }
 
-    pNewGroup->iStart = Me->InputInfo->m_vCharacters.size()+1;
+    pNewGroup->iStart = InputInfo->m_vCharacters.size()+1;
 
     pNewGroup->pChild = NULL;
 
-    if(Me->m_vGroups.size() > 0) {
-      pNewGroup->pNext = Me->m_vGroups.back()->pChild;
-      Me->m_vGroups.back()->pChild = pNewGroup;
+    if(m_vGroups.size() > 0) {
+      pNewGroup->pNext = m_vGroups.back()->pChild;
+      m_vGroups.back()->pChild = pNewGroup;
     }
     else {
-      pNewGroup->pNext = Me->InputInfo->m_pBaseGroup;
-      Me->InputInfo->m_pBaseGroup = pNewGroup;
+      pNewGroup->pNext = InputInfo->m_pBaseGroup;
+      InputInfo->m_pBaseGroup = pNewGroup;
     }
 
 
-    Me->m_vGroups.push_back(pNewGroup);
+    m_vGroups.push_back(pNewGroup);
 
     return;
   }
@@ -569,13 +496,13 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
   if(!strcmp(name, "conversionmode")) {
     while(*atts != 0) {
       if(strcmp(*atts, "id") == 0) {
-        Me->InputInfo->m_iConversionID = atoi(*(atts+1));
+        InputInfo->m_iConversionID = atoi(*(atts+1));
       } else if (strcmp(*atts, "target") == 0) {
-        Me->InputInfo->m_strConversionTarget = *(atts+1);
+        InputInfo->m_strConversionTarget = *(atts+1);
       } else if (strcmp(*atts, "delim") == 0) {
         //TODO, should check this is only a single unicode character;
         // no training will occur, if not...
-        Me->InputInfo->m_strConversionTrainingDelimiter = *(atts+1);
+        InputInfo->m_strConversionTrainingDelimiter = *(atts+1);
       }
       atts += 2;
     }
@@ -585,23 +512,21 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
 
   // Special characters for character composition
   if(strcmp(name, "convert") == 0) {
-    if (!Me->InputInfo->StartConvertCharacter) Me->InputInfo->StartConvertCharacter = new CAlphInfo::character();
-    Me->ReadCharAtts(atts, *(Me->InputInfo->StartConvertCharacter));
+    if (!InputInfo->StartConvertCharacter) InputInfo->StartConvertCharacter = new CAlphInfo::character();
+    ReadCharAtts(atts, *(InputInfo->StartConvertCharacter));
     return;
   }
 
   if(strcmp(name, "protect") == 0) {
-    if (!Me->InputInfo->EndConvertCharacter) Me->InputInfo->EndConvertCharacter = new CAlphInfo::character();
-    Me->ReadCharAtts(atts, *(Me->InputInfo->EndConvertCharacter));
+    if (!InputInfo->EndConvertCharacter) InputInfo->EndConvertCharacter = new CAlphInfo::character();
+    ReadCharAtts(atts, *(InputInfo->EndConvertCharacter));
     return;
   }
 
   if(strcmp(name, "context") == 0) {
     while(*atts != 0) {
       if(strcmp(*atts, "default") == 0) {
-        atts++;
-        Me->InputInfo->m_strDefaultContext = *atts;
-        atts--;
+        InputInfo->m_strDefaultContext = *(atts+1);
       }
       atts += 2;
     }
@@ -610,14 +535,14 @@ void CAlphIO::XML_StartElement(void *userData, const XML_Char *name, const XML_C
 
   if(strcmp(name, "s") == 0) {
 
-    if (Me->m_vGroups.empty()) Me->InputInfo->iNumChildNodes++; else Me->m_vGroups.back()->iNumChildNodes++;
-    Me->InputInfo->m_vCharacters.resize(Me->InputInfo->m_vCharacters.size()+1);
-    CAlphInfo::character &Ch(Me->InputInfo->m_vCharacters.back());
+    if (m_vGroups.empty()) InputInfo->iNumChildNodes++; else m_vGroups.back()->iNumChildNodes++;
+    InputInfo->m_vCharacters.resize(InputInfo->m_vCharacters.size()+1);
+    CAlphInfo::character &Ch(InputInfo->m_vCharacters.back());
 
     // FIXME - need to do a more sensible job of ensuring that
     // defaults are correct (plus more generally fixing behaviour when
     // incomplete/invalid XML is supplied)
-    Me->ReadCharAtts(atts, Ch);
+    ReadCharAtts(atts, Ch);
     return;
   }
 }
@@ -644,53 +569,52 @@ void Reverse(SGroupInfo *&pList) {
   pList=pPrev;
 }
 
-void CAlphIO::XML_EndElement(void *userData, const XML_Char *name) {
-  CAlphIO *Me = (CAlphIO *) userData;
+void CAlphIO::XmlEndHandler(const XML_Char *name) {
 
   if(strcmp(name, "alphabet") == 0) {
-    Reverse(Me->InputInfo->m_pBaseGroup);
+    Reverse(InputInfo->m_pBaseGroup);
 
-    if (Me->ParagraphCharacter) {
-      Me->InputInfo->iParagraphCharacter = Me->InputInfo->m_vCharacters.size()+1;
-      Me->InputInfo->m_vCharacters.push_back(*(Me->ParagraphCharacter));
-      Me->InputInfo->iNumChildNodes++;
-      delete Me->ParagraphCharacter;
+    if (ParagraphCharacter) {
+      InputInfo->iParagraphCharacter = InputInfo->m_vCharacters.size()+1;
+      InputInfo->m_vCharacters.push_back(*ParagraphCharacter);
+      InputInfo->iNumChildNodes++;
+      delete ParagraphCharacter;
     }
-    if (Me->SpaceCharacter) {
-      Me->InputInfo->iSpaceCharacter = Me->InputInfo->m_vCharacters.size()+1;
-      Me->InputInfo->m_vCharacters.push_back(*(Me->SpaceCharacter));
-      Me->InputInfo->iNumChildNodes++;
-      delete Me->SpaceCharacter;
+    if (SpaceCharacter) {
+      InputInfo->iSpaceCharacter = InputInfo->m_vCharacters.size()+1;
+      InputInfo->m_vCharacters.push_back(*SpaceCharacter);
+      InputInfo->iNumChildNodes++;
+      delete SpaceCharacter;
     }
 
-    //if (Me->InputInfo->StartConvertCharacter.Text != "") Me->InputInfo->iNumChildNodes++;
-    //if (Me->InputInfo->EndConvertCharacter.Text != "") Me->InputInfo->iNumChildNodes++;
-    Me->Alphabets[Me->InputInfo->AlphID] = Me->InputInfo;
+    //if (InputInfo->StartConvertCharacter.Text != "") InputInfo->iNumChildNodes++;
+    //if (InputInfo->EndConvertCharacter.Text != "") InputInfo->iNumChildNodes++;
+    Alphabets[InputInfo->AlphID] = InputInfo;
     return;
   }
 
   if(strcmp(name, "train") == 0) {
-    Me->InputInfo->TrainingFile = Me->CData;
+    InputInfo->TrainingFile = CData;
     return;
   }
 
   if(strcmp(name, "gamemode") == 0) {
-    Me->InputInfo->GameModeFile = Me->CData;
+    InputInfo->GameModeFile = CData;
     return;
   }
 
   if(strcmp(name, "palette") == 0) {
-    Me->InputInfo->PreferredColours = Me->CData;
+    InputInfo->PreferredColours = CData;
     return;
   }
 
   if(!strcmp(name, "group")) {
-    SGroupInfo *finished = Me->m_vGroups.back();
-    Me->m_vGroups.pop_back();
-    finished->iEnd = Me->InputInfo->m_vCharacters.size()+1;
+    SGroupInfo *finished = m_vGroups.back();
+    m_vGroups.pop_back();
+    finished->iEnd = InputInfo->m_vCharacters.size()+1;
     if (finished->iEnd == finished->iStart) {
       //empty group. Delete it now, and elide from sibling chain
-      SGroupInfo *&ptr(Me->m_vGroups.size()==0 ? Me->InputInfo->m_pBaseGroup : Me->m_vGroups.back()->pChild);
+      SGroupInfo *&ptr(m_vGroups.size()==0 ? InputInfo->m_pBaseGroup : m_vGroups.back()->pChild);
       DASHER_ASSERT(ptr == finished);
       ptr = finished->pNext;
       delete finished;
@@ -702,12 +626,9 @@ void CAlphIO::XML_EndElement(void *userData, const XML_Char *name) {
   }
 }
 
-void CAlphIO::XML_CharacterData(void *userData, const XML_Char *s, int len) {
+void CAlphIO::XmlCData(const XML_Char *s, int len) {
   // CAREFUL: s points to a string which is NOT null-terminated.
-
-  CAlphIO *Me = (CAlphIO *) userData;
-
-  Me->CData.append(s, len);
+  CData.append(s, len);
 }
 
 CAlphIO::~CAlphIO() {
diff --git a/Src/DasherCore/Alphabet/AlphIO.h b/Src/DasherCore/Alphabet/AlphIO.h
index ac01426..092a6dd 100644
--- a/Src/DasherCore/Alphabet/AlphIO.h
+++ b/Src/DasherCore/Alphabet/AlphIO.h
@@ -26,15 +26,14 @@
 #include <config.h>
 #endif
 
+#include "../AbstractXMLParser.h"
+
 #include "../DasherTypes.h"
 #include "AlphInfo.h"
 
-#include <expat.h>
-#include <string>
 #include <map>
 #include <vector>
 #include <utility>              // for std::pair
-#include <stdio.h>              // for C style file IO
 
 namespace Dasher {
   class CAlphIO;
@@ -52,7 +51,7 @@ namespace Dasher {
 /// Note the alphabet-management functions (SetInfo, Delete, Save, and
 /// hence the mutability of alphabets loaded) don't seem to be fully
 /// implemented...
-class Dasher::CAlphIO {
+class Dasher::CAlphIO : private AbstractXMLParser {
 public:
 
   CAlphIO(std::string SystemLocation, std::string UserLocation, std::vector < std::string > &Filenames);
@@ -79,26 +78,20 @@ private:
   /////////////////////////
 
   bool LoadMutable;
-  void ParseFile(std::string Filename);
   void ReadCharAtts(const XML_Char **atts, CAlphInfo::character &ch);
   // Alphabet types:
   std::map < std::string, Opts::AlphabetTypes > StoT;
   std::map < Opts::AlphabetTypes, std::string > TtoS;
 
-  // & to &amp;  < to &lt; and > to &gt;  and if (Attribute) ' to &apos; and " to &quot;
-  void XML_Escape(std::string * Text, bool Attribute);
-
   // Data gathered
   std::string CData;            // Text gathered from when an elemnt starts to when it ends
   CAlphInfo *InputInfo;
   bool bFirstGroup;
   int iGroupIdx;
 
-  // Callback functions. These involve the normal dodgy casting to a pointer
-  // to an instance to get a C++ class to work with a plain C library.
-  static void XML_StartElement(void *userData, const XML_Char * name, const XML_Char ** atts);
-  static void XML_EndElement(void *userData, const XML_Char * name);
-  static void XML_CharacterData(void *userData, const XML_Char * s, int len);
+  void XmlStartHandler(const XML_Char * name, const XML_Char ** atts);
+  void XmlEndHandler(const XML_Char * name);
+  void XmlCData(const XML_Char * s, int len);
 };
 /// @}
 
diff --git a/Src/DasherCore/ColourIO.cpp b/Src/DasherCore/ColourIO.cpp
index 2a68326..fff8658 100644
--- a/Src/DasherCore/ColourIO.cpp
+++ b/Src/DasherCore/ColourIO.cpp
@@ -43,37 +43,6 @@ CColourIO::CColourIO(std::string SystemLocation, std::string UserLocation, std::
   }
 }
 
-void CColourIO::ParseFile(std::string Filename) {
-  FILE *Input;
-  if((Input = fopen(Filename.c_str(), "r")) == (FILE *) 0) {
-    // could not open file
-    return;
-  }
-
-  XML_Parser Parser = XML_ParserCreate(NULL);
-
-  // Members passed as callbacks must be static, so don't have a "this" pointer.
-  // We give them one through horrible casting so they can effect changes.
-  XML_SetUserData(Parser, this);
-
-  XML_SetElementHandler(Parser, XML_StartElement, XML_EndElement);
-  XML_SetCharacterDataHandler(Parser, XML_CharacterData);
-
-  const unsigned int BufferSize = 1024;
-  char Buffer[BufferSize];
-  int Done;
-  do {
-    size_t len = fread(Buffer, 1, sizeof(Buffer), Input);
-    Done = len < sizeof(Buffer);
-    if(XML_Parse(Parser, Buffer, len, Done) == XML_STATUS_ERROR) {
-      break;
-    }
-  } while(!Done);
-
-  XML_ParserFree(Parser);
-  fclose(Input);
-}
-
 void CColourIO::GetColours(std::vector <std::string >*ColourList) const {
   ColourList->clear();
 
@@ -869,58 +838,20 @@ void CColourIO::CreateDefault() {
 
 }
 
-void CColourIO::XML_Escape(std::string *Text, bool Attribute) {
-  // The XML "W3C Recommendation" is here: http://www.w3.org/TR/REC-xml
-
-  std::string & Input = *Text;       // Makes syntax less fiddly below
-
-  for(unsigned int i = 0; i < Text->size(); i++) {
-    // & and < need escaping in XML. In one rare circumstance >
-    // needs escaping too. I'll always do it, as I'm allowed to.
-    if(Input[i] == '&') {
-      Input.replace(i, 1, "&amp;");
-      continue;
-    }
-    if(Input[i] == '<') {
-      Input.replace(i, 1, "&lt;");
-      continue;
-    }
-    if(Input[i] == '>') {
-      Input.replace(i, 1, "&gt;");
-      continue;
-    }
-    // " and ' might need escaping inside attributes, I'll do them all.
-    if(Attribute == false)
-      continue;
-
-    if(Input[i] == '\'') {
-      Input.replace(i, 1, "&apos;");
-      continue;
-    }
-    if(Input[i] == '"') {
-      Input.replace(i, 1, "&quot;");
-      continue;
-    }
-  }
-}
-
 // Below here handlers for the Expat XML input library
 ////////////////////////////////////////////////////////////////////////////////////
 
-void CColourIO::XML_StartElement(void *userData, const XML_Char *name, const XML_Char **atts) {
-  CColourIO *Me = (CColourIO *) userData;
+void CColourIO::XmlStartHandler(const XML_Char *name, const XML_Char **atts) {
 
-  Me->CData = "";
+  CData = "";
 
   if(strcmp(name, "palette") == 0) {
     ColourInfo NewInfo;
-    Me->InputInfo = NewInfo;
-    Me->InputInfo.Mutable = Me->LoadMutable;
+    InputInfo = NewInfo;
+    InputInfo.Mutable = LoadMutable;
     while(*atts != 0) {
       if(strcmp(*atts, "name") == 0) {
-        atts++;
-        Me->InputInfo.ColourID = *atts;
-        atts--;
+        InputInfo.ColourID = *(atts+1);
       }
       atts += 2;
     }
@@ -929,38 +860,28 @@ void CColourIO::XML_StartElement(void *userData, const XML_Char *name, const XML
   if(strcmp(name, "colour") == 0) {
     while(*atts != 0) {
       if(strcmp(*atts, "r") == 0) {
-        atts++;
-        Me->InputInfo.Reds.push_back(atoi(*atts));
-        atts--;
+        InputInfo.Reds.push_back(atoi(*(atts+1)));
       }
       if(strcmp(*atts, "g") == 0) {
-        atts++;
-        Me->InputInfo.Greens.push_back(atoi(*atts));
-        atts--;
+        InputInfo.Greens.push_back(atoi(*(atts+1)));
       }
       if(strcmp(*atts, "b") == 0) {
-        atts++;
-        Me->InputInfo.Blues.push_back(atoi(*atts));
-        atts--;
+        InputInfo.Blues.push_back(atoi(*(atts+1)));
       }
       atts += 2;
     }
     return;
   }
 }
-void CColourIO::XML_EndElement(void *userData, const XML_Char *name) {
-  CColourIO *Me = (CColourIO *) userData;
-
+void CColourIO::XmlEndHandler(const XML_Char *name) {
+  
   if(strcmp(name, "palette") == 0) {
-    Me->Colours[Me->InputInfo.ColourID] = Me->InputInfo;
+    Colours[InputInfo.ColourID] = InputInfo;
     return;
   }
 }
 
-void CColourIO::XML_CharacterData(void *userData, const XML_Char *s, int len) {
+void CColourIO::XmlCData(const XML_Char *s, int len) {
   // CAREFUL: s points to a string which is NOT null-terminated.
-
-  CColourIO *Me = (CColourIO *) userData;
-
-  Me->CData.append(s, len);
+  CData.append(s, len);
 }
diff --git a/Src/DasherCore/ColourIO.h b/Src/DasherCore/ColourIO.h
index 5f18697..e77ba69 100644
--- a/Src/DasherCore/ColourIO.h
+++ b/Src/DasherCore/ColourIO.h
@@ -11,12 +11,11 @@
 
 #include "DasherTypes.h"
 
-#include <expat.h>
-#include <string>
+#include "AbstractXMLParser.h"
+
 #include <map>
 #include <vector>
 #include <utility>              // for std::pair
-#include <stdio.h>              // for C style file IO
 
 namespace Dasher {
   class CColourIO;
@@ -25,7 +24,7 @@ namespace Dasher {
 
 /// \defgroup Colours Colour scheme information
 /// @{
-class Dasher::CColourIO {
+class Dasher::CColourIO : private AbstractXMLParser {
 public:
   // This structure completely describes the characters used in alphabet
   struct ColourInfo {
@@ -59,20 +58,14 @@ private:
   /////////////////////////
 
   bool LoadMutable;
-  void ParseFile(std::string Filename);
-
-  // & to &amp;  < to &lt; and > to &gt;  and if (Attribute) ' to &apos; and " to &quot;
-  void XML_Escape(std::string * Text, bool Attribute);
 
   // Data gathered
   std::string CData;            // Text gathered from when an elemnt starts to when it ends
   ColourInfo InputInfo;
 
-  // Callback functions. These involve the normal dodgy casting to a pointer
-  // to an instance to get a C++ class to work with a plain C library.
-  static void XML_StartElement(void *userData, const XML_Char * name, const XML_Char ** atts);
-  static void XML_EndElement(void *userData, const XML_Char * name);
-  static void XML_CharacterData(void *userData, const XML_Char * s, int len);
+  void XmlStartHandler(const XML_Char * name, const XML_Char ** atts);
+  void XmlEndHandler(const XML_Char * name);
+  void XmlCData(const XML_Char * s, int len);
 };
 /// @}
 
diff --git a/Src/DasherCore/Makefile.am b/Src/DasherCore/Makefile.am
index ce60d1e..c65f802 100644
--- a/Src/DasherCore/Makefile.am
+++ b/Src/DasherCore/Makefile.am
@@ -8,6 +8,8 @@ libdasherprefs_a_SOURCES = \
 		SettingsStore.h 
 
 libdashercore_a_SOURCES = \
+		AbstractXMLParser.cpp \
+		AbstracTXMLParser.h \
 		Alphabet/AlphIO.cpp \
 		Alphabet/AlphIO.h \
 		Alphabet/AlphInfo.cpp \
@@ -119,8 +121,6 @@ libdashercore_a_SOURCES = \
 		TimeSpan.h \
 		Trainer.cpp \
 		Trainer.h \
-		TrainingHelper.cpp \
-		TrainingHelper.h \
 		TwoBoxStartHandler.cpp \
 		TwoBoxStartHandler.h \
 		TwoButtonDynamicFilter.cpp \
diff --git a/Src/DasherCore/Trainer.cpp b/Src/DasherCore/Trainer.cpp
index a1a922f..0e65390 100644
--- a/Src/DasherCore/Trainer.cpp
+++ b/Src/DasherCore/Trainer.cpp
@@ -4,6 +4,8 @@
 #include "Trainer.h"
 #include "DasherInterfaceBase.h"
 #include "LanguageModelling/PPMPYLanguageModel.h"
+#include <cstring>
+#include <sstream>
 
 using namespace Dasher;
 
@@ -18,7 +20,7 @@ static char THIS_FILE[] = __FILE__;
 #endif
 
 CTrainer::CTrainer(CLanguageModel *pLanguageModel, const CAlphInfo *pInfo, const CAlphabetMap *pAlphabet)
-  : CTrainingHelper(pAlphabet), m_pLanguageModel(pLanguageModel), m_pInfo(pInfo) {
+  : m_pAlphabet(pAlphabet), m_pLanguageModel(pLanguageModel), m_pInfo(pInfo) {
     vector<symbol> syms;
     pAlphabet->GetSymbols(syms,pInfo->GetContextEscapeChar());
     if (syms.size()==1)
@@ -76,6 +78,61 @@ bool CTrainer::readEscape(CLanguageModel::Context &sContext, CAlphabetMap::Symbo
   return true;  
 }
 
+void 
+Dasher::CTrainer::LoadFile(const std::string &strFileName) {
+  if(strFileName == "")
+    return;
+  
+  FILE *pInputFile;
+  if((pInputFile = fopen(strFileName.c_str(), "r")) == (FILE *) 0)
+    return;
+  
+  char szTestBuffer[6];
+  
+  int iNumberRead = fread(szTestBuffer, 1, 5, pInputFile);
+  szTestBuffer[iNumberRead] = '\0';
+  
+  fclose(pInputFile);
+  
+  if(!strcmp(szTestBuffer, "<?xml")) {
+    //Invoke AbstractXMLParser method
+    m_bInSegment = false;
+    ParseFile(strFileName);
+  } else {
+    std::ifstream in(strFileName.c_str(), std::ios::binary);
+    if (in.fail()) {
+      std::cerr << "Unable to open file \"" << strFileName << "\" for reading" << std::endl;
+      return;
+    }
+    CAlphabetMap::SymbolStream syms(in);
+    Train(syms);
+  
+    in.close();
+  }
+}
+
+void CTrainer::XmlStartHandler(const XML_Char *szName, const XML_Char **pAtts) {
+  if(!strcmp(szName, "segment")) {
+    m_strCurrentText = "";
+    m_bInSegment = true;
+  }
+}
+
+void CTrainer::XmlEndHandler(const XML_Char *szName) {
+  if(!strcmp(szName, "segment")) {
+    std::istringstream in(m_strCurrentText);
+    CAlphabetMap::SymbolStream syms(in);
+    Train(syms);
+    
+    m_bInSegment = false;
+  }
+}
+
+void CTrainer::XmlCData(const XML_Char *szS, int iLen) {
+  if(m_bInSegment)
+    m_strCurrentText += std::string(szS, iLen);
+}
+
 CMandarinTrainer::CMandarinTrainer(CPPMPYLanguageModel *pLanguageModel, const CAlphInfo *pInfo, const CAlphabetMap *pPYAlphabet, const CAlphabetMap *pCHAlphabet, const std::string &strDelim)
 : CTrainer(pLanguageModel, pInfo, pCHAlphabet), m_pPYAlphabet(pPYAlphabet), m_strDelim(strDelim) {
 }
diff --git a/Src/DasherCore/Trainer.h b/Src/DasherCore/Trainer.h
index 0e87714..a48a894 100644
--- a/Src/DasherCore/Trainer.h
+++ b/Src/DasherCore/Trainer.h
@@ -2,17 +2,25 @@
 #define __trainer_h__
 
 #include "LanguageModelling/PPMPYLanguageModel.h"
-#include "TrainingHelper.h"
 #include "Alphabet/AlphInfo.h"
+#include "AbstractXMLParser.h"
 
 namespace Dasher {
   class CDasherInterfaceBase;
 	
-  class CTrainer : public CTrainingHelper {
+  class CTrainer : private AbstractXMLParser {
+            
   public:
     CTrainer(CLanguageModel *pLanguageModel, const CAlphInfo *pInfo, const CAlphabetMap *pAlphabet);
 
+    void LoadFile(const std::string &strFileName);
+  
   protected:
+    ///Override AbstractXMLParser methods to extract text in <segment>...</segment> pairs
+    void XmlStartHandler(const XML_Char *szName, const XML_Char **pAtts);
+    void XmlEndHandler(const XML_Char *szName);
+    void XmlCData(const XML_Char *szS, int iLen);
+
     virtual void Train(CAlphabetMap::SymbolStream &syms);
     CLanguageModel *m_pLanguageModel;
     
@@ -23,9 +31,14 @@ namespace Dasher {
     ///  false, if instead a double-escape-character (=encoding of that actual symbol) was read
     bool readEscape(CLanguageModel::Context &sContext, CAlphabetMap::SymbolStream &syms);
     
+    const CAlphabetMap *m_pAlphabet;
     const CAlphInfo *m_pInfo;
     // symbol number in alphabet of the context-switch character (maybe 0 if not in alphabet!)
     int m_iCtxEsc;
+  private:
+    //For dealing with XML CData:    
+    bool m_bInSegment;
+    std::string m_strCurrentText;
   };
 	
   /// Trains a PPMPYLanguageModel (dual alphabet), as for e.g. MandarinDasher.
diff --git a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
index 90f762b..38dbcf8 100755
--- a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
+++ b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
@@ -331,8 +331,6 @@
 		19F36D900B18B60E002F41F1 /* ZippyStringGlyph.h in Headers */ = {isa = PBXBuildFile; fileRef = 19F36D8C0B18B60E002F41F1 /* ZippyStringGlyph.h */; };
 		19F36D910B18B60E002F41F1 /* ZippyStringGlyph.m in Sources */ = {isa = PBXBuildFile; fileRef = 19F36D8D0B18B60E002F41F1 /* ZippyStringGlyph.m */; };
 		19F8C7E60C858A2800276B4F /* I18n.h in Headers */ = {isa = PBXBuildFile; fileRef = 19F8C7E50C858A2800276B4F /* I18n.h */; };
-		19F8C7F90C858E9900276B4F /* TrainingHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 19F8C7F70C858E9900276B4F /* TrainingHelper.cpp */; };
-		19F8C7FA0C858E9900276B4F /* TrainingHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 19F8C7F80C858E9900276B4F /* TrainingHelper.h */; };
 		3300115210A2EA7700D31B1D /* ExpansionPolicy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3300115010A2EA7700D31B1D /* ExpansionPolicy.cpp */; };
 		3300115310A2EA7700D31B1D /* ExpansionPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 3300115110A2EA7700D31B1D /* ExpansionPolicy.h */; };
 		33008360120CB7F900C41FAA /* ConvertingAlphMgr.h in Headers */ = {isa = PBXBuildFile; fileRef = 3300835E120CB7F900C41FAA /* ConvertingAlphMgr.h */; };
@@ -390,6 +388,8 @@
 		33E173E60F3E0B6400D19B38 /* training_welsh_GB.txt in Resources */ = {isa = PBXBuildFile; fileRef = 33E173C60F3E0B6400D19B38 /* training_welsh_GB.txt */; };
 		33E91A770F55E60B00B5F513 /* KeyboardHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33E91A750F55E60B00B5F513 /* KeyboardHelper.cpp */; };
 		33E91A780F55E60B00B5F513 /* KeyboardHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 33E91A760F55E60B00B5F513 /* KeyboardHelper.h */; };
+		33F6C9EA133241A000745B06 /* AbstractXMLParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 33F6C9E8133241A000745B06 /* AbstractXMLParser.h */; };
+		33F6C9EB133241A000745B06 /* AbstractXMLParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33F6C9E9133241A000745B06 /* AbstractXMLParser.cpp */; };
 		33FC93390FEFA2C900A9F08D /* TwoPushDynamicFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33FC93370FEFA2C900A9F08D /* TwoPushDynamicFilter.cpp */; };
 		33FC933A0FEFA2C900A9F08D /* TwoPushDynamicFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 33FC93380FEFA2C900A9F08D /* TwoPushDynamicFilter.h */; };
 		33FC93430FEFA2FB00A9F08D /* FrameRate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33FC93420FEFA2FB00A9F08D /* FrameRate.cpp */; };
@@ -736,8 +736,6 @@
 		19F36D8C0B18B60E002F41F1 /* ZippyStringGlyph.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ZippyStringGlyph.h; sourceTree = "<group>"; };
 		19F36D8D0B18B60E002F41F1 /* ZippyStringGlyph.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ZippyStringGlyph.m; sourceTree = "<group>"; };
 		19F8C7E50C858A2800276B4F /* I18n.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = I18n.h; path = ../Common/I18n.h; sourceTree = SOURCE_ROOT; };
-		19F8C7F70C858E9900276B4F /* TrainingHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TrainingHelper.cpp; sourceTree = "<group>"; };
-		19F8C7F80C858E9900276B4F /* TrainingHelper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = TrainingHelper.h; sourceTree = "<group>"; };
 		29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
 		29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; };
 		29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
@@ -799,6 +797,8 @@
 		33E173C60F3E0B6400D19B38 /* training_welsh_GB.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = training_welsh_GB.txt; sourceTree = "<group>"; };
 		33E91A750F55E60B00B5F513 /* KeyboardHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyboardHelper.cpp; sourceTree = "<group>"; };
 		33E91A760F55E60B00B5F513 /* KeyboardHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyboardHelper.h; sourceTree = "<group>"; };
+		33F6C9E8133241A000745B06 /* AbstractXMLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbstractXMLParser.h; sourceTree = "<group>"; };
+		33F6C9E9133241A000745B06 /* AbstractXMLParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AbstractXMLParser.cpp; sourceTree = "<group>"; };
 		33FC93370FEFA2C900A9F08D /* TwoPushDynamicFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TwoPushDynamicFilter.cpp; sourceTree = "<group>"; };
 		33FC93380FEFA2C900A9F08D /* TwoPushDynamicFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TwoPushDynamicFilter.h; sourceTree = "<group>"; };
 		33FC93420FEFA2FB00A9F08D /* FrameRate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameRate.cpp; sourceTree = "<group>"; };
@@ -920,6 +920,8 @@
 				1988ABB70C9FF97000D97977 /* GameLevel.cpp */,
 				1988ABB80C9FF97000D97977 /* GameMessages.h */,
 				1988ABB90C9FF97000D97977 /* GameStatistics.h */,
+				33F6C9E8133241A000745B06 /* AbstractXMLParser.h */,
+				33F6C9E9133241A000745B06 /* AbstractXMLParser.cpp */,
 				1948BDF60C226CFC001DFA32 /* ActionButton.cpp */,
 				1948BDF70C226CFC001DFA32 /* ActionButton.h */,
 				1948BDF80C226CFC001DFA32 /* Alphabet */,
@@ -1017,8 +1019,6 @@
 				1948BE840C226CFD001DFA32 /* StylusFilter.h */,
 				1948BE850C226CFD001DFA32 /* TimeSpan.cpp */,
 				1948BE860C226CFD001DFA32 /* TimeSpan.h */,
-				19F8C7F70C858E9900276B4F /* TrainingHelper.cpp */,
-				19F8C7F80C858E9900276B4F /* TrainingHelper.h */,
 				1948BE870C226CFD001DFA32 /* TwoBoxStartHandler.cpp */,
 				1948BE880C226CFD001DFA32 /* TwoBoxStartHandler.h */,
 				1948BE890C226CFD001DFA32 /* TwoButtonDynamicFilter.cpp */,
@@ -1460,7 +1460,6 @@
 				1921DB6F0C7ECB9900E6DAA5 /* GameScorer.h in Headers */,
 				193731A80C8586F20022CBC7 /* config.h in Headers */,
 				19F8C7E60C858A2800276B4F /* I18n.h in Headers */,
-				19F8C7FA0C858E9900276B4F /* TrainingHelper.h in Headers */,
 				1988ABBD0C9FF97000D97977 /* GameMessages.h in Headers */,
 				1988ABBE0C9FF97000D97977 /* GameStatistics.h in Headers */,
 				33E91A780F55E60B00B5F513 /* KeyboardHelper.h in Headers */,
@@ -1477,6 +1476,7 @@
 				33008360120CB7F900C41FAA /* ConvertingAlphMgr.h in Headers */,
 				339794D5120F2A9600CEA168 /* AlphInfo.h in Headers */,
 				330B91641292FE700022831C /* ModuleSettingsController.h in Headers */,
+				33F6C9EA133241A000745B06 /* AbstractXMLParser.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1804,7 +1804,6 @@
 				1921DB390C7ECAA400E6DAA5 /* OneButtonDynamicFilter.cpp in Sources */,
 				1921DB400C7ECB4B00E6DAA5 /* DasherGameMode.cpp in Sources */,
 				1921DB6E0C7ECB9900E6DAA5 /* GameScorer.cpp in Sources */,
-				19F8C7F90C858E9900276B4F /* TrainingHelper.cpp in Sources */,
 				1988ABCF0C9FFADA00D97977 /* GameLevel.cpp in Sources */,
 				33E91A770F55E60B00B5F513 /* KeyboardHelper.cpp in Sources */,
 				33ABFEC60FC379EA00EA2BA5 /* ButtonMultiPress.cpp in Sources */,
@@ -1822,6 +1821,7 @@
 				33008361120CB7F900C41FAA /* ConvertingAlphMgr.cpp in Sources */,
 				339794D4120F2A9600CEA168 /* AlphInfo.cpp in Sources */,
 				330B91621292FE520022831C /* ModuleSettingsController.mm in Sources */,
+				33F6C9EB133241A000745B06 /* AbstractXMLParser.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/Src/iPhone/Dasher.xcodeproj/project.pbxproj b/Src/iPhone/Dasher.xcodeproj/project.pbxproj
index 5e22a5c..6d0d624 100755
--- a/Src/iPhone/Dasher.xcodeproj/project.pbxproj
+++ b/Src/iPhone/Dasher.xcodeproj/project.pbxproj
@@ -209,7 +209,6 @@
 		3344FE5B0F71717C00506EAA /* SocketInputBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FDF90F71717C00506EAA /* SocketInputBase.cpp */; };
 		3344FE5C0F71717C00506EAA /* StylusFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FDFC0F71717C00506EAA /* StylusFilter.cpp */; };
 		3344FE5D0F71717C00506EAA /* TimeSpan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FDFE0F71717C00506EAA /* TimeSpan.cpp */; };
-		3344FE5E0F71717C00506EAA /* TrainingHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FE000F71717C00506EAA /* TrainingHelper.cpp */; };
 		3344FE5F0F71717C00506EAA /* TwoBoxStartHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FE020F71717C00506EAA /* TwoBoxStartHandler.cpp */; };
 		3344FE600F71717C00506EAA /* TwoButtonDynamicFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FE040F71717C00506EAA /* TwoButtonDynamicFilter.cpp */; };
 		3344FE610F71717C00506EAA /* UserButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FE060F71717C00506EAA /* UserButton.cpp */; };
@@ -251,6 +250,7 @@
 		337690140F989C870083FEB2 /* SBTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 337690130F989C870083FEB2 /* SBTree.cpp */; };
 		337691710F9CE8630083FEB2 /* StringParamController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 337691700F9CE8630083FEB2 /* StringParamController.mm */; };
 		337691860F9CEFC70083FEB2 /* InputMethodSelector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 337691850F9CEFC70083FEB2 /* InputMethodSelector.mm */; };
+		3378A23F1335425300A96C5D /* AbstractXMLParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3378A23D1335425200A96C5D /* AbstractXMLParser.cpp */; };
 		337ECC1B10DD5E0700D0C6A5 /* ExpansionPolicy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 337ECC1910DD5E0700D0C6A5 /* ExpansionPolicy.cpp */; };
 		339F8A330FF5088000282847 /* CalibrationController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 339F8A320FF5088000282847 /* CalibrationController.mm */; };
 		33C71AF20FF7B51700A20992 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 33C71AF10FF7B51700A20992 /* Default.png */; };
@@ -637,8 +637,6 @@
 		3344FDFD0F71717C00506EAA /* StylusFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StylusFilter.h; sourceTree = "<group>"; };
 		3344FDFE0F71717C00506EAA /* TimeSpan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimeSpan.cpp; sourceTree = "<group>"; };
 		3344FDFF0F71717C00506EAA /* TimeSpan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TimeSpan.h; sourceTree = "<group>"; };
-		3344FE000F71717C00506EAA /* TrainingHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrainingHelper.cpp; sourceTree = "<group>"; };
-		3344FE010F71717C00506EAA /* TrainingHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrainingHelper.h; sourceTree = "<group>"; };
 		3344FE020F71717C00506EAA /* TwoBoxStartHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TwoBoxStartHandler.cpp; sourceTree = "<group>"; };
 		3344FE030F71717C00506EAA /* TwoBoxStartHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TwoBoxStartHandler.h; sourceTree = "<group>"; };
 		3344FE040F71717C00506EAA /* TwoButtonDynamicFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TwoButtonDynamicFilter.cpp; sourceTree = "<group>"; };
@@ -697,6 +695,8 @@
 		337691700F9CE8630083FEB2 /* StringParamController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StringParamController.mm; sourceTree = "<group>"; };
 		337691840F9CEFC70083FEB2 /* InputMethodSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputMethodSelector.h; sourceTree = "<group>"; };
 		337691850F9CEFC70083FEB2 /* InputMethodSelector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InputMethodSelector.mm; sourceTree = "<group>"; };
+		3378A23D1335425200A96C5D /* AbstractXMLParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AbstractXMLParser.cpp; sourceTree = "<group>"; };
+		3378A23E1335425200A96C5D /* AbstractXMLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbstractXMLParser.h; sourceTree = "<group>"; };
 		337ECC1910DD5E0700D0C6A5 /* ExpansionPolicy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExpansionPolicy.cpp; sourceTree = "<group>"; };
 		337ECC1A10DD5E0700D0C6A5 /* ExpansionPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExpansionPolicy.h; sourceTree = "<group>"; };
 		339F8A310FF5088000282847 /* CalibrationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CalibrationController.h; sourceTree = "<group>"; };
@@ -1168,6 +1168,8 @@
 			children = (
 				337ECC1910DD5E0700D0C6A5 /* ExpansionPolicy.cpp */,
 				337ECC1A10DD5E0700D0C6A5 /* ExpansionPolicy.h */,
+				3378A23D1335425200A96C5D /* AbstractXMLParser.cpp */,
+				3378A23E1335425200A96C5D /* AbstractXMLParser.h */,
 				3344FD680F71717C00506EAA /* ActionButton.cpp */,
 				3344FD690F71717C00506EAA /* ActionButton.h */,
 				3344FD6A0F71717C00506EAA /* Alphabet */,
@@ -1269,8 +1271,6 @@
 				3344FDFD0F71717C00506EAA /* StylusFilter.h */,
 				3344FDFE0F71717C00506EAA /* TimeSpan.cpp */,
 				3344FDFF0F71717C00506EAA /* TimeSpan.h */,
-				3344FE000F71717C00506EAA /* TrainingHelper.cpp */,
-				3344FE010F71717C00506EAA /* TrainingHelper.h */,
 				3344FE020F71717C00506EAA /* TwoBoxStartHandler.cpp */,
 				3344FE030F71717C00506EAA /* TwoBoxStartHandler.h */,
 				3344FE040F71717C00506EAA /* TwoButtonDynamicFilter.cpp */,
@@ -1601,7 +1601,6 @@
 				3344FE5B0F71717C00506EAA /* SocketInputBase.cpp in Sources */,
 				3344FE5C0F71717C00506EAA /* StylusFilter.cpp in Sources */,
 				3344FE5D0F71717C00506EAA /* TimeSpan.cpp in Sources */,
-				3344FE5E0F71717C00506EAA /* TrainingHelper.cpp in Sources */,
 				3344FE5F0F71717C00506EAA /* TwoBoxStartHandler.cpp in Sources */,
 				3344FE600F71717C00506EAA /* TwoButtonDynamicFilter.cpp in Sources */,
 				3344FE610F71717C00506EAA /* UserButton.cpp in Sources */,
@@ -1710,6 +1709,7 @@
 				337472D3121A976B001A858C /* AlphInfo.cpp in Sources */,
 				3324F491129C119C00EE6A22 /* IPhoneFilters.mm in Sources */,
 				3324F7BF129D744D00EE6A22 /* ActionConfigurator.mm in Sources */,
+				3378A23F1335425300A96C5D /* AbstractXMLParser.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]