Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
21 andreas 2
 * Copyright (C) 2020, 2021 by Andreas Theofilu <andreas@theosys.at>
2 andreas 3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
#include <errno.h>
19
#include <iostream>
20
#include <fstream>
21
#include <exception>
22
#include "tnameformat.h"
23
#include "treadxml.h"
24
 
25
using std::ifstream;
44 andreas 26
using std::ofstream;
2 andreas 27
using std::string;
28
using std::exception;
29
 
44 andreas 30
TReadXML::TReadXML(const std::string& fname, bool trim)
2 andreas 31
	: mFName(fname)
32
{
33
	DECL_TRACER("TReadXML::TReadXML(const std::string& fname)");
44 andreas 34
	openFile(trim);
2 andreas 35
}
36
 
37
TReadXML::~TReadXML()
38
{
39
	DECL_TRACER("TReadXML::~TReadXML()");
40
 
41
	if (mTree)
42
		mxmlDelete(mTree);
43
}
44
 
44 andreas 45
bool TReadXML::openFile(bool trim)
2 andreas 46
{
47
	DECL_TRACER("TReadXML::openFile()");
48
 
49
	TError::clear();
50
 
51
	if (mFName.empty())
52
	{
53
		TError::setErrorMsg("No XML file to read!");
54
		MSG_ERROR(TError::getErrorMsg());
55
		return false;
56
	}
57
 
78 andreas 58
	MSG_TRACE("Opening XML file " << mFName << " for reading ...");
59
 
2 andreas 60
	try
61
	{
44 andreas 62
		ifstream xml(mFName.c_str());
2 andreas 63
 
64
		if (!xml)
65
		{
66
			TError::setErrorMsg("Error opening the file " + mFName);
67
			MSG_ERROR(TError::getErrorMsg());
68
			return false;
69
		}
70
 
71
		string buffer;
72
 
73
		try
74
		{
75
			xml.seekg(0, xml.end);
76
			size_t length = xml.tellg();
77
			xml.seekg(0, xml.beg);
78
			buffer.resize(length, ' ');
79
			char *begin = &*buffer.begin();
80
			xml.read(begin, length);
81
		}
82
		catch (exception& e)
83
		{
84
			TError::setErrorMsg("Error reading a file: " + string(e.what()));
85
			MSG_ERROR(TError::getErrorMsg());
86
			xml.close();
87
			return false;
88
		}
89
 
90
		xml.close();
91
		string cbuf = TNameFormat::cp1250ToUTF8(buffer);
44 andreas 92
 
45 andreas 93
        // The used XML parser has a bug. If it is a formatted XML file, then
94
        // it crashes. Therefore the following call removes all formatting
95
        // characters to ensure the XML parser succeeds. To avoid this (maybe)
96
        // time consuming trimming, there is a parameter to control whether
97
        // the trimming should be made or not.
44 andreas 98
        if (trim)
99
            cbuf = TNameFormat::trimXML(cbuf);
100
 
2 andreas 101
		mTree = mxmlLoadString(NULL, cbuf.c_str(), MXML_OPAQUE_CALLBACK);
102
		buffer.clear();
103
 
104
		if (mTree == NULL)
105
		{
106
			TError::setErrorMsg("Error reading XML file " + mFName);
107
			MSG_ERROR(TError::getErrorMsg());
108
			return false;
109
		}
110
	}
111
	catch (exception& e)
112
	{
113
		TError::setErrorMsg("Fatal error: " + string(e.what()));
114
		MSG_ERROR(TError::getErrorMsg());
115
		return false;
116
	}
117
 
118
	return true;
119
}
120
 
121
std::string & TReadXML::findElement(const std::string& name)
122
{
123
	DECL_TRACER("TReadXML::findElement(const std::string& name)");
124
	const string none;
125
	return findElement(name, none);
126
}
127
 
