Salome HOME
Merge remote-tracking branch 'origin/cbr/export_to_geom_via_xao'
[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::resourcesConfigFile()
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 + "resources";
74     }
75   }
76   return aValue;
77 }
78
79 std::string Config_XMLReader::pluginConfigFile()
80 {
81   std::string aValue;
82   char* anEnv = getenv("SHAPER_ROOT_DIR");
83   if (anEnv) {
84     aValue = std::string(anEnv) +
85       FSEP + "share" + FSEP + "salome" + FSEP + "resources" + FSEP + "shaper";
86   } else {
87     anEnv = getenv("OPENPARTS_ROOT_DIR");
88     if (anEnv) {
89       aValue = std::string(anEnv) + FSEP + "plugins";
90     }
91   }
92   return aValue;
93 }
94
95 std::string Config_XMLReader::findConfigFile(const std::string theFileName, const int theFindIndex)
96 {
97   int aResultIndex = 0;
98   for(int aSolution = 0; aSolution < 12; aSolution++) {
99     std::string aFileName;
100     if (aSolution == 0) {
101       Config_Prop* aProp = Config_PropManager::findProp("Plugins", "default_path");
102       if (!aProp)
103         continue;
104       aFileName = aProp->value();
105     } else {
106       std::ostringstream anEnvName;
107       if (aSolution == 1)
108         anEnvName<<"SHAPER_ROOT_DIR";
109       else if (aSolution == 2)
110         anEnvName<<"OPENPARTS_ROOT_DIR";
111       else
112         anEnvName<<"OPENPARTS_PLUGINS_DIR";
113
114       char* anEnv = getenv(anEnvName.str().c_str());
115       if (!anEnv)
116         continue;
117       if (aSolution > 2) { // there may be several paths separated by ";" symbol
118         std::string anEnvPart = anEnv;
119         size_t aPosStart = 0, aPosEnd;
120         for(int aSubNum = 0; aSubNum < aSolution - 3; aSubNum++) {
121           aPosStart++;
122           aPosStart = anEnvPart.find(';', aPosStart);
123           if (aPosStart == std::string::npos)
124             break;
125         }
126         if (aPosStart == std::string::npos)
127           break;
128         if (aPosStart != 0)
129           aPosStart++;
130         aPosEnd = anEnvPart.find(';', aPosStart);
131         aFileName = anEnvPart.substr(aPosStart,
132           aPosEnd == std::string::npos ? aPosEnd : aPosEnd - aPosStart) + FSEP;
133       } else {
134         aFileName = std::string(anEnv) + FSEP;
135       }
136       if (aSolution == 1)
137         aFileName += std::string("share") + FSEP + "salome" + FSEP + "resources" + FSEP + "shaper";
138       else if (aSolution == 2)
139         aFileName += "plugins";
140     }
141
142     aFileName += FSEP + theFileName;
143     std::ifstream aTestFile(aFileName);
144     if (aTestFile) {
145       if (aResultIndex == theFindIndex)
146         return aFileName;
147       aResultIndex++;
148       if (aSolution == 1) // don't allow SHAPER and OpenParts paths treated simultaneously
149         aSolution++;
150     }
151   }
152   return ""; // no files found
153 }
154
155 void Config_XMLReader::readAll()
156 {
157   // to load external modules dependencies (like GEOM for Connector Feature)
158   Config_ModuleReader::loadScript("salome.shaper.initConfig", false);
159
160   for(int aSolution = 0; true; aSolution++) {
161     std::string aFoundFile = findConfigFile(myRootFileName, aSolution);
162     if (aFoundFile.empty()) {
163       break; // no more solutions
164     }
165
166     if (myXmlDoc != NULL) { // clear the previous XML document - now the new one will be opened
167       xmlFreeDoc(myXmlDoc);
168       myXmlDoc = NULL;
169     }
170     xmlNodePtr aRoot = findRoot(aFoundFile);
171     readRecursively(aRoot);
172   }
173 }
174
175 void Config_XMLReader::processNode(xmlNodePtr theNode)
176 {
177   if (isNode(theNode, NODE_SOURCE, NULL)) {
178     std::string aSourceFile = getProperty(theNode, SOURCE_FILE);
179     Config_XMLReader aSourceReader = Config_XMLReader(aSourceFile);
180     readRecursively(aSourceReader.findRoot());
181 #ifdef _DEBUG
182     //std::cout << "Config_XMLReader::sourced node: " << aSourceFile << std::endl;
183 #endif
184   }
185 }
186
187 void Config_XMLReader::cleanup(xmlNodePtr)
188 {
189   // do nothing;
190 }
191
192 bool Config_XMLReader::processChildren(xmlNodePtr aNode)
193 {
194   return true;
195 }
196
197 xmlNodePtr Config_XMLReader::findRoot(const std::string theDocumentPath)
198 {
199   std::string aDocPath = theDocumentPath.empty() ? myDocumentPath : theDocumentPath;
200   if (myXmlDoc == NULL) {
201     myXmlDoc = xmlParseFile(aDocPath.c_str());
202   }
203   if (myXmlDoc == NULL) {
204 #ifdef _DEBUG
205     std::cout << "Config_XMLReader::import: " << "Document " << aDocPath
206     << " is not parsed successfully." << std::endl;
207 #endif
208     return NULL;
209   }
210   xmlNodePtr aRoot = xmlDocGetRootElement(myXmlDoc);
211 #ifdef _DEBUG
212   if(aRoot == NULL) {
213     std::cout << "Config_XMLReader::import: " << "Error: empty document";
214   }
215 #endif
216   return aRoot;
217 }
218
219 void Config_XMLReader::readRecursively(xmlNodePtr theParent)
220 {
221   if (!theParent)
222     return;
223   xmlNodePtr aNode = theParent->xmlChildrenNode;
224   for (; aNode; aNode = aNode->next) {
225     //Still no text processing in features...
226     if (!isElementNode(aNode)) {
227       continue;
228     }
229     processNode(aNode);
230     if (processChildren(aNode)) {
231       readRecursively(aNode);
232     }
233     cleanup(aNode);
234   }
235 }
236
237 xmlNodePtr Config_XMLReader::node(void* theNode)
238 {
239   return static_cast<xmlNodePtr>(theNode);
240 }
241
242 std::string Config_XMLReader::getNodeName(xmlNodePtr theNode)
243 {
244   std::string result = "";
245   char* aPropChars = (char*) theNode->name;
246   if (!aPropChars || aPropChars[0] == 0)
247     return result;
248   result = std::string(aPropChars);
249   return result;
250 }
251
252 void Config_XMLReader::storeAttribute(xmlNodePtr theNode, const char* theAttribute, bool doClean)
253 {
254   std::string aKey = getNodeName(theNode) + ":" + std::string(theAttribute);
255   std::string aValue = getProperty(theNode, theAttribute);
256   if (doClean || !aValue.empty()) {
257     myCachedAttributes[aKey] = aValue;
258   }
259 }
260
261 std::string Config_XMLReader::restoreAttribute(xmlNodePtr theNode, const char* theAttribute)
262 {
263   return restoreAttribute(getNodeName(theNode).c_str(), theAttribute);
264 }
265
266 std::string Config_XMLReader::restoreAttribute(const char* theNodeName, const char* theAttribute)
267 {
268   std::string aKey = std::string(theNodeName) + ":" + std::string(theAttribute);
269   std::string result = "";
270   if(myCachedAttributes.find(aKey) != myCachedAttributes.end()) {
271     result = myCachedAttributes[aKey];
272   }
273   return result;
274 }
275
276 bool Config_XMLReader::cleanupAttribute(xmlNodePtr theNode, const char* theNodeAttribute)
277 {
278   return cleanupAttribute(getNodeName(theNode).c_str(), theNodeAttribute);
279 }
280
281 bool Config_XMLReader::cleanupAttribute(const char* theNodeName, const char* theNodeAttribute)
282 {
283   std::string aKey = std::string(theNodeName) + ":" + std::string(theNodeAttribute);
284   bool result = false;
285   std::map<std::string, std::string>::iterator anEntry = myCachedAttributes.find(aKey);
286   if( anEntry != myCachedAttributes.end()) {
287     myCachedAttributes.erase(anEntry);
288     result = true;
289   }
290   return result;
291 }
292
293 const char* Config_XMLReader::encoding() const
294 {
295   return (const char*) myXmlDoc->encoding;
296 }