diff --git a/Modules/SceneSerialization/mitkPropertyListDeserializer.cpp b/Modules/SceneSerialization/mitkPropertyListDeserializer.cpp index 12387c2f90..1166e226a4 100644 --- a/Modules/SceneSerialization/mitkPropertyListDeserializer.cpp +++ b/Modules/SceneSerialization/mitkPropertyListDeserializer.cpp @@ -1,93 +1,93 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPropertyListDeserializer.h" #include mitk::PropertyListDeserializer::PropertyListDeserializer() { } mitk::PropertyListDeserializer::~PropertyListDeserializer() { } bool mitk::PropertyListDeserializer::Deserialize() { bool error(false); TiXmlDocument document( m_Filename ); if (!document.LoadFile()) { MITK_ERROR << "Could not open/read/parse " << m_Filename << "\nTinyXML reports: " << document.ErrorDesc() << std::endl; return false; } // find version node --> note version in some variable int fileVersion = 1; TiXmlElement* versionObject = document.FirstChildElement("Version"); if (versionObject) { if ( versionObject->QueryIntAttribute( "FileVersion", &fileVersion ) != TIXML_SUCCESS ) { MITK_ERROR << "Property file " << m_Filename << " does not contain version information! Trying version 1 format." << std::endl; } } std::stringstream propertyListDeserializerClassName; propertyListDeserializerClassName << "PropertyListDeserializerV" << fileVersion; std::list readers = itk::ObjectFactoryBase::CreateAllInstance(propertyListDeserializerClassName.str().c_str()); if (readers.size() < 1) { MITK_ERROR << "No property list reader found for file version " << fileVersion; } if (readers.size() > 1) { MITK_WARN << "Multiple property list readers found for file version " << fileVersion << ". Using arbitrary first one."; } for ( std::list::iterator iter = readers.begin(); iter != readers.end(); ++iter ) { if (PropertyListDeserializer* reader = dynamic_cast( iter->GetPointer() ) ) { reader->SetFilename( m_Filename ); bool success = reader->Deserialize(); error |= !success; m_PropertyList = reader->GetOutput(); if ( error ) { - MITK_ERROR << "There were errors while loding property list file " << m_Filename << ". Your data may be corrupted"; + MITK_ERROR << "There were errors while loading property list file " << m_Filename << ". Your data may be corrupted"; } break; } } return !error; } mitk::PropertyList::Pointer mitk::PropertyListDeserializer::GetOutput() { return m_PropertyList; } diff --git a/Modules/SceneSerialization/mitkPropertyListDeserializerV1.cpp b/Modules/SceneSerialization/mitkPropertyListDeserializerV1.cpp index 0644f26aca..a983424353 100644 --- a/Modules/SceneSerialization/mitkPropertyListDeserializerV1.cpp +++ b/Modules/SceneSerialization/mitkPropertyListDeserializerV1.cpp @@ -1,90 +1,90 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSerializerMacros.h" #include "mitkPropertyListDeserializerV1.h" #include "mitkBasePropertySerializer.h" #include MITK_REGISTER_SERIALIZER(PropertyListDeserializerV1) mitk::PropertyListDeserializerV1::PropertyListDeserializerV1() { } mitk::PropertyListDeserializerV1::~PropertyListDeserializerV1() { } bool mitk::PropertyListDeserializerV1::Deserialize() { bool error(false); m_PropertyList = PropertyList::New(); TiXmlDocument document( m_Filename ); if (!document.LoadFile()) { MITK_ERROR << "Could not open/read/parse " << m_Filename << "\nTinyXML reports: " << document.ErrorDesc() << std::endl; return false; } for( TiXmlElement* propertyElement = document.FirstChildElement("property"); propertyElement != NULL; propertyElement = propertyElement->NextSiblingElement("property") ) { const char* keya = propertyElement->Attribute("key"); std::string key( keya ? keya : ""); const char* typea = propertyElement->Attribute("type"); std::string type( typea ? typea : ""); // hand propertyElement to specific reader std::stringstream propertyDeserializerClassName; propertyDeserializerClassName << type << "Serializer"; std::list readers = itk::ObjectFactoryBase::CreateAllInstance(propertyDeserializerClassName.str().c_str()); if (readers.size() < 1) { MITK_ERROR << "No property reader found for " << type; error = true; } if (readers.size() > 1) { MITK_WARN << "Multiple property readers found for " << type << ". Using arbitrary first one."; } for ( std::list::iterator iter = readers.begin(); iter != readers.end(); ++iter ) { if (BasePropertySerializer* reader = dynamic_cast( iter->GetPointer() ) ) { BaseProperty::Pointer property = reader->Deserialize( propertyElement->FirstChildElement() ); if (property.IsNotNull()) { m_PropertyList->ReplaceProperty(key, property); } else { - MITK_ERROR << "There were errors while loding property '" << key << "' of type " << type << ". Your data may be corrupted"; + MITK_ERROR << "There were errors while loading property '" << key << "' of type " << type << ". Your data may be corrupted"; error = true; } break; } } } return !error; } diff --git a/Modules/SceneSerialization/mitkSceneIO.cpp b/Modules/SceneSerialization/mitkSceneIO.cpp index 7be4213556..cb68cc0ecd 100644 --- a/Modules/SceneSerialization/mitkSceneIO.cpp +++ b/Modules/SceneSerialization/mitkSceneIO.cpp @@ -1,533 +1,533 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include "mitkSceneIO.h" #include "mitkBaseDataSerializer.h" #include "mitkPropertyListSerializer.h" #include "mitkSceneReader.h" #include "mitkProgressBar.h" #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" #include "mitkStandaloneDataStorage.h" #include #include #include #include #include #include "itksys/SystemTools.hxx" mitk::SceneIO::SceneIO() :m_WorkingDirectory(""), m_UnzipErrors(0) { } mitk::SceneIO::~SceneIO() { } std::string mitk::SceneIO::CreateEmptyTempDirectory() { mitk::UIDGenerator uidGen("UID_",6); //std::string returnValue = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory() + Poco::Path::separator() + "SceneIOTemp" + uidGen.GetUID(); std::string returnValue = Poco::Path::temp() + "SceneIOTemp" + uidGen.GetUID(); std::string uniquename = returnValue + Poco::Path::separator(); Poco::File tempdir( uniquename ); try { bool existsNot = tempdir.createDirectory(); if (!existsNot) { MITK_ERROR << "Warning: Directory already exitsts: " << uniquename << " (choosing another)"; returnValue = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory() + Poco::Path::separator() + "SceneIOTempDirectory" + uidGen.GetUID(); uniquename = returnValue + Poco::Path::separator(); Poco::File tempdir2( uniquename ); if (!tempdir2.createDirectory()) { MITK_ERROR << "Warning: Second directory also already exitsts: " << uniquename; } } } catch( std::exception& e ) { MITK_ERROR << "Could not create temporary directory " << uniquename << ":" << e.what(); return ""; } return returnValue; } mitk::DataStorage::Pointer mitk::SceneIO::LoadScene( const std::string& filename, DataStorage* pStorage, bool clearStorageFirst ) { // prepare data storage DataStorage::Pointer storage = pStorage; if ( storage.IsNull() ) { storage = StandaloneDataStorage::New().GetPointer(); } if ( clearStorageFirst ) { try { storage->Remove( storage->GetAll() ); } catch(...) { MITK_ERROR << "DataStorage cannot be cleared properly."; } } // test input filename if ( filename.empty() ) { MITK_ERROR << "No filename given. Not possible to load scene."; return NULL; } // test if filename can be read std::ifstream file( filename.c_str(), std::ios::binary ); if (!file.good()) { MITK_ERROR << "Cannot open '" << filename << "' for reading"; return NULL; } // get new temporary directory m_WorkingDirectory = CreateEmptyTempDirectory(); if (m_WorkingDirectory.empty()) { MITK_ERROR << "Could not create temporary directory. Cannot open scene files."; return NULL; } // unzip all filenames contents to temp dir m_UnzipErrors = 0; Poco::Zip::Decompress unzipper( file, Poco::Path( m_WorkingDirectory ) ); unzipper.EError += Poco::Delegate >(this, &SceneIO::OnUnzipError); unzipper.EOk += Poco::Delegate >(this, &SceneIO::OnUnzipOk); unzipper.decompressAllFiles(); unzipper.EError -= Poco::Delegate >(this, &SceneIO::OnUnzipError); unzipper.EOk -= Poco::Delegate >(this, &SceneIO::OnUnzipOk); if ( m_UnzipErrors ) { MITK_ERROR << "There were " << m_UnzipErrors << " errors unzipping '" << filename << "'. Will attempt to read whatever could be unzipped."; } // test if index.xml exists // parse index.xml with TinyXML TiXmlDocument document( m_WorkingDirectory + Poco::Path::separator() + "index.xml" ); if (!document.LoadFile()) { MITK_ERROR << "Could not open/read/parse " << m_WorkingDirectory << "/index.xml\nTinyXML reports: " << document.ErrorDesc() << std::endl; return NULL; } SceneReader::Pointer reader = SceneReader::New(); if ( !reader->LoadScene( document, m_WorkingDirectory, storage ) ) { - MITK_ERROR << "There were errors while loding scene file " << filename << ". Your data may be corrupted"; + MITK_ERROR << "There were errors while loading scene file " << filename << ". Your data may be corrupted"; } // delete temp directory try { Poco::File deleteDir( m_WorkingDirectory ); deleteDir.remove(true); // recursive } catch(...) { MITK_ERROR << "Could not delete temporary directory " << m_WorkingDirectory; } // return new data storage, even if empty or uncomplete (return as much as possible but notify calling method) return storage; } bool mitk::SceneIO::SaveScene( DataStorage::SetOfObjects::ConstPointer sceneNodes, const DataStorage* storage, const std::string& filename) { if (!sceneNodes) { MITK_ERROR << "No set of nodes given. Not possible to save scene."; return false; } if (!storage) { MITK_ERROR << "No data storage given. Not possible to save scene."; // \TODO: Technically, it would be possible to save the nodes without their relation return false; } if ( filename.empty() ) { MITK_ERROR << "No filename given. Not possible to save scene."; return false; } try { m_FailedNodes = DataStorage::SetOfObjects::New(); m_FailedProperties = PropertyList::New(); // start XML DOM TiXmlDocument document; TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "UTF-8", "" ); // TODO what to write here? encoding? standalone would mean that we provide a DTD somewhere... document.LinkEndChild( decl ); TiXmlElement* version = new TiXmlElement("Version"); version->SetAttribute("Writer", __FILE__ ); version->SetAttribute("Revision", "$Revision: 17055 $" ); version->SetAttribute("FileVersion", 1 ); document.LinkEndChild(version); //DataStorage::SetOfObjects::ConstPointer sceneNodes = storage->GetSubset( predicate ); if ( sceneNodes.IsNull() ) { MITK_WARN << "Saving empty scene to " << filename; } else { if ( sceneNodes->size() == 0 ) { MITK_WARN << "Saving empty scene to " << filename; } MITK_INFO << "Storing scene with " << sceneNodes->size() << " objects to " << filename; m_WorkingDirectory = CreateEmptyTempDirectory(); if (m_WorkingDirectory.empty()) { MITK_ERROR << "Could not create temporary directory. Cannot create scene files."; return false; } ProgressBar::GetInstance()->AddStepsToDo( sceneNodes->size() ); // find out about dependencies typedef std::map< DataNode*, std::string > UIDMapType; typedef std::map< DataNode*, std::list > SourcesMapType; UIDMapType nodeUIDs; // for dependencies: ID of each node SourcesMapType sourceUIDs; // for dependencies: IDs of a node's parent nodes UIDGenerator nodeUIDGen("OBJECT_"); for (DataStorage::SetOfObjects::const_iterator iter = sceneNodes->begin(); iter != sceneNodes->end(); ++iter) { DataNode* node = iter->GetPointer(); if (!node) continue; // unlikely event that we get a NULL pointer as an object for saving. just ignore // generate UIDs for all source objects DataStorage::SetOfObjects::ConstPointer sourceObjects = storage->GetSources( node ); for ( mitk::DataStorage::SetOfObjects::const_iterator sourceIter = sourceObjects->begin(); sourceIter != sourceObjects->end(); ++sourceIter ) { if ( std::find( sceneNodes->begin(), sceneNodes->end(), *sourceIter ) == sceneNodes->end() ) continue; // source is not saved, so don't generate a UID for this source // create a uid for the parent object if ( nodeUIDs[ *sourceIter ].empty() ) { nodeUIDs[ *sourceIter ] = nodeUIDGen.GetUID(); } // store this dependency for writing sourceUIDs[ node ].push_back( nodeUIDs[*sourceIter] ); } if ( nodeUIDs[ node ].empty() ) { nodeUIDs[ node ] = nodeUIDGen.GetUID(); } } // write out objects, dependencies and properties for (DataStorage::SetOfObjects::const_iterator iter = sceneNodes->begin(); iter != sceneNodes->end(); ++iter) { DataNode* node = iter->GetPointer(); if (node) { TiXmlElement* nodeElement = new TiXmlElement("node"); std::string filenameHint( node->GetName() ); filenameHint = itksys::SystemTools::MakeCindentifier(filenameHint.c_str()); // escape filename <-- only allow [A-Za-z0-9_], replace everything else with _ // store dependencies UIDMapType::iterator searchUIDIter = nodeUIDs.find(node); if ( searchUIDIter != nodeUIDs.end() ) { // store this node's ID nodeElement->SetAttribute("UID", searchUIDIter->second.c_str() ); } SourcesMapType::iterator searchSourcesIter = sourceUIDs.find(node); if ( searchSourcesIter != sourceUIDs.end() ) { // store all source IDs for ( std::list::iterator sourceUIDIter = searchSourcesIter->second.begin(); sourceUIDIter != searchSourcesIter->second.end(); ++sourceUIDIter ) { TiXmlElement* uidElement = new TiXmlElement("source"); uidElement->SetAttribute("UID", sourceUIDIter->c_str() ); nodeElement->LinkEndChild( uidElement ); } } // store basedata if ( BaseData* data = node->GetData() ) { //std::string filenameHint( node->GetName() ); bool error(false); TiXmlElement* dataElement( SaveBaseData( data, filenameHint, error ) ); // returns a reference to a file if (error) { m_FailedNodes->push_back( node ); } // store basedata properties PropertyList* propertyList = data->GetPropertyList(); if (propertyList && !propertyList->IsEmpty() ) { TiXmlElement* baseDataPropertiesElement( SavePropertyList( propertyList, filenameHint + "-data") ); // returns a reference to a file dataElement->LinkEndChild( baseDataPropertiesElement ); } nodeElement->LinkEndChild( dataElement ); } // store all renderwindow specific propertylists const RenderingManager::RenderWindowVector& allRenderWindows( RenderingManager::GetInstance()->GetAllRegisteredRenderWindows() ); for ( RenderingManager::RenderWindowVector::const_iterator rw = allRenderWindows.begin(); rw != allRenderWindows.end(); ++rw) { if (vtkRenderWindow* renderWindow = *rw) { std::string renderWindowName( mitk::BaseRenderer::GetInstance(renderWindow)->GetName() ); BaseRenderer* renderer = mitk::BaseRenderer::GetInstance(renderWindow); PropertyList* propertyList = node->GetPropertyList(renderer); if ( propertyList && !propertyList->IsEmpty() ) { TiXmlElement* renderWindowPropertiesElement( SavePropertyList( propertyList, filenameHint + "-" + renderWindowName) ); // returns a reference to a file renderWindowPropertiesElement->SetAttribute("renderwindow", renderWindowName); nodeElement->LinkEndChild( renderWindowPropertiesElement ); } } } // don't forget the renderwindow independent list PropertyList* propertyList = node->GetPropertyList(); if ( propertyList && !propertyList->IsEmpty() ) { TiXmlElement* propertiesElement( SavePropertyList( propertyList, filenameHint + "-node") ); // returns a reference to a file nodeElement->LinkEndChild( propertiesElement ); } document.LinkEndChild( nodeElement ); } else { MITK_WARN << "Ignoring NULL node during scene serialization."; } ProgressBar::GetInstance()->Progress(); } // end for all nodes } // end if sceneNodes if ( !document.SaveFile( m_WorkingDirectory + Poco::Path::separator() + "index.xml" ) ) { MITK_ERROR << "Could not write scene to " << m_WorkingDirectory << Poco::Path::separator() << "index.xml" << "\nTinyXML reports '" << document.ErrorDesc() << "'"; return false; } else { try { Poco::File deleteFile( filename.c_str() ); if (deleteFile.exists()) { deleteFile.remove(); } // create zip at filename std::ofstream file( filename.c_str(), std::ios::binary | std::ios::out); if (!file.good()) { MITK_ERROR << "Could not open a zip file for writing: '" << filename << "'"; } else { Poco::Zip::Compress zipper( file, true ); Poco::Path tmpdir( m_WorkingDirectory ); zipper.addRecursive( tmpdir ); zipper.close(); } try { Poco::File deleteDir( m_WorkingDirectory ); deleteDir.remove(true); // recursive } catch(...) { MITK_ERROR << "Could not delete temporary directory " << m_WorkingDirectory; return false; // ok? } } catch(std::exception& e) { MITK_ERROR << "Could not create ZIP file from " << m_WorkingDirectory << "\nReason: " << e.what(); return false; } return true; } } catch(std::exception& e) { MITK_ERROR << "Caught exception during saving temporary files to disk. Error description: '" << e.what() << "'"; return false; } } TiXmlElement* mitk::SceneIO::SaveBaseData( BaseData* data, const std::string& filenamehint, bool& error ) { assert(data); error = true; // find correct serializer // the serializer must // - create a file containing all information to recreate the BaseData object --> needs to know where to put this file (and a filename?) // - TODO what to do about writers that creates one file per timestep? TiXmlElement* element = new TiXmlElement("data"); element->SetAttribute( "type", data->GetNameOfClass() ); // construct name of serializer class std::string serializername(data->GetNameOfClass()); serializername += "Serializer"; std::list thingsThatCanSerializeThis = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str()); if (thingsThatCanSerializeThis.size() < 1) { MITK_ERROR << "No serializer found for " << data->GetNameOfClass() << ". Skipping object"; } for ( std::list::iterator iter = thingsThatCanSerializeThis.begin(); iter != thingsThatCanSerializeThis.end(); ++iter ) { if (BaseDataSerializer* serializer = dynamic_cast( iter->GetPointer() ) ) { serializer->SetData(data); serializer->SetFilenameHint(filenamehint); serializer->SetWorkingDirectory( m_WorkingDirectory ); try { std::string writtenfilename = serializer->Serialize(); element->SetAttribute("file", writtenfilename); error = false; } catch (std::exception& e) { MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what(); } break; } } return element; } TiXmlElement* mitk::SceneIO::SavePropertyList( PropertyList* propertyList, const std::string& filenamehint) { assert(propertyList); // - TODO what to do about shared properties (same object in two lists or behind several keys)? TiXmlElement* element = new TiXmlElement("properties"); // construct name of serializer class PropertyListSerializer::Pointer serializer = PropertyListSerializer::New(); serializer->SetPropertyList(propertyList); serializer->SetFilenameHint(filenamehint); serializer->SetWorkingDirectory( m_WorkingDirectory ); try { std::string writtenfilename = serializer->Serialize(); element->SetAttribute("file", writtenfilename); PropertyList::Pointer failedProperties = serializer->GetFailedProperties(); if (failedProperties.IsNotNull()) { // move failed properties to global list m_FailedProperties->ConcatenatePropertyList( failedProperties, true ); } } catch (std::exception& e) { MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what(); } return element; } const mitk::SceneIO::FailedBaseDataListType* mitk::SceneIO::GetFailedNodes() { return m_FailedNodes.GetPointer(); } const mitk::PropertyList* mitk::SceneIO::GetFailedProperties() { return m_FailedProperties; } void mitk::SceneIO::OnUnzipError(const void* /*pSender*/, std::pair& info) { ++m_UnzipErrors; MITK_ERROR << "Error while unzipping: " << info.second; } void mitk::SceneIO::OnUnzipOk(const void* /*pSender*/, std::pair& /*info*/) { // MITK_INFO << "Unzipped ok: " << info.second.toString(); } diff --git a/Modules/SceneSerialization/mitkSceneReader.cpp b/Modules/SceneSerialization/mitkSceneReader.cpp index f94bc1cf0a..4b9c2673f5 100644 --- a/Modules/SceneSerialization/mitkSceneReader.cpp +++ b/Modules/SceneSerialization/mitkSceneReader.cpp @@ -1,63 +1,63 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSceneReader.h" bool mitk::SceneReader::LoadScene( TiXmlDocument& document, const std::string& workingDirectory, DataStorage* storage ) { // find version node --> note version in some variable int fileVersion = 1; TiXmlElement* versionObject = document.FirstChildElement("Version"); if (versionObject) { if ( versionObject->QueryIntAttribute( "FileVersion", &fileVersion ) != TIXML_SUCCESS ) { MITK_ERROR << "Scene file " << workingDirectory + "/index.xml" << " does not contain version information! Trying version 1 format." << std::endl; } } std::stringstream sceneReaderClassName; sceneReaderClassName << "SceneReaderV" << fileVersion; std::list sceneReaders = itk::ObjectFactoryBase::CreateAllInstance(sceneReaderClassName.str().c_str()); if (sceneReaders.size() < 1) { MITK_ERROR << "No scene reader found for scene file version " << fileVersion; } if (sceneReaders.size() > 1) { MITK_WARN << "Multiple scene readers found for scene file version " << fileVersion << ". Using arbitrary first one."; } for ( std::list::iterator iter = sceneReaders.begin(); iter != sceneReaders.end(); ++iter ) { if (SceneReader* reader = dynamic_cast( iter->GetPointer() ) ) { if ( !reader->LoadScene( document, workingDirectory, storage ) ) { - MITK_ERROR << "There were errors while loding scene file " << workingDirectory + "/index.xml. Your data may be corrupted"; + MITK_ERROR << "There were errors while loading scene file " << workingDirectory + "/index.xml. Your data may be corrupted"; return false; } else { return true; } } } return false; }