128
std::string & TReadXML::findElement(const std::string& name, const std::string& attr)
129
{
130
	DECL_TRACER("TReadXML::findElement(const std::string& name, const std::string& attr)");
131
 
132
	TError::clear();
133
 
134
	if (!mTree)
135
	{
136
		TError::setErrorMsg("No valid XML available!");
137
		MSG_ERROR(TError::getErrorMsg());
138
		mValue.clear();
3 andreas 139
        mValid = false;
2 andreas 140
		return mValue;
141
	}
142
 
44 andreas 143
	try
2 andreas 144
	{
44 andreas 145
        if (!attr.empty())
146
            mNode = mxmlFindElement(mTree, mTree, name.c_str(), attr.c_str(), NULL, MXML_DESCEND);
147
        else
148
            mNode = mxmlFindElement(mTree, mTree, name.c_str(), NULL, NULL, MXML_DESCEND);
2 andreas 149
 
44 andreas 150
        if (!mNode)
151
        {
152
            if (attr.empty())
153
            {
154
                MSG_WARNING("Element " << name << " not found!");
155
            }
156
            else
157
            {
158
                MSG_WARNING("Element " << name << " with attribute " << attr << " not found!");
159
            }
2 andreas 160
 
44 andreas 161
            mValue.clear();
162
            mValid = false;
163
            return mValue;
164
        }
2 andreas 165
 
44 andreas 166
        mLastNode = mNode;
167
        extractValue(mNode);
2 andreas 168
 
44 andreas 169
        if (!attr.empty())
170
        {
171
            const char *attribute = mxmlElementGetAttr(mNode, attr.c_str());
3 andreas 172
 
44 andreas 173
            if (attribute)
174
                mAttribute.assign(attribute);
175
            else
176
                mAttribute.clear();
177
 
178
    //        MSG_DEBUG("Found attribute " << mAttribute);
179
        }
3 andreas 180
    }
44 andreas 181
    catch (exception& e)
182
    {
183
        TError::setErrorMsg("Fatal error: " + string(e.what()));
184
        MSG_ERROR(TError::getErrorMsg());
185
        mValid = false;
186
        mValue.clear();
187
        return mValue;
188
    }
3 andreas 189
 
190
    mValid = true;
191
    return mValue;
2 andreas 192
}
193
 
194
std::string & TReadXML::findElement(mxml_node_t* node, const std::string& name)
195
{
196
	DECL_TRACER("TReadXML::findElement(mxml_node_t* node, const std::string& name)");
197
	const string none;
198
	return findElement(node, name, none);
199
}
200
 
201
std::string & TReadXML::findElement(mxml_node_t* node, const std::string& name, const std::string& attr)
202
{
203
	DECL_TRACER("TReadXML::findElement(mxml_node_t* node, const std::string& name, const std::string& attr)");
204
 
205
	TError::clear();
206
 
207
	if (!mTree || !node)
208
	{
209
		TError::setErrorMsg("No valid XML available!");
210
		MSG_ERROR(TError::getErrorMsg());
211
		mValue.clear();
3 andreas 212
        mValid = false;
2 andreas 213
		return mValue;
214
	}
215
 
216
	if (!attr.empty())
217
		mNode = mxmlFindElement(node, mTree, name.c_str(), attr.c_str(), NULL, MXML_DESCEND);
218
	else
219
		mNode = mxmlFindElement(node, mTree, name.c_str(), NULL, NULL, MXML_DESCEND);
220
 
221
	if (!mNode)
222
	{
223
		if (attr.empty())
224
		{
225
			MSG_WARNING("Element " << name << " not found!");
226
		}
227
		else
228
		{
229
			MSG_WARNING("Element " << name << " with attribute " << attr << " not found!");
230
		}
231
 
232
		mValue.clear();
3 andreas 233
        mValid = false;
2 andreas 234
		return mValue;
235
	}
236
 
237
	mLastNode = mNode;
3 andreas 238
    extractValue(mNode);
239
 
240
    if (!attr.empty())
241
    {
242
        const char *attribute = mxmlElementGetAttr(mNode, attr.c_str());
243
 
244
        if (attribute)
245
            mAttribute.assign(attribute);
246
        else
247
            mAttribute.clear();
248
 
33 andreas 249
//        MSG_DEBUG("Found attribute " << mAttribute);
3 andreas 250
    }
251
 
252
    mValid = true;
253
    return mValue;
2 andreas 254
}
255
 
256
std::string & TReadXML::findNextElement(const std::string& name)
257
{
258
	DECL_TRACER("TReadXML::findNextElement(const std::string& name)");
259
	return findElement(mLastNode, name);
260
}
261
 
262
std::string & TReadXML::findNextElement(const std::string& name, const std::string& attr)
263
{
264
	DECL_TRACER("TReadXML::findNextElement(const std::string& name, const std::string& attr)");
265
	return findElement(mLastNode, name, attr);
266
}
3 andreas 267
 
268
std::string & TReadXML::getAttribute(const string& name)
269
{
270
    DECL_TRACER("TReadXML::getAttribute(const string& name)");
271
 
272
    const char *value = mxmlElementGetAttr(mNode, name.c_str());
273
 
274
    if (!value)
275
        mAttribute.clear();
276
    else
277
        mAttribute.assign(value);
278
 
33 andreas 279
//    MSG_DEBUG("Found attribute " << mAttribute << " from name " << name);
3 andreas 280
    return mAttribute;
281
}
282
 
