// // libavg - Media Playback Engine. // Copyright (C) 2003-2014 Ulrich von Zadow // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // Current versions can be found at www.libavg.de #include "TrackerConfig.h" #include "trackerconfigdtd.h" #include "DeDistort.h" #include "../base/XMLHelper.h" #include "../base/Logger.h" #include "../base/FileHelper.h" #include "../base/Exception.h" #include "../base/StringHelper.h" #include "../base/ConfigMgr.h" #include #include #include #include #include #include using namespace std; namespace avg { TrackerConfig::TrackerConfig() : m_Doc(0) { } TrackerConfig::TrackerConfig(const TrackerConfig& other) { m_Doc = 0; if (other.m_Doc) { m_Doc = xmlCopyDoc(other.m_Doc, true); m_sFilename = other.m_sFilename; m_pRoot = xmlDocGetRootElement(m_Doc); } } TrackerConfig::~TrackerConfig() { xmlFreeDoc(m_Doc); } void TrackerConfig::loadConfigFile(const string& sFilename) { // TODO: There is duplicated code here and in Player::loadFile which belongs // in a lower-level xml handling class. registerDTDEntityLoader("trackerconfig.dtd", g_pTrackerConfigDTD); xmlDtdPtr dtd; string sDTDFName = "trackerconfig.dtd"; dtd = xmlParseDTD(NULL, (const xmlChar*) sDTDFName.c_str()); if (!dtd) { AVG_LOG_WARNING("DTD not found at " << sDTDFName << ". Not validating trackerconfig files."); } // xmlParseFile crashes for some reason under Lion. string sFileContents; readWholeFile(sFilename, sFileContents); m_Doc = xmlParseMemory(sFileContents.c_str(), sFileContents.length()); if (!m_Doc) { AVG_LOG_ERROR("Could not open tracker config file " << sFilename << ". Using defaults which will probably not work."); return; } xmlValidCtxtPtr cvp = xmlNewValidCtxt(); cvp->error = xmlParserValidityError; cvp->warning = xmlParserValidityWarning; int isValid = xmlValidateDtd(cvp, m_Doc, dtd); xmlFreeValidCtxt(cvp); if (!isValid) { throw (Exception(AVG_ERR_XML_PARSE, sFilename + " does not validate.")); } m_pRoot = xmlDocGetRootElement(m_Doc); xmlFreeDtd(dtd); m_sFilename = sFilename; AVG_TRACE(Logger::category::CONFIG, Logger::severity::INFO, "Reading Tracker config file from " << sFilename); } void TrackerConfig::load() { // Give precedence to local configuration string sFName = "avgtrackerrc"; if (fileExists(sFName) || !fileExists(getGlobalConfigDir() + sFName)) { loadConfigFile(sFName); } else { loadConfigFile(getGlobalConfigDir() + sFName); } } xmlXPathObjectPtr TrackerConfig::findConfigNodes(const string& sXPathExpr) const { string sFullPath = string("/trackerconfig"+sXPathExpr); xmlXPathContextPtr xpCtx; xmlXPathObjectPtr xpElement; xpCtx = xmlXPathNewContext(m_Doc); if(!xpCtx) { AVG_LOG_ERROR("Unable to create new XPath context"); return NULL; } xpElement = xmlXPathEvalExpression(BAD_CAST sFullPath.c_str(), xpCtx); if(!xpElement) { AVG_LOG_ERROR("Unable to evaluate XPath expression '" << sFullPath << "'"); xmlXPathFreeContext(xpCtx); return NULL; } xmlXPathFreeContext(xpCtx); return xpElement; } void TrackerConfig::setParam(const string& sXPathExpr, const string& sValue) { xmlXPathObjectPtr xpElement = findConfigNodes(sXPathExpr); xmlNodeSetPtr nodes = xpElement->nodesetval; if (!nodes || nodes->nodeNr == 0) throw (Exception(AVG_ERR_OPTION_UNKNOWN, string("setParam(): cannot find requested element ")+sXPathExpr)); for (int i = nodes->nodeNr-1; i >= 0; i--) { AVG_ASSERT(nodes->nodeTab[i]); xmlNodeSetContent(nodes->nodeTab[i], BAD_CAST sValue.c_str()); if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL) nodes->nodeTab[i] = NULL; } xmlXPathFreeObject(xpElement); } string TrackerConfig::getParam(const string& sXPathExpr) const { xmlXPathObjectPtr xpElement = findConfigNodes(sXPathExpr); xmlNodeSetPtr nodes = xpElement->nodesetval; if (!nodes || nodes->nodeNr == 0) { throw (Exception(AVG_ERR_OPTION_UNKNOWN, string("getParam(): cannot find requested element ")+sXPathExpr)); } else if (nodes->nodeNr > 1) { AVG_LOG_WARNING( "getParam(): expression selects more than one node. Returning the first."); } xmlChar* xsRc = xmlNodeGetContent(nodes->nodeTab[0]); string sValue((char *)xsRc); xmlFree(xsRc); xmlXPathFreeObject(xpElement); return sValue; } bool TrackerConfig::getBoolParam(const std::string& sXPathExpr) const { return stringToBool(getParam(sXPathExpr)); } int TrackerConfig::getIntParam(const std::string& sXPathExpr) const { return stringToInt(getParam(sXPathExpr)); } float TrackerConfig::getFloatParam(const std::string& sXPathExpr) const { return stringToFloat(getParam(sXPathExpr)); } glm::vec2 TrackerConfig::getPointParam(const std::string& sXPathExpr) const { return glm::vec2(getFloatParam(sXPathExpr+"@x"), getFloatParam(sXPathExpr+"@y")); } FRect TrackerConfig::getRectParam(const std::string& sXPathExpr) const { glm::vec2 pos1 = glm::vec2(getFloatParam(sXPathExpr+"@x1"), getFloatParam(sXPathExpr+"@y1")); glm::vec2 pos2 = glm::vec2(getFloatParam(sXPathExpr+"@x2"), getFloatParam(sXPathExpr+"@y2")); return FRect(pos1, pos2); } xmlNodePtr TrackerConfig::getXmlNode(const std::string& sXPathExpr) const { xmlXPathObjectPtr xpElement = findConfigNodes(sXPathExpr); xmlNodeSetPtr nodes = xpElement->nodesetval; if (!nodes || nodes->nodeNr == 0) { throw (Exception(AVG_ERR_OPTION_UNKNOWN, string("getParam(): cannot find requested element ")+sXPathExpr)); } else if (nodes->nodeNr > 1) { AVG_LOG_WARNING( "getXmlNode(): expression selects more than one node. Returning the first."); } return nodes->nodeTab[0]; } DeDistortPtr TrackerConfig::getTransform() const { glm::vec2 CameraExtents = getPointParam("/camera/size/"); DeDistortPtr pDD(new DeDistort); pDD->load(CameraExtents, *this); return pDD; } void TrackerConfig::setTransform(DeDistortPtr pDeDistort) { pDeDistort->save(*this); } void TrackerConfig::dump() const { string s; xmlBufferPtr pBuffer = xmlBufferCreate(); xmlNodeDump(pBuffer, m_Doc, m_pRoot, 0, 0); cerr << xmlBufferContent(pBuffer) << endl; } void TrackerConfig::save() { AVG_TRACE(Logger::category::CONFIG, Logger::severity::INFO, "Saving tracker configuration to " << m_sFilename << "."); if (m_Doc) { if (fileExists(m_sFilename)) { string sBakFile = m_sFilename + ".bak"; unlink(sBakFile.c_str()); if (rename(m_sFilename.c_str(), sBakFile.c_str())) { AVG_LOG_WARNING("Cannot create tracker config backup. Backing " "it up on current workdir."); copyFile(m_sFilename, "avgtrackerrc.bak"); } } xmlSaveFileEnc(m_sFilename.c_str(), m_Doc, "utf-8"); } else throw (Exception(AVG_ERR_FILEIO, "save(): tracker configuration not initialized")); } }