diff --git a/src/App/Extension.h b/src/App/Extension.h
index 79171b2071..84bb442a10 100644
--- a/src/App/Extension.h
+++ b/src/App/Extension.h
@@ -273,6 +273,7 @@ public:
//@{
virtual void extensionSave(Base::Writer&) const {}
virtual void extensionRestore(Base::XMLReader&) {}
+ virtual void extensionRestore(Base::DocumentReader&) {}
//@}
/** @name TypeHandling */
diff --git a/src/App/ExtensionContainer.cpp b/src/App/ExtensionContainer.cpp
index 30022e809b..372967dbae 100644
--- a/src/App/ExtensionContainer.cpp
+++ b/src/App/ExtensionContainer.cpp
@@ -30,6 +30,7 @@
#include "Extension.h"
#include "ExtensionContainer.h"
+#include
using namespace App;
@@ -307,6 +308,18 @@ void ExtensionContainer::Restore(Base::XMLReader& reader) {
App::PropertyContainer::Restore(reader);
}
+void ExtensionContainer::Restore(Base::DocumentReader& reader,XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *viewProviderEl) {
+ //restore dynamic extensions.
+ //Note 1: The extension element must be read first, before all other object elements. That is
+ // needed as the element works together with an object element attribute, which would be
+ // cleared if another attribute is read first
+ //Note 2: This must happen before the py object of this container is used, as only in the
+ // pyobject constructor the extension methods are added to the container.
+ restoreExtensions(reader,viewProviderEl);
+ //TODO NOW:
+ //App::PropertyContainer::Restore(reader);
+}
+
void ExtensionContainer::saveExtensions(Base::Writer& writer) const {
//we don't save anything if there are no dynamic extensions
@@ -352,6 +365,70 @@ void ExtensionContainer::saveExtensions(Base::Writer& writer) const {
writer.decInd();
}
+void ExtensionContainer::restoreExtensions(Base::DocumentReader& reader,XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *viewProviderEl) {
+ //Dynamic extensions are optional (also because they are introduced late into the document format)
+ //and hence it is possible that the element does not exist. As we cannot check for the existence of
+ //an element a object attribute is set if extensions are available. Here we check that
+ //attribute, and only if it exists the extensions element will be available.
+ const char* expanded_cstr = reader.GetAttribute(viewProviderEl,"expanded");
+ if(!expanded_cstr)
+ return;
+ auto ExtensionsDOM = reader.FindElement(viewProviderEl,"Extensions");
+ if(ExtensionsDOM){
+ const char* cnt_cstr = reader.GetAttribute(ExtensionsDOM,"Count");
+ if(cnt_cstr){
+ long Cnt = reader.ContentToInt( cnt_cstr );
+ for (int i=0 ;i(extension.createInstance());
+ //check if this really is a python extension!
+ if (!ext->isPythonExtension()) {
+ delete ext;
+ std::stringstream str;
+ str << "Extension is not a python addable version: '" << type_cstr << "'" << std::ends;
+ throw Base::TypeError(str.str());
+ }
+ ext->initExtension(this);
+ if( strcmp(ext->getExtensionTypeId().getName(), type_cstr) == 0 )
+ ext->extensionRestore(reader);
+ }
+ }
+ catch (const Base::XMLParseException&) {
+ throw; // re-throw
+ }
+ catch (const Base::Exception &e) {
+ Base::Console().Error("%s\n", e.what());
+ }
+ catch (const std::exception &e) {
+ Base::Console().Error("%s\n", e.what());
+ }
+ catch (const char* e) {
+ Base::Console().Error("%s\n", e);
+ }
+ #ifndef FC_DEBUG
+ catch (...) {
+ Base::Console().Error("ExtensionContainer::Restore: Unknown C++ exception thrown\n");
+ }
+ #endif
+ }
+ }
+ }
+}
+
void ExtensionContainer::restoreExtensions(Base::XMLReader& reader) {
//Dynamic extensions are optional (also because they are introduced late into the document format)
diff --git a/src/App/ExtensionContainer.h b/src/App/ExtensionContainer.h
index d3661c1dcf..9c90b95fbf 100644
--- a/src/App/ExtensionContainer.h
+++ b/src/App/ExtensionContainer.h
@@ -25,6 +25,14 @@
#define APP_EXTENSIONCONTAINER_H
#include "PropertyContainer.h"
+#include
+
+XERCES_CPP_NAMESPACE_BEGIN
+ class DOMNode;
+ class DOMElement;
+// class DefaultHandler;
+// class SAX2XMLReader;
+XERCES_CPP_NAMESPACE_END
namespace App {
@@ -177,11 +185,13 @@ public:
void Save(Base::Writer& writer) const override;
void Restore(Base::XMLReader& reader) override;
+ void Restore(Base::DocumentReader& reader,XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *viewProviderEl);
//those methods save/restore the dynamic extensions without handling properties, which is something
//done by the default Save/Restore methods.
void saveExtensions(Base::Writer& writer) const;
void restoreExtensions(Base::XMLReader& reader);
+ void restoreExtensions(Base::DocumentReader& reader,XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *viewProviderEl);
/** Extends the rules for handling property name changed, so that extensions are given an opportunity to handle it.
* If an extension handles a change, neither the rest of the extensions, nor the container itself get to handle it.
diff --git a/src/App/PropertyContainer.cpp b/src/App/PropertyContainer.cpp
index 09e9120c69..837162fc4b 100644
--- a/src/App/PropertyContainer.cpp
+++ b/src/App/PropertyContainer.cpp
@@ -30,6 +30,7 @@
#include "Property.h"
#include "PropertyContainer.h"
+#include
FC_LOG_LEVEL_INIT("App",true,true)
@@ -402,6 +403,103 @@ void PropertyContainer::Restore(Base::XMLReader &reader)
reader.readEndElement("Properties");
}
+void PropertyContainer::Restore(Base::DocumentReader &reader)
+{
+ //TODO NOW
+ Base::Console().Error("PropertyContainer::Restore: DocumentReader\n");
+ reader.clearPartialRestoreProperty();
+ /*
+ reader.clearPartialRestoreProperty();
+ reader.readElement("Properties");
+ int Cnt = reader.getAttributeAsInteger("Count");
+
+ int transientCount = 0;
+ if(reader.hasAttribute("TransientCount"))
+ transientCount = reader.getAttributeAsUnsigned("TransientCount");
+
+ for (int i=0;igetName() << "'");
+ if(prop && reader.hasAttribute("status"))
+ prop->setStatusValue(reader.getAttributeAsUnsigned("status"));
+ }
+
+ for (int i=0 ;igetContainer() != this)
+ prop = dynamicProps.restore(*this,PropName.c_str(),TypeName.c_str(),reader);
+
+ decltype(Property::StatusBits) status;
+ if(reader.hasAttribute("status")) {
+ status = decltype(status)(reader.getAttributeAsUnsigned("status"));
+ if(prop)
+ prop->setStatusValue(status.to_ulong());
+ }
+ // name and type match
+ if (prop && strcmp(prop->getTypeId().getName(), TypeName.c_str()) == 0) {
+ if (!prop->testStatus(Property::Transient)
+ && !status.test(Property::Transient)
+ && !status.test(Property::PropTransient)
+ && !prop->testStatus(Property::PropTransient))
+ {
+ FC_TRACE("restore property '" << prop->getName() << "'");
+ prop->Restore(reader);
+ }else
+ FC_TRACE("skip transient '" << prop->getName() << "'");
+ }
+ // name matches but not the type
+ else if (prop) {
+ handleChangedPropertyType(reader, TypeName.c_str(), prop);
+ }
+ // name doesn't match, the sub-class then has to know
+ // if the property has been renamed or removed
+ else {
+ handleChangedPropertyName(reader, TypeName.c_str(), PropName.c_str());
+ }
+
+ if (reader.testStatus(Base::XMLReader::ReaderStatus::PartialRestoreInProperty)) {
+ Base::Console().Error("Property %s of type %s was subject to a partial restore.\n",PropName.c_str(),TypeName.c_str());
+ reader.clearPartialRestoreProperty();
+ }
+ }
+ catch (const Base::XMLParseException&) {
+ throw; // re-throw
+ }
+ catch (const Base::RestoreError &) {
+ reader.setPartialRestore(true);
+ reader.clearPartialRestoreProperty();
+ Base::Console().Error("Property %s of type %s was subject to a partial restore.\n",PropName.c_str(),TypeName.c_str());
+ }
+ catch (const Base::Exception &e) {
+ Base::Console().Error("%s\n", e.what());
+ }
+ catch (const std::exception &e) {
+ Base::Console().Error("%s\n", e.what());
+ }
+ catch (const char* e) {
+ Base::Console().Error("%s\n", e);
+ }
+#ifndef FC_DEBUG
+ catch (...) {
+ Base::Console().Error("PropertyContainer::Restore: Unknown C++ exception thrown\n");
+ }
+#endif
+ reader.readEndElement("Property");
+ }
+ reader.readEndElement("Properties");
+ */
+}
+
void PropertyContainer::onPropertyStatusChanged(const Property &prop, unsigned long oldStatus)
{
(void)prop;
diff --git a/src/App/PropertyContainer.h b/src/App/PropertyContainer.h
index c86b03e9a4..4a165d51ee 100644
--- a/src/App/PropertyContainer.h
+++ b/src/App/PropertyContainer.h
@@ -220,6 +220,7 @@ public:
void Save (Base::Writer &writer) const override;
void Restore(Base::XMLReader &reader) override;
+ void Restore(Base::DocumentReader &reader) override;
virtual void editProperty(const char * /*propName*/) {}
diff --git a/src/Base/CMakeLists.txt b/src/Base/CMakeLists.txt
index 3b5c9e159a..1c8ad149b6 100644
--- a/src/Base/CMakeLists.txt
+++ b/src/Base/CMakeLists.txt
@@ -267,6 +267,7 @@ SET(FreeCADBase_CPP_SRCS
Writer.cpp
XMLTools.cpp
ZipHeader.cpp
+ DocumentReader.cpp
)
SET(SWIG_HEADERS
diff --git a/src/Base/DocumentReader.cpp b/src/Base/DocumentReader.cpp
new file mode 100644
index 0000000000..01b97285f0
--- /dev/null
+++ b/src/Base/DocumentReader.cpp
@@ -0,0 +1,314 @@
+/***************************************************************************
+ * Copyright (c) 2011 Jürgen Riegel *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+//#include "PreCompiled.h"
+
+//#include
+
+#include "DocumentReader.h"
+
+//#include "Reader.h"
+//#include "Base64.h"
+//#include "Console.h"
+#include "InputSource.h"
+//#include "Persistence.h"
+//#include "Sequencer.h"
+//#include "Stream.h"
+#include "XMLTools.h"
+//#ifdef _MSC_VER
+//#include
+//#endif
+//#include
+
+#include
+#include
+#ifndef _PreComp_
+//# include
+//# include
+# include
+//# include
+//# include
+//# include
+//# include
+# include
+//# include
+//# include
+//# include
+//# include
+//# include
+#endif
+
+XERCES_CPP_NAMESPACE_USE
+
+//using namespace std;
+using namespace Base;
+
+// ---------------------------------------------------------------------------
+// DocumentReader: Constructors and Destructor
+// ---------------------------------------------------------------------------
+static XercesDOMParser::ValSchemes gValScheme = XercesDOMParser::Val_Auto;
+DocumentReader::DocumentReader()
+{
+
+ gDoNamespaces = false;
+ gDoSchema = false;
+ gSchemaFullChecking = false;
+ gDoCreate = true;
+
+ /*
+ gOutputEncoding = nullptr;
+ gMyEOLSequence = nullptr;
+
+ gSplitCdataSections = true;
+ gDiscardDefaultContent = true;
+ gUseFilter = true;
+ gFormatPrettyPrint = true;
+ */
+
+}
+
+//DocumentReader::~DocumentReader()
+//{
+ //delete parser;
+//}
+//int DocumentReader::LoadDocument(const XERCES_CPP_NAMESPACE_QUALIFIER InputSource& inputSource)
+//int DocumentReader::LoadDocument(std::istream& Stream,std::string filename)
+int DocumentReader::LoadDocument(Base::Reader& reader)
+{
+ FileInfo _File( reader.getFileName() );
+ StdInputSource inputSource(reader, _File.filePath().c_str());
+
+ //
+ // Create our parser, then attach an error handler to the parser.
+ // The parser will call back to methods of the ErrorHandler if it
+ // discovers errors during the course of parsing the XML document.
+ //
+ XercesDOMParser *parser = new XercesDOMParser;
+ parser->setValidationScheme(gValScheme);
+ parser->setDoNamespaces(gDoNamespaces);
+ parser->setDoSchema(gDoSchema);
+ parser->setValidationSchemaFullChecking(gSchemaFullChecking);
+ parser->setCreateEntityReferenceNodes(gDoCreate);
+
+ DOMTreeErrorReporter *errReporter = new DOMTreeErrorReporter();
+ parser->setErrorHandler(errReporter);
+ //
+ // Parse the XML file, catching any XML exceptions that might propagate
+ // out of it.
+ //
+ bool errorsOccured = false;
+ try {
+ parser->parse(inputSource);
+ }
+ catch (const XMLException& e) {
+ std::cerr << "An error occurred during parsing\n Message: "
+ << StrX(e.getMessage()) << std::endl;
+ errorsOccured = true;
+ }
+ catch (const DOMException& e) {
+ std::cerr << "A DOM error occurred during parsing\n DOMException code: "
+ << e.code << std::endl;
+ errorsOccured = true;
+ }
+ catch (...) {
+ std::cerr << "An error occurred during parsing\n " << std::endl;
+ errorsOccured = true;
+ }
+
+ if (errorsOccured) {
+ delete parser;
+ delete errReporter;
+ return 0;
+ }
+
+ XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* _pDocument = parser->adoptDocument();
+ delete parser;
+ delete errReporter;
+
+ if (!_pDocument)
+ throw XMLBaseException("Malformed Parameter document: Invalid document");
+
+ DOMElement* rootElem = _pDocument->getDocumentElement();
+ if (!rootElem)
+ throw XMLBaseException("Malformed Parameter document: Root group not found");
+
+ _pGroupNode = rootElem;
+
+ if (!_pGroupNode){
+ throw XMLBaseException("Malformed document.");
+ }
+
+ return 1;
+}
+
+XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *DocumentReader::GetRootElement() const
+{
+ //if (!_pGroupNode)
+ //return nullptr;
+ return _pGroupNode;
+}
+
+XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *DocumentReader::FindElement(const char* Type) const
+{
+ if(!Type)
+ return nullptr;
+
+ for (DOMNode *clChild = _pGroupNode->getFirstChild(); clChild != nullptr; clChild = clChild->getNextSibling()) {
+ if (clChild->getNodeType() == DOMNode::ELEMENT_NODE) {
+ if (!strcmp(Type,StrX(clChild->getNodeName()).c_str())) {
+ if (clChild->getAttributes()->getLength() > 0) {
+ return static_cast(clChild);
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *DocumentReader::FindElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* Start, const char* Type) const
+{
+ if(!Start || !Type)
+ return nullptr;
+ for (DOMNode *clChild = Start->getFirstChild(); clChild != nullptr; clChild = clChild->getNextSibling()) {
+ if (clChild->getNodeType() == DOMNode::ELEMENT_NODE) {
+ if (!strcmp(Type,StrX(clChild->getNodeName()).c_str())) {
+ return static_cast(clChild);
+ //if (clChild->getAttributes()->getLength() > 0) {
+ //return static_cast(clChild);
+ //}
+ }
+ }
+ }
+ return nullptr;
+}
+
+XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *DocumentReader::FindNextElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *Prev, const char* Type) const
+{
+ if (!Prev || !Type)
+ return nullptr;
+ DOMNode *clChild = Prev;
+ while ((clChild = clChild->getNextSibling()) != nullptr) {
+ if (clChild->getNodeType() == DOMNode::ELEMENT_NODE) {
+ // the right node Type
+ if (!strcmp(Type,StrX(clChild->getNodeName()).c_str())) {
+ return static_cast(clChild);
+ }
+ }
+ }
+ return nullptr;
+}
+
+/*
+//CONTENT:
+const char * DocumentReader::GetContent(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *DOMEl) const
+{
+ if (!DOMEl)
+ return nullptr;
+ return StrX(DOMEl->getAttribute(XStr("Value").unicodeForm())).c_str();
+}
+
+std::string DocumentReader::GetContentASCII(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *DOMEl) const
+{
+ //return std::string(StrXUTF8(pcElem->getNodeValue()).c_str() );
+ //maybe its better to use getNodeValue()
+ if (!DOMEl)
+ return nullptr;
+ return std::string( StrXUTF8(DOMEl->getAttribute(XStr("Value").unicodeForm())).c_str() );
+}
+*/
+
+long DocumentReader::ContentToInt( const char* content ) const
+{
+ return atol( content );
+}
+
+unsigned long DocumentReader::ContentToUnsigned(const char* content) const
+{
+ return strtoul(content,nullptr,10);
+}
+
+double DocumentReader::ContentToFloat(const char* content) const
+{
+ return atof(content);
+}
+
+bool DocumentReader::ContentToBool(const char* content) const
+{
+ if (strcmp(content,"1"))
+ return false;
+ else
+ return true;
+}
+
+//ATTRIBUTE:
+const char * DocumentReader::GetAttribute(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *DOMEl, const char* Attr) const
+{
+ if(!Attr)
+ return nullptr;
+ XStr xstr( Attr );
+ bool hasAttr = DOMEl->hasAttribute(xstr.unicodeForm());
+ if (!hasAttr){
+ return nullptr;
+ }
+ const XMLCh * attr = DOMEl->getAttribute( xstr.unicodeForm() );
+ return strdup( StrX( attr ).c_str() );
+}
+
+const char * DocumentReader::GetAttribute(const char* Attr) const
+{
+ if(!Attr)
+ return nullptr;
+ XStr xstr( Attr );
+ bool hasAttr = _pGroupNode->hasAttribute(xstr.unicodeForm());
+ if (!hasAttr){
+ return nullptr;
+ }
+ const XMLCh * attr = _pGroupNode->getAttribute( xstr.unicodeForm() );
+ //stringLen
+ return strdup( StrX( attr ).c_str() );//strdup is needed since pointer from strx only exists in context where StrX() is created.
+}
+
+/*
+unsigned int Base::XMLReader::getAttributeCount() const
+{
+ return static_cast(AttrMap.size());
+}
+*/
+
+//Status
+
+void Base::DocumentReader::clearPartialRestoreProperty()
+{
+ setStatus(PartialRestoreInProperty, false);
+ setStatus(PartialRestoreInObject, false);
+}
+
+bool Base::DocumentReader::testStatus(ReaderStatus pos) const
+{
+ return StatusBits.test(static_cast(pos));
+}
+
+void Base::DocumentReader::setStatus(ReaderStatus pos, bool on)
+{
+ StatusBits.set(static_cast(pos), on);
+}
+
+
diff --git a/src/Base/DocumentReader.h b/src/Base/DocumentReader.h
new file mode 100644
index 0000000000..e414046f37
--- /dev/null
+++ b/src/Base/DocumentReader.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+ * Copyright (c) 2011 Jürgen Riegel *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#ifndef BASE_DOCUMENTREADER_H
+#define BASE_DOCUMENTREADER_H
+
+#include
+#include