283
std::string & TReadXML::getAttribute(const string& name, int index)
284
{
285
    DECL_TRACER("TReadXML::getAttribute(const string& name)");
286
 
287
    const char *pname = name.c_str();
288
    const char *value = mxmlElementGetAttrByIndex(mNode, index, &pname);
289
 
290
    if (!value)
291
        mAttribute.clear();
292
    else
293
        mAttribute.assign(value);
294
 
33 andreas 295
//    MSG_DEBUG("Found attribute " << mAttribute << " from name " << name << " at index " << index);
3 andreas 296
    return mAttribute;
297
}
298
 
299
mxml_node_t *TReadXML::getFirstChild()
300
{
301
    DECL_TRACER("*TReadXML::getFirstChild()");
302
 
303
    mxml_node_t *n = mxmlGetFirstChild(mLastNode);
304
 
305
    if (n)
306
    {
307
        inode = n;
308
        mElement = mxmlGetElement(n);
309
    }
310
 
33 andreas 311
//    if (inode)
312
//        MSG_DEBUG("Found element " << mElement);
3 andreas 313
 
314
    return n;
315
}
316
 
317
mxml_node_t *TReadXML::getNextChild()
318
{
319
    DECL_TRACER("*TReadXML::getNextChild()");
320
 
321
    if (!inode)
322
        return nullptr;
323
 
324
    mxml_node_t *n = mxmlGetNextSibling(inode);
325
 
326
    if (n)
327
    {
328
        inode = n;
329
        mElement = mxmlGetElement(n);
330
    }
331
 
33 andreas 332
//    if (inode)
333
//        MSG_DEBUG("Found element " << mElement);
3 andreas 334
 
335
    return n;
336
}
337
 
338
mxml_node_t *TReadXML::getLastChild()
339
{
340
    DECL_TRACER("*TReadXML::getLastChild()");
341
 
342
    mxml_node_t *n = mxmlGetLastChild(mLastNode);
343
 
344
    if (n)
345
    {
346
        inode = n;
347
        mElement = mxmlGetElement(n);
348
    }
349
 
33 andreas 350
//    if (inode)
351
//        MSG_DEBUG("Found element " << mElement);
3 andreas 352
 
353
    return n;
354
}
355
 
356
mxml_node_t *TReadXML::getFirstChild(mxml_node_t* node)
357
{
358
    DECL_TRACER("TReadXML::getFirstChild(mxml_node_t* node)");
359
 
360
    if (!node)
361
        return nullptr;
362
 
363
    mxml_node_t *n = mxmlGetFirstChild(node);
364
 
33 andreas 365
//    if (n)
366
//        MSG_DEBUG("Found element " << mxmlGetElement(n));
3 andreas 367
 
368
    return n;
369
}
370
 
371
mxml_node_t *TReadXML::getNextChild(mxml_node_t* node)
372
{
373
    DECL_TRACER("TReadXML::getNextChild(mxml_node_t* node)");
374
 
375
    if (!node)
376
        return nullptr;
377
 
378
    mxml_node_t *n = mxmlGetNextSibling(node);
379
 
33 andreas 380
//    if (n)
381
//        MSG_DEBUG("Found element " << mxmlGetElement(n));
3 andreas 382
 
383
    return n;
384
}
385
 
386
mxml_node_t *TReadXML::getLastChild(mxml_node_t* node)
387
{
388
    DECL_TRACER("TReadXML::getLastChild(mxml_node_t* node)");
389
 
390
    mxml_node_t *n = mxmlGetLastChild(node);
391
 
392
    if (!node)
393
        return nullptr;
394
 
33 andreas 395
//    if (n)
396
//        MSG_DEBUG("Found element " << mxmlGetElement(n));
3 andreas 397
 
398
    return n;
399
}
400
 
401
std::string& TReadXML::getTextFromNode(mxml_node_t* n)
402
{
403
    DECL_TRACER("TReadXML::getTextFromNode(mxml_node_t* n)");
404
 
405
    mValue.clear();
406
 
407
    if (!n)
408
        return mValue;
409
 
410
    extractValue(n);
33 andreas 411
//    MSG_DEBUG("Value = " << mValue << ", Element = " << mxmlGetElement(n));
3 andreas 412
    return mValue;
413
}
414
 
