diff --git a/src/App/ComplexGeoData.cpp b/src/App/ComplexGeoData.cpp
index fcf7977e46..d805daaa11 100644
--- a/src/App/ComplexGeoData.cpp
+++ b/src/App/ComplexGeoData.cpp
@@ -38,9 +38,12 @@
#include
#include
+#include
#include
+#include
#include
+#include
using namespace Data;
@@ -386,4 +389,208 @@ char ComplexGeoData::elementType(const char *name) const {
return 0;
}
+void ComplexGeoData::setPersistenceFileName(const char *filename) const {
+ if(!filename)
+ filename = "";
+ _PersistenceName = filename;
+}
+
+void ComplexGeoData::Save(Base::Writer &writer) const {
+
+ if(!getElementMapSize()) {
+ writer.Stream() << writer.ind() << "\n";
+ return;
+ }
+
+ // Store some dummy map entry to trigger recompute in older version.
+ writer.Stream() << writer.ind()
+ << ""
+ << ""
+ << "\n";
+
+ // New layout of element map, so we use new xml tag, ElementMap2
+ writer.Stream() << writer.ind() << "\n";
+ return;
+ }
+ writer.Stream() << " count=\"" << _elementMap->size() << "\">\n";
+ _elementMap->save(writer.beginCharStream(Base::CharStreamFormat::Raw) << '\n');
+ writer.endCharStream() << '\n';
+ writer.Stream() << writer.ind() << "\n" ;
+}
+
+void ComplexGeoData::Restore(Base::XMLReader &reader) {
+ resetElementMap();
+
+ reader.readElement("ElementMap");
+ bool newtag = false;
+ if (reader.hasAttribute("new") && reader.getAttributeAsInteger("new") > 0) {
+ reader.readEndElement("ElementMap");
+ reader.readElement("ElementMap2");
+ newtag = true;
+ }
+
+ const char *file = "";
+ if (reader.hasAttribute("file")) {
+ reader.getAttribute("file");
+ }
+ if(*file) {
+ reader.addFile(file,this);
+ return;
+ }
+
+ std::size_t count = 0;
+ if (reader.hasAttribute("count")) {
+ reader.getAttributeAsUnsigned("count");
+ }
+ if(!count)
+ return;
+
+ if (newtag) {
+ resetElementMap(std::make_shared());
+ _elementMap = _elementMap->restore(Hasher, reader.beginCharStream(Base::CharStreamFormat::Raw));
+ reader.endCharStream();
+ reader.readEndElement("ElementMap2");
+ return;
+ }
+
+ if(reader.FileVersion>1) {
+ restoreStream(reader.beginCharStream(Base::CharStreamFormat::Raw), count);
+ reader.endCharStream();
+ return;
+ }
+
+ size_t invalid_count = 0;
+ bool warned = false;
+
+ const auto & types = getElementTypes();
+
+ for(size_t i=0;i iss(attr, std::strlen(attr));
+ long id;
+ while((iss >> id)) {
+ if (id == 0)
+ continue;
+ auto sid = Hasher->getID(id);
+ if(!sid)
+ ++invalid_count;
+ else
+ sids.push_back(sid);
+ char sep;
+ iss >> sep;
+ }
+ }
+ }
+ _elementMap->setElementName(IndexedName(reader.getAttribute("value"), types),
+ MappedName(reader.getAttribute("key")),
+ Tag,
+ &sids);
+ }
+ if(invalid_count)
+ FC_ERR("Found " << invalid_count << " invalid string id");
+ reader.readEndElement("ElementMap");
+}
+
+void ComplexGeoData::restoreStream(std::istream &s, std::size_t count) {
+ resetElementMap();
+
+ size_t invalid_count = 0;
+ std::string key,value,sid;
+ bool warned = false;
+
+ const auto & types = getElementTypes();
+ try {
+ for(size_t i=0;i> value >> key >> scount))
+ FC_THROWM(Base::RuntimeError,
+ "Failed to restore element map " << _PersistenceName);
+ sids.reserve(scount);
+ for(std::size_t j=0;j> id))
+ FC_THROWM(Base::RuntimeError,
+ "Failed to restore element map " << _PersistenceName);
+ if (Hasher) {
+ auto sid = Hasher->getID(id);
+ if(!sid)
+ ++invalid_count;
+ else
+ sids.push_back(sid);
+ }
+ }
+ if(scount && !Hasher) {
+ sids.clear();
+ if(!warned) {
+ warned = true;
+ FC_ERR("missing hasher");
+ }
+ }
+ _elementMap->setElementName(IndexedName(value.c_str(), types), MappedName(key), Tag, &sids);
+ }
+ } catch (Base::Exception &e) {
+ e.ReportException();
+ _restoreFailed = true;
+ _elementMap.reset();
+ }
+ if(invalid_count)
+ FC_ERR("Found " << invalid_count << " invalid string id");
+}
+
+void ComplexGeoData::SaveDocFile(Base::Writer &writer) const {
+ flushElementMap();
+ if (_elementMap) {
+ writer.Stream() << "BeginElementMap v1\n";
+ _elementMap->save(writer.Stream());
+ }
+}
+
+void ComplexGeoData::RestoreDocFile(Base::Reader &reader) {
+ std::string marker, ver;
+ reader >> marker;
+ if (boost::equals(marker, "BeginElementMap")) {
+ resetElementMap();
+ reader >> ver;
+ if (ver != "v1")
+ FC_WARN("Unknown element map format");
+ else {
+ resetElementMap(std::make_shared());
+ _elementMap = _elementMap->restore(Hasher, reader);
+ return;
+ }
+ }
+ std::size_t count = atoi(marker.c_str());
+ restoreStream(reader,count);
+}
+
+unsigned int ComplexGeoData::getMemSize(void) const {
+ flushElementMap();
+ if(_elementMap)
+ return _elementMap->size()*10;
+ return 0;
+}
+
+void ComplexGeoData::beforeSave() const
+{
+ flushElementMap();
+ if (this->_elementMap)
+ this->_elementMap->beforeSave(Hasher);
+}
+
+
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
diff --git a/src/App/ComplexGeoData.h b/src/App/ComplexGeoData.h
index 52cbb29580..1706551eed 100644
--- a/src/App/ComplexGeoData.h
+++ b/src/App/ComplexGeoData.h
@@ -280,6 +280,19 @@ public:
virtual void flushElementMap() const;
//@}
+ /** @name Save/restore */
+ //@{
+ void Save (Base::Writer &writer) const;
+ void Restore(Base::XMLReader &reader);
+ void SaveDocFile(Base::Writer &writer) const;
+ void RestoreDocFile(Base::Reader &reader);
+ unsigned int getMemSize (void) const;
+ void setPersistenceFileName(const char *name) const;
+ virtual void beforeSave() const;
+ bool isRestoreFailed() const { return _restoreFailed; }
+ void resetRestoreFailure() const { _restoreFailed = true; }
+ //@}
+
protected:
/// from local to outside
@@ -347,6 +360,8 @@ public:
protected:
+ void restoreStream(std::istream &s, std::size_t count);
+
/// from local to outside
inline Base::Vector3d transformToOutside(const Base::Vector3f& vec) const
{
@@ -370,6 +385,10 @@ protected:
private:
ElementMapPtr _elementMap;
+
+protected:
+ mutable std::string _PersistenceName;
+ mutable bool _restoreFailed = false;
};
} //namespace App