-
Notifications
You must be signed in to change notification settings - Fork 0
/
utilxmltools.cpp
299 lines (220 loc) · 9.9 KB
/
utilxmltools.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
#include "utilxmltools.h"
namespace UtilXmlTools{
// As this will not likely be modified we use QVector instead of QList since it is more cache friendly
QVector<QString> getAllXmlFilesByWildcard(const QString &wildcard){
QStringList validFilesMatching;
QStringList filesMatching;
// Get all files matching the wildcard
filesMatching=UtilXmlTools::getAllFilesByWildcard(wildcard);
// Check if all are XmlFiles, only return valid XmlFiles
for(int i=0; i<filesMatching.size(); i++){
if(filesMatching[i].endsWith(".xml",Qt::CaseInsensitive)){
validFilesMatching << filesMatching[i];
}
}
return validFilesMatching.toVector();
}
QVector<QString> getAllPatchFilesByWildcard(const QString &wildcard){
QStringList validFilesMatching;
QStringList filesMatching;
// Get all files matching the wildcard
filesMatching=UtilXmlTools::getAllFilesByWildcard(wildcard);
// Check if all are PatchFiles, only return valid PatchFiles
for(int i=0; i<filesMatching.size(); i++){
if(filesMatching[i].endsWith(".patch",Qt::CaseInsensitive) || filesMatching[i].endsWith(".oni-patch",Qt::CaseInsensitive)){
validFilesMatching << filesMatching[i];
}
}
return validFilesMatching.toVector();
}
void backupFile(const QString &file, bool verboseEnabled){
if(!QFile::exists(file+".bak")){
if(!Util::FileSystem::backupFile(file)){
std::cerr << "Couldn't back up file '" << file.toUtf8().constData() << "'. Aborting." << std::endl;
exit(1);
}
}
else{
if(verboseEnabled){
std::cout << "Backup file '" << file.toUtf8().constData() << "'' already exists. Skipping..." << std::endl;
}
}
}
void getAllXpathElements(const QString &xPathExpression, pugi::xml_document &doc, QList<pugi::xml_node> &result){
pugi::xpath_node_set selectedNodes;
pugi::xpath_node node;
try
{
selectedNodes = doc.select_nodes(xPathExpression.toUtf8().constData());
}
catch (const pugi::xpath_exception& e)
{
displayErrorMessage("XPath element selection","Selection of elements using the XPathExpression: '" + xPathExpression + "' failed:\n" + e.what());
}
for (pugi::xpath_node_set::const_iterator currNode = selectedNodes.begin(); currNode != selectedNodes.end(); ++currNode)
{
node = *currNode;
if(node){ // if node != null
result << node.node();
}
}
if(result.isEmpty()){
result << pugi::xml_node(); // add an empty node if none found
}
}
pugi::xml_node getFirstXpathElement(const QString &xPathExpression, pugi::xml_document &doc){
pugi::xpath_node selectedNode;
try
{
selectedNode = doc.select_single_node(xPathExpression.toUtf8().constData());
}
catch (const pugi::xpath_exception& e)
{
displayErrorMessage("XPath element selection","Selection of element using the XPathExpression: '" + xPathExpression + "' failed:\n" + e.what());
}
return selectedNode.node();
}
void getAllNamedElements(pugi::xml_node &node, QList<pugi::xml_node> &result, XmlFilter &filters){
for (pugi::xml_node_iterator currNode = node.begin(); currNode != node.end(); ++currNode)
{
if ((*currNode).name() == filters.getElementName() && (filters.getParentElementName() == "" || filters.getParentElementName() == (*currNode).parent().name())
&& (filters.getAttributeName() == "" ||
QString((*currNode).attribute(filters.getAttributeName().toUtf8().constData()).value()) == filters.getAttributeValue()) ){ // Seems node attribute must be converted to qtsring to remove \r\n needs to check in future!
result << *currNode;
continue;
}
getAllNamedElements(*currNode,result,filters);
}
}
pugi::xml_node getFirstNamedElement(pugi::xml_node &node, XmlFilter &filters){
pugi::xml_node foundNode;
for (pugi::xml_node_iterator currNode = node.begin(); currNode != node.end(); ++currNode)
{
if ((*currNode).name() == filters.getElementName() && (filters.getParentElementName() == "" || filters.getParentElementName() == (*currNode).parent().name())
&& (filters.getAttributeName() == "" ||
QString((*currNode).attribute(filters.getAttributeName().toUtf8().constData()).value()) == filters.getAttributeValue()) ){
return *currNode;
}
foundNode=getFirstNamedElement(*currNode,filters);
if(foundNode.type()!=pugi::node_null){
return foundNode;
}
}
return foundNode;
}
void displaySuccessMessage(const int numberOperations, const QString &operation){
std::cout << "------------------------------------------------------------------------" << std::endl;
std::cout << numberOperations << " " << operation.toUtf8().constData() << " operation(s) completed with success!" << std::endl;
std::cout << "------------------------------------------------------------------------" << std::endl;
}
void displayErrorMessage(const QString& operation, const QString &message, bool exitProgram){
std::cerr << "************************************************************************" << std::endl;
std::cerr << operation.toUtf8().constData() << " operation failed!" << std::endl << std::endl;
std::cerr << message.toUtf8().constData() << std::endl << std::endl;
if(exitProgram) std::cerr << "Aborting..." << std::endl;
std::cerr << "************************************************************************" << std::endl;
if(exitProgram) exit(1);
}
QStringList qStringListFromSpacedString(const QString &mySpacedString){
return mySpacedString.split(" ");
}
QList<int> qListIntFromSpacedString(const QString &mySpacedString){
QStringList stringList;
QList<int> intList;
stringList = mySpacedString.split(" ");
foreach(QString value, stringList){
bool ok;
intList << value.toInt(&ok);
if(!ok){
throw std::runtime_error(QString("Impossible to convert string '" + value + "' to int!").toUtf8().constData());
}
}
return intList;
}
QList<double> qListDoubleFromSpacedString(const QString &mySpacedString){
QStringList stringList;
QList<double> doubleList;
stringList = mySpacedString.split(" ");
foreach(QString value, stringList){
bool ok;
doubleList << value.toDouble(&ok);
if(!ok){
throw std::runtime_error(QString("Impossible to convert string '" + value + "' to double!").toUtf8().constData());
}
}
return doubleList;
}
void loadXmlFile(const QString &file, pugi::xml_document &document, pugi::xml_node &rootNode, bool backupsEnabled, bool verboseEnabled, const QString &operationForErrorMessage){
pugi::xml_parse_result result = document.load_file(file.toUtf8().constData());
rootNode=document.root();
if(result.status==pugi::status_ok){
if(verboseEnabled){
std::cout << "File '" << file.toUtf8().constData() << "' loaded with sucess." << std::endl;
}
}
else{
UtilXmlTools::displayErrorMessage(operationForErrorMessage,"An error ocurred while loading '" +file + "' XML file\n" + result.description());
}
if(backupsEnabled){
UtilXmlTools::backupFile(file,verboseEnabled); // bake a backup of the file.
}
}
void saveXmlFile(const QString &file, pugi::xml_document &document, const QString &operationForErrorMessage){
if(!document.save_file(file.toUtf8().constData(), "\t", pugi::format_indent | pugi::format_save_file_text | pugi::format_no_escapes)){ // output as the system new lines ending
UtilXmlTools::displayErrorMessage(operationForErrorMessage,"An error ocurred while saving '" + file + "' XML file");
}
}
//TODO Needs optimization
QStringList QStringToArgsArray(const QString &args){
QStringList result;
int startIdx=0, endIdx=0;
if(!args.isEmpty()){ // if non empty arguments
while(endIdx<args.length()){
startIdx=endIdx;
if(args.at(startIdx)==' '){ // Ignore spaces until a different char is found
endIdx++;
continue;
}
else if(args.at(startIdx)!='"'){ // if first character is different from quote it ends with space
endIdx=args.indexOf(' ',startIdx+1);
}
else{ // If is a quote try to get the all the string until next quote
endIdx=args.indexOf('"',startIdx+1);
}
if(endIdx==-1) break;
endIdx++;
result << args.mid(startIdx,endIdx-startIdx).replace("\"","").trimmed(); // remove quotes
}
}
return result;
}
// TODO: Replace later with a more generic function and put in util library
// Supports wildcards, and directory with wildcard e.g.:
// *.xml
// C:/myXmls/*.xml
QStringList getAllFilesByWildcard(const QString &wildcard){
QString pathNormalized;
QStringList nameWildCard; // entryList requires a QStringList
QStringList resultFiles; // result files with absolute path
int endOfPathIdx;
QDir directory;
if(wildcard==""){
std::cout << "You need to specify a wildcard! Aborting..." << std::endl;
exit(1);
}
pathNormalized=Util::FileSystem::normalizePath(wildcard); // Convert slashes to work in both mac and windows
if(pathNormalized.contains("/")){ // If contains full path
endOfPathIdx=pathNormalized.lastIndexOf("/"); // get last slash
nameWildCard.append(pathNormalized.right(pathNormalized.size()-1-endOfPathIdx)); // get the names wildcard // -1 because starts with zeo
pathNormalized=pathNormalized.left(endOfPathIdx); // get the complete path
directory=QDir(pathNormalized);
}
else{ // if relative
nameWildCard << wildcard;
}
foreach (QFileInfo fileInfo, directory.entryInfoList(nameWildCard)){
resultFiles << fileInfo.absoluteFilePath();
}
return resultFiles;
}
}