415
int TReadXML::getIntFromNode(mxml_node_t* n)
416
{
417
    DECL_TRACER("TReadXML::getIntFromNode(mxml_node_t* n)");
418
 
419
    if (!n)
420
        return 0;
421
 
422
    string val = getTextFromNode(n);
423
 
424
    if (val.empty())
425
        return 0;
426
 
427
    return atoi(val.c_str());
428
}
429
 
430
double TReadXML::getDoubleFromNode(mxml_node_t* n)
431
{
432
    DECL_TRACER("TReadXML::getDoubleFromNode(mxml_node_t* n)");
433
 
434
    if (!n)
435
        return 0.0;
436
 
437
    string val = getTextFromNode(n);
438
 
439
    if (val.empty())
440
        return 0.0;
441
 
442
    return atof(val.c_str());
443
}
444
 
445
std::string TReadXML::getAttributeFromNode(mxml_node_t* n, const std::string& attr)
446
{
447
    DECL_TRACER("TReadXML::getAttributeFromNode(mxml_node_t* n, const std::string& attr)");
448
 
449
    const char *a = mxmlElementGetAttr(n, attr.c_str());
450
 
451
    if (a)
452
        mAttribute = a;
453
    else
454
        mAttribute.clear();
455
 
456
    return mAttribute;
457
}
458
 
459
std::string& TReadXML::getElementName()
460
{
461
    DECL_TRACER("TReadXML::getElementName()");
462
 
463
    mElement.clear();
464
 
465
    if (!mLastNode)
466
        return mElement;
467
 
468
    const char *name = mxmlGetElement(mLastNode);
469
 
470
    if (name)
471
        mElement = name;
472
 
473
    return mElement;
474
}
475
 
476
std::string& TReadXML::getElementName(mxml_node_t* node)
477
{
478
    DECL_TRACER("TReadXML::getElementName(mxml_node_t* node)");
479
 
480
    mElement.clear();
481
 
482
    if (!node)
483
        return mElement;
484
 
485
    const char *name = mxmlGetElement(node);
486
 
487
    if (name)
488
        mElement = name;
489
 
490
    return mElement;
491
}
492
 
493
std::string TReadXML::_typeName(mxml_type_t t)
494
{
495
    string ret;
496
 
497
    switch (t)
498
    {
499
        case MXML_CUSTOM:   ret = "MXML_CUSTOM"; break;
500
        case MXML_ELEMENT:  ret = "MXML_ELEMENT"; break;
501
        case MXML_INTEGER:  ret = "MXML_INTEGER"; break;
502
        case MXML_OPAQUE:   ret = "MXML_OPAQUE"; break;
503
        case MXML_REAL:     ret = "MXML_REAL"; break;
504
        case MXML_TEXT:     ret = "MXML_TEXT"; break;
505
        case MXML_IGNORE:   ret = "MXML_IGNORE"; break;
506
    }
507
 
508
    return ret;
509
}
510
 
511
void TReadXML::extractValue(mxml_node_t *n)
512
{
513
    DECL_TRACER("TReadXML::extractValue(mxml_node_t *n)");
514
 
515
    const char *ename = nullptr, *txt = nullptr;
516
    int val = 0;
517
    double fval = 0.0;
518
    mxml_type_t t = mxmlGetType(n);
519
 
520
    if (!n)
521
        return;
522
 
523
    mValue.clear();
524
    ename = mxmlGetElement(n);
525
 
526
    if (ename)
527
        mElement = ename;
528
    else
529
        mElement.clear();
530
 
531
    switch(t)
532
    {
533
        case MXML_CUSTOM:   txt = (const char *)mxmlGetCustom(n); break;
534
        case MXML_ELEMENT:  txt = mxmlGetOpaque(n); break;
535
 
536
        case MXML_INTEGER:
537
            val = mxmlGetInteger(n);
538
            mValue = std::to_string(val);
539
            break;
540
 
541
        case MXML_OPAQUE:   txt = mxmlGetOpaque(n); break;
542
        case MXML_REAL:
543
            fval = mxmlGetReal(n);
544
            mValue = std::to_string(fval);
545
            break;
546
 
547
        case MXML_TEXT:     txt = mxmlGetText(n, 0); break;
548
 
549
        case MXML_IGNORE:   mValue.clear(); break;
550
    }
551
 
552
    if (txt)
553
        mValue = txt;
554
 
33 andreas 555
//    MSG_DEBUG("Element: " << mElement << ", type: " << _typeName(t) << ", content: " << mValue);
3 andreas 556
}