/*************************************************************************** PMuppStartupHandler.cpp Author: Andreas Suter e-mail: andreas.suter@psi.ch This file implements the PMuppStartupHandler class, a SAX parser handler for reading mupp_startup.xml configuration files. The implementation: - Searches for mupp_startup.xml in current directory or $HOME/.musrfit/mupp/ - Parses marker styles, sizes, and colors using ROOT's SAX parser - Generates random defaults if file is not found or lists are incomplete - Provides a parseXmlFile() utility function for reliable XML parsing SAX Parsing Flow: 1. OnStartDocument() - initialize state 2. OnStartElement() - detect marker/color blocks 3. OnCharacters() - extract numeric values and color names 4. OnEndElement() - finalize current block 5. OnEndDocument() - validate lists with CheckLists() The CheckLists() method ensures all three lists (marker styles, sizes, colors) have the same length, generating random values as needed for consistency. ***************************************************************************/ /*************************************************************************** * Copyright (C) 2007-2025 by Andreas Suter * * andreas.suter@psi.ch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include "PMuppStartupHandler.h" ClassImpQ(PMuppStartupHandler) //-------------------------------------------------------------------------- // This function is a replacement for the ParseFile method of TSAXParser. // It is needed because in certain environments ParseFile does not work but ParseBuffer does. //-------------------------------------------------------------------------- /** *

Replacement for the ParseFile method of TSAXParser. * *

return: * - 1 if file cannot be read * - 0 if the file has been parsed successfully * - parse error code otherwise * * \param saxParser pointer to a TSAXParser object * \param startup_path_name full path to the XML file to be read */ int parseXmlFile(TSAXParser *saxParser, const char *startup_path_name) { int status; std::fstream xmlFile; unsigned int xmlSize = 0; char *xmlBuffer = 0; xmlFile.open(startup_path_name, std::ios::in | std::ios::ate); // open file for reading and go to the end of the file if (xmlFile.is_open()) { // check if file has been opened successfully xmlSize = xmlFile.tellg(); // get the position within the stream == size of the file (since we are at the end) xmlFile.seekg(0, std::ios::beg); // go back to the beginning of the stream xmlBuffer = new char[xmlSize]; // allocate buffer memory for the whole XML file xmlFile.read(xmlBuffer, xmlSize); // read in the whole XML file into the buffer xmlFile.close(); // close the XML file } if (!xmlBuffer) { // file has not been read into the buffer status = 1; } else { status = saxParser->ParseBuffer(xmlBuffer, xmlSize); // parse buffer delete[] xmlBuffer; // free the buffer memory xmlBuffer = 0; } return status; } //-------------------------------------------------------------------------- // Constructor //-------------------------------------------------------------------------- /** * @brief Constructor that searches for mupp_startup.xml configuration file. * * Search order: * 1. ./mupp_startup.xml (current directory) * 2. $HOME/.musrfit/mupp/mupp_startup.xml (user configuration directory) * * Sets fStartupFileFound and fStartupFilePath based on search results. */ PMuppStartupHandler::PMuppStartupHandler() { fStartupFileFound = false; fStartupFilePath = ""; // get default path (for the moment only linux like) Char_t *home=0; Char_t musrpath[128]; Char_t startup_path_name[128]; strncpy(musrpath, "", sizeof(musrpath)); // check if the startup file is found in the current directory strcpy(startup_path_name, "./mupp_startup.xml"); if (StartupFileExists(startup_path_name)) { fStartupFileFound = true; fStartupFilePath = TString(startup_path_name); } if (!fStartupFileFound) { // startup file not found in the current directory // check if the startup file is found under $HOME/.musrfit/mupp home = getenv("HOME"); if (home != 0) { snprintf(startup_path_name, sizeof(startup_path_name), "%s/.musrfit/mupp/mupp_startup.xml", home); if (StartupFileExists(startup_path_name)) { fStartupFilePath = TString(startup_path_name); fStartupFileFound = true; } } } } //-------------------------------------------------------------------------- // Destructor //-------------------------------------------------------------------------- /** * @brief Destructor that cleans up style list vectors. * * Clears all marker style, size, and color list vectors to free memory. */ PMuppStartupHandler::~PMuppStartupHandler() { fMarkerStyleList.clear(); fMarkerSizeList.clear(); fColorList.clear(); } //-------------------------------------------------------------------------- // OnStartDocument //-------------------------------------------------------------------------- /** *

Called on start of the XML file reading. Initializes all necessary variables. */ void PMuppStartupHandler::OnStartDocument() { fKey = eEmpty; } //-------------------------------------------------------------------------- // OnEndDocument //-------------------------------------------------------------------------- /** *

Called on end of XML file reading. */ void PMuppStartupHandler::OnEndDocument() { // check if anything was set, and if not set some default stuff CheckLists(); } //-------------------------------------------------------------------------- // OnStartElement //-------------------------------------------------------------------------- /** *

Called when a XML start element is found. Filters out the needed elements * and sets a proper key. * * \param str XML element name * \param attributes not used */ void PMuppStartupHandler::OnStartElement(const Char_t *str, const TList *attributes) { if (!strcmp(str, "marker")) { fKey = eMarker; } else if (!strcmp(str, "color")) { fKey = eColor; } } //-------------------------------------------------------------------------- // OnEndElement //-------------------------------------------------------------------------- /** *

Called when a XML end element is found. Resets the handler key. * * \param str not used */ void PMuppStartupHandler::OnEndElement(const Char_t *str) { fKey = eEmpty; } //-------------------------------------------------------------------------- // OnCharacters //-------------------------------------------------------------------------- /** *

Content of a given XML element. Filters out the data and feeds them to * the internal variables. * * \param str XML element string */ void PMuppStartupHandler::OnCharacters(const Char_t *str) { TObjArray *tokens; TObjString *ostr; TString tstr; Int_t color, r, g, b; switch (fKey) { case eMarker: // check that str is , tstr = TString(str); tokens = tstr.Tokenize(","); if (tokens == 0) { std::cerr << std::endl << "PMuppStartupHandler **WARNING** '" << str << "' is not a marker code, will ignore it"; std::cerr << std::endl; return; } if (tokens->GetEntries() != 2) { std::cerr << std::endl << "PMuppStartupHandler **WARNING** '" << str << "' is not a marker code, will ignore it"; std::cerr << std::endl; return; } // get marker style ostr = dynamic_cast(tokens->At(0)); tstr = ostr->GetString(); if (tstr.IsDigit()) { fMarkerStyleList.push_back(tstr.Atoi()); } else { std::cerr << std::endl << "PMuppStartupHandler **WARNING** marker style '" << str << "' is not a number, will ignore it"; std::cerr << std::endl; } // get marker size ostr = dynamic_cast(tokens->At(1)); tstr = ostr->GetString(); if (tstr.IsFloat()) { fMarkerSizeList.push_back(tstr.Atof()); } else { std::cerr << std::endl << "PMuppStartupHandler **WARNING** marker size '" << str << "' is not a float, will ignore it"; std::cerr << std::endl; } // clean up tokens if (tokens) { delete tokens; tokens = 0; } break; case eColor: // check that str is a rbg code tstr = TString(str); tokens = tstr.Tokenize(","); // check that there any tokens if (tokens == 0) { std::cerr << std::endl << "PMuppStartupHandler **WARNING** '" << str << "' is not a rbg code, will ignore it"; std::cerr << std::endl; return; } // check there is the right number of tokens if (tokens->GetEntries() < 3) { std::cerr << std::endl << "PMuppStartupHandler **WARNING** '" << str << "' is not a rbg code, will ignore it"; std::cerr << std::endl; return; } // get r ostr = dynamic_cast(tokens->At(0)); tstr = ostr->GetString(); if (tstr.IsDigit()) { r = tstr.Atoi(); } else { std::cerr << std::endl << "PMuppStartupHandler **WARNING** r within the rgb code is not a number, will ignore it"; std::cerr << std::endl; return; } // get g ostr = dynamic_cast(tokens->At(1)); tstr = ostr->GetString(); if (tstr.IsDigit()) { g = tstr.Atoi(); } else { std::cerr << std::endl << "PMuppStartupHandler **WARNING** g within the rgb code is not a number, will ignore it"; std::cerr << std::endl; return; } // get b ostr = dynamic_cast(tokens->At(2)); tstr = ostr->GetString(); if (tstr.IsDigit()) { b = tstr.Atoi(); } else { std::cerr << std::endl << "PMuppStartupHandler **WARNING** b within the rgb code is not a number, will ignore it"; std::cerr << std::endl; return; } // clean up tokens if (tokens) { delete tokens; tokens = 0; } // generate the ROOT color code based on str color = TColor::GetColor(r,g,b); // add the color code to the color list fColorList.push_back(color); break; default: break; } } //-------------------------------------------------------------------------- // OnComment //-------------------------------------------------------------------------- /** *

Called when a XML comment is found. Not used. * * \param str not used. */ void PMuppStartupHandler::OnComment(const Char_t *str) { // nothing to be done for now } //-------------------------------------------------------------------------- // OnWarning //-------------------------------------------------------------------------- /** *

Called when the XML parser emits a warning. * * \param str warning string */ void PMuppStartupHandler::OnWarning(const Char_t *str) { std::cerr << std::endl << "PMuppStartupHandler **WARNING** " << str; std::cerr << std::endl; } //-------------------------------------------------------------------------- // OnError //-------------------------------------------------------------------------- /** *

Called when the XML parser emits an error. * * \param str error string */ void PMuppStartupHandler::OnError(const Char_t *str) { std::cerr << std::endl << "PMuppStartupHandler **ERROR** " << str; std::cerr << std::endl; } //-------------------------------------------------------------------------- // OnFatalError //-------------------------------------------------------------------------- /** *

Called when the XML parser emits a fatal error. * * \param str fatal error string */ void PMuppStartupHandler::OnFatalError(const Char_t *str) { std::cerr << std::endl << "PMuppStartupHandler **FATAL ERROR** " << str; std::cerr << std::endl; } //-------------------------------------------------------------------------- // OnCdataBlock //-------------------------------------------------------------------------- /** *

Not used. * * \param str not used * \param len not used */ void PMuppStartupHandler::OnCdataBlock(const Char_t *str, Int_t len) { // nothing to be done for now } //-------------------------------------------------------------------------- // CheckLists //-------------------------------------------------------------------------- /** *

Check if the default lists are present and if not, feed them with some default settings * */ void PMuppStartupHandler::CheckLists() { // check if anything was set, and if not set some default stuff // check if any marker styles are given if (fMarkerStyleList.size() == 0) { fMarkerStyleList.push_back(24); // open circle fMarkerStyleList.push_back(25); // open square fMarkerStyleList.push_back(26); // open triangle fMarkerStyleList.push_back(27); // open diamond fMarkerStyleList.push_back(28); // open cross fMarkerStyleList.push_back(29); // full star fMarkerStyleList.push_back(30); // open star fMarkerStyleList.push_back(20); // full circle fMarkerStyleList.push_back(21); // full square fMarkerStyleList.push_back(22); // full triangle fMarkerStyleList.push_back(23); // full down triangle fMarkerStyleList.push_back(2); // thin cross fMarkerStyleList.push_back(3); // thin star fMarkerStyleList.push_back(5); // thin cross 45° rotated } // check if any marker ssizes are given if (fMarkerSizeList.size() == 0) { fMarkerSizeList.push_back(1.3); fMarkerSizeList.push_back(1.3); fMarkerSizeList.push_back(1.5); fMarkerSizeList.push_back(1.5); fMarkerSizeList.push_back(1.5); fMarkerSizeList.push_back(1.5); fMarkerSizeList.push_back(1.3); fMarkerSizeList.push_back(1.3); fMarkerSizeList.push_back(1.5); fMarkerSizeList.push_back(1.5); fMarkerSizeList.push_back(1.5); fMarkerSizeList.push_back(1.5); fMarkerSizeList.push_back(1.5); fMarkerSizeList.push_back(1.5); } // check if any colors are given if (fColorList.size() == 0) { fColorList.push_back(TColor::GetColor(0, 0, 0)); // kBlack fColorList.push_back(TColor::GetColor(255, 0, 0)); // kRed fColorList.push_back(TColor::GetColor(0, 255, 0)); // kGreen fColorList.push_back(TColor::GetColor(0, 0, 255)); // kBlue fColorList.push_back(TColor::GetColor(255, 0, 255)); // kMagneta fColorList.push_back(TColor::GetColor(0, 255, 255)); // kCyan fColorList.push_back(TColor::GetColor(156, 0, 255)); // kViolette-3 fColorList.push_back(TColor::GetColor(99, 101, 49)); // kYellow-1 fColorList.push_back(TColor::GetColor(49, 101, 49)); // kGreen-1 fColorList.push_back(TColor::GetColor(156, 48, 0)); // kOrange-4 } } //-------------------------------------------------------------------------- // StartupFileExists //-------------------------------------------------------------------------- /** *

Checks if a file is present on the disc. * * return: * - true, if the file is present * - false, otherwise * * \param fln file name */ Bool_t PMuppStartupHandler::StartupFileExists(Char_t *fln) { Bool_t result = false; std::ifstream ifile(fln); if (ifile.fail()) { result = false; } else { result = true; ifile.close(); } return result; }