/*
* File: gedconf.cc
* Project: GED -bitmap editor (ICP)
* Author: Jakub Filak. xfilak01
* Team: xdudka00, xfilak01, xhefka00, xhradi08
* Created: 2006-04-14
*/
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include <xercesc/framework/StdOutFormatTarget.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <map>
XERCES_CPP_NAMESPACE_USE
#include "gedconf.h"
/*
* Initialize
*/
GedConf *GedConf::_instance= 0;
/*
* Create instance
*/
GedConf *GedConf::ptr ()
{
if ( _instance == 0 ) {
_instance = new GedConf();
}
return _instance;
}
/*
* Destroy on the end of program
*/
void GedConf::destroy()
{
delete _instance;
}
/*
* Reset after
*/
GedConf::~GedConf()
{
_instance = 0;
_change = false;
}
/*
* Read config file, and parse plugin dir and macros
*/
void GedConf::readConfig( const char* pathToFile )
{
std::ifstream config(pathToFile);
if ( !config.is_open() ) {
return; // if cant open config file
}
else {
config.close(); // if can then close file
}
try {
XMLPlatformUtils::Initialize();
}
catch ( const XMLException& toCatch ) {
char* message = XMLString::transcode( toCatch.getMessage() );
std::cerr << "ged2006: warning: Error during initialization config file: " << message << std::endl;
XMLString::release(&message);
return;
}
XercesDOMParser* parser = new XercesDOMParser();
parser->setValidationScheme( XercesDOMParser::Val_Always ); // volitelne
parser->setDoNamespaces( true );
ErrorHandler* errorH = ( ErrorHandler* ) new HandlerBase();
parser->setErrorHandler( errorH );
try {
parser->parse( pathToFile );
}
catch ( const XMLException& toCatch ) {
char* message = XMLString::transcode(toCatch.getMessage());
std::cerr << "ged2006: warning: Error during parsing confi file: " << message << std::endl;
XMLString::release(&message);
return;
}
catch ( const DOMException& toCatch ) {
char* message = XMLString::transcode(toCatch.msg);
std::cerr << "ged2006: warning: Error during parsing config file: " << message << std::endl;
XMLString::release(&message);
return;
}
catch (...) {
std::cerr << "ged2006: warning: Unexpected erro during parsing config file\n";
}
_PLFR = _MLFR = _HLFR = _ILFR = _FLFR = false;
_lastCofingFile = pathToFile;
DOMDocument* pDoc = parser->getDocument();
DOMTreeWalker* tWalker = pDoc->createTreeWalker(pDoc->getDocumentElement(), 1, NULL, true);
DOMNode* currentNode;
XMLCh* PluginNodeName = XMLString::transcode("Plugins");
XMLCh* MacroNodeName = XMLString::transcode("Macros");
XMLCh* HelpNodeName = XMLString::transcode("Help");
XMLCh* ImageNodeName = XMLString::transcode("Images");
XMLCh* FontNodeName = XMLString::transcode("Fonts");
while ( ( currentNode = tWalker->nextNode() ) != NULL ) {
if ( currentNode->getNodeType() == DOMNode::ELEMENT_NODE ) {
if ( XMLString::equals( PluginNodeName, currentNode->getNodeName()) ) {
if ( currentNode->hasChildNodes() ) { // if has child then can try read dirs with plugins
parsePluginDirs(currentNode->getChildNodes());
}
}
if ( XMLString::equals( MacroNodeName, currentNode->getNodeName()) ) {
if ( currentNode->hasChildNodes()) { // if has child then can try read macros
parseMacros(currentNode->getChildNodes());
}
}
if ( XMLString::equals( HelpNodeName, currentNode->getNodeName()) ) {
if ( currentNode->hasAttributes()) { // only if has attribute
parseNodeWithOneAttribute( currentNode, "dir", _helpdir, &_HLFR );
}
}
if ( XMLString::equals( ImageNodeName, currentNode->getNodeName()) ) {
if ( currentNode->hasAttributes()) { // only if has attribute
parseNodeWithOneAttribute( currentNode, "dir", _imagesDir, &_ILFR );
}
}
if ( XMLString::equals( FontNodeName, currentNode->getNodeName()) ) {
if ( currentNode->hasAttributes()) { // only if has attribute
parseFont( currentNode );
}
}
}
}
delete parser;
delete errorH;
delete [] PluginNodeName;
delete [] MacroNodeName;
delete [] HelpNodeName;
delete [] ImageNodeName;
delete [] FontNodeName;
XMLPlatformUtils::Terminate();
return;
}
/*
* To saving config file
*/
void GedConf::saveConfig()
{
if ( !_change ) {
return;
}
try {
XMLPlatformUtils::Initialize();
}
catch ( const XMLException& toCatch ) {
char* message = XMLString::transcode( toCatch.getMessage() );
std::cerr << "ged2006: warning: Error during initialization: " << message << std::endl;
XMLString::release(&message);
return;
}
XMLCh tStr[100];
XMLString::transcode( "xml", tStr, 99 );
DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation(tStr);
DOMDocument* pDoc = impl->createDocument();
DOMWriter* writer = ((DOMImplementationLS*)impl)->createDOMWriter();
if ( writer->canSetFeature( XMLUni::fgDOMWRTDiscardDefaultContent, false ) ){
writer->setFeature( XMLUni::fgDOMWRTDiscardDefaultContent, false );
}
if ( writer->canSetFeature( XMLUni::fgDOMWRTFormatPrettyPrint, true )){
writer->setFeature( XMLUni::fgDOMWRTFormatPrettyPrint, true);
}
XMLString::transcode("UTF-8", tStr, 99 );
pDoc->setEncoding(tStr); // set encoding
XMLString::transcode("1.0", tStr, 99 );
pDoc->setVersion(tStr); // set version of xml
XMLString::transcode("Data", tStr, 99);
DOMNode* root = pDoc->createElement(tStr); // creating root node with tag Data
/* CREATING HELP NODE */
if ( _HLFR ) {
XMLString::transcode("Help", tStr, 99);
DOMElement* helpNode = pDoc->createElement(tStr); // creating elemnt for help dir
XMLString::transcode("dir", tStr, 99);
XMLCh* value = XMLString::transcode( _helpdir.c_str() ); // transcode help dir string
helpNode->setAttribute( tStr, value ); // set attribute to dir node
delete [] value;
root->appendChild( helpNode ); // append help node
}
/* CREATING IMAGES NODE */
if ( _ILFR ) {
XMLString::transcode("Images", tStr, 99);
DOMElement* imageNode = pDoc->createElement(tStr); // creating elemnt for help dir
XMLString::transcode("dir", tStr, 99);
XMLCh* value = XMLString::transcode( _imagesDir.c_str() ); // transcode help dir string
imageNode->setAttribute( tStr, value ); // set attribute to dir node
delete [] value;
root->appendChild( imageNode ); // append help node
}
/* CREATING FONT NODE */
if ( _FLFR ) {
XMLString::transcode("Fonts", tStr, 99);
DOMElement* fontNode = pDoc->createElement(tStr); // creating elemnt for help dir
XMLString::transcode("file", tStr, 99);
XMLCh* value = XMLString::transcode( _fontFile.c_str() ); // transcode help dir string
fontNode->setAttribute( tStr, value ); // set attribute to dir node
delete [] value;
XMLString::transcode("dpi", tStr, 99);
value = XMLString::transcode( _fontDPI.c_str() ); // transcode help dir string
fontNode->setAttribute( tStr, value ); // set attribute to dir node
delete [] value;
XMLString::transcode("size", tStr, 99);
value = XMLString::transcode( _fontSize.c_str() ); // transcode help dir string
fontNode->setAttribute( tStr, value ); // set attribute to dir node
delete [] value;
root->appendChild( fontNode ); // append help node
}
/* CREATING PLUGIN DIRS NODES */
if ( !_PluginDirs.empty() && _PLFR ) {
XMLString::transcode("Plugins", tStr, 99);
DOMNode* rootChild = pDoc->createElement(tStr); // mreating first child of root with tag Plugins
root->appendChild(rootChild); // append Plugins node
PluginDirsListIterator pIter = _PluginDirs.begin();
while ( pIter != _PluginDirs.end()) {
if ( pIter->second == _lastCofingFile ) { // only if is form last cofig or new, and or isn`t empty
XMLString::transcode("dir",tStr, 99);
DOMNode* tnode = pDoc->createElement( tStr ); // create node dir for Plugins
rootChild->appendChild( tnode ); // append node dir
XMLString::transcode( pIter->first.c_str(), tStr, 99); // transcode path to dir
tnode->appendChild(pDoc->createTextNode(tStr)); // append text to dir node, value is path to dir
}
pIter++;
}
}
/* CREATING MACROS NODES */
if ( !_MacroList.empty() && _MLFR ) {
XMLString::transcode("Macros", tStr, 99);
DOMNode* rootChild = pDoc->createElement(tStr); // creating second child of root with tag Macros
root->appendChild(rootChild); // append Macros node
MacroList::iterator mIter = _MacroList.begin(); // iterator for macro list
while ( mIter != _MacroList.end() ) {
if ( mIter->second == _lastCofingFile ) {
XMLString::transcode( "macro",tStr, 99 );
DOMElement* tnode = pDoc->createElement( tStr ); // create element macro
XMLString::transcode( "name",tStr, 99 );
XMLCh* value = XMLString::transcode( mIter->first.c_str() ); // transcode value
tnode->setAttribute( tStr, value ); // set attribute 'name' with value value
CommandVector::iterator cIter = _MacroCommands[mIter->first].begin(); // iterator for command vector
while ( cIter != _MacroCommands[mIter->first].end() ) {
XMLString::transcode( "command", tStr, 99);
DOMElement* comNode = pDoc->createElement( tStr ); // create elemnt command
XMLCh* tname = XMLString::transcode("name");
XMLCh* tparams = XMLString::transcode("params");
XMLCh* tnameVal = XMLString::transcode(cIter->getName().c_str()); // value for name
XMLCh* tparamsVal = XMLString::transcode(cIter->getParam().c_str()); // value for param
comNode->setAttribute(tname, tnameVal); // set attribute name
comNode->setAttribute(tparams, tparamsVal); // set attribute param
tnode->appendChild(comNode); // append node command to macro
delete [] tname;
delete [] tnameVal;
delete [] tparams;
delete [] tparamsVal;
cIter++;
}
rootChild->appendChild( tnode ); // append node macro to root
delete [] value;
}
mIter++;
}
}
if ( !_lastCofingFile.empty() ) { // check to can write to last config file
std::ofstream config(_lastCofingFile.c_str());
if ( !config.is_open() ) {
_lastCofingFile = "ged.conf"; // if cant write we set config file to ged.conf
}
else {
config.close(); // if can then close file
}
}
else {
_lastCofingFile = "ged.conf"; // if doest exist config file we set config file to ged.conf
}
XMLFormatTarget* mFoTa = new LocalFileFormatTarget(_lastCofingFile.c_str() );
pDoc->appendChild( root );
/* WRITING FILE */
try {
writer->writeNode( mFoTa, *pDoc); // write config file
}
catch (const XMLException& toCatch ) {
char* message = XMLString::transcode(toCatch.getMessage());
std::cerr << "ged2006: warning: Error message" << message << std::endl;
XMLString::release(&message);
return;
}
catch (const DOMException& toCatch) {
char* message = XMLString::transcode(toCatch.msg);
std::cerr << "ged2006: warning: Exception message is: " << message << "\n";
XMLString::release(&message);
return;
}
catch (...) {
std::cerr << "ged2006: warning: Unexpected Exception \n" ;
}
_change = false;
writer->release();
pDoc->release();
delete mFoTa;
XMLPlatformUtils::Terminate();
return;
}
/*
* Create list of dirs
*/
void GedConf::parsePluginDirs( DOMNodeList* listPluginNodes )
{
XMLCh* tagDir = XMLString::transcode("dir");
for ( XMLSize_t i = 0; i < listPluginNodes->getLength(); i++ ) { // go throw out list of all childs node
DOMNode* current = listPluginNodes->item(i); // take child
if ( current->getNodeType() == DOMNode::ELEMENT_NODE ) { // if is child element node
if ( XMLString::equals(tagDir, current->getNodeName()) ) { // and if has name dir
if ( current->hasChildNodes() ) { // and has some childs
current = current->getFirstChild(); // take his first child
if ( current->getNodeType() == DOMNode::TEXT_NODE ) { // if is child text node
char* tmp = XMLString::transcode(current->getNodeValue()); // read his value
if ( tmp != NULL ) {
_PluginDirs[std::string( tmp )] = _lastCofingFile; // and store his value
_PLFR = true;
delete [] tmp;
}
}
}
}
}
}
delete [] tagDir;
}
/*
* Retur map of dirs maped with their config files
*/
PluginDirsList GedConf::getPluginDirs()
{
return _PluginDirs;
}
/*
* Map new dir with last config gfile
*/
void GedConf::setPluginDir( const char* pathToDir )
{
if ( _lastCofingFile.empty() ) { // if doesnt exist config file
_lastCofingFile = "ged.conf";
}
_PLFR = true;
_change = true;
_PluginDirs[std::string( pathToDir )] = _lastCofingFile; // store dir with plugins
}
/*
* remove config file, should be used only to local config file
*/
void GedConf::removePluginDir( const char* pathToDir )
{
PluginDirsListIterator pIter = _PluginDirs.find( std::string( pathToDir ) );
if ( pIter == _PluginDirs.end() || pIter->second != _lastCofingFile ) { // if isnt from last config file
return; // or if dont find dir to delete, the change is imposible
}
_PLFR = true;
_change = true;
_PluginDirs.erase( pIter );
}
/*
* Read macro commands from config file and store this to commands vector
* and return this vector
*/
CommandVector GedConf::parseMacroCommands( DOMNodeList* listPluginNodes )
{
XMLCh* tagCommand = XMLString::transcode("command");
XMLCh* tagName = XMLString::transcode("name");
XMLCh* tagParams = XMLString::transcode("params");
CommandVector commands;
for ( XMLSize_t i = 0; i < listPluginNodes->getLength(); i++ ) { // go throw out list of all childs node
DOMNode* current = listPluginNodes->item(i); // take child
if ( current->getNodeType() == DOMNode::ELEMENT_NODE && XMLString::equals(tagCommand, current->getNodeName())) {
// if child has name command and is element node then
if ( current->hasAttributes()) { // if has attributes
char* tmpName = NULL;
char* tmpParams = NULL;
DOMNamedNodeMap* attribut = current->getAttributes(); // create attributes list
current = attribut->getNamedItem(tagName); // take attribute name
if ( current != NULL && current->getNodeType() == DOMNode::ATTRIBUTE_NODE ) { // if not NULL and is attribute node
tmpName = XMLString::transcode(current->getNodeValue()); // transcode name value
}
current = attribut->getNamedItem(tagParams); // take attribute params
if ( current != NULL && current->getNodeType() == DOMNode::ATTRIBUTE_NODE ) { // if not NULL and is attribute node
tmpParams = XMLString::transcode(current->getNodeValue()); // transcode params value
}
if ( tmpName != NULL && tmpParams != NULL ) { // if has all attributes and vales then store this data
commands.push_back(GedMacroCommand(tmpName,tmpParams));
delete [] tmpName;
delete [] tmpParams;
}
else{
if ( tmpName != NULL ) {
delete [] tmpName;
}
if ( tmpParams != NULL ) {
delete [] tmpParams;
}
}
}
}
}
delete [] tagCommand;
delete [] tagName;
delete [] tagParams;
return commands;
}
/*
* Read macros from config file, using parseMacroCommands for creating command vector
*/
void GedConf::parseMacros( DOMNodeList* listPluginNodes )
{
XMLCh* tagMacro = XMLString::transcode("macro");
XMLCh* tagName = XMLString::transcode("name");
for ( XMLSize_t i = 0; i < listPluginNodes->getLength(); i++ ) { // go throw out list of all childs node
DOMNode* current = listPluginNodes->item(i); // take child
if ( current->getNodeType() == DOMNode::ELEMENT_NODE && XMLString::equals(tagMacro, current->getNodeName())) {
// if is element node and has name macro
if ( current->hasAttributes()) { // and if has attributes
DOMNamedNodeMap* attribut = current->getAttributes();
DOMNode* forList = current; // save node macro
current = attribut->getNamedItem(tagName); // take attribute with name 'name'
if ( current != NULL && current->getNodeType() == DOMNode::ATTRIBUTE_NODE ) { // if exist and is attribute node
char* tmp = XMLString::transcode(current->getNodeValue()); // transcode attribute value
if ( tmp != NULL ) {
CommandVector tcomm = parseMacroCommands( forList->getChildNodes() ); // create vector of commands
if ( !tcomm.empty() ) {
_MacroList[std::string(tmp)] = _lastCofingFile; // store macro name with his config file
_MacroCommands[std::string(tmp)] = tcomm; // store commads wtih macro name
_MLFR = true;
}
delete [] tmp;
}
}
}
}
}
delete [] tagMacro;
delete [] tagName;
}
/*
* return map with first item macro name and second item config file
*/
MacroList GedConf::getMacroList()
{
return _MacroList;
}
/*
* return vector of commands used in macro
*/
CommandVector GedConf::getCommands( const std::string macroName )
{
return _MacroCommands[macroName]; // return Command vector by macro name
}
/*
* Remove macro, without efect to macro which ins't from last user config file
*/
void GedConf::removeMacro( const std::string macroName )
{
MacroList::iterator mIter = _MacroList.find( macroName );
if ( mIter == _MacroList.end() || mIter->second != _lastCofingFile ) { // if not from last config
return; // or if dont find nacro, the remove action is not saving
}
_MLFR = true;
_change = true;
_MacroList.erase( mIter ); // delete macro from config file
MacroCommands::iterator cIter = _MacroCommands.begin();
while ( cIter != _MacroCommands.end() && cIter->first != macroName ) { // finding commands
cIter++;
}
if ( cIter != _MacroCommands.end() ) {
_MacroCommands.erase( cIter ); // delete commands
}
}
/*
* Adding macro when macro doesnt exist or adding commad to macro when macro exist,
* first param is name of macro, second param is name of command and third param is params of command
*/
void GedConf::addMacro( const char* macroName, const char* commandName, const char* commandParams )
{
if ( _lastCofingFile.empty() ) { // if config file doesnt exist
_lastCofingFile = "ged.conf"; // then we saved to ged.conf
}
_MLFR = true;
_change = true;
_MacroList[std::string(macroName)] = _lastCofingFile; // map name with last config file
_MacroCommands[macroName].push_back( GedMacroCommand( std::string(commandName), std::string(commandParams))); // add command
}
/*
* Read dir which contains help files
*/
void GedConf::parseNodeWithOneAttribute( DOMNode* helpNode, const char* nName, std::string &store, bool* record )
{
XMLCh* tagDir = XMLString::transcode(nName);
DOMNamedNodeMap* attribut = helpNode->getAttributes(); // get all atributes
DOMNode* current = attribut->getNamedItem(tagDir); // take atribute dir
if ( current != NULL && current->getNodeType() == DOMNode::ATTRIBUTE_NODE ) { // if has attribute dir
char* tmp = XMLString::transcode(current->getNodeValue()); // transcode value
if ( tmp != NULL ) {
store = tmp; // store dir
*record = true;
delete [] tmp;
}
}
delete [] tagDir;
}
/*
* Return string with help dir
*/
std::string GedConf::getHelpDir()
{
if ( !_helpdir.empty() ) {
return _helpdir;
}
else {
return std::string("helpdir"); // if config files doesnt contain help dir then is used this
}
}
/*
* Return string with images dir
*/
std::string GedConf::getImageDir()
{
if ( !_imagesDir.empty()) {
return _imagesDir;
}
else {
return std::string("images"); // if config files doesnt contain help dir then is used this
}
}
/*
* Read node with font
*/
void GedConf::parseFont( DOMNode *fontNode)
{
XMLCh* aFile = XMLString::transcode("file");
XMLCh* aDpi = XMLString::transcode("dpi");
XMLCh* aSize = XMLString::transcode("size");
char* value = NULL;
DOMNamedNodeMap* attribut = fontNode->getAttributes(); // create attributes list
DOMNode* current = attribut->getNamedItem( aFile ); // take attribute name
if ( current != NULL && current->getNodeType() == DOMNode::ATTRIBUTE_NODE ) { // if not NULL and is attribute node
value = XMLString::transcode(current->getNodeValue()); // transcode name value
if ( value != NULL ) {
_fontFile = value;
delete [] value;
}
}
current = attribut->getNamedItem( aDpi ); // take attribute params
if ( current != NULL && current->getNodeType() == DOMNode::ATTRIBUTE_NODE ) { // if not NULL and is attribute node
value = XMLString::transcode(current->getNodeValue()); // transcode name value
if ( value != NULL ) {
_fontDPI = value;
delete [] value;
}
}
current = attribut->getNamedItem( aSize ); // take attribute params
if ( current != NULL && current->getNodeType() == DOMNode::ATTRIBUTE_NODE ) { // if not NULL and is attribute node
value = XMLString::transcode(current->getNodeValue()); // transcode name value
if ( value != NULL ) {
_fontSize = value;
delete [] value;
}
}
_FLFR = true;
delete [] aSize;
delete [] aDpi;
delete [] aFile;
}
/*
* To get font property
*/
void GedConf::getFont( std::string &fileName, std::string &dpi, std::string &size )
{
fileName = _fontFile;
dpi = _fontDPI;
size = _fontSize;
}