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