Salome HOME
Support of additional environment-defined path to plugins. Also make plugins.xml...
[modules/shaper.git] / src / Config / Config_XMLReader.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include <Config_XMLReader.h>
22 #include <Config_Keywords.h>
23 #include <Config_Common.h>
24 #include <Config_PropManager.h>
25 #include <Config_ModuleReader.h>
26
27 #include <Events_Loop.h>
28 #include <Events_InfoMessage.h>
29 #include <libxml/parser.h>
30 #include <libxml/tree.h>
31
32 #include <fstream>
33 #include <sstream>
34
35 #ifdef WIN32
36 #pragma warning(disable : 4996) // for getenv
37 #endif
38
39 #ifdef _DEBUG
40 #include <iostream>
41 #endif
42
43 #ifdef WIN32
44     static const char FSEP = '\\';
45 #else
46     static const char FSEP = '/';
47 #endif
48
49 Config_XMLReader::Config_XMLReader(const std::string& theXmlFileName)
50     : myXmlDoc(NULL), myRootFileName(theXmlFileName)
51 {
52   myDocumentPath = findConfigFile(theXmlFileName);
53   if (myDocumentPath.empty()) {
54     Events_InfoMessage("Config_XMLReader", "Unable to open %1").arg(theXmlFileName).send();
55   }
56 }
57
58 Config_XMLReader::~Config_XMLReader()
59 {
60   xmlFreeDoc(myXmlDoc);
61 }
62
63 std::string Config_XMLReader::pluginConfigFile()
64 {
65   std::string aValue;
66   char* anEnv = getenv("SHAPER_ROOT_DIR");
67   if (anEnv) {
68     aValue = std::string(anEnv) +
69       FSEP + "share" + FSEP + "salome" + FSEP + "resources" + FSEP + "shaper";
70   } else {
71     anEnv = getenv("OPENPARTS_ROOT_DIR");
72     if (anEnv) {
73       aValue = std::string(anEnv) + FSEP + "plugins";
74     }
75   }
76   return aValue;
77 }
78
79 std::string Config_XMLReader::findConfigFile(const std::string theFileName, const int theFindIndex)
80 {
81   int aResultIndex = 0;
82   for(int aSolution = 0; aSolution < 12; aSolution++) {
83     std::string aFileName;
84     if (aSolution == 0) {
85       Config_Prop* aProp = Config_PropManager::findProp("Plugins", "default_path");
86       if (!aProp)
87         continue;
88       aFileName = aProp->value();
89     } else {
90       std::ostringstream anEnvName;
91       if (aSolution == 1)
92         anEnvName<<"SHAPER_ROOT_DIR";
93       else if (aSolution == 2)
94         anEnvName<<"OPENPARTS_ROOT_DIR";
95       else
96         anEnvName<<"OPENPARTS_PLUGINS_DIR";
97
98       char* anEnv = getenv(anEnvName.str().c_str());
99       if (!anEnv)
100         continue;
101       if (aSolution > 2) { // there may be several paths separated by ";" symbol
102         std::string anEnvPart = anEnv;
103         size_t aPosStart = 0, aPosEnd;
104         for(int aSubNum = 0; aSubNum < aSolution - 3; aSubNum++) {
105           aPosStart++;
106           aPosStart = anEnvPart.find(';', aPosStart);
107           if (aPosStart == std::string::npos)
108             break;
109         }
110         if (aPosStart == std::string::npos)
111           break;
112         if (aPosStart != 0)
113           aPosStart++;
114         aPosEnd = anEnvPart.find(';', aPosStart);
115         aFileName = anEnvPart.substr(aPosStart,
116           aPosEnd == std::string::npos ? aPosEnd : aPosEnd - aPosStart) + FSEP;
117       } else {
118         aFileName = std::string(anEnv) + FSEP;
119       }
120       if (aSolution == 1)
121         aFileName += std::string("share") + FSEP + "salome" + FSEP + "resources" + FSEP + "shaper";
122       else if (aSolution == 2)
123         aFileName += "plugins";
124     }
125
126     aFileName += FSEP + theFileName;
127     std::ifstream aTestFile(aFileName);
128     if (aTestFile) {
129       if (aResultIndex == theFindIndex)
130         return aFileName;
131       aResultIndex++;
132       if (aSolution == 1) // don't allow SHAPER and OpenParts paths treated simultaneously
133         aSolution++;
134     }
135   }
136   return ""; // no files found
137 }
138
139 void Config_XMLReader::readAll()
140 {
141   // to load external modules dependencies (like GEOM for Connector Feature)
142   Config_ModuleReader::loadScript("salome.shaper.initConfig", false);
143
144   for(int aSolution = 0; true; aSolution++) {
145     std::string aFoundFile = findConfigFile(myRootFileName, aSolution);
146     if (aFoundFile.empty()) {
147       break; // no more solutions
148     }
149
150     if (myXmlDoc != NULL) { // clear the previous XML document - now the new one will be opened
151       xmlFreeDoc(myXmlDoc);
152       myXmlDoc = NULL;
153     }
154     xmlNodePtr aRoot = findRoot(aFoundFile);
155     readRecursively(aRoot);
156   }
157 }
158
159 void Config_XMLReader::processNode(xmlNodePtr theNode)
160 {
161   if (isNode(theNode, NODE_SOURCE, NULL)) {
162     std::string aSourceFile = getProperty(theNode, SOURCE_FILE);
163     Config_XMLReader aSourceReader = Config_XMLReader(aSourceFile);
164     readRecursively(aSourceReader.findRoot());
165 #ifdef _DEBUG
166     //std::cout << "Config_XMLReader::sourced node: " << aSourceFile << std::endl;
167 #endif
168   }
169 }
170
171 void Config_XMLReader::cleanup(xmlNodePtr)
172 {
173   // do nothing;
174 }
175
176 bool Config_XMLReader::processChildren(xmlNodePtr aNode)
177 {
178   return true;
179 }
180
181 xmlNodePtr Config_XMLReader::findRoot(const std::string theDocumentPath)
182 {
183   std::string aDocPath = theDocumentPath.empty() ? myDocumentPath : theDocumentPath;
184   if (myXmlDoc == NULL) {
185     myXmlDoc = xmlParseFile(aDocPath.c_str());
186   }
187   if (myXmlDoc == NULL) {
188 #ifdef _DEBUG
189     std::cout << "Config_XMLReader::import: " << "Document " << aDocPath
190     << " is not parsed successfully." << std::endl;
191 #endif
192     return NULL;
193   }
194   xmlNodePtr aRoot = xmlDocGetRootElement(myXmlDoc);
195 #ifdef _DEBUG
196   if(aRoot == NULL) {
197     std::cout << "Config_XMLReader::import: " << "Error: empty document";
198   }
199 #endif
200   return aRoot;
201 }
202
203 void Config_XMLReader::readRecursively(xmlNodePtr theParent)
204 {
205   if (!theParent)
206     return;
207   xmlNodePtr aNode = theParent->xmlChildrenNode;
208   for (; aNode; aNode = aNode->next) {
209     //Still no text processing in features...
210     if (!isElementNode(aNode)) {
211       continue;
212     }
213     processNode(aNode);
214     if (processChildren(aNode)) {
215       readRecursively(aNode);
216     }
217     cleanup(aNode);
218   }
219 }
220
221 xmlNodePtr Config_XMLReader::node(void* theNode)
222 {
223   return static_cast<xmlNodePtr>(theNode);
224 }
225
226 std::string Config_XMLReader::getNodeName(xmlNodePtr theNode)
227 {
228   std::string result = "";
229   char* aPropChars = (char*) theNode->name;
230   if (!aPropChars || aPropChars[0] == 0)
231     return result;
232   result = std::string(aPropChars);
233   return result;
234 }
235
236 void Config_XMLReader::storeAttribute(xmlNodePtr theNode, const char* theAttribute, bool doClean)
237 {
238   std::string aKey = getNodeName(theNode) + ":" + std::string(theAttribute);
239   std::string aValue = getProperty(theNode, theAttribute);
240   if (doClean || !aValue.empty()) {
241     myCachedAttributes[aKey] = aValue;
242   }
243 }
244
245 std::string Config_XMLReader::restoreAttribute(xmlNodePtr theNode, const char* theAttribute)
246 {
247   return restoreAttribute(getNodeName(theNode).c_str(), theAttribute);
248 }
249
250 std::string Config_XMLReader::restoreAttribute(const char* theNodeName, const char* theAttribute)
251 {
252   std::string aKey = std::string(theNodeName) + ":" + std::string(theAttribute);
253   std::string result = "";
254   if(myCachedAttributes.find(aKey) != myCachedAttributes.end()) {
255     result = myCachedAttributes[aKey];
256   }
257   return result;
258 }
259
260 bool Config_XMLReader::cleanupAttribute(xmlNodePtr theNode, const char* theNodeAttribute)
261 {
262   return cleanupAttribute(getNodeName(theNode).c_str(), theNodeAttribute);
263 }
264
265 bool Config_XMLReader::cleanupAttribute(const char* theNodeName, const char* theNodeAttribute)
266 {
267   std::string aKey = std::string(theNodeName) + ":" + std::string(theNodeAttribute);
268   bool result = false;
269   std::map<std::string, std::string>::iterator anEntry = myCachedAttributes.find(aKey);
270   if( anEntry != myCachedAttributes.end()) {
271     myCachedAttributes.erase(anEntry);
272     result = true;
273   }
274   return result;
275 }
276
277 const char* Config_XMLReader::encoding() const
278 {
279   return (const char*) myXmlDoc->encoding;
280 }