1
/***************************************************************************
2
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This program is free software; you can redistribute it and/or modify *
7
* it under the terms of the GNU Library General Public License (LGPL) *
8
* as published by the Free Software Foundation; either version 2 of *
9
* the License, or (at your option) any later version. *
10
* for detail see the LICENCE text file. *
12
* FreeCAD is distributed in the hope that it will be useful, *
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
* GNU Library General Public License for more details. *
17
* You should have received a copy of the GNU Library General Public *
18
* License along with FreeCAD; if not, write to the Free Software *
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
22
***************************************************************************/
25
#include "PreCompiled.h"
31
#include <xercesc/dom/DOM.hpp>
32
#include <xercesc/framework/LocalFileFormatTarget.hpp>
33
#include <xercesc/framework/LocalFileInputSource.hpp>
34
#include <xercesc/framework/MemBufFormatTarget.hpp>
35
#include <xercesc/framework/MemBufInputSource.hpp>
36
#include <xercesc/parsers/XercesDOMParser.hpp>
37
#include <xercesc/sax/ErrorHandler.hpp>
38
#include <xercesc/sax/SAXParseException.hpp>
52
#include <boost/algorithm/string.hpp>
53
#include <fmt/printf.h>
56
#include "Parameter.inl"
61
FC_LOG_LEVEL_INIT("Parameter", true, true)
63
#ifndef XERCES_CPP_NAMESPACE_BEGIN
64
#define XERCES_CPP_NAMESPACE_QUALIFIER
65
using namespace XERCES_CPP_NAMESPACE;
67
XERCES_CPP_NAMESPACE_USE
74
//**************************************************************************
75
//**************************************************************************
76
// private classes declaration:
77
// - DOMTreeErrorReporter
80
// - DOMPrintErrorHandler
82
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
84
class DOMTreeErrorReporter: public ErrorHandler
87
// -----------------------------------------------------------------------
88
// Implementation of the error handler interface
89
// -----------------------------------------------------------------------
90
void warning(const SAXParseException& toCatch) override;
91
void error(const SAXParseException& toCatch) override;
92
void fatalError(const SAXParseException& toCatch) override;
93
void resetErrors() override;
95
// -----------------------------------------------------------------------
97
// -----------------------------------------------------------------------
98
bool getSawErrors() const;
100
// -----------------------------------------------------------------------
101
// Private data members
104
// This is set if we get any errors, and is queryable via a getter
105
// method. Its used by the main code to suppress output if there are
107
// -----------------------------------------------------------------------
108
bool fSawErrors {false};
112
class DOMPrintFilter: public DOMLSSerializerFilter
115
/** @name Constructors */
116
explicit DOMPrintFilter(ShowType whatToShow = DOMNodeFilter::SHOW_ALL);
119
/** @name Destructors */
120
~DOMPrintFilter() override = default;
123
/** @ interface from DOMWriterFilter */
124
FilterAction acceptNode(const XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node) const override;
127
ShowType getWhatToShow() const override
132
// unimplemented copy ctor and assignment operator
133
DOMPrintFilter(const DOMPrintFilter&) = delete;
134
DOMPrintFilter(DOMPrintFilter&&) = delete;
135
DOMPrintFilter& operator=(const DOMPrintFilter&) = delete;
136
DOMPrintFilter& operator=(DOMPrintFilter&&) = delete;
138
ShowType fWhatToShow;
141
class DOMPrintErrorHandler: public DOMErrorHandler
144
DOMPrintErrorHandler() = default;
145
~DOMPrintErrorHandler() override = default;
147
/** @name The error handler interface */
148
bool handleError(const DOMError& domError) override;
152
/* Unimplemented constructors and operators */
153
DOMPrintErrorHandler(const DOMPrintErrorHandler&) = delete;
154
DOMPrintErrorHandler(DOMPrintErrorHandler&&) = delete;
155
void operator=(const DOMPrintErrorHandler&) = delete;
156
void operator=(DOMPrintErrorHandler&&) = delete;
160
inline bool DOMTreeErrorReporter::getSawErrors() const
166
//**************************************************************************
167
//**************************************************************************
169
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
172
//**************************************************************************
173
// Construction/Destruction
176
/** Default construction
178
ParameterGrp::ParameterGrp(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* GroupNode,
180
ParameterGrp* Parent)
181
: _pGroupNode(GroupNode)
188
_Manager = _Parent->_Manager;
194
* complete destruction of the object
196
ParameterGrp::~ParameterGrp()
198
for (auto& v : _GroupMap) {
199
v.second->_Parent = nullptr;
200
v.second->_Manager = nullptr;
202
if (_Detached && _pGroupNode) {
203
_pGroupNode->release();
207
//**************************************************************************
210
void ParameterGrp::copyTo(const Base::Reference<ParameterGrp>& Grp)
216
// delete previous content
223
void ParameterGrp::insertTo(const Base::Reference<ParameterGrp>& Grp)
230
std::vector<Base::Reference<ParameterGrp>> Grps = GetGroups();
231
std::vector<Base::Reference<ParameterGrp>>::iterator It1;
232
for (It1 = Grps.begin(); It1 != Grps.end(); ++It1) {
233
(*It1)->insertTo(Grp->GetGroup((*It1)->GetGroupName()));
237
std::vector<std::pair<std::string, std::string>> StringMap = GetASCIIMap();
238
std::vector<std::pair<std::string, std::string>>::iterator It2;
239
for (It2 = StringMap.begin(); It2 != StringMap.end(); ++It2) {
240
Grp->SetASCII(It2->first.c_str(), It2->second.c_str());
244
std::vector<std::pair<std::string, bool>> BoolMap = GetBoolMap();
245
std::vector<std::pair<std::string, bool>>::iterator It3;
246
for (It3 = BoolMap.begin(); It3 != BoolMap.end(); ++It3) {
247
Grp->SetBool(It3->first.c_str(), It3->second);
251
std::vector<std::pair<std::string, long>> IntMap = GetIntMap();
252
std::vector<std::pair<std::string, long>>::iterator It4;
253
for (It4 = IntMap.begin(); It4 != IntMap.end(); ++It4) {
254
Grp->SetInt(It4->first.c_str(), It4->second);
258
std::vector<std::pair<std::string, double>> FloatMap = GetFloatMap();
259
std::vector<std::pair<std::string, double>>::iterator It5;
260
for (It5 = FloatMap.begin(); It5 != FloatMap.end(); ++It5) {
261
Grp->SetFloat(It5->first.c_str(), It5->second);
265
std::vector<std::pair<std::string, unsigned long>> UIntMap = GetUnsignedMap();
266
std::vector<std::pair<std::string, unsigned long>>::iterator It6;
267
for (It6 = UIntMap.begin(); It6 != UIntMap.end(); ++It6) {
268
Grp->SetUnsigned(It6->first.c_str(), It6->second);
272
void ParameterGrp::exportTo(const char* FileName)
274
auto Mngr = ParameterManager::Create();
276
Mngr->CreateDocument();
278
// copy all into the new document
279
insertTo(Base::Reference<ParameterGrp>(Mngr));
281
Mngr->SaveDocument(FileName);
284
void ParameterGrp::importFrom(const char* FileName)
286
auto Mngr = ParameterManager::Create();
288
if (Mngr->LoadDocument(FileName) != 1) {
289
throw FileException("ParameterGrp::import() cannot load document", FileName);
292
Mngr->copyTo(Base::Reference<ParameterGrp>(this));
295
void ParameterGrp::insert(const char* FileName)
297
auto Mngr = ParameterManager::Create();
299
if (Mngr->LoadDocument(FileName) != 1) {
300
throw FileException("ParameterGrp::import() cannot load document", FileName);
303
Mngr->insertTo(Base::Reference<ParameterGrp>(this));
306
void ParameterGrp::revert(const char* FileName)
308
auto Mngr = ParameterManager::Create();
310
if (Mngr->LoadDocument(FileName) != 1) {
311
throw FileException("ParameterGrp::revert() cannot load document", FileName);
314
revert(Base::Reference<ParameterGrp>(Mngr));
317
void ParameterGrp::revert(const Base::Reference<ParameterGrp>& Grp)
323
for (auto& grp : Grp->GetGroups()) {
324
if (HasGroup(grp->GetGroupName())) {
325
GetGroup(grp->GetGroupName())->revert(grp);
329
for (const auto& v : Grp->GetASCIIMap()) {
330
if (GetASCII(v.first.c_str(), v.second.c_str()) == v.second) {
331
RemoveASCII(v.first.c_str());
335
for (const auto& v : Grp->GetBoolMap()) {
336
if (GetBool(v.first.c_str(), v.second) == v.second) {
337
RemoveBool(v.first.c_str());
341
for (const auto& v : Grp->GetIntMap()) {
342
if (GetInt(v.first.c_str(), v.second) == v.second) {
343
RemoveInt(v.first.c_str());
347
for (const auto& v : Grp->GetUnsignedMap()) {
348
if (GetUnsigned(v.first.c_str(), v.second) == v.second) {
349
RemoveUnsigned(v.first.c_str());
353
for (const auto& v : Grp->GetFloatMap()) {
354
if (GetFloat(v.first.c_str(), v.second) == v.second) {
355
RemoveFloat(v.first.c_str());
360
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement*
361
ParameterGrp::CreateElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* Start,
365
if (XMLString::compareString(Start->getNodeName(), XStr("FCParamGroup").unicodeForm()) != 0
366
&& XMLString::compareString(Start->getNodeName(), XStr("FCParameters").unicodeForm())
368
Base::Console().Warning("CreateElement: %s cannot have the element %s of type %s\n",
369
StrX(Start->getNodeName()).c_str(),
375
if (_Detached && _Parent) {
376
// re-attach the group
377
_Parent->_GetGroup(_cName.c_str());
380
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* pDocument = Start->getOwnerDocument();
382
auto pcElem = pDocument->createElement(XStr(Type).unicodeForm());
383
pcElem->setAttribute(XStr("Name").unicodeForm(), XStr(Name).unicodeForm());
384
Start->appendChild(pcElem);
389
Base::Reference<ParameterGrp> ParameterGrp::GetGroup(const char* Name)
392
throw Base::ValueError("Empty group name");
395
Base::Reference<ParameterGrp> hGrp = this;
396
std::vector<std::string> tokens;
397
boost::split(tokens, Name, boost::is_any_of("/"));
398
for (auto& token : tokens) {
403
hGrp = hGrp->_GetGroup(token.c_str());
405
// The group is clearing. Return some dummy group to avoid caller
406
// crashing for backward compatibility.
407
hGrp = new ParameterGrp();
413
throw Base::ValueError("Empty group name");
418
Base::Reference<ParameterGrp> ParameterGrp::_GetGroup(const char* Name)
420
Base::Reference<ParameterGrp> rParamGrp;
422
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
423
FC_WARN("Adding group " << Name << " in an orphan group " << _cName);
428
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
429
FC_WARN("Adding group " << Name << " while clearing " << GetPath());
434
DOMElement* pcTemp {};
436
// search if Group node already there
437
pcTemp = FindElement(_pGroupNode, "FCParamGroup", Name);
440
if (!(rParamGrp = _GroupMap[Name]).isValid()) {
442
pcTemp = CreateElement(_pGroupNode, "FCParamGroup", Name);
444
// create and register handle
445
rParamGrp = Base::Reference<ParameterGrp>(new ParameterGrp(pcTemp, Name, this));
446
_GroupMap[Name] = rParamGrp;
449
_pGroupNode->appendChild(rParamGrp->_pGroupNode);
450
rParamGrp->_Detached = false;
451
if (this->_Detached && this->_Parent) {
452
// Re-attach the group. Note that this may fail if the parent is
453
// clearing. That's why we check this->_Detached below.
454
this->_Parent->_GetGroup(_cName.c_str());
458
if (!pcTemp && !this->_Detached) {
459
_Notify(ParamType::FCGroup, Name, Name);
465
std::string ParameterGrp::GetPath() const
468
if (_Parent && _Parent != _Manager) {
469
path = _Parent->GetPath();
471
if (!path.empty() && !_cName.empty()) {
478
std::vector<Base::Reference<ParameterGrp>> ParameterGrp::GetGroups()
480
Base::Reference<ParameterGrp> rParamGrp;
481
std::vector<Base::Reference<ParameterGrp>> vrParamGrp;
489
DOMElement* pcTemp = FindElement(_pGroupNode, "FCParamGroup");
492
StrX(pcTemp->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue())
495
if (!(rParamGrp = _GroupMap[Name]).isValid()) {
496
rParamGrp = Base::Reference<ParameterGrp>(new ParameterGrp(pcTemp, Name.c_str(), this));
497
_GroupMap[Name] = rParamGrp;
499
vrParamGrp.push_back(rParamGrp);
501
pcTemp = FindNextElement(pcTemp, "FCParamGroup");
507
/// test if this group is empty
508
bool ParameterGrp::IsEmpty() const
510
return !(_pGroupNode && _pGroupNode->getFirstChild());
513
/// test if a special sub group is in this group
514
bool ParameterGrp::HasGroup(const char* Name) const
516
if (_GroupMap.find(Name) != _GroupMap.end()) {
520
if (_pGroupNode && FindElement(_pGroupNode, "FCParamGroup", Name) != nullptr) {
527
const char* ParameterGrp::TypeName(ParamType Type)
530
case ParamType::FCBool:
532
case ParamType::FCInt:
534
case ParamType::FCUInt:
536
case ParamType::FCText:
538
case ParamType::FCFloat:
540
case ParamType::FCGroup:
541
return "FCParamGroup";
547
ParameterGrp::ParamType ParameterGrp::TypeValue(const char* Name)
550
if (boost::equals(Name, "FCBool")) {
551
return ParamType::FCBool;
553
if (boost::equals(Name, "FCInt")) {
554
return ParamType::FCInt;
556
if (boost::equals(Name, "FCUInt")) {
557
return ParamType::FCUInt;
559
if (boost::equals(Name, "FCText")) {
560
return ParamType::FCText;
562
if (boost::equals(Name, "FCFloat")) {
563
return ParamType::FCFloat;
565
if (boost::equals(Name, "FCParamGroup")) {
566
return ParamType::FCGroup;
569
return ParamType::FCInvalid;
572
void ParameterGrp::SetAttribute(ParamType Type, const char* Name, const char* Value)
575
case ParamType::FCBool:
576
case ParamType::FCInt:
577
case ParamType::FCUInt:
578
case ParamType::FCFloat:
579
return _SetAttribute(Type, Name, Value);
580
case ParamType::FCText:
581
return SetASCII(Name, Value);
582
case ParamType::FCGroup:
583
RenameGrp(Name, Value);
590
void ParameterGrp::RemoveAttribute(ParamType Type, const char* Name)
593
case ParamType::FCBool:
594
return RemoveBool(Name);
595
case ParamType::FCInt:
596
return RemoveInt(Name);
597
case ParamType::FCUInt:
598
return RemoveUnsigned(Name);
599
case ParamType::FCText:
600
return RemoveASCII(Name);
601
case ParamType::FCFloat:
602
return RemoveFloat(Name);
603
case ParamType::FCGroup:
604
return RemoveGrp(Name);
610
const char* ParameterGrp::GetAttribute(ParamType Type,
613
const char* Default) const
619
const char* T = TypeName(Type);
624
DOMElement* pcElem = FindElement(_pGroupNode, T, Name);
629
if (Type == ParamType::FCText) {
630
Value = GetASCII(Name, Default);
632
else if (Type != ParamType::FCGroup) {
633
Value = StrX(pcElem->getAttribute(XStr("Value").unicodeForm())).c_str();
635
return Value.c_str();
638
std::vector<std::pair<std::string, std::string>>
639
ParameterGrp::GetAttributeMap(ParamType Type, const char* sFilter) const
641
std::vector<std::pair<std::string, std::string>> res;
646
const char* T = TypeName(Type);
653
DOMElement* pcTemp = FindElement(_pGroupNode, T);
655
Name = StrX(static_cast<DOMElement*>(pcTemp)
657
->getNamedItem(XStr("Name").unicodeForm())
660
// check on filter condition
661
if (!sFilter || Name.find(sFilter) != std::string::npos) {
662
if (Type == ParamType::FCGroup) {
663
res.emplace_back(Name, std::string());
666
res.emplace_back(Name,
667
StrX(static_cast<DOMElement*>(pcTemp)->getAttribute(
668
XStr("Value").unicodeForm()))
672
pcTemp = FindNextElement(pcTemp, T);
677
void ParameterGrp::_Notify(ParamType Type, const char* Name, const char* Value)
680
_Manager->signalParamChanged(this, Type, Name, Value);
684
void ParameterGrp::_SetAttribute(ParamType T, const char* Name, const char* Value)
686
const char* Type = TypeName(T);
691
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
692
FC_WARN("Setting attribute " << Type << ":" << Name << " in an orphan group "
698
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
699
FC_WARN("Adding attribute " << Type << ":" << Name << " while clearing " << GetPath());
704
// find or create the Element
705
DOMElement* pcElem = FindOrCreateElement(_pGroupNode, Type, Name);
708
// set the value only if different
709
if (strcmp(StrX(pcElem->getAttribute(attr.unicodeForm())).c_str(), Value) != 0) {
710
pcElem->setAttribute(attr.unicodeForm(), XStr(Value).unicodeForm());
712
_Notify(T, Name, Value);
714
// For backward compatibility, old observer gets notified regardless of
715
// value changes or not.
720
bool ParameterGrp::GetBool(const char* Name, bool bPreset) const
726
// check if Element in group
727
DOMElement* pcElem = FindElement(_pGroupNode, "FCBool", Name);
728
// if not return preset
733
// if yes check the value and return
734
return (strcmp(StrX(pcElem->getAttribute(XStr("Value").unicodeForm())).c_str(), "1") == 0);
737
void ParameterGrp::SetBool(const char* Name, bool bValue)
739
_SetAttribute(ParamType::FCBool, Name, bValue ? "1" : "0");
742
std::vector<bool> ParameterGrp::GetBools(const char* sFilter) const
744
std::vector<bool> vrValues;
751
DOMElement* pcTemp = FindElement(_pGroupNode, "FCBool");
753
Name = StrX(pcTemp->getAttribute(XStr("Name").unicodeForm())).c_str();
754
// check on filter condition
755
if (!sFilter || Name.find(sFilter) != std::string::npos) {
756
if (strcmp(StrX(pcTemp->getAttribute(XStr("Value").unicodeForm())).c_str(), "1") != 0) {
757
vrValues.push_back(false);
760
vrValues.push_back(true);
763
pcTemp = FindNextElement(pcTemp, "FCBool");
769
std::vector<std::pair<std::string, bool>> ParameterGrp::GetBoolMap(const char* sFilter) const
771
std::vector<std::pair<std::string, bool>> vrValues;
778
DOMElement* pcTemp = FindElement(_pGroupNode, "FCBool");
780
Name = StrX(pcTemp->getAttribute(XStr("Name").unicodeForm())).c_str();
781
// check on filter condition
782
if (!sFilter || Name.find(sFilter) != std::string::npos) {
783
if (strcmp(StrX(pcTemp->getAttribute(XStr("Value").unicodeForm())).c_str(), "1") != 0) {
784
vrValues.emplace_back(Name, false);
787
vrValues.emplace_back(Name, true);
790
pcTemp = FindNextElement(pcTemp, "FCBool");
796
long ParameterGrp::GetInt(const char* Name, long lPreset) const
802
// check if Element in group
803
DOMElement* pcElem = FindElement(_pGroupNode, "FCInt", Name);
804
// if not return preset
808
// if yes check the value and return
809
return atol(StrX(pcElem->getAttribute(XStr("Value").unicodeForm())).c_str());
812
void ParameterGrp::SetInt(const char* Name, long lValue)
814
std::string buf = fmt::sprintf("%li", lValue);
815
_SetAttribute(ParamType::FCInt, Name, buf.c_str());
818
std::vector<long> ParameterGrp::GetInts(const char* sFilter) const
820
std::vector<long> vrValues;
827
DOMElement* pcTemp = FindElement(_pGroupNode, "FCInt");
829
Name = StrX(pcTemp->getAttribute(XStr("Name").unicodeForm())).c_str();
830
// check on filter condition
831
if (!sFilter || Name.find(sFilter) != std::string::npos) {
833
atol(StrX(pcTemp->getAttribute(XStr("Value").unicodeForm())).c_str()));
835
pcTemp = FindNextElement(pcTemp, "FCInt");
841
std::vector<std::pair<std::string, long>> ParameterGrp::GetIntMap(const char* sFilter) const
843
std::vector<std::pair<std::string, long>> vrValues;
850
DOMElement* pcTemp = FindElement(_pGroupNode, "FCInt");
852
Name = StrX(pcTemp->getAttribute(XStr("Name").unicodeForm())).c_str();
853
// check on filter condition
854
if (!sFilter || Name.find(sFilter) != std::string::npos) {
855
vrValues.emplace_back(
857
(atol(StrX(pcTemp->getAttribute(XStr("Value").unicodeForm())).c_str())));
859
pcTemp = FindNextElement(pcTemp, "FCInt");
865
unsigned long ParameterGrp::GetUnsigned(const char* Name, unsigned long lPreset) const
871
// check if Element in group
872
DOMElement* pcElem = FindElement(_pGroupNode, "FCUInt", Name);
873
// if not return preset
878
// if yes check the value and return
880
return strtoul(StrX(pcElem->getAttribute(XStr("Value").unicodeForm())).c_str(), nullptr, base);
883
void ParameterGrp::SetUnsigned(const char* Name, unsigned long lValue)
885
std::string buf = fmt::sprintf("%lu", lValue);
886
_SetAttribute(ParamType::FCUInt, Name, buf.c_str());
889
std::vector<unsigned long> ParameterGrp::GetUnsigneds(const char* sFilter) const
891
std::vector<unsigned long> vrValues;
899
DOMElement* pcTemp = FindElement(_pGroupNode, "FCUInt");
901
Name = StrX(pcTemp->getAttribute(XStr("Name").unicodeForm())).c_str();
902
// check on filter condition
903
if (!sFilter || Name.find(sFilter) != std::string::npos) {
905
strtoul(StrX(pcTemp->getAttribute(XStr("Value").unicodeForm())).c_str(),
909
pcTemp = FindNextElement(pcTemp, "FCUInt");
915
std::vector<std::pair<std::string, unsigned long>>
916
ParameterGrp::GetUnsignedMap(const char* sFilter) const
918
std::vector<std::pair<std::string, unsigned long>> vrValues;
926
DOMElement* pcTemp = FindElement(_pGroupNode, "FCUInt");
928
Name = StrX(pcTemp->getAttribute(XStr("Name").unicodeForm())).c_str();
929
// check on filter condition
930
if (!sFilter || Name.find(sFilter) != std::string::npos) {
931
vrValues.emplace_back(
933
(strtoul(StrX(pcTemp->getAttribute(XStr("Value").unicodeForm())).c_str(),
937
pcTemp = FindNextElement(pcTemp, "FCUInt");
943
double ParameterGrp::GetFloat(const char* Name, double dPreset) const
949
// check if Element in group
950
DOMElement* pcElem = FindElement(_pGroupNode, "FCFloat", Name);
951
// if not return preset
955
// if yes check the value and return
956
return atof(StrX(pcElem->getAttribute(XStr("Value").unicodeForm())).c_str());
959
void ParameterGrp::SetFloat(const char* Name, double dValue)
961
// use %.12f instead of %f to handle values < 1.0e-6
962
std::string buf = fmt::sprintf("%.12f", dValue);
963
_SetAttribute(ParamType::FCFloat, Name, buf.c_str());
966
std::vector<double> ParameterGrp::GetFloats(const char* sFilter) const
968
std::vector<double> vrValues;
975
DOMElement* pcTemp = FindElement(_pGroupNode, "FCFloat");
977
Name = StrX(pcTemp->getAttribute(XStr("Name").unicodeForm())).c_str();
978
// check on filter condition
979
if (!sFilter || Name.find(sFilter) != std::string::npos) {
981
atof(StrX(pcTemp->getAttribute(XStr("Value").unicodeForm())).c_str()));
983
pcTemp = FindNextElement(pcTemp, "FCFloat");
989
std::vector<std::pair<std::string, double>> ParameterGrp::GetFloatMap(const char* sFilter) const
991
std::vector<std::pair<std::string, double>> vrValues;
998
DOMElement* pcTemp = FindElement(_pGroupNode, "FCFloat");
1000
Name = StrX(pcTemp->getAttribute(XStr("Name").unicodeForm())).c_str();
1001
// check on filter condition
1002
if (!sFilter || Name.find(sFilter) != std::string::npos) {
1003
vrValues.emplace_back(
1005
(atof(StrX(pcTemp->getAttribute(XStr("Value").unicodeForm())).c_str())));
1007
pcTemp = FindNextElement(pcTemp, "FCFloat");
1014
void ParameterGrp::SetASCII(const char* Name, const char* sValue)
1017
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
1018
FC_WARN("Setting attribute " << "FCText:" << Name << " in an orphan group " << _cName);
1023
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
1024
FC_WARN("Adding attribute " << "FCText:" << Name << " while clearing " << GetPath());
1030
DOMElement* pcElem = FindElement(_pGroupNode, "FCText", Name);
1032
pcElem = CreateElement(_pGroupNode, "FCText", Name);
1036
// and set the value
1037
DOMNode* pcElem2 = pcElem->getFirstChild();
1039
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* pDocument = _pGroupNode->getOwnerDocument();
1040
DOMText* pText = pDocument->createTextNode(XUTF8Str(sValue).unicodeForm());
1041
pcElem->appendChild(pText);
1042
if (isNew || sValue[0] != 0) {
1043
_Notify(ParamType::FCText, Name, sValue);
1046
else if (strcmp(StrXUTF8(pcElem2->getNodeValue()).c_str(), sValue) != 0) {
1047
pcElem2->setNodeValue(XUTF8Str(sValue).unicodeForm());
1048
_Notify(ParamType::FCText, Name, sValue);
1055
std::string ParameterGrp::GetASCII(const char* Name, const char* pPreset) const
1058
return pPreset ? pPreset : "";
1061
// check if Element in group
1062
DOMElement* pcElem = FindElement(_pGroupNode, "FCText", Name);
1063
// if not return preset
1070
// if yes check the value and return
1071
DOMNode* pcElem2 = pcElem->getFirstChild();
1073
return {StrXUTF8(pcElem2->getNodeValue()).c_str()};
1078
std::vector<std::string> ParameterGrp::GetASCIIs(const char* sFilter) const
1080
std::vector<std::string> vrValues;
1087
DOMElement* pcTemp = FindElement(_pGroupNode, "FCText");
1089
Name = StrXUTF8(pcTemp->getAttribute(XStr("Name").unicodeForm())).c_str();
1090
// check on filter condition
1091
if (!sFilter || Name.find(sFilter) != std::string::npos) {
1092
// retrieve the text element
1093
DOMNode* pcElem2 = pcTemp->getFirstChild();
1095
vrValues.emplace_back(StrXUTF8(pcElem2->getNodeValue()).c_str());
1098
vrValues.emplace_back(""); // For a string, an empty value is possible and allowed
1101
pcTemp = FindNextElement(pcTemp, "FCText");
1107
std::vector<std::pair<std::string, std::string>>
1108
ParameterGrp::GetASCIIMap(const char* sFilter) const
1110
std::vector<std::pair<std::string, std::string>> vrValues;
1117
DOMElement* pcTemp = FindElement(_pGroupNode, "FCText");
1119
Name = StrXUTF8(pcTemp->getAttribute(XStr("Name").unicodeForm())).c_str();
1120
// check on filter condition
1121
if (!sFilter || Name.find(sFilter) != std::string::npos) {
1122
// retrieve the text element
1123
DOMNode* pcElem2 = pcTemp->getFirstChild();
1125
vrValues.emplace_back(Name, std::string(StrXUTF8(pcElem2->getNodeValue()).c_str()));
1128
vrValues.emplace_back(
1130
std::string()); // For a string, an empty value is possible and allowed
1133
pcTemp = FindNextElement(pcTemp, "FCText");
1139
//**************************************************************************
1142
void ParameterGrp::RemoveASCII(const char* Name)
1148
// check if Element in group
1149
DOMElement* pcElem = FindElement(_pGroupNode, "FCText", Name);
1155
DOMNode* node = _pGroupNode->removeChild(pcElem);
1159
_Notify(ParamType::FCText, Name, nullptr);
1163
void ParameterGrp::RemoveBool(const char* Name)
1169
// check if Element in group
1170
DOMElement* pcElem = FindElement(_pGroupNode, "FCBool", Name);
1176
DOMNode* node = _pGroupNode->removeChild(pcElem);
1180
_Notify(ParamType::FCBool, Name, nullptr);
1185
void ParameterGrp::RemoveFloat(const char* Name)
1191
// check if Element in group
1192
DOMElement* pcElem = FindElement(_pGroupNode, "FCFloat", Name);
1198
DOMNode* node = _pGroupNode->removeChild(pcElem);
1202
_Notify(ParamType::FCFloat, Name, nullptr);
1206
void ParameterGrp::RemoveInt(const char* Name)
1212
// check if Element in group
1213
DOMElement* pcElem = FindElement(_pGroupNode, "FCInt", Name);
1219
DOMNode* node = _pGroupNode->removeChild(pcElem);
1223
_Notify(ParamType::FCInt, Name, nullptr);
1227
void ParameterGrp::RemoveUnsigned(const char* Name)
1233
// check if Element in group
1234
DOMElement* pcElem = FindElement(_pGroupNode, "FCUInt", Name);
1240
DOMNode* node = _pGroupNode->removeChild(pcElem);
1244
_Notify(ParamType::FCUInt, Name, nullptr);
1248
void ParameterGrp::RemoveGrp(const char* Name)
1254
auto it = _GroupMap.find(Name);
1255
if (it == _GroupMap.end()) {
1259
// If this or any of its children is referenced by an observer we do not
1260
// delete the handle, just in case the group is later added again, or else
1261
// those existing observer won't get any notification. BUT, we DO delete
1262
// the underlying xml elements, so that we don't save the empty group
1264
it->second->Clear(false);
1265
if (!it->second->_Detached) {
1266
it->second->_Detached = true;
1267
_pGroupNode->removeChild(it->second->_pGroupNode);
1269
if (it->second->ShouldRemove()) {
1270
it->second->_Parent = nullptr;
1271
it->second->_Manager = nullptr;
1272
_GroupMap.erase(it);
1279
bool ParameterGrp::RenameGrp(const char* OldName, const char* NewName)
1285
auto it = _GroupMap.find(OldName);
1286
if (it == _GroupMap.end()) {
1289
auto jt = _GroupMap.find(NewName);
1290
if (jt != _GroupMap.end()) {
1294
// rename group handle
1295
_GroupMap[NewName] = _GroupMap[OldName];
1296
_GroupMap.erase(OldName);
1297
_GroupMap[NewName]->_cName = NewName;
1299
// check if Element in group
1300
DOMElement* pcElem = FindElement(_pGroupNode, "FCParamGroup", OldName);
1302
pcElem->setAttribute(XStr("Name").unicodeForm(), XStr(NewName).unicodeForm());
1305
_Notify(ParamType::FCGroup, NewName, OldName);
1309
void ParameterGrp::Clear(bool notify)
1315
Base::StateLocker guard(_Clearing);
1317
// early trigger notification of group removal when all its children
1318
// hierarchies are intact.
1319
_Notify(ParamType::FCGroup, nullptr, nullptr);
1321
// checking on references
1322
for (auto it = _GroupMap.begin(); it != _GroupMap.end();) {
1323
// If a group handle is referenced by some observer, then do not remove
1324
// it but clear it, so that any existing observer can still get
1325
// notification if the group is later on add back. We do remove the
1326
// underlying xml element from its parent so that we won't save this
1328
it->second->Clear(notify);
1329
if (!it->second->_Detached) {
1330
it->second->_Detached = true;
1331
_pGroupNode->removeChild(it->second->_pGroupNode);
1333
if (!it->second->ShouldRemove()) {
1337
it->second->_Parent = nullptr;
1338
it->second->_Manager = nullptr;
1339
it = _GroupMap.erase(it);
1343
// Remove the rest of non-group nodes;
1344
std::vector<std::pair<ParamType, std::string>> params;
1345
for (DOMNode *child = _pGroupNode->getFirstChild(), *next = child; child != nullptr;
1347
next = next->getNextSibling();
1348
ParamType type = TypeValue(StrX(child->getNodeName()).c_str());
1349
if (type != ParamType::FCInvalid && type != ParamType::FCGroup) {
1350
params.emplace_back(type,
1351
StrX(child->getAttributes()
1352
->getNamedItem(XStr("Name").unicodeForm())
1356
DOMNode* node = _pGroupNode->removeChild(child);
1360
for (auto& v : params) {
1361
_Notify(v.first, v.second.c_str(), nullptr);
1363
Notify(v.second.c_str());
1371
//**************************************************************************
1374
bool ParameterGrp::ShouldRemove() const
1376
if (this->getRefCount() > 1) {
1380
return std::all_of(_GroupMap.cbegin(), _GroupMap.cend(), [](const auto& it) {
1381
return it.second->ShouldRemove();
1385
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement*
1386
ParameterGrp::FindElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* Start,
1388
const char* Name) const
1390
if (XMLString::compareString(Start->getNodeName(), XStr("FCParamGroup").unicodeForm()) != 0
1391
&& XMLString::compareString(Start->getNodeName(), XStr("FCParameters").unicodeForm())
1393
Base::Console().Warning("FindElement: %s cannot have the element %s of type %s\n",
1394
StrX(Start->getNodeName()).c_str(),
1399
for (DOMNode* clChild = Start->getFirstChild(); clChild != nullptr;
1400
clChild = clChild->getNextSibling()) {
1401
if (clChild->getNodeType() == DOMNode::ELEMENT_NODE) {
1402
// the right node Type
1403
if (!strcmp(Type, StrX(clChild->getNodeName()).c_str())) {
1404
if (clChild->getAttributes()->getLength() > 0) {
1406
DOMNode* attr = FindAttribute(clChild, "Name");
1407
if (attr && !strcmp(Name, StrX(attr->getNodeValue()).c_str())) {
1408
return dynamic_cast<DOMElement*>(clChild);
1412
return dynamic_cast<DOMElement*>(clChild);
1421
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement*
1422
ParameterGrp::FindNextElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* Prev, const char* Type) const
1424
DOMNode* clChild = Prev;
1429
while ((clChild = clChild->getNextSibling()) != nullptr) {
1430
if (clChild->getNodeType() == DOMNode::ELEMENT_NODE) {
1431
// the right node Type
1432
if (!strcmp(Type, StrX(clChild->getNodeName()).c_str())) {
1433
return dynamic_cast<DOMElement*>(clChild);
1440
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement*
1441
ParameterGrp::FindOrCreateElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* Start,
1445
// first try to find it
1446
DOMElement* pcElem = FindElement(Start, Type, Name);
1451
return CreateElement(Start, Type, Name);
1454
XERCES_CPP_NAMESPACE_QUALIFIER DOMNode*
1455
ParameterGrp::FindAttribute(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* Node, const char* Name) const
1457
DOMNamedNodeMap* attr = Node->getAttributes();
1459
return attr->getNamedItem(XStr(Name).unicodeForm());
1464
std::vector<std::pair<ParameterGrp::ParamType, std::string>>
1465
ParameterGrp::GetParameterNames(const char* sFilter) const
1467
std::vector<std::pair<ParameterGrp::ParamType, std::string>> res;
1474
for (DOMNode* clChild = _pGroupNode->getFirstChild(); clChild != nullptr;
1475
clChild = clChild->getNextSibling()) {
1476
if (clChild->getNodeType() == DOMNode::ELEMENT_NODE) {
1477
StrX type(clChild->getNodeName());
1478
ParamType Type = TypeValue(type.c_str());
1479
if (Type != ParamType::FCInvalid && Type != ParamType::FCGroup) {
1480
if (clChild->getAttributes()->getLength() > 0) {
1481
StrX name(clChild->getAttributes()
1482
->getNamedItem(XStr("Name").unicodeForm())
1484
if (!sFilter || strstr(name.c_str(), sFilter)) {
1485
res.emplace_back(Type, name.c_str());
1494
void ParameterGrp::NotifyAll()
1496
// get all ints and notify
1497
std::vector<std::pair<std::string, long>> IntMap = GetIntMap();
1498
for (const auto& it : IntMap) {
1499
Notify(it.first.c_str());
1502
// get all booleans and notify
1503
std::vector<std::pair<std::string, bool>> BoolMap = GetBoolMap();
1504
for (const auto& it : BoolMap) {
1505
Notify(it.first.c_str());
1508
// get all Floats and notify
1509
std::vector<std::pair<std::string, double>> FloatMap = GetFloatMap();
1510
for (const auto& it : FloatMap) {
1511
Notify(it.first.c_str());
1514
// get all strings and notify
1515
std::vector<std::pair<std::string, std::string>> StringMap = GetASCIIMap();
1516
for (const auto& it : StringMap) {
1517
Notify(it.first.c_str());
1520
// get all uints and notify
1521
std::vector<std::pair<std::string, unsigned long>> UIntMap = GetUnsignedMap();
1522
for (const auto& it : UIntMap) {
1523
Notify(it.first.c_str());
1527
void ParameterGrp::_Reset()
1529
_pGroupNode = nullptr;
1530
for (auto& v : _GroupMap) {
1535
//**************************************************************************
1536
//**************************************************************************
1537
// ParameterSerializer
1538
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1539
ParameterSerializer::ParameterSerializer(std::string fn)
1540
: filename(std::move(fn))
1543
ParameterSerializer::~ParameterSerializer() = default;
1545
void ParameterSerializer::SaveDocument(const ParameterManager& mgr)
1547
mgr.SaveDocument(filename.c_str());
1550
int ParameterSerializer::LoadDocument(ParameterManager& mgr)
1552
return mgr.LoadDocument(filename.c_str());
1555
bool ParameterSerializer::LoadOrCreateDocument(ParameterManager& mgr)
1557
return mgr.LoadOrCreateDocument(filename.c_str());
1560
//**************************************************************************
1561
//**************************************************************************
1563
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1565
static XercesDOMParser::ValSchemes gValScheme = XercesDOMParser::Val_Auto; // NOLINT
1567
//**************************************************************************
1568
// Construction/Destruction
1570
/** Default construction
1572
ParameterManager::ParameterManager()
1576
// initialize the XML system
1579
// ---------------------------------------------------------------------------
1583
// The path to the file to parser. Set via command line.
1586
// Indicates whether namespace processing should be done.
1589
// Indicates whether schema processing should be done.
1591
// gSchemaFullChecking
1592
// Indicates whether full schema constraint checking should be done.
1595
// Indicates whether entity reference nodes needs to be created or not.
1596
// Defaults to false.
1599
// The encoding we are to output in. If not set on the command line,
1600
// then it is defaults to the encoding of the input XML file.
1603
// The end of line sequence we are to output.
1605
// gSplitCdataSections
1606
// Indicates whether split-cdata-sections is to be enabled or not.
1608
// gDiscardDefaultContent
1609
// Indicates whether default content is discarded or not.
1612
// Indicates if user wants to plug in the DOMPrintFilter.
1615
// Indicates what validation scheme to use. It defaults to 'auto', but
1616
// can be set via the -v= command.
1618
// ---------------------------------------------------------------------------
1621
gIgnoreSave = false;
1622
gDoNamespaces = false;
1624
gSchemaFullChecking = false;
1627
gOutputEncoding = nullptr;
1628
gMyEOLSequence = nullptr;
1630
gSplitCdataSections = true;
1631
gDiscardDefaultContent = true;
1633
gFormatPrettyPrint = true;
1638
* complete destruction of the object
1640
ParameterManager::~ParameterManager()
1644
delete paramSerializer;
1647
Base::Reference<ParameterManager> ParameterManager::Create()
1649
return {new ParameterManager()};
1652
void ParameterManager::Init()
1654
static bool Init = false;
1657
XMLPlatformUtils::Initialize();
1659
catch (const XMLException& toCatch) {
1660
#if defined(FC_OS_LINUX) || defined(FC_OS_CYGWIN)
1661
std::ostringstream err;
1663
std::stringstream err;
1665
char* pMsg = XMLString::transcode(toCatch.getMessage());
1666
err << "Error during Xerces-c Initialization.\n"
1667
<< " Exception message:" << pMsg;
1668
XMLString::release(&pMsg);
1669
throw XMLBaseException(err.str().c_str());
1675
void ParameterManager::Terminate()
1677
XMLTools::terminate();
1678
XMLPlatformUtils::Terminate();
1681
//**************************************************************************
1682
// Serializer handling
1684
void ParameterManager::SetSerializer(ParameterSerializer* ps)
1686
if (paramSerializer != ps) {
1687
delete paramSerializer;
1689
paramSerializer = ps;
1692
bool ParameterManager::HasSerializer() const
1694
return (paramSerializer != nullptr);
1697
const std::string& ParameterManager::GetSerializeFileName() const
1699
static const std::string _dummy;
1700
return paramSerializer ? paramSerializer->GetFileName() : _dummy;
1703
int ParameterManager::LoadDocument()
1705
if (paramSerializer) {
1706
return paramSerializer->LoadDocument(*this);
1712
bool ParameterManager::LoadOrCreateDocument()
1714
if (paramSerializer) {
1715
return paramSerializer->LoadOrCreateDocument(*this);
1721
void ParameterManager::SaveDocument() const
1723
if (paramSerializer) {
1724
paramSerializer->SaveDocument(*this);
1728
void ParameterManager::SetIgnoreSave(bool value)
1730
gIgnoreSave = value;
1733
bool ParameterManager::IgnoreSave() const
1740
QString getLockFile(const Base::FileInfo& file)
1742
QFileInfo fi(QDir::tempPath(), QString::fromStdString(file.fileName() + ".lock"));
1743
return fi.absoluteFilePath();
1748
const int timeout = 5000;
1753
//**************************************************************************
1756
bool ParameterManager::LoadOrCreateDocument(const char* sFileName)
1758
Base::FileInfo file(sFileName);
1759
if (file.exists()) {
1760
LoadDocument(sFileName);
1768
int ParameterManager::LoadDocument(const char* sFileName)
1771
Base::FileInfo file(sFileName);
1772
QLockFile lock(getLockFile(file));
1773
if (!lock.tryLock(getTimeout())) {
1774
// Continue with empty config
1776
SetIgnoreSave(true);
1777
std::cerr << "Failed to access file for reading: " << sFileName << std::endl;
1780
#if defined(FC_OS_WIN32)
1781
std::wstring name = file.toStdWString();
1782
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1783
LocalFileInputSource inputSource(reinterpret_cast<const XMLCh*>(name.c_str()));
1785
LocalFileInputSource inputSource(XStr(file.filePath().c_str()).unicodeForm());
1787
return LoadDocument(inputSource);
1789
catch (const Base::Exception& e) {
1790
std::cerr << e.what() << std::endl;
1794
std::cerr << "An error occurred during parsing\n " << std::endl;
1799
int ParameterManager::LoadDocument(const XERCES_CPP_NAMESPACE_QUALIFIER InputSource& inputSource)
1802
// Create our parser, then attach an error handler to the parser.
1803
// The parser will call back to methods of the ErrorHandler if it
1804
// discovers errors during the course of parsing the XML document.
1806
auto parser = new XercesDOMParser;
1807
parser->setValidationScheme(gValScheme);
1808
parser->setDoNamespaces(gDoNamespaces);
1809
parser->setDoSchema(gDoSchema);
1810
parser->setValidationSchemaFullChecking(gSchemaFullChecking);
1811
parser->setCreateEntityReferenceNodes(gDoCreate);
1813
auto errReporter = new DOMTreeErrorReporter();
1814
parser->setErrorHandler(errReporter);
1817
// Parse the XML file, catching any XML exceptions that might propagate
1820
bool errorsOccured = false;
1822
parser->parse(inputSource);
1824
catch (const XMLException& e) {
1825
std::cerr << "An error occurred during parsing\n Message: " << StrX(e.getMessage())
1827
errorsOccured = true;
1829
catch (const DOMException& e) {
1830
std::cerr << "A DOM error occurred during parsing\n DOMException code: " << e.code
1832
errorsOccured = true;
1835
std::cerr << "An error occurred during parsing\n " << std::endl;
1836
errorsOccured = true;
1839
if (errorsOccured) {
1845
_pDocument = parser->adoptDocument();
1850
throw XMLBaseException("Malformed Parameter document: Invalid document");
1853
DOMElement* rootElem = _pDocument->getDocumentElement();
1855
throw XMLBaseException("Malformed Parameter document: Root group not found");
1858
_pGroupNode = FindElement(rootElem, "FCParamGroup", "Root");
1861
throw XMLBaseException("Malformed Parameter document: Root group not found");
1867
void ParameterManager::SaveDocument(const char* sFileName) const
1870
Base::FileInfo file(sFileName);
1871
QLockFile lock(getLockFile(file));
1872
if (!lock.tryLock(getTimeout())) {
1873
std::cerr << "Failed to access file for writing: " << sFileName << std::endl;
1877
// Plug in a format target to receive the resultant
1878
// XML stream from the serializer.
1880
// LocalFileFormatTarget prints the resultant XML stream
1881
// to a file once it receives any thing from the serializer.
1883
XMLFormatTarget* myFormTarget {};
1884
#if defined(FC_OS_WIN32)
1885
std::wstring name = file.toStdWString();
1886
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
1887
myFormTarget = new LocalFileFormatTarget(reinterpret_cast<const XMLCh*>(name.c_str()));
1889
myFormTarget = new LocalFileFormatTarget(file.filePath().c_str());
1891
SaveDocument(myFormTarget);
1892
delete myFormTarget;
1894
catch (XMLException& e) {
1895
std::cerr << "An error occurred during creation of output transcoder. Msg is:" << std::endl
1896
<< StrX(e.getMessage()) << std::endl;
1900
void ParameterManager::SaveDocument(XMLFormatTarget* pFormatTarget) const
1903
std::unique_ptr<DOMPrintFilter> myFilter;
1904
std::unique_ptr<DOMErrorHandler> myErrorHandler;
1907
// get a serializer, an instance of DOMWriter
1909
XMLString::transcode("LS", tempStr, 99);
1910
DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
1911
DOMLSSerializer* theSerializer =
1912
static_cast<DOMImplementationLS*>(impl)->createLSSerializer();
1915
// set user specified end of line sequence and output encoding
1916
theSerializer->setNewLine(gMyEOLSequence);
1920
// do the serialization through DOMWriter::writeNode();
1923
DOMLSOutput* theOutput = static_cast<DOMImplementationLS*>(impl)->createLSOutput();
1924
theOutput->setEncoding(gOutputEncoding);
1927
myFilter = std::make_unique<DOMPrintFilter>(
1928
DOMNodeFilter::SHOW_ELEMENT | DOMNodeFilter::SHOW_ATTRIBUTE
1929
| DOMNodeFilter::SHOW_DOCUMENT_TYPE | DOMNodeFilter::SHOW_TEXT);
1930
theSerializer->setFilter(myFilter.get());
1933
// plug in user's own error handler
1934
myErrorHandler = std::make_unique<DOMPrintErrorHandler>();
1935
DOMConfiguration* config = theSerializer->getDomConfig();
1938
config->setParameter(XMLUni::fgDOMErrorHandler, myErrorHandler.get());
1940
// set feature if the serializer supports the feature/mode
1941
if (config->canSetParameter(XMLUni::fgDOMWRTSplitCdataSections, gSplitCdataSections)) {
1942
config->setParameter(XMLUni::fgDOMWRTSplitCdataSections, gSplitCdataSections);
1945
if (config->canSetParameter(XMLUni::fgDOMWRTDiscardDefaultContent,
1946
gDiscardDefaultContent)) {
1947
config->setParameter(XMLUni::fgDOMWRTDiscardDefaultContent, gDiscardDefaultContent);
1950
if (config->canSetParameter(XMLUni::fgDOMWRTFormatPrettyPrint, gFormatPrettyPrint)) {
1951
config->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, gFormatPrettyPrint);
1955
theOutput->setByteStream(pFormatTarget);
1956
theSerializer->write(_pDocument, theOutput);
1958
theOutput->release();
1961
theSerializer->release();
1963
catch (XMLException& e) {
1964
std::cerr << "An error occurred during creation of output transcoder. Msg is:" << std::endl
1965
<< StrX(e.getMessage()) << std::endl;
1969
void ParameterManager::CreateDocument()
1971
// creating a document from screatch
1972
DOMImplementation* impl =
1973
DOMImplementationRegistry::getDOMImplementation(XStr("Core").unicodeForm());
1975
_pDocument = impl->createDocument(nullptr, // root element namespace URI.
1976
XStr("FCParameters").unicodeForm(), // root element name
1977
nullptr); // document type object (DTD).
1979
// creating the node for the root group
1980
DOMElement* rootElem = _pDocument->getDocumentElement();
1981
_pGroupNode = _pDocument->createElement(XStr("FCParamGroup").unicodeForm());
1982
_pGroupNode->setAttribute(XStr("Name").unicodeForm(), XStr("Root").unicodeForm());
1983
rootElem->appendChild(_pGroupNode);
1986
void ParameterManager::CheckDocument() const
1994
// Plug in a format target to receive the resultant
1995
// XML stream from the serializer.
1997
// LocalFileFormatTarget prints the resultant XML stream
1998
// to a file once it receives any thing from the serializer.
2000
MemBufFormatTarget myFormTarget;
2001
SaveDocument(&myFormTarget);
2003
// Either use the file saved on disk or write the current XML into a buffer in memory
2004
// const char* xmlFile = "...";
2005
MemBufInputSource xmlFile(myFormTarget.getRawBuffer(), myFormTarget.getLen(), "(memory)");
2007
// Either load the XSD file from disk or use the built-in string
2008
// const char* xsdFile = "...";
2009
std::string xsdStr(xmlSchemeString); // NOLINT
2010
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
2011
MemBufInputSource xsdFile(reinterpret_cast<const XMLByte*>(xsdStr.c_str()),
2016
// http://apache-xml-project.6118.n7.nabble.com/validating-xml-with-xsd-schema-td17515.html
2018
XercesDOMParser parser;
2019
Grammar* grammar = parser.loadGrammar(xsdFile, Grammar::SchemaGrammarType, true);
2021
Base::Console().Error("Grammar file cannot be loaded.\n");
2025
parser.setExternalNoNamespaceSchemaLocation("Parameter.xsd");
2026
// parser.setExitOnFirstFatalError(true);
2027
// parser.setValidationConstraintFatal(true);
2028
parser.cacheGrammarFromParse(true);
2029
parser.setValidationScheme(XercesDOMParser::Val_Auto);
2030
parser.setDoNamespaces(true);
2031
parser.setDoSchema(true);
2033
DOMTreeErrorReporter errHandler;
2034
parser.setErrorHandler(&errHandler);
2035
parser.parse(xmlFile);
2037
if (parser.getErrorCount() > 0) {
2038
Base::Console().Error("Unexpected XML structure detected: %zu errors\n",
2039
parser.getErrorCount());
2042
catch (XMLException& e) {
2043
std::cerr << "An error occurred while checking document. Msg is:" << std::endl
2044
<< StrX(e.getMessage()) << std::endl;
2049
//**************************************************************************
2050
//**************************************************************************
2051
// DOMTreeErrorReporter
2052
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2054
void DOMTreeErrorReporter::warning(const SAXParseException& /*exc*/)
2057
// Ignore all warnings.
2061
void DOMTreeErrorReporter::error(const SAXParseException& toCatch)
2064
std::cerr << "Error at file \"" << StrX(toCatch.getSystemId()) << "\", line "
2065
<< toCatch.getLineNumber() << ", column " << toCatch.getColumnNumber()
2066
<< "\n Message: " << StrX(toCatch.getMessage()) << std::endl;
2069
void DOMTreeErrorReporter::fatalError(const SAXParseException& toCatch)
2072
std::cerr << "Fatal Error at file \"" << StrX(toCatch.getSystemId()) << "\", line "
2073
<< toCatch.getLineNumber() << ", column " << toCatch.getColumnNumber()
2074
<< "\n Message: " << StrX(toCatch.getMessage()) << std::endl;
2077
void DOMTreeErrorReporter::resetErrors()
2079
// No-op in this case
2083
//**************************************************************************
2084
//**************************************************************************
2086
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2087
DOMPrintFilter::DOMPrintFilter(ShowType whatToShow)
2088
: fWhatToShow(whatToShow)
2091
DOMPrintFilter::FilterAction DOMPrintFilter::acceptNode(const DOMNode* node) const
2093
if (XMLString::compareString(node->getNodeName(), XStr("FCParameters").unicodeForm()) == 0) {
2094
// This node is supposed to have a single FCParamGroup and two text nodes.
2095
// Over time it can happen that the text nodes collect extra newlines.
2096
const DOMNodeList* children = node->getChildNodes();
2097
for (XMLSize_t i = 0; i < children->getLength(); i++) {
2098
DOMNode* child = children->item(i);
2099
if (child->getNodeType() == DOMNode::TEXT_NODE) {
2100
child->setNodeValue(XStr("\n").unicodeForm());
2106
switch (node->getNodeType()) {
2107
case DOMNode::TEXT_NODE: {
2108
// Filter out text element if it is under a group node. Note text xml
2109
// element is plain text in between tags, and we do not store any text
2111
auto parent = node->getParentNode();
2112
if (parent && XMLString::compareString(parent->getNodeName(),
2113
XStr("FCParamGroup").unicodeForm()) == 0) {
2114
return DOMNodeFilter::FILTER_REJECT;
2116
return DOMNodeFilter::FILTER_ACCEPT;
2118
case DOMNode::DOCUMENT_TYPE_NODE:
2119
case DOMNode::DOCUMENT_NODE: {
2120
return DOMNodeFilter::FILTER_REJECT; // no effect
2123
return DOMNodeFilter::FILTER_ACCEPT;
2129
//**************************************************************************
2130
//**************************************************************************
2131
// DOMPrintErrorHandler
2132
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2135
bool DOMPrintErrorHandler::handleError(const DOMError& domError)
2137
// Display whatever error message passed from the serializer
2138
char* msg = XMLString::transcode(domError.getMessage());
2139
std::cout << msg << std::endl;
2140
XMLString::release(&msg);
2142
// Instructs the serializer to continue serialization if possible.