diff --git a/CMake/mitkMacroCreateExecutable.cmake b/CMake/mitkMacroCreateExecutable.cmake index 23fbf25464..a849f7339a 100644 --- a/CMake/mitkMacroCreateExecutable.cmake +++ b/CMake/mitkMacroCreateExecutable.cmake @@ -1,99 +1,100 @@ ################################################################## # # MITK_CREATE_EXECUTABLE # #! Creates an executable with MITK dependencies and batch files #! for proper application start-up. #! #! USAGE: #! #! \code #! MITK_CREATE_EXECUTABLE( [] #! [DEPENDS ] #! [PACKAGE_DEPENDS ] #! [INCLUDE_DIRS ] #! [TARGET_DEPENDS #! [WARNINGS_AS_ERRORS] #! \endcode #! #! \param EXECUTABLE_NAME The name for the new executable target ################################################################## macro(mitk_create_executable) set(_macro_params SUBPROJECTS # list of CDash labels VERSION # version number, e.g. "1.2.0" INCLUDE_DIRS # additional include dirs DEPENDS # list of modules this module depends on PACKAGE_DEPENDS # list of "packages" this module depends on (e.g. Qt, VTK, etc.) TARGET_DEPENDS # list of CMake targets this executable should depend on ADDITIONAL_LIBS # list of additional libraries linked to this executable FILES_CMAKE # file name of a CMake file setting source list variables # (defaults to files.cmake) DESCRIPTION # a description for the executable ) set(_macro_options NO_INIT # do not create CppMicroServices initialization code NO_FEATURE_INFO # do not create a feature info by calling add_feature_info() NO_BATCH_FILE # do not create batch files on Windows WARNINGS_AS_ERRORS # treat all compiler warnings as errors ) MACRO_PARSE_ARGUMENTS(EXEC "${_macro_params}" "${_macro_options}" ${ARGN}) set(_EXEC_OPTIONS EXECUTABLE) if(EXEC_NO_INIT) list(APPEND _EXEC_OPTIONS NO_INIT) endif() if(EXEC_WARNINGS_AS_ERRORS) list(APPEND _EXEC_OPTIONS WARNINGS_AS_ERRORS) endif() if(EXEC_NO_FEATURE_INFO) list(APPEND _EXEC_OPTIONS NO_FEATURE_INFO) endif() mitk_create_module(${EXEC_DEFAULT_ARGS} SUBPROJECTS ${EXEC_SUBPROJECTS} VERSION ${EXEC_VERSION} INCLUDE_DIRS ${EXEC_INCLUDE_DIRS} DEPENDS ${EXEC_DEPENDS} PACKAGE_DEPENDS ${EXEC_PACKAGE_DEPENDS} TARGET_DEPENDS ${EXEC_TARGET_DEPENDS} ADDITIONAL_LIBS ${EXEC_ADDITIONAL_LIBS} FILES_CMAKE ${EXEC_FILES_CMAKE} DESCRIPTION "${DESCRIPTION}" ${_EXEC_OPTIONS} ) set(EXECUTABLE_IS_ENABLED ${MODULE_IS_ENABLED}) set(EXECUTABLE_TARGET ${MODULE_TARGET}) if(MODULE_IS_ENABLED) # Add meta dependencies (e.g. on auto-load modules from depending modules) if(ALL_META_DEPENDENCIES) add_dependencies(${MODULE_TARGET} ${ALL_META_DEPENDENCIES}) endif() + add_dependencies(${MODULE_TARGET} MitkLegacyIO) # Create batch files for Windows platforms if(WIN32) set(_batch_file_in "${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_TARGET}.bat.in") if(NOT EXISTS "${_batch_file_in}") set(_batch_file_in "${MITK_CMAKE_DIR}/StartApp.bat.in") endif() if(CMAKE_RUNTIME_OUTPUT_DIRECTORY) set(_batch_file_out_dir "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") else() set(_batch_file_out_dir "${CMAKE_CURRENT_BINARY_DIR}") endif() if(NOT EXEC_NO_BATCH_FILE) foreach(BUILD_TYPE debug release) mitkFunctionCreateWindowsBatchScript( ${_batch_file_in} ${_batch_file_out_dir}/${MODULE_TARGET}_${BUILD_TYPE}.bat ${BUILD_TYPE} ) endforeach() endif() endif() endif() endmacro() diff --git a/CMake/mitkMacroCreateModuleTests.cmake b/CMake/mitkMacroCreateModuleTests.cmake index 1dd422c7e1..93f0d0c025 100644 --- a/CMake/mitkMacroCreateModuleTests.cmake +++ b/CMake/mitkMacroCreateModuleTests.cmake @@ -1,137 +1,138 @@ # # Create tests and testdriver for this module # # Usage: MITK_CREATE_MODULE_TESTS( [EXTRA_DRIVER_INIT init_code] ) # # EXTRA_DRIVER_INIT is inserted as c++ code in the testdriver and will be executed before each test # macro(MITK_CREATE_MODULE_TESTS) MACRO_PARSE_ARGUMENTS(MODULE_TEST "EXTRA_DRIVER_INIT;EXTRA_DRIVER_INCLUDE;EXTRA_DEPENDS" "" ${ARGN}) if(BUILD_TESTING AND MODULE_IS_ENABLED) set(OLD_MOC_H_FILES ${MOC_H_FILES}) set(MOC_H_FILES) include(files.cmake) include_directories(.) if(DEFINED MOC_H_FILES) QT4_WRAP_CPP(MODULE_TEST_GENERATED_MOC_CPP ${MOC_H_FILES} OPTIONS -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) endif(DEFINED MOC_H_FILES) mitk_check_module_dependencies(MODULES ${MODULE_NAME} MitkTestingHelper ${MODULE_TEST_EXTRA_DEPENDS} PACKAGE_DEPENDENCIES_VAR package_deps) _link_directories_for_packages(${package_deps}) set(TESTDRIVER ${MODULE_NAME}TestDriver) set(MODULE_TEST_EXTRA_DRIVER_INIT "${MODULE_TEST_EXTRA_DRIVER_INIT}") # Write a header file containing include directives and custom code # for the test driver. set(TESTDRIVER_EXTRA_INCLUDES ) list(APPEND MODULE_TEST_EXTRA_DRIVER_INCLUDE "mitkLog.h") list(REMOVE_DUPLICATES MODULE_TEST_EXTRA_DRIVER_INCLUDE) foreach(_include ${MODULE_TEST_EXTRA_DRIVER_INCLUDE}) set(TESTDRIVER_EXTRA_INCLUDES "${TESTDRIVER_EXTRA_INCLUDES} #include <${_include}>") endforeach() set(TESTDRIVER_EXTRA_INCLUDES "${TESTDRIVER_EXTRA_INCLUDES} #include std::vector globalCmdLineArgs;") set(_extra_include_file ${CMAKE_CURRENT_BINARY_DIR}/${TESTDRIVER}_extras.h) configure_file(${MITK_CMAKE_DIR}/mitkTestDriverExtraIncludes.h.in ${_extra_include_file}) set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN " for (int avIndex = 1; avIndex < ac; ++avIndex) globalCmdLineArgs.push_back(av[avIndex]); mitk::LoggingBackend::Register(); ${MODULE_TEST_EXTRA_DRIVER_INIT};" ) set(CMAKE_TESTDRIVER_AFTER_TESTMAIN "mitk::LoggingBackend::Unregister();") create_test_sourcelist(MODULETEST_SOURCE ${MODULE_NAME}TestDriver.cpp ${MODULE_TESTS} ${MODULE_IMAGE_TESTS} ${MODULE_SURFACE_TESTS} ${MODULE_CUSTOM_TESTS} EXTRA_INCLUDE ${_extra_include_file} ) add_executable(${TESTDRIVER} ${MODULETEST_SOURCE} ${MODULE_TEST_GENERATED_MOC_CPP} ${TEST_CPP_FILES}) mitk_use_modules(TARGET ${TESTDRIVER} MODULES ${MODULE_NAME} MitkTestingHelper ${MODULE_TEST_EXTRA_DEPENDS} ) if(MODULE_SUBPROJECTS) foreach(subproject ${MODULE_SUBPROJECTS}) add_dependencies(${subproject} ${TESTDRIVER}) endforeach() endif() # Add meta dependencies (e.g. on auto-load modules from depending modules) if(ALL_META_DEPENDENCIES) add_dependencies(${TESTDRIVER} ${ALL_META_DEPENDENCIES}) endif() + add_dependencies(${TESTDRIVER} MitkLegacyIO) # # Now tell CMake which tests should be run. This is done automatically # for all tests in ${KITNAME}_TESTS and ${KITNAME}_IMAGE_TESTS. The IMAGE_TESTS # are run for each image in the TESTIMAGES list. # foreach( test ${MODULE_TESTS} ) get_filename_component(TName ${test} NAME_WE) add_test(${TName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${TName}) # Add labels for CDash subproject support if(MODULE_SUBPROJECTS) set_property(TEST ${TName} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) endif() endforeach( test ) foreach(image ${MODULE_TESTIMAGES} ${ADDITIONAL_TEST_IMAGES} ) if(EXISTS ${image}) set(IMAGE_FULL_PATH ${image}) else(EXISTS ${image}) # todo: maybe search other paths as well # yes, please in mitk/Testing/Data, too set(IMAGE_FULL_PATH ${MITK_DATA_DIR}/${image}) endif(EXISTS ${image}) if(EXISTS ${IMAGE_FULL_PATH}) foreach( test ${MODULE_IMAGE_TESTS} ) get_filename_component(TName ${test} NAME_WE) get_filename_component(ImageName ${IMAGE_FULL_PATH} NAME) add_test(${TName}_${ImageName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${TName} ${IMAGE_FULL_PATH}) # Add labels for CDash subproject support if(MODULE_SUBPROJECTS) set_property(TEST ${TName}_${ImageName} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) endif() endforeach( test ) else(EXISTS ${IMAGE_FULL_PATH}) message("!!!!! No such file: ${IMAGE_FULL_PATH} !!!!!") endif(EXISTS ${IMAGE_FULL_PATH}) endforeach( image ) foreach(surface ${MODULE_TESTSURFACES} ${ADDITIONAL_TEST_SURFACES} ) if(EXISTS ${surface}) set(SURFACE_FULL_PATH ${surface}) else(EXISTS ${surface}) # todo: maybe search other paths as well # yes, please in mitk/Testing/Data, too set(SURFACE_FULL_PATH ${MITK_DATA_DIR}/${surface}) endif(EXISTS ${surface}) if(EXISTS ${SURFACE_FULL_PATH}) foreach( test ${MODULE_SURFACE_TESTS} ) get_filename_component(TName ${test} NAME_WE) get_filename_component(SurfaceName ${SURFACE_FULL_PATH} NAME) add_test(${TName}_${SurfaceName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${TName} ${SURFACE_FULL_PATH}) # Add labels for CDash subproject support if(MODULE_SUBPROJECTS) set_property(TEST ${TName}_${SurfaceName} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) endif() endforeach( test ) else(EXISTS ${SURFACE_FULL_PATH}) message("!!!!! No such surface file: ${SURFACE_FULL_PATH} !!!!!") endif(EXISTS ${SURFACE_FULL_PATH}) endforeach( surface ) set(MOC_H_FILES ${OLD_MOC_H_FILES}) endif(BUILD_TESTING AND MODULE_IS_ENABLED) endmacro(MITK_CREATE_MODULE_TESTS) diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index b90a08109f..181090590a 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -1,43 +1,48 @@ #----------------------------------------------------------------------------- # Configure the CppMicroServices build #----------------------------------------------------------------------------- set(US_ENABLE_AUTOLOADING_SUPPORT ON) set(US_ENABLE_THREADING_SUPPORT ON) # Don't create a "doc" target and don't install the documentation files set(US_NO_DOCUMENTATION ON) # Don't use an install component for SDK artifacts set(US_SDK_INSTALL_COMPONENT "") if(BUILD_TESTING) set(US_BUILD_TESTING ON) endif() -add_subdirectory(CppMicroServices) -set(CppMicroServices_DIR ${CMAKE_CURRENT_BINARY_DIR}/CppMicroServices CACHE PATH "Path to the CppMicroServices library") +set(CppMicroServices_DIR_default "${CMAKE_CURRENT_BINARY_DIR}/CppMicroServices") +set(CppMicroServices_DIR ${CppMicroServices_DIR_default} CACHE PATH "Path to the CppMicroServices library") mark_as_advanced(CppMicroServices_DIR) +if ("${CppMicroServices_DIR}" STREQUAL "${CppMicroServices_DIR_default}") + add_subdirectory(CppMicroServices) +endif() + # create a custom module conf file for CppMicroServices function(_generate_cppmicroservices_conf) set(MITK_MODULE_NAME_PREFIX "") set(MODULE_IS_ENABLED 1) set(MODULE_NAME CppMicroServices) set(MODULE_TARGET ${MODULE_NAME}) set(MODULE_EXTRA_CMAKE_CODE "find_package(CppMicroServices NO_MODULE REQUIRED)") set(MODULE_INCLUDE_DIRS "\${CppMicroServices_INCLUDE_DIRS}") + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "\${US_RUNTIME_LIBRARY_DIRS}") set(CppMicroServices_CONFIG_FILE "${CMAKE_BINARY_DIR}/${MODULES_CONF_DIRNAME}/CppMicroServicesConfig.cmake" CACHE INTERNAL "Path to module config" FORCE) configure_file(${MITK_SOURCE_DIR}/CMake/moduleConf.cmake.in ${CppMicroServices_CONFIG_FILE} @ONLY) endfunction() _generate_cppmicroservices_conf() #----------------------------------------------------------------------------- # Add the MITK Core library #----------------------------------------------------------------------------- set(MITK_DEFAULT_SUBPROJECTS MITK-Core) add_subdirectory(Code) diff --git a/Core/Code/Common/mitkExceptionMacro.h b/Core/Code/Common/mitkExceptionMacro.h index b26b0c5d26..b63ada2deb 100644 --- a/Core/Code/Common/mitkExceptionMacro.h +++ b/Core/Code/Common/mitkExceptionMacro.h @@ -1,96 +1,96 @@ /*=================================================================== 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. ===================================================================*/ #ifndef MITK_EXCEPTIONMACRO_H_DEFINED #define MITK_EXCEPTIONMACRO_H_DEFINED #include #include #include #include "mitkException.h" /** The exception macro is used to throw an exception * (i.e., usually a condition that results in program failure). * * Example usage looks like: * mitkThrow() << "this is error info"; */ #define mitkThrow() throw mitk::Exception(__FILE__,__LINE__,"",ITK_LOCATION) /** The rethrow macro is used to rethrow an existing exception. The * rethrow information (file,line of code) is then additionally stored * in the exception. To check if an exception was rethrown you can use * the methods GetNumberOfRethrows() and GetRethrowData(). * * Example usage: * try * { * //some code that throws an exception * } * catch(mitk::Exception e) * { * //here we want to rethrow the exception - * mitkmitkReThrow(e) << "Message that will be appended to the exception (optional)"; + * mitkReThrow(e) << "Message that will be appended to the exception (optional)"; * } */ #define mitkReThrow(mitkexception) \ mitkexception.AddRethrowData(__FILE__,__LINE__,"Rethrow by mitkReThrow macro.");\ throw mitkexception /** The specialized exception macro is used to throw exceptions * in cases of specialized errors. This means the second parameter must be a class which * inherits from mitk::Exception. An object of this exception is thrown when using the macro. * Thus, more differentiated excaptions can be thrown, when needed. * * Example usage: * mitkSpecializedExceptionMacro(mitk::MySpecializedException) << "this is error info"; */ #define mitkThrowException(classname) throw classname(__FILE__,__LINE__,"",ITK_LOCATION) /** Class macro for MITK exception classes. * All MITK exception classes should derive from MITK::Exception. */ #define mitkExceptionClassMacro(ClassName,SuperClassName) \ ClassName(const char *file, unsigned int lineNumber, const char *desc, const char *loc) :\ SuperClassName(file,lineNumber,desc,loc){}\ itkTypeMacro(ClassName, SuperClassName);\ /** \brief Definition of the bit shift operator for this class. It can be used to add messages.*/\ template inline ClassName& operator<<(const T& data)\ {\ std::stringstream ss;\ ss << this->GetDescription() << data;\ this->SetDescription(ss.str());\ return *this;\ }\ /** \brief Definition of the bit shift operator for this class (for non const data).*/\ template inline ClassName& operator<<(T& data)\ {\ std::stringstream ss;\ ss << this->GetDescription() << data;\ this->SetDescription(ss.str());\ return *this;\ }\ /** \brief Definition of the bit shift operator for this class (for functions).*/\ inline ClassName& operator<<(std::ostream& (*func)(std::ostream&))\ {\ std::stringstream ss;\ ss << this->GetDescription() << func;\ this->SetDescription(ss.str());\ return *this;\ }\ #endif diff --git a/Core/Code/IO/mitkAbstractFileReader.cpp b/Core/Code/IO/mitkAbstractFileReader.cpp index d3a6edb344..616869e162 100644 --- a/Core/Code/IO/mitkAbstractFileReader.cpp +++ b/Core/Code/IO/mitkAbstractFileReader.cpp @@ -1,410 +1,382 @@ /*=================================================================== 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 #include #include #include -#include - #include namespace mitk { -class AbstractFileReader::Impl +class AbstractFileReader::Impl : public FileReaderWriterBase { public: Impl() - : m_Ranking(0) + : FileReaderWriterBase() , m_PrototypeFactory(NULL) {} Impl(const Impl& other) - : m_MimeType(other.m_MimeType) - , m_Category(other.m_Category) - , m_Extensions(other.m_Extensions) - , m_Description(other.m_Description) - , m_Ranking(other.m_Ranking) - , m_Options(other.m_Options) + : FileReaderWriterBase(other) , m_PrototypeFactory(NULL) {} - std::string m_MimeType; - std::string m_Category; - std::vector m_Extensions; - std::string m_Description; - int m_Ranking; - - /** - * \brief Options supported by this reader. Set sensible default values! - * - * Can be left emtpy if no special options are required. - */ - IFileReader::OptionList m_Options; - us::PrototypeServiceFactory* m_PrototypeFactory; - Message1 m_ProgressMessage; - - SimpleMimeType m_SimpleMimeType; - us::ServiceRegistration m_MimeTypeReg; }; AbstractFileReader::AbstractFileReader() : d(new Impl) { } AbstractFileReader::~AbstractFileReader() { delete d->m_PrototypeFactory; - if (d->m_MimeTypeReg) - { - d->m_MimeTypeReg.Unregister(); - } + d->UnregisterMimeType(); } AbstractFileReader::AbstractFileReader(const AbstractFileReader& other) : d(new Impl(*other.d.get())) { } AbstractFileReader::AbstractFileReader(const MimeType& mimeType, const std::string& description) : d(new Impl) { - d->m_MimeType = mimeType; - d->m_Description = description; + d->SetMimeType(mimeType); + d->SetDescription(description); } AbstractFileReader::AbstractFileReader(const std::string& extension, const std::string& description) : d(new Impl) { - d->m_Description = description; - - d->m_Extensions.push_back(extension); + d->SetDescription(description); + d->AddExtension(extension); } ////////////////////// Reading ///////////////////////// std::vector > AbstractFileReader::Read(const std::string& path) { if (!itksys::SystemTools::FileExists(path.c_str())) + { mitkThrow() << "File '" + path + "' not found."; + } std::ifstream stream; - stream.open(path.c_str()); - return this->Read(stream); + stream.open(path.c_str(), std::ios_base::in | std::ios_base::binary); + try + { + return this->Read(stream); + } + catch (mitk::Exception& e) + { + mitkReThrow(e) << "Error reading file '" << path << "'"; + } + catch (const std::exception& e) + { + mitkThrow() << "Error reading file '" << path << "': " << e.what(); + } } std::vector > AbstractFileReader::Read(std::istream& stream) { // Create a temporary file and copy the data to it std::ofstream tmpOutputStream; std::string tmpFilePath = IOUtil::CreateTemporaryFile(tmpOutputStream); tmpOutputStream << stream.rdbuf(); tmpOutputStream.close(); // Now read from the temporary file std::vector > result = this->Read(tmpFilePath); std::remove(tmpFilePath.c_str()); return result; } -std::vector,bool> > AbstractFileReader::Read(const std::string& path, DataStorage& /*ds*/) +DataStorage::SetOfObjects::Pointer AbstractFileReader::Read(const std::string& path, DataStorage& ds) { - std::vector > result; + DataStorage::SetOfObjects::Pointer result = DataStorage::SetOfObjects::New(); std::vector data = this->Read(path); for (std::vector::iterator iter = data.begin(); iter != data.end(); ++iter) { - result.push_back(std::make_pair(*iter, false)); + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(*iter); + this->SetDefaultDataNodeProperties(node, path); + ds.Add(node); + result->InsertElement(result->Size(), node); } return result; } -std::vector,bool> > AbstractFileReader::Read(std::istream& stream, DataStorage& /*ds*/) +DataStorage::SetOfObjects::Pointer AbstractFileReader::Read(std::istream& stream, DataStorage& ds) { - std::vector > result; + DataStorage::SetOfObjects::Pointer result = DataStorage::SetOfObjects::New(); std::vector data = this->Read(stream); for (std::vector::iterator iter = data.begin(); iter != data.end(); ++iter) { - result.push_back(std::make_pair(*iter, false)); + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(*iter); + this->SetDefaultDataNodeProperties(node, std::string()); + ds.Add(node); + result->InsertElement(result->Size(), node); } return result; } + //////////// µS Registration & Properties ////////////// us::ServiceRegistration AbstractFileReader::RegisterService(us::ModuleContext* context) { if (d->m_PrototypeFactory) return us::ServiceRegistration(); if(context == NULL) { context = us::GetModuleContext(); } - d->m_MimeTypeReg = this->RegisterMimeType(context); + d->RegisterMimeType(context); if (this->GetMimeType().empty()) { MITK_WARN << "Not registering reader " << typeid(this).name() << " due to empty MIME type."; return us::ServiceRegistration(); } struct PrototypeFactory : public us::PrototypeServiceFactory { AbstractFileReader* const m_Prototype; PrototypeFactory(AbstractFileReader* prototype) : m_Prototype(prototype) {} us::InterfaceMap GetService(us::Module* /*module*/, const us::ServiceRegistrationBase& /*registration*/) { return us::MakeInterfaceMap(m_Prototype->Clone()); } void UngetService(us::Module* /*module*/, const us::ServiceRegistrationBase& /*registration*/, const us::InterfaceMap& service) { delete us::ExtractInterface(service); } }; d->m_PrototypeFactory = new PrototypeFactory(this); us::ServiceProperties props = this->GetServiceProperties(); return context->RegisterService(d->m_PrototypeFactory, props); } us::ServiceProperties AbstractFileReader::GetServiceProperties() const { - if ( d->m_Description.empty() ) - MITK_WARN << "Registered a Reader with no description defined. Reader will have no human readable extension information.)"; - us::ServiceProperties result; result[IFileReader::PROP_DESCRIPTION()] = this->GetDescription(); result[IFileReader::PROP_MIMETYPE()] = this->GetMimeType(); result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); - - for (IFileReader::OptionList::const_iterator it = d->m_Options.begin(); it != d->m_Options.end(); ++it) { - if (it->second) - result[it->first] = std::string("true"); - else result[it->first] = std::string("false"); - } return result; } us::ServiceRegistration AbstractFileReader::RegisterMimeType(us::ModuleContext* context) { - if (context == NULL) throw std::invalid_argument("The context argument must not be NULL."); - - const std::string mimeType = this->GetMimeType(); - std::vector extensions = this->GetExtensions(); - const std::string primaryExtension = extensions.empty() ? "" : extensions.front(); - std::sort(extensions.begin(), extensions.end()); - extensions.erase(std::unique(extensions.begin(), extensions.end()), extensions.end()); - - us::ServiceProperties props; - - props[IMimeType::PROP_ID()] = mimeType; - props[IMimeType::PROP_CATEGORY()] = this->GetCategory(); - props[IMimeType::PROP_EXTENSIONS()] = extensions; - props[IMimeType::PROP_DESCRIPTION()] = std::string("Generated MIME type from mitk::AbstractFileReader"); - props[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); - - // If the mime type is set and the list of extensions is not empty, - // register a new IMimeType service - if (!mimeType.empty() && !extensions.empty()) - { - return context->RegisterService(&d->m_SimpleMimeType, props); - } - - // If the mime type is set and the list of extensions is empty, - // look up the mime type in the registry and print a warning if - // there is none - if (!mimeType.empty() && extensions.empty()) - { - if(us::GetModuleContext()->GetServiceReferences(us::LDAPProp(IMimeType::PROP_ID()) == mimeType).empty()) - { - MITK_WARN << "Registering a MITK reader with an unknown MIME type " << mimeType; - } - return us::ServiceRegistration(); - } - - // If the mime type is empty, get a mime type using the extensions list - assert(mimeType.empty()); - mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); - - if(extensions.empty()) - { - MITK_WARN << "Trying to register a MITK reader with an empty mime type and empty extension list."; - return us::ServiceRegistration(); - } - else if(extensions.size() == 1) - { - // If there is only one extension, try to look-up an existing mime tpye - std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForExtension(extensions.front()); - if (!mimeTypes.empty()) - { - d->m_MimeType = mimeTypes.front(); - } - } - - if (d->m_MimeType.empty()) - { - // There is no registered mime type for the extension or the extensions - // list contains more than one entry. - // Register a new mime type by creating a synthetic mime type id from the - // first extension in the list - d->m_MimeType = "application/vnd.mitk." + primaryExtension; - props[IMimeType::PROP_ID()] = d->m_MimeType; - return context->RegisterService(&d->m_SimpleMimeType, props); - } - else - { - // A mime type for one of the listed extensions was found, do nothing. - return us::ServiceRegistration(); - } + return d->RegisterMimeType(context); } void AbstractFileReader::SetMimeType(const std::string& mimeType) { - d->m_MimeType = mimeType; + d->SetMimeType(mimeType); } void AbstractFileReader::SetCategory(const std::string& category) { - d->m_Category = category; + d->SetCategory(category); } void AbstractFileReader::AddExtension(const std::string& extension) { - d->m_Extensions.push_back(extension); + d->AddExtension(extension); } void AbstractFileReader::SetDescription(const std::string& description) { - d->m_Description = description; + d->SetDescription(description); } void AbstractFileReader::SetRanking(int ranking) { - d->m_Ranking = ranking; + d->SetRanking(ranking); } int AbstractFileReader::GetRanking() const { - return d->m_Ranking; + return d->GetRanking(); } //////////////////////// Options /////////////////////// -IFileReader::OptionList AbstractFileReader::GetOptions() const +void AbstractFileReader::SetDefaultOptions(const IFileReader::Options& defaultOptions) +{ + d->SetDefaultOptions(defaultOptions); +} + +IFileReader::Options AbstractFileReader::GetDefaultOptions() const +{ + return d->GetDefaultOptions(); +} + +IFileReader::Options AbstractFileReader::GetOptions() const { - return d->m_Options; + return d->GetOptions(); } -void AbstractFileReader::SetOptions(const OptionList& options) +us::Any AbstractFileReader::GetOption(const std::string& name) const { - if (options.size() != d->m_Options.size()) MITK_WARN << "Number of set Options differs from Number of available Options, which is a sign of false usage. Please consult documentation"; - d->m_Options = options; + return d->GetOption(name); +} + +void AbstractFileReader::SetOptions(const Options& options) +{ + d->SetOptions(options); +} + +void AbstractFileReader::SetOption(const std::string& name, const us::Any& value) +{ + d->SetOption(name, value); } ////////////////// MISC ////////////////// bool AbstractFileReader::CanRead(const std::string& path) const { if (!itksys::SystemTools::FileExists(path.c_str(), true)) { return false; } // Default implementation only checks if extension is correct std::string extension = itksys::SystemTools::GetFilenameExtension(path); extension = extension.substr(1, extension.size()-1); - if (std::find(d->m_Extensions.begin(), d->m_Extensions.end(), extension) == d->m_Extensions.end()) + if (!d->HasExtension(extension)) { return false; } std::ifstream stream(path.c_str()); return this->CanRead(stream); } bool AbstractFileReader::CanRead(std::istream& stream) const { return stream.good(); } void AbstractFileReader::AddProgressCallback(const ProgressCallback& callback) { - d->m_ProgressMessage += callback; + d->AddProgressCallback(callback); } void AbstractFileReader::RemoveProgressCallback(const ProgressCallback& callback) { - d->m_ProgressMessage -= callback; + d->RemoveProgressCallback(callback); } ////////////////// µS related Getters ////////////////// std::string AbstractFileReader::GetCategory() const { - return d->m_Category; + return d->GetCategory(); } std::string AbstractFileReader::GetMimeType() const { - return d->m_MimeType; + return d->GetMimeType(); } std::vector AbstractFileReader::GetExtensions() const { - return d->m_Extensions; + return d->GetExtensions(); } std::string AbstractFileReader::GetDescription() const { - return d->m_Description; + return d->GetDescription(); } AbstractFileReader::MimeType::MimeType(const std::string& mimeType) : std::string(mimeType) { if (this->empty()) { throw std::invalid_argument("MIME type must not be empty."); } } AbstractFileReader::MimeType::MimeType() { } +void AbstractFileReader::SetDefaultDataNodeProperties(DataNode* node, const std::string& filePath) +{ + // path + if (!filePath.empty()) + { + mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New( itksys::SystemTools::GetFilenamePath(filePath) ); + node->SetProperty(StringProperty::PATH, pathProp); + } + + // name already defined? + mitk::StringProperty::Pointer nameProp = dynamic_cast(node->GetProperty("name")); + if(nameProp.IsNull() || (strcmp(nameProp->GetValue(),"No Name!")==0)) + { + // name already defined in BaseData + mitk::StringProperty::Pointer baseDataNameProp = dynamic_cast(node->GetData()->GetProperty("name").GetPointer() ); + if(baseDataNameProp.IsNull() || (strcmp(baseDataNameProp->GetValue(),"No Name!")==0)) + { + // name neither defined in node, nor in BaseData -> name = filebasename; + nameProp = mitk::StringProperty::New(itksys::SystemTools::GetFilenameWithoutExtension(itksys::SystemTools::GetFilenameName(filePath))); + node->SetProperty("name", nameProp); + } + else + { + // name defined in BaseData! + nameProp = mitk::StringProperty::New(baseDataNameProp->GetValue()); + node->SetProperty("name", nameProp); + } + } + + // visibility + if(!node->GetProperty("visible")) + { + node->SetVisibility(true); + } +} + } diff --git a/Core/Code/IO/mitkAbstractFileReader.h b/Core/Code/IO/mitkAbstractFileReader.h index b5b4944719..5f7e7628e5 100644 --- a/Core/Code/IO/mitkAbstractFileReader.h +++ b/Core/Code/IO/mitkAbstractFileReader.h @@ -1,201 +1,219 @@ /*=================================================================== 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. ===================================================================*/ #ifndef AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 #define AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 // Macro #include // MITK #include #include -#include +#include // Microservices #include #include #include namespace us { struct PrototypeServiceFactory; } namespace mitk { /** - * @brief Interface class of readers that read from files + * @brief Base class for creating mitk::BaseData objects from files or streams. * @ingroup Process */ class MITK_CORE_EXPORT AbstractFileReader : public mitk::IFileReader { public: + /** + * @brief Reads the given \c path and creates a list BaseData objects. + * + * The default implementation opens a std::ifstream in binary mode for reading + * and passed the stream to Read(std::istream&). + * + * @param path The absolute path to a file include the file name extension. + * @return + */ virtual std::vector > Read(const std::string& path); virtual std::vector > Read(std::istream& stream) = 0; - virtual std::vector,bool> > Read(const std::string& path, mitk::DataStorage& ds); + virtual DataStorage::SetOfObjects::Pointer Read(const std::string& path, mitk::DataStorage& ds); - virtual std::vector,bool> > Read(std::istream& stream, mitk::DataStorage& ds); + virtual DataStorage::SetOfObjects::Pointer Read(std::istream& stream, mitk::DataStorage& ds); - virtual OptionList GetOptions() const; + virtual Options GetOptions() const; + virtual us::Any GetOption(const std::string &name) const; - virtual void SetOptions(const OptionList& options); + virtual void SetOptions(const Options& options); + virtual void SetOption(const std::string& name, const us::Any& value); /** * @brief Checks if the specified path can be read. * * The default implementation checks if the path exists and contains a * file extension associated with the mime-type of this reader. * It then creates a std::ifstream object for the given path and * calls CanRead(const std::istream&). * * @param path The absolute path to a file. * @return \c true if the file can be read, \c false otherwise. */ virtual bool CanRead(const std::string& path) const; /** * @brief Checks if the specified input stream can be read. * * @param stream The stream to be read. * @return \c true if the stream is good, \c false otherwise. */ virtual bool CanRead(std::istream& stream) const; virtual void AddProgressCallback(const ProgressCallback& callback); virtual void RemoveProgressCallback(const ProgressCallback& callback); /** * Associate this reader with the MIME type returned by the current IMimeTypeProvider * service for the provided extension if the MIME type exists, otherwise registers * a new MIME type when RegisterService() is called. * * If no MIME type for \c extension is already registered, a call to RegisterService() * will register a new MIME type and associate this reader instance with it. The MIME * type id can be set via SetMimeType() or it will be auto-generated using \c extension, * having the form "application/vnd.mitk.". * * @param extension The file extension (without a leading period) for which a registered * IMimeType object is looked up and associated with this reader instance. * @param description A human readable description of this reader. */ us::ServiceRegistration RegisterService(us::ModuleContext* context = us::GetModuleContext()); protected: class MITK_CORE_EXPORT MimeType : public std::string { public: MimeType(const std::string& mimeType); private: MimeType(); friend class AbstractFileReader; }; AbstractFileReader(); ~AbstractFileReader(); AbstractFileReader(const AbstractFileReader& other); /** * Associate this reader instance with the given MIME type. * * @param mimeType The mime type this reader can read. * @param description A human readable description of this reader. * * @throws std::invalid_argument if \c mimeType is empty. * * @see RegisterService */ explicit AbstractFileReader(const MimeType& mimeType, const std::string& description); /** * Associate this reader with the given file extension. * * Additonal file extensions can be added by sub-classes by calling AddExtension * or SetExtensions. * * @param extension The file extension (without a leading period) for which a registered * IMimeType object is looked up and associated with this reader instance. * @param description A human readable description of this reader. * * @see RegisterService */ explicit AbstractFileReader(const std::string& extension, const std::string& description); virtual us::ServiceProperties GetServiceProperties() const; - /** - * @return The mime-type this reader can handle. - */ - std::string GetMimeType() const; - /** * Registers a new IMimeType service object. * * This method is called from RegisterService and the default implementation * registers a new IMimeType service object if all of the following conditions * are true: * * - The reader * * @param context * @return * @throws std::invalid_argument if \c context is NULL. */ virtual us::ServiceRegistration RegisterMimeType(us::ModuleContext* context); void SetMimeType(const std::string& mimeType); + + /** + * @return The mime-type this reader can handle. + */ + std::string GetMimeType() const; + void SetCategory(const std::string& category); + std::string GetCategory() const; + + std::vector GetExtensions() const; void AddExtension(const std::string& extension); + void SetDescription(const std::string& description); + std::string GetDescription() const; + + void SetDefaultOptions(const Options& defaultOptions); + Options GetDefaultOptions() const; /** * \brief Set the service ranking for this file reader. * * Default is zero and should only be chosen differently for a reason. * The ranking is used to determine which reader to use if several * equivalent readers have been found. * It may be used to replace a default reader from MITK in your own project. * E.g. if you want to use your own reader for nrrd files instead of the default, * implement it and give it a higher ranking than zero. */ void SetRanking(int ranking); int GetRanking() const; - std::string GetCategory() const; - std::vector GetExtensions() const; - std::string GetDescription() const; + virtual void SetDefaultDataNodeProperties(DataNode* node, const std::string& filePath); private: AbstractFileReader& operator=(const AbstractFileReader& other); virtual mitk::IFileReader* Clone() const = 0; class Impl; std::auto_ptr d; }; } // namespace mitk #endif /* AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkAbstractFileWriter.cpp b/Core/Code/IO/mitkAbstractFileWriter.cpp index 6919c7bf7e..006708ec75 100644 --- a/Core/Code/IO/mitkAbstractFileWriter.cpp +++ b/Core/Code/IO/mitkAbstractFileWriter.cpp @@ -1,266 +1,300 @@ /*=================================================================== 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 #include #include #include #include namespace mitk { -class AbstractFileWriter::Impl +class AbstractFileWriter::Impl : public FileReaderWriterBase { public: Impl() - : m_Ranking(0) + : FileReaderWriterBase() , m_PrototypeFactory(NULL) {} Impl(const Impl& other) - : m_MimeType(other.m_MimeType) - , m_Category(other.m_Category) + : FileReaderWriterBase(other) , m_BaseDataType(other.m_BaseDataType) - , m_Extensions(other.m_Extensions) - , m_Description(other.m_Description) - , m_Ranking(other.m_Ranking) - , m_Options(other.m_Options) , m_PrototypeFactory(NULL) {} - std::string m_MimeType; - std::string m_Category; std::string m_BaseDataType; - std::vector m_Extensions; - std::string m_Description; - int m_Ranking; - - /** - * \brief Options supported by this writer. Set sensible default values! - * - * Can be left emtpy if no special options are required. - */ - IFileWriter::OptionList m_Options; - us::PrototypeServiceFactory* m_PrototypeFactory; - Message1 m_ProgressMessage; - - SimpleMimeType m_SimpleMimeType; - us::ServiceRegistration m_MimeTypeReg; }; AbstractFileWriter::AbstractFileWriter() : d(new Impl) { } AbstractFileWriter::~AbstractFileWriter() { delete d->m_PrototypeFactory; - if (d->m_MimeTypeReg) - { - d->m_MimeTypeReg.Unregister(); - } + d->UnregisterMimeType(); } AbstractFileWriter::AbstractFileWriter(const AbstractFileWriter& other) : d(new Impl(*other.d.get())) { } +AbstractFileWriter::AbstractFileWriter(const std::string& baseDataType, const MimeType& mimeType, + const std::string& description) + : d(new Impl) +{ + d->m_BaseDataType = baseDataType; + d->SetMimeType(mimeType); + d->SetDescription(description); +} + AbstractFileWriter::AbstractFileWriter(const std::string& baseDataType, const std::string& extension, const std::string& description) : d(new Impl) { d->m_BaseDataType = baseDataType; - d->m_Description = description; - d->m_Extensions.push_back(extension); + d->SetDescription(description); + d->AddExtension(extension); } ////////////////////// Writing ///////////////////////// void AbstractFileWriter::Write(const BaseData* data, const std::string& path) { std::ofstream stream; stream.open(path.c_str()); - this->Write(data, stream); + try + { + this->Write(data, stream); + } + catch(mitk::Exception& e) + { + mitkReThrow(e) << "Error writing file '" << path << "'"; + } + catch(const std::exception& e) + { + mitkThrow() << "Error writing file '" << path << "': " << e.what(); + } } void AbstractFileWriter::Write(const BaseData* data, std::ostream& stream) { // Create a temporary file and write the data to it std::ofstream tmpOutputStream; std::string tmpFilePath = IOUtil::CreateTemporaryFile(tmpOutputStream); this->Write(data, tmpFilePath); tmpOutputStream.close(); // Now copy the contents std::ifstream tmpInputStream(tmpFilePath.c_str(), std::ios_base::binary); stream << tmpInputStream.rdbuf(); tmpInputStream.close(); std::remove(tmpFilePath.c_str()); } //////////// µS Registration & Properties ////////////// us::ServiceRegistration AbstractFileWriter::RegisterService(us::ModuleContext* context) { if (d->m_PrototypeFactory) return us::ServiceRegistration(); + if(context == NULL) + { + context = us::GetModuleContext(); + } + + d->RegisterMimeType(context); + + if (this->GetMimeType().empty()) + { + MITK_WARN << "Not registering writer " << typeid(this).name() << " due to empty MIME type."; + return us::ServiceRegistration(); + } + struct PrototypeFactory : public us::PrototypeServiceFactory { AbstractFileWriter* const m_Prototype; PrototypeFactory(AbstractFileWriter* prototype) : m_Prototype(prototype) {} us::InterfaceMap GetService(us::Module* /*module*/, const us::ServiceRegistrationBase& /*registration*/) { return us::MakeInterfaceMap(m_Prototype->Clone()); } void UngetService(us::Module* /*module*/, const us::ServiceRegistrationBase& /*registration*/, const us::InterfaceMap& service) { delete us::ExtractInterface(service); } }; d->m_PrototypeFactory = new PrototypeFactory(this); us::ServiceProperties props = this->GetServiceProperties(); return context->RegisterService(d->m_PrototypeFactory, props); } us::ServiceProperties AbstractFileWriter::GetServiceProperties() const { - if ( d->m_Extensions.empty() ) - MITK_WARN << "Registered a Writer with no extension defined (m_Extension is empty). Writer will not be found by calls from WriterManager.)"; - if ( d->m_BaseDataType.empty() ) - MITK_WARN << "Registered a Writer with no BasedataType defined (m_BasedataType is empty). Writer will not be found by calls from WriterManager.)"; - if ( d->m_Description.empty() ) - MITK_WARN << "Registered a Writer with no description defined (m_Description is empty). Writer will have no human readable extension information in FileDialogs.)"; - us::ServiceProperties result; - //result[IFileWriter::PROP_EXTENSION()] = d->m_Extensions; - result[IFileWriter::PROP_DESCRIPTION()] = d->m_Description; + result[IFileWriter::PROP_DESCRIPTION()] = this->GetDescription(); + result[IFileWriter::PROP_MIMETYPE()] = this->GetMimeType(); result[IFileWriter::PROP_BASEDATA_TYPE()] = d->m_BaseDataType; - result[us::ServiceConstants::SERVICE_RANKING()] = d->m_Ranking; + result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); - for (IFileWriter::OptionList::const_iterator it = d->m_Options.begin(); it != d->m_Options.end(); ++it) - { - result[it->first] = std::string("true"); - } +// for (IFileWriter::OptionList::const_iterator it = d->m_Options.begin(); it != d->m_Options.end(); ++it) +// { +// result[it->first] = std::string("true"); +// } return result; } +std::string AbstractFileWriter::GetMimeType() const +{ + return d->GetMimeType(); +} + +us::ServiceRegistration AbstractFileWriter::RegisterMimeType(us::ModuleContext* context) +{ + return d->RegisterMimeType(context); +} + +void AbstractFileWriter::SetMimeType(const std::string& mimeType) +{ + d->SetMimeType(mimeType); +} + void AbstractFileWriter::SetRanking(int ranking) { - d->m_Ranking = ranking; + d->SetRanking(ranking); } //////////////////////// Options /////////////////////// -IFileWriter::OptionList AbstractFileWriter::GetOptions() const +IFileWriter::Options AbstractFileWriter::GetOptions() const { - return d->m_Options; + return d->GetOptions(); } -void AbstractFileWriter::SetOptions(const OptionList& options) +us::Any AbstractFileWriter::GetOption(const std::string& name) const { - if (options.size() != d->m_Options.size()) MITK_WARN << "Number of set Options differs from Number of available Options, which is a sign of false usage. Please consult documentation"; - d->m_Options = options; + return d->GetOption(name); } -////////////////// MISC ////////////////// +void AbstractFileWriter::SetOption(const std::string& name, const us::Any& value) +{ + d->SetOption(name, value); +} -bool AbstractFileWriter::CanWrite(const BaseData* data) const +void AbstractFileWriter::SetOptions(const Options& options) { - // Default implementation only checks if basedatatype is correct - std::string externalDataType = data->GetNameOfClass(); - return (externalDataType == d->m_BaseDataType); + d->SetOptions(options); } +////////////////// MISC ////////////////// + + void AbstractFileWriter::AddProgressCallback(const ProgressCallback& callback) { - d->m_ProgressMessage += callback; + d->AddProgressCallback(callback); } void AbstractFileWriter::RemoveProgressCallback(const ProgressCallback& callback) { - d->m_ProgressMessage -= callback; + d->RemoveProgressCallback(callback); } ////////////////// µS related Getters ////////////////// int AbstractFileWriter::GetRanking() const { - return d->m_Ranking; + return d->GetRanking(); } std::vector AbstractFileWriter::GetExtensions() const { - return d->m_Extensions; + return d->GetExtensions(); } void AbstractFileWriter::AddExtension(const std::string& extension) { - d->m_Extensions.push_back(extension); + d->AddExtension(extension); } void AbstractFileWriter::SetCategory(const std::string& category) { - d->m_Category = category; + d->SetCategory(category); } std::string AbstractFileWriter::GetCategory() const { - return d->m_Category; + return d->GetCategory(); } void AbstractFileWriter::SetBaseDataType(const std::string& baseDataType) { d->m_BaseDataType = baseDataType; } std::string AbstractFileWriter::GetDescription() const { - return d->m_Description; + return d->GetDescription(); } std::string AbstractFileWriter::GetBaseDataType() const { return d->m_BaseDataType; } void AbstractFileWriter::SetDescription(const std::string& description) { - d->m_Description = description; + d->SetDescription(description); +} + +AbstractFileWriter::MimeType::MimeType(const std::string& mimeType) + : std::string(mimeType) +{ + if (this->empty()) + { + throw std::invalid_argument("MIME type must not be empty."); + } +} + +AbstractFileWriter::MimeType::MimeType() +{ } } diff --git a/Core/Code/IO/mitkAbstractFileWriter.h b/Core/Code/IO/mitkAbstractFileWriter.h index 6b42c021f0..5395c9d7d9 100644 --- a/Core/Code/IO/mitkAbstractFileWriter.h +++ b/Core/Code/IO/mitkAbstractFileWriter.h @@ -1,171 +1,177 @@ /*=================================================================== 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. ===================================================================*/ #ifndef AbstractFileWriter_H_HEADER_INCLUDED_C1E7E521 #define AbstractFileWriter_H_HEADER_INCLUDED_C1E7E521 // Macro #include // MITK #include +#include // Microservices #include #include #include #include namespace us { struct PrototypeServiceFactory; } namespace mitk { +/** + * @brief Base class for writing mitk::BaseData objects to files or streams. + * + * In general, all file writers should derive from this class, this way it is + * made sure that the new implementation is + * exposed to the Microservice-Framework and that is automatically available troughout MITK. + * The default implementation only requires one Write() + * method and the Clone() method to be implemented. + * + * @ingroup Process + */ +class MITK_CORE_EXPORT AbstractFileWriter : public mitk::IFileWriter +{ +public: + /** - * @brief This abstract class gives a meaningful default implementations to most methods of mitkIFileWriter.h. - * - * In general, all FileWriters should derive from this class, this way it is made sure that the new implementation is - * exposed to the Microservice-Framework and that is automatically available troughout MITK. - * The default implementation only requires the two write - * methods and the Clone() method to be implemented. Be sure to set all important members in the constructor. These are: - *
    - *
  • m_Extension: To define which file extension can be written. - *
  • m_Description: To give a human readable name for this writer to be displayed in FileDialogs. - *
  • m_BasedataType: To define which type of Basedata this fileWriter can handle. - *
  • (Optional) m_Priority: To make this writer rank higher when choosing writers automatically - *
  • (Optional) m_SupportedOptions: To define which options this writer can handle. Options can modify writing behaviour (e.g. set a compression) - *
- * You can also use the protected constructor for this. - * - * @ingroup Process + * \brief Write the data in data to the the location specified in path */ - class MITK_CORE_EXPORT AbstractFileWriter : public mitk::IFileWriter + virtual void Write(const BaseData* data, const std::string& path); + + /** + * \brief Write the data in data to the the stream specified in stream + */ + virtual void Write(const BaseData* data, std::ostream& stream ) = 0; + + virtual Options GetOptions() const; + virtual us::Any GetOption(const std::string &name) const; + + virtual void SetOptions(const Options& options); + virtual void SetOption(const std::string& name, const us::Any& value); + + virtual void AddProgressCallback(const ProgressCallback& callback); + + virtual void RemoveProgressCallback(const ProgressCallback& callback); + + us::ServiceRegistration RegisterService(us::ModuleContext* context = us::GetModuleContext()); + +protected: + + class MITK_CORE_EXPORT MimeType : public std::string { public: - - /** - * \brief Write the data in data to the the location specified in path - */ - virtual void Write(const BaseData* data, const std::string& path); - - /** - * \brief Write the data in data to the the stream specified in stream - */ - virtual void Write(const BaseData* data, std::ostream& stream ) = 0; - - /** - * \brief returns a list of the supported Options - * - * Options are strings that are treated as flags when passed to the read method. - */ - virtual OptionList GetOptions() const; - - virtual void SetOptions(const OptionList& options); - - /** - * \brief Return true if this writer can confirm that it can read this file and false otherwise. - * - * The default implementation of AbstractFileWriter checks if the supplied filename is of the same extension as m_extension. - * Overwrite this method if you require more specific behaviour - */ - virtual bool CanWrite(const BaseData* data) const; - - virtual void AddProgressCallback(const ProgressCallback& callback); - - virtual void RemoveProgressCallback(const ProgressCallback& callback); - - us::ServiceRegistration RegisterService(us::ModuleContext* context = us::GetModuleContext()); - - protected: - AbstractFileWriter(); - ~AbstractFileWriter(); - - AbstractFileWriter(const AbstractFileWriter& other); - - AbstractFileWriter(const std::string& basedataType, const std::string& extension, const std::string& description); - - virtual us::ServiceProperties GetServiceProperties() const; - - /** - * @return The mime-type this writer supports. - */ - std::string GetMimeType() const; - - void SetMimeType(const std::string& mimeType); - - /** - * \brief Returns the priority which defined how 'good' the FileWriter can handle it's file format. - * - * Default is zero and should only be chosen differently for a reason. - * The priority is intended to be used by the MicroserviceFramework to determine - * which reader to use if several equivalent readers have been found. - * It may be used to replace a default reader from MITK in your own project. - * E.g. if you want to use your own writer for *.nrrd files instead of the default, - * implement it and give it a higher priority than zero. - * - * This method has a default implementation and need not be reimplemented, simply set m_Priority in the constructor. - */ - void SetRanking(int ranking); - int GetRanking() const; - - /** - * \brief returns the file extension that this FileWriter is able to handle. - * - * Please enter only the characters after the fullstop, e.g "nrrd" is correct - * while "*.nrrd" and ".nrrd" are incorrect. - * - * This method has a default implementation and need not be reimplemented, simply set m_Extension in the constructor. - */ - std::vector GetExtensions() const; - void AddExtension(const std::string& extension); - - void SetCategory(const std::string& category); - std::string GetCategory() const; - - /** - * \brief returns the name of the itk Basedata that this FileWriter is able to handle. - * - * The correct value is the one given as the first parameter in the mitkNewMacro of that Basedata derivate. - * You can also retrieve it by calling GetNameOfClass() on an instance of said data. - * - * This method has a default implementation and need not be reimplemented, simply set m_BaseDataType in the constructor. - */ - void SetBaseDataType(const std::string& baseDataType); - virtual std::string GetBaseDataType() const; - - /** - * \brief Returns a human readable description of the file format. - * - * This will be used in FileDialogs for example. - * This method has a default implementation and need not be reimplemented, simply set m_BaseDataType in the constructor. - */ - void SetDescription(const std::string& description); - std::string GetDescription() const; + MimeType(const std::string& mimeType); private: + MimeType(); + + friend class AbstractFileReader; + }; - AbstractFileWriter& operator=(const AbstractFileWriter& other); + AbstractFileWriter(); + ~AbstractFileWriter(); - virtual mitk::IFileWriter* Clone() const = 0; + AbstractFileWriter(const AbstractFileWriter& other); + + AbstractFileWriter(const std::string& basedataType, const MimeType& mimeType, const std::string& description); + + AbstractFileWriter(const std::string& basedataType, const std::string& extension, const std::string& description); + + virtual us::ServiceProperties GetServiceProperties() const; + + /** + * Registers a new IMimeType service object. + * + * This method is called from RegisterService and the default implementation + * registers a new IMimeType service object if all of the following conditions + * are true: + * + * - The writer + * + * @param context + * @return + * @throws std::invalid_argument if \c context is NULL. + */ + virtual us::ServiceRegistration RegisterMimeType(us::ModuleContext* context); + + void SetMimeType(const std::string& mimeType); + + /** + * @return Get the mime-type this writer can handle. + */ + std::string GetMimeType() const; + + void SetCategory(const std::string& category); + std::string GetCategory() const; + + /** + * \brief Get file extension that this writer is able to handle. + */ + std::vector GetExtensions() const; + void AddExtension(const std::string& extension); + + /** + * \brief Sets a human readable description of this writer. + * + * This will be used in file dialogs for example. + */ + void SetDescription(const std::string& description); + std::string GetDescription() const; + + void SetDefaultOptions(const Options& defaultOptions); + Options GetDefaultOptions() const; + + /** + * \brief Set the service ranking for this file writer. + * + * Default is zero and should only be chosen differently for a reason. + * The ranking is used to determine which writer to use if several + * equivalent writers have been found. + * It may be used to replace a default writer from MITK in your own project. + * E.g. if you want to use your own writer for nrrd files instead of the default, + * implement it and give it a higher ranking than zero. + */ + void SetRanking(int ranking); + int GetRanking() const; + + /** + * \brief Sets the name of the mitk::Basedata that this writer is able to handle. + * + * The correct value is the one given as the first parameter in the mitkNewMacro of that BaseData derivate. + * You can also retrieve it by calling GetNameOfClass() on an instance of said data. + */ + void SetBaseDataType(const std::string& baseDataType); + virtual std::string GetBaseDataType() const; + +private: + + AbstractFileWriter& operator=(const AbstractFileWriter& other); + + virtual mitk::IFileWriter* Clone() const = 0; + + class Impl; + std::auto_ptr d; +}; - class Impl; - std::auto_ptr d; - }; } // namespace mitk #endif /* AbstractFileWriter_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkFileReaderRegistry.cpp b/Core/Code/IO/mitkFileReaderRegistry.cpp index 79b780716a..098477197b 100644 --- a/Core/Code/IO/mitkFileReaderRegistry.cpp +++ b/Core/Code/IO/mitkFileReaderRegistry.cpp @@ -1,240 +1,121 @@ /*=================================================================== 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 "mitkFileReaderRegistry.h" #include "mitkIMimeTypeProvider.h" #include "mitkCoreServices.h" // Microservices #include #include #include #include #include "itksys/SystemTools.hxx" mitk::FileReaderRegistry::FileReaderRegistry() { } mitk::FileReaderRegistry::~FileReaderRegistry() { for (std::map >::iterator iter = m_ServiceObjects.begin(), end = m_ServiceObjects.end(); iter != end; ++iter) { iter->second.UngetService(iter->first); } } -//////////////////// READING DIRECTLY //////////////////// - -std::vector< mitk::BaseData::Pointer > mitk::FileReaderRegistry::Read(const std::string& path, us::ModuleContext* context) -{ - // Find extension - std::string extension = itksys::SystemTools::GetFilenameExtension(path); - if (!extension.empty()) - { - extension = extension.substr(1, extension.size()-1); - } - - // Get best Reader - FileReaderRegistry readerRegistry; - mitk::IFileReader* reader = readerRegistry.GetReader(extension, context); - // Throw exception if no compatible reader was found - if (reader == NULL) mitkThrow() << "Tried to directly read a file with extension '" + extension + "' via FileReaderRegistry, but no reader supporting this file type was found."; - return reader->Read(path); -} - -std::vector< mitk::BaseData::Pointer > mitk::FileReaderRegistry::ReadAll( - const std::vector& paths, std::vector* unreadableFiles, - us::ModuleContext* context) -{ - FileReaderRegistry readerRegistry; - std::vector< mitk::BaseData::Pointer > result; - for (std::vector::const_iterator iterator = paths.begin(), end = paths.end(); iterator != end; ++iterator) - { - try - { - std::string extension = itksys::SystemTools::GetFilenameExtension(*iterator); - if (!extension.empty()) - { - extension = extension.substr(1, extension.size()-1); - } - mitk::IFileReader* reader = readerRegistry.GetReader(extension, context); - // Throw exception if no compatible reader was found - if (reader == NULL) throw; - - std::vector baseDataList = reader->Read( *iterator ); - result.insert(result.end(), baseDataList.begin(), baseDataList.end()); - } - catch (...) - { - if (unreadableFiles) unreadableFiles->push_back( *iterator ); - } - } - return result; -} - - -//////////////////// GETTING READERS //////////////////// - -mitk::FileReaderRegistry::ReaderReference mitk::FileReaderRegistry::GetReaderReference(const std::string& mimeType, us::ModuleContext* context) +mitk::FileReaderRegistry::ReaderReference mitk::FileReaderRegistry::GetReference(const std::string& mimeType, us::ModuleContext* context) { - std::vector refs = GetReaderReferences(mimeType, context); + std::vector refs = GetReferences(mimeType, context); if (refs.empty()) return ReaderReference(); std::sort(refs.begin(), refs.end()); return refs.back(); } -std::vector mitk::FileReaderRegistry::GetReaderReferences(const std::string& mimeType, us::ModuleContext* context) +std::vector mitk::FileReaderRegistry::GetReferences(const std::string& mimeType, us::ModuleContext* context) { std::string filter = us::LDAPProp(us::ServiceConstants::OBJECTCLASS()) == us_service_interface_iid() && us::LDAPProp(IFileReader::PROP_MIMETYPE()) == mimeType; return context->GetServiceReferences(filter); } mitk::IFileReader* mitk::FileReaderRegistry::GetReader(const mitk::FileReaderRegistry::ReaderReference& ref, us::ModuleContext* context) { us::ServiceObjects serviceObjects = context->GetServiceObjects(ref); mitk::IFileReader* reader = serviceObjects.GetService(); m_ServiceObjects.insert(std::make_pair(reader, serviceObjects)); return reader; } mitk::IFileReader* mitk::FileReaderRegistry::GetReader(const std::string& extension, us::ModuleContext* context ) { std::vector results = GetReaders(extension, context); if (results.empty()) return NULL; return results.front(); } std::vector mitk::FileReaderRegistry::GetReaders(const std::string& extension, us::ModuleContext* context ) { std::vector result; - const std::vector > refs = GetReaderList(extension, context); + + // filter for mime type + mitk::IMimeTypeProvider* mimeTypeProvider = mitk::CoreServices::GetMimeTypeProvider(context); + std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForExtension(extension); + if (mimeTypes.empty()) + { + MITK_WARN << "No mime-type information for extension " << extension << " available."; + return result; + } + std::vector > refs = GetReferences(mimeTypes.front(), context); + std::sort(refs.begin(), refs.end()); + result.reserve(refs.size()); // Translate List of ServiceRefs to List of Pointers - for (std::vector >::const_iterator iter = refs.begin(), end = refs.end(); - iter != end; ++iter) + for (std::vector >::const_reverse_iterator iter = refs.rbegin(), end = refs.rend(); + iter != end; ++iter) { us::ServiceObjects serviceObjects = context->GetServiceObjects(*iter); mitk::IFileReader* reader = serviceObjects.GetService(); m_ServiceObjects.insert(std::make_pair(reader, serviceObjects)); result.push_back(reader); } return result; } -mitk::IFileReader* mitk::FileReaderRegistry::GetReader( - const std::string& extension, const mitk::IFileReader::OptionNames& options, - us::ModuleContext* context ) -{ - std::vector matching = mitk::FileReaderRegistry::GetReaders(extension, options, context); - if (matching.empty()) return NULL; - return matching.front(); -} - -std::vector mitk::FileReaderRegistry::GetReaders( - const std::string& extension, const mitk::IFileReader::OptionNames& options, - us::ModuleContext* context ) -{ - const std::vector allReaders = mitk::FileReaderRegistry::GetReaders(extension, context); - std::vector result; - result.reserve(allReaders.size()); - // the list is already sorted by priority. Now find reader that supports all options - - for (std::vector ::const_iterator iter = allReaders.begin(), end = allReaders.end(); - iter != end; ++iter) - { - mitk::IFileReader * currentReader = *iter; - // Now see if this reader supports all options. If yes, push to results - if ( mitk::FileReaderRegistry::ReaderSupportsOptions(currentReader, options) ) - { - result.push_back(currentReader); - } - } - return result; -} - void mitk::FileReaderRegistry::UngetReader(mitk::IFileReader* reader) { std::map >::iterator readerIter = m_ServiceObjects.find(reader); if (readerIter != m_ServiceObjects.end()) { readerIter->second.UngetService(reader); m_ServiceObjects.erase(readerIter); } } void mitk::FileReaderRegistry::UngetReaders(const std::vector& readers) { for (std::vector::const_iterator iter = readers.begin(), end = readers.end(); iter != end; ++iter) { this->UngetReader(*iter); } } - -//////////////////// INTERNAL CODE //////////////////// - -bool mitk::FileReaderRegistry::ReaderSupportsOptions(mitk::IFileReader* reader, - const mitk::IFileReader::OptionNames& options ) -{ - const mitk::IFileReader::OptionList readerOptions = reader->GetOptions(); - if (options.empty()) return true; // if no options were requested, return true unconditionally - if (readerOptions.empty()) return false; // if options were requested and reader supports no options, return false - - // For each of the strings in requested options, check if option is available in reader - for(mitk::IFileReader::OptionNames::const_iterator options_i = options.begin(), i_end = options.end(); options_i != i_end; ++options_i) - { - { - bool optionFound = false; - // Iterate over each available option from reader to check if one of them matches the current option - for(mitk::IFileReader::OptionList::const_iterator options_j = readerOptions.begin(), j_end = readerOptions.end(); - options_j != j_end; ++options_j) - { - if ( *options_i == options_j->first ) optionFound = true; - } - if (optionFound == false) return false; // If one option was not found, leave method and return false - } - } - return true; // if all options have been found, return true -} - -//////////////////// uS-INTERACTION //////////////////// - -std::vector< us::ServiceReference > mitk::FileReaderRegistry::GetReaderList(const std::string& extension, us::ModuleContext* context ) -{ - std::vector > result; - - // filter for mime type - mitk::IMimeTypeProvider* mimeTypeProvider = mitk::CoreServices::GetMimeTypeProvider(context); - std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForExtension(extension); - if (mimeTypes.empty()) - { - MITK_WARN << "No mime-type information for extension " << extension << " available."; - return result; - } - std::string filter = us::LDAPProp(mitk::IFileReader::PROP_MIMETYPE()) == mimeTypes.front(); - result = context->GetServiceReferences(filter); - std::sort(result.begin(), result.end()); - std::reverse(result.begin(), result.end()); - return result; -} diff --git a/Core/Code/IO/mitkFileReaderRegistry.h b/Core/Code/IO/mitkFileReaderRegistry.h index 09c2bfa286..4291e6684d 100644 --- a/Core/Code/IO/mitkFileReaderRegistry.h +++ b/Core/Code/IO/mitkFileReaderRegistry.h @@ -1,114 +1,81 @@ /*=================================================================== 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. ===================================================================*/ #ifndef FileReaderRegistry_H_HEADER_INCLUDED_C1E7E521 #define FileReaderRegistry_H_HEADER_INCLUDED_C1E7E521 #include #include #include // Microservices #include #include #include namespace mitk { /** * @ingroup Process * * Provides convenient access to mitk::IFileReader instances and reading * files into mitk::BaseData types. * * \note The life-time of all mitk::IFileReader objects returned by an * instance of this class ends with the destruction of that instance. */ class MITK_CORE_EXPORT FileReaderRegistry { public: typedef us::ServiceReference ReaderReference; FileReaderRegistry(); ~FileReaderRegistry(); - /** - * Reads the file located at path and returns the - * contents as a DataNode. - * - * This method will select the best available reader in the service - * registry for the task. - * - * UnsupportedFileException: If no compatible reader was found - * FileNotFoundException: If no file was found at path - * FileReadException: If the selected reader failed to read the file - **/ - static std::vector< itk::SmartPointer > Read(const std::string& path, us::ModuleContext* context = us::GetModuleContext()); + static ReaderReference GetReference(const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); - static std::vector< mitk::BaseData::Pointer > ReadAll(const std::vector& paths, std::vector* unreadableFiles = 0, - us::ModuleContext* context = us::GetModuleContext()); + static std::vector GetReferences(const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); - template - static itk::SmartPointer Read(const std::string& path, us::ModuleContext* context = us::GetModuleContext()) - { - std::vector basedatas = Read(path, context); - if (basedatas.empty()) return NULL; - T* result = dynamic_cast (basedatas.front().GetPointer()); - return result; - } + mitk::IFileReader* GetReader(const ReaderReference& ref, us::ModuleContext* context = us::GetModuleContext()); - static ReaderReference GetReaderReference(const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); + /** + * Returns a compatible Reader to the given file extension + */ + mitk::IFileReader* GetReader(const std::string& extension, us::ModuleContext* context = us::GetModuleContext() ); - static std::vector GetReaderReferences(const std::string& mimeType, us::ModuleContext* context = us::GetModuleContext()); + std::vector GetReaders(const std::string& extension, us::ModuleContext* context = us::GetModuleContext() ); - mitk::IFileReader* GetReader(const ReaderReference& ref, us::ModuleContext* context = us::GetModuleContext()); - - /** - * Returns a compatible Reader to the given file extension - **/ - mitk::IFileReader* GetReader(const std::string& extension, us::ModuleContext* context = us::GetModuleContext() ); - - mitk::IFileReader* GetReader(const std::string& extension, const mitk::IFileReader::OptionNames& options, us::ModuleContext* context = us::GetModuleContext() ); - - std::vector GetReaders(const std::string& extension, us::ModuleContext* context = us::GetModuleContext() ); - - std::vector GetReaders(const std::string& extension, const mitk::IFileReader::OptionNames& options, us::ModuleContext* context = us::GetModuleContext() ); - - void UngetReader(mitk::IFileReader* reader); - void UngetReaders(const std::vector& readers); - -protected: - - std::vector< us::ServiceReference > GetReaderList(const std::string& extension, us::ModuleContext* context); - - bool ReaderSupportsOptions(mitk::IFileReader* reader, const mitk::IFileReader::OptionNames& options); + void UngetReader(mitk::IFileReader* reader); + void UngetReaders(const std::vector& readers); private: - // purposely not implemented - FileReaderRegistry(const FileReaderRegistry&); - FileReaderRegistry& operator=(const FileReaderRegistry&); + // purposely not implemented + FileReaderRegistry(const FileReaderRegistry&); + FileReaderRegistry& operator=(const FileReaderRegistry&); - std::map > m_ServiceObjects; + std::map > m_ServiceObjects; }; + } // namespace mitk + #endif /* FileReaderRegistry_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkFileWriterRegistry.cpp b/Core/Code/IO/mitkFileWriterRegistry.cpp index ac1b2bcd48..4407513e9a 100644 --- a/Core/Code/IO/mitkFileWriterRegistry.cpp +++ b/Core/Code/IO/mitkFileWriterRegistry.cpp @@ -1,236 +1,127 @@ /*=================================================================== 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 "mitkFileWriterRegistry.h" // MITK #include "mitkIMimeTypeProvider.h" #include "mitkCoreServices.h" #include "mitkBaseData.h" // Microservices #include #include #include #include -// ITK -#include - mitk::FileWriterRegistry::FileWriterRegistry() { } mitk::FileWriterRegistry::~FileWriterRegistry() { for (std::map >::iterator iter = m_ServiceObjects.begin(), end = m_ServiceObjects.end(); iter != end; ++iter) { iter->second.UngetService(iter->first); } } -//////////////////// WRITING DIRECTLY //////////////////// - -void mitk::FileWriterRegistry::Write(const mitk::BaseData* data, const std::string& path, us::ModuleContext* context) +std::string mitk::FileWriterRegistry::GetDefaultExtension(const mitk::FileWriterRegistry::WriterReference& ref, us::ModuleContext* context) { - // Find extension - std::string extension = itksys::SystemTools::GetFilenameExtension(path); - if (!extension.empty()) - { - extension = extension.substr(1, extension.size()-1); - } + std::string mimeType = ref.GetProperty(IFileWriter::PROP_MIMETYPE()).ToString(); - // Get best Writer - FileWriterRegistry writerRegistry; - mitk::IFileWriter* writer = writerRegistry.GetWriter(data, extension, mitk::IFileWriter::OptionNames(), context); - // Throw exception if no compatible Writer was found - if (writer == NULL) - { - mitkThrow() << "Tried to directly write a file of type '" << data->GetNameOfClass() - << "' and extension '" << extension - << "' via FileWriterRegistry, but no writer supporting this file type was found."; - } - writer->Write(data, path); + CoreServicePointer mimeTypeProvider(CoreServices::GetMimeTypeProvider(context)); + std::vector extensions = mimeTypeProvider->GetExtensions(mimeType); + if (extensions.empty()) return std::string(); + return extensions.front(); } -void mitk::FileWriterRegistry::Write(const mitk::BaseData* data, std::ostream& os, us::ModuleContext* context) +mitk::FileWriterRegistry::WriterReference mitk::FileWriterRegistry::GetReference(const mitk::BaseData* baseData, us::ModuleContext* context) { - // Get best Writer - FileWriterRegistry writerRegistry; - mitk::IFileWriter* writer = writerRegistry.GetWriter(data, std::string(), mitk::IFileWriter::OptionNames(), context); - // Throw exception if no compatible Writer was found - if (writer == NULL) - { - mitkThrow() << "Tried to directly write a file of type '" << data->GetNameOfClass() - << "' to a std::ostream via FileWriterRegistry, but no writer supporting this BaseData type was found."; - } - writer->Write(data, os); + return GetReference(baseData->GetNameOfClass(), context); +} + +mitk::FileWriterRegistry::WriterReference mitk::FileWriterRegistry::GetReference(const std::string& baseDataType, us::ModuleContext* context) +{ + std::vector refs = GetReferences(baseDataType, context); + if (refs.empty()) return WriterReference(); + std::sort(refs.begin(), refs.end()); + return refs.back(); } +std::vector mitk::FileWriterRegistry::GetReferences(const mitk::BaseData* baseData, us::ModuleContext* context) +{ + return GetReferences(baseData->GetNameOfClass(), context); +} -//////////////////// GETTING WRITERS //////////////////// +std::vector mitk::FileWriterRegistry::GetReferences(const std::string& baseDataType, us::ModuleContext* context) +{ + std::string filter = us::LDAPProp(us::ServiceConstants::OBJECTCLASS()) == us_service_interface_iid() && + us::LDAPProp(IFileWriter::PROP_BASEDATA_TYPE()) == baseDataType; + return context->GetServiceReferences(filter); +} -mitk::IFileWriter* mitk::FileWriterRegistry::GetWriter( - const mitk::BaseData* baseData, const std::string& extension, - const mitk::IFileWriter::OptionNames& options, us::ModuleContext* context) +mitk::IFileWriter*mitk::FileWriterRegistry::GetWriter(const mitk::FileWriterRegistry::WriterReference& ref, us::ModuleContext* context) { - return GetWriter(baseData->GetNameOfClass(), extension, options, context); + us::ServiceObjects serviceObjects = context->GetServiceObjects(ref); + mitk::IFileWriter* writer = serviceObjects.GetService(); + m_ServiceObjects.insert(std::make_pair(writer, serviceObjects)); + return writer; } -mitk::IFileWriter* mitk::FileWriterRegistry::GetWriter( - const std::string& baseDataType, const std::string& extension, - const mitk::IFileWriter::OptionNames& options, us::ModuleContext* context) +mitk::IFileWriter*mitk::FileWriterRegistry::GetWriter(const std::string& baseDataType, us::ModuleContext* context) { - std::vector results = GetWriters(baseDataType, extension, options, context); - if (results.empty()) return NULL; - return results.front(); + std::vector result = GetWriters(baseDataType, context); + if (result.empty()) + { + return NULL; + } + return result.front(); } -std::vector mitk::FileWriterRegistry::GetWriters( - const mitk::BaseData* baseData, const std::string& extension, - const mitk::IFileWriter::OptionNames& options, us::ModuleContext* context) +mitk::IFileWriter*mitk::FileWriterRegistry::GetWriter(const mitk::BaseData* baseData, us::ModuleContext* context) { - return GetWriters(baseData->GetNameOfClass(), extension, options, context); + return GetWriter(baseData->GetNameOfClass(), context); } -std::vector mitk::FileWriterRegistry::GetWriters( - const std::string& baseDataType, const std::string& extension, - const mitk::IFileWriter::OptionNames& options, us::ModuleContext* context) +std::vector mitk::FileWriterRegistry::GetWriters(const std::string& baseDataType, us::ModuleContext* context) { - std::vector > refs = GetRefs(baseDataType, extension, context); + std::vector result; + + std::vector > refs = GetReferences(baseDataType, context); + std::sort(refs.begin(), refs.end()); - std::vector result; result.reserve(refs.size()); // Translate List of ServiceRefs to List of Pointers - for (std::vector >::const_iterator iter = refs.begin(), end = refs.end(); + for (std::vector >::const_reverse_iterator iter = refs.rbegin(), end = refs.rend(); iter != end; ++iter) { us::ServiceObjects serviceObjects = context->GetServiceObjects(*iter); mitk::IFileWriter* writer = serviceObjects.GetService(); - - // Now see if this Writer supports all options. If yes, push to results - if (mitk::FileWriterRegistry::WriterSupportsOptions(writer, options)) - { - m_ServiceObjects.insert(std::make_pair(writer, serviceObjects)); - result.push_back(writer); - } + m_ServiceObjects.insert(std::make_pair(writer, serviceObjects)); + result.push_back(writer); } return result; } - -//////////////////// GENERIC INFORMATION //////////////////// - -//std::string mitk::FileWriterRegistry::GetSupportedExtensions(const std::string& extension, us::ModuleContext* context) -//{ -// std::string filter = us::LDAPProp(mitk::IFileWriter::PROP_EXTENSION()) == extension; -// const std::vector > refs = context->GetServiceReferences(filter); -// return CreateFileDialogString(refs); -//} - -//std::string mitk::FileWriterRegistry::GetSupportedWriters(const std::string& baseDataType, us::ModuleContext* context) -//{ -// std::string filter = us::LDAPProp(mitk::IFileWriter::PROP_BASEDATA_TYPE()) == baseDataType; -// const std::vector > refs = context->GetServiceReferences(filter); -// return CreateFileDialogString(refs); -//} - - -//////////////////// INTERNAL CODE //////////////////// - -bool mitk::FileWriterRegistry::WriterSupportsOptions(mitk::IFileWriter* writer, const mitk::IFileWriter::OptionNames& options ) +std::vector mitk::FileWriterRegistry::GetWriters(const mitk::BaseData* baseData, us::ModuleContext* context) { - const mitk::IFileWriter::OptionList writerOptions = writer->GetOptions(); - if (options.empty()) return true; // if no options were requested, return true unconditionally - if (writerOptions.empty()) return false; // if options were requested and reader supports no options, return false - - // For each of the strings in requested options, check if option is available in reader - for(mitk::IFileWriter::OptionNames::const_iterator options_i = options.begin(), i_end = options.end(); options_i != i_end; ++options_i) - { - { - bool optionFound = false; - // Iterate over each available option from reader to check if one of them matches the current option - for(mitk::IFileWriter::OptionList::const_iterator options_j = writerOptions.begin(), j_end = writerOptions.end(); - options_j != j_end; ++options_j) - { - if ( *options_i == options_j->first ) optionFound = true; - } - if (optionFound == false) return false; // If one option was not found, leave method and return false - } - } - return true; // if all options have been found, return true -} - -//std::string mitk::FileWriterRegistry::CreateFileDialogString(const std::vector >& refs) -//{ -// std::vector entries; // Will contain Description + Extension (Human readable) -// entries.reserve(refs.size()); -// std::string knownExtensions; // Will contain plain list of all known extensions (for the QFileDialog entry "All Known Extensions") -// for (std::vector >::const_iterator iterator = refs.begin(), end = refs.end(); -// iterator != end; ++iterator) -// { -// // Generate List of Extensions -// if (iterator == refs.begin()) // First entry without semicolon -// knownExtensions += "*" + iterator->GetProperty(mitk::IFileWriter::PROP_EXTENSION()).ToString(); -// else // Ad semicolon for each following entry -// knownExtensions += "; *" + iterator->GetProperty(mitk::IFileWriter::PROP_EXTENSION()).ToString(); - -// // Generate List of human readable entries composed of Description + Extension -// std::string entry = iterator->GetProperty(mitk::IFileWriter::PROP_DESCRIPTION()).ToString() + "(*" + iterator->GetProperty(mitk::IFileWriter::PROP_EXTENSION()).ToString() + ");;"; -// entries.push_back(entry); -// } -// std::sort(entries.begin(), entries.end()); - -// std::string result = "Known Extensions (" + knownExtensions + ");;All (*)"; -// for (std::vector::const_iterator iterator = entries.begin(), end = entries.end(); -// iterator != end; ++iterator) -// { -// result += ";;" + *iterator; -// } -// return result; -//} - -std::vector< us::ServiceReference > -mitk::FileWriterRegistry::GetRefs(const std::string& baseData, const std::string& extension, - us::ModuleContext* context ) -{ - std::vector > result; - - std::string mimeExpr; - if (!extension.empty()) - { - // filter for mime type - mitk::IMimeTypeProvider* mimeTypeProvider = mitk::CoreServices::GetMimeTypeProvider(context); - std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForExtension(extension); - if (mimeTypes.empty()) - { - MITK_WARN << "No mime-type information for extension " << extension << " available."; - } - else - { - mimeExpr = us::LDAPProp(mitk::IFileWriter::PROP_MIMETYPE()) == mimeTypes.front(); - } - } - std::string filter = us::LDAPProp(mitk::IFileWriter::PROP_BASEDATA_TYPE()) == baseData && us::LDAPPropExpr(mimeExpr); - result = context->GetServiceReferences(filter); - std::sort(result.begin(), result.end()); - std::reverse(result.begin(), result.end()); - return result; + return GetWriters(baseData->GetNameOfClass(), context); } diff --git a/Core/Code/IO/mitkFileWriterRegistry.h b/Core/Code/IO/mitkFileWriterRegistry.h index 001a3e57e4..0b07bd21dd 100644 --- a/Core/Code/IO/mitkFileWriterRegistry.h +++ b/Core/Code/IO/mitkFileWriterRegistry.h @@ -1,110 +1,97 @@ /*=================================================================== 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. ===================================================================*/ #ifndef FileWriterRegistry_H_HEADER_INCLUDED_C1E7E521 #define FileWriterRegistry_H_HEADER_INCLUDED_C1E7E521 #include // Microservices #include #include #include #include "mitkIFileWriter.h" -// Temporarily disable warning until PIMPL pattern is implemented here -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4251) -#endif - namespace mitk { class BaseData; } namespace mitk { - /** - * @ingroup Process - * - * Provides convenient access to mitk::IFileWriter instances and writing - * files from mitk::BaseData types. - * - * \note The life-time of all mitk::IFileWriter objects returned by an - * instance of this class ends with the destruction of that instance. - */ - class MITK_CORE_EXPORT FileWriterRegistry - { - public: - - FileWriterRegistry(); - ~FileWriterRegistry(); - static void Write(const mitk::BaseData* data, const std::string& path, us::ModuleContext* context = us::GetModuleContext()); +/** + * @ingroup Process + * + * Provides convenient access to mitk::IFileWriter instances and writing + * files from mitk::BaseData types. + * + * \note The life-time of all mitk::IFileWriter objects returned by an + * instance of this class ends with the destruction of that instance. + */ +class MITK_CORE_EXPORT FileWriterRegistry +{ - static void Write(const mitk::BaseData* data, std::ostream& os, us::ModuleContext* context = us::GetModuleContext()); +public: - /** - * Returns a compatible Writer to the given file extension - */ - mitk::IFileWriter* GetWriter(const std::string& baseDataType, const std::string& extension = std::string(), - const mitk::IFileWriter::OptionNames& options = mitk::IFileWriter::OptionNames(), - us::ModuleContext* context = us::GetModuleContext() ); + typedef us::ServiceReference WriterReference; - mitk::IFileWriter* GetWriter(const mitk::BaseData* baseData, const std::string& extension = std::string(), - const mitk::IFileWriter::OptionNames& options = mitk::IFileWriter::OptionNames(), - us::ModuleContext* context = us::GetModuleContext() ); + FileWriterRegistry(); + ~FileWriterRegistry(); - std::vector GetWriters(const std::string& baseDataType, const std::string& extension = std::string(), - const mitk::IFileWriter::OptionNames& options = mitk::IFileWriter::OptionNames(), - us::ModuleContext* context = us::GetModuleContext() ); - - std::vector GetWriters(const mitk::BaseData* baseData, const std::string& extension = std::string(), - const mitk::IFileWriter::OptionNames& options = mitk::IFileWriter::OptionNames(), - us::ModuleContext* context = us::GetModuleContext() ); + /** + * @brief Get the default file name extension for writing. + * + * The default extension is computed by retrieving the highest ranked + * mitk::IMimeType instance for the given mitk::IFileWriter reference + * and using the first extension from the mime types extension list. + * + * @param ref The IFileWriter service reference + * @param context The us::ModuleContext to look up IMimeType services + * @return The default extension without a leading period for the given + * \c ref. Returns an empty string if there is no registered + * mime type with this file writer reference. + */ + static std::string GetDefaultExtension(const WriterReference& ref, us::ModuleContext* context = us::GetModuleContext()); - void UngetWriter(mitk::IFileWriter* writer); - void UngetWriters(const std::vector& writers); + static WriterReference GetReference(const BaseData* baseData, us::ModuleContext* context = us::GetModuleContext()); + static WriterReference GetReference(const std::string& baseDataType, us::ModuleContext* context = us::GetModuleContext()); - // TODO: We should not generate GUI dependent strings here. Maybe just return a pair of extensions - // and descriptions. - //std::string GetSupportedExtensions(const std::string& extension = std::string(), us::ModuleContext* context = us::GetModuleContext()); + static std::vector GetReferences(const BaseData* baseData, us::ModuleContext* context = us::GetModuleContext()); + static std::vector GetReferences(const std::string& baseDataType, us::ModuleContext* context = us::GetModuleContext()); - //std::string GetSupportedWriters(const std::string& basedataType, us::ModuleContext* context = us::GetModuleContext()); + IFileWriter* GetWriter(const WriterReference& ref, us::ModuleContext* context = us::GetModuleContext()); - protected: + IFileWriter* GetWriter(const std::string& baseDataType, us::ModuleContext* context = us::GetModuleContext()); + IFileWriter* GetWriter(const BaseData* baseData, us::ModuleContext* context = us::GetModuleContext()); - std::string CreateFileDialogString(const std::vector >& refs); + std::vector GetWriters(const std::string& baseDataType, us::ModuleContext* context = us::GetModuleContext()); + std::vector GetWriters(const BaseData* baseData, us::ModuleContext* context = us::GetModuleContext()); - bool WriterSupportsOptions(mitk::IFileWriter* writer, const mitk::IFileWriter::OptionNames& options); + void UngetWriter(IFileWriter* writer); + void UngetWriters(const std::vector& writers); - std::vector > GetRefs(const std::string& baseData, const std::string& extension, us::ModuleContext* context); +private: - private: + // purposely not implemented + FileWriterRegistry(const FileWriterRegistry&); + FileWriterRegistry& operator=(const FileWriterRegistry&); - // purposely not implemented - FileWriterRegistry(const FileWriterRegistry&); - FileWriterRegistry& operator=(const FileWriterRegistry&); + std::map > m_ServiceObjects; +}; - std::map > m_ServiceObjects; - }; } // namespace mitk -#ifdef _MSC_VER -# pragma warning(pop) -#endif - #endif /* FileWriterRegistry_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Core/Code/IO/mitkIOConstants.cpp b/Core/Code/IO/mitkIOConstants.cpp new file mode 100644 index 0000000000..74706637cc --- /dev/null +++ b/Core/Code/IO/mitkIOConstants.cpp @@ -0,0 +1,141 @@ +/*=================================================================== + +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 "mitkIOConstants.h" + +namespace mitk { + +std::string IOConstants::PIXEL_TYPE() +{ + static std::string s("org.mitk.io.Pixel Type"); + return s; +} + +std::string IOConstants::PIXEL_TYPE_CHAR() +{ + static std::string s("char"); + return s; +} + +std::string IOConstants::PIXEL_TYPE_UCHAR() +{ + static std::string s("unsigned char"); + return s; +} + +std::string IOConstants::PIXEL_TYPE_SHORT() +{ + static std::string s("short"); + return s; +} + +std::string IOConstants::PIXEL_TYPE_USHORT() +{ + static std::string s("unsigned short"); + return s; +} + +std::string IOConstants::PIXEL_TYPE_INT() +{ + static std::string s("int"); + return s; +} + +std::string IOConstants::PIXEL_TYPE_UINT() +{ + static std::string s("unsigned int"); + return s; +} + +std::string IOConstants::PIXEL_TYPE_FLOAT() +{ + static std::string s("float"); + return s; +} + +std::string IOConstants::PIXEL_TYPE_DOUBLE() +{ + static std::string s("double"); + return s; +} + +std::string IOConstants::PIXEL_TYPE_ENUM() +{ + static std::string s("org.mitk.io.Pixel Type.enum"); + return s; +} + +std::string IOConstants::DIMENSION() +{ + static std::string s("org.mitk.io.Dimension"); + return s; +} + +std::string IOConstants::DIMENSION_ENUM() +{ + static std::string s("org.mitk.io.Dimension.enum"); + return s; +} + +std::string IOConstants::ENDIANNESS() +{ + static std::string s("org.mitk.io.Endianness"); + return s; +} + +std::string IOConstants::ENDIANNESS_LITTLE() +{ + static std::string s("Little Endian"); + return s; +} + +std::string IOConstants::ENDIANNESS_BIG() +{ + static std::string s("Big Endian"); + return s; +} + +std::string IOConstants::ENDIANNESS_ENUM() +{ + static std::string s("org.mitk.io.Endianness.enum"); + return s; +} + +std::string IOConstants::SIZE_X() +{ + static std::string s("org.mitk.io.Size X"); + return s; +} + +std::string IOConstants::SIZE_Y() +{ + static std::string s("org.mitk.io.Size Y"); + return s; +} + +std::string IOConstants::SIZE_Z() +{ + static std::string s("org.mitk.io.Size Z"); + return s; +} + +std::string IOConstants::SIZE_T() +{ + static std::string s("org.mitk.io.Size t"); + return s; +} + +} diff --git a/Core/Code/IO/mitkIOConstants.h b/Core/Code/IO/mitkIOConstants.h new file mode 100644 index 0000000000..14879353fd --- /dev/null +++ b/Core/Code/IO/mitkIOConstants.h @@ -0,0 +1,55 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#ifndef MITKIOCONSTANTS_H_ +#define MITKIOCONSTANTS_H_ + +#include + +#include + +namespace mitk { + +struct MITK_CORE_EXPORT IOConstants +{ + static std::string PIXEL_TYPE(); + static std::string PIXEL_TYPE_CHAR(); + static std::string PIXEL_TYPE_UCHAR(); + static std::string PIXEL_TYPE_SHORT(); + static std::string PIXEL_TYPE_USHORT(); + static std::string PIXEL_TYPE_INT(); + static std::string PIXEL_TYPE_UINT(); + static std::string PIXEL_TYPE_FLOAT(); + static std::string PIXEL_TYPE_DOUBLE(); + static std::string PIXEL_TYPE_ENUM(); + + static std::string DIMENSION(); + static std::string DIMENSION_ENUM(); + + static std::string ENDIANNESS(); + static std::string ENDIANNESS_LITTLE(); + static std::string ENDIANNESS_BIG(); + static std::string ENDIANNESS_ENUM(); + + static std::string SIZE_X(); + static std::string SIZE_Y(); + static std::string SIZE_Z(); + static std::string SIZE_T(); +}; + +} + +#endif // MITKIOCONSTANTS_H_ diff --git a/Core/Code/IO/mitkIOUtil.cpp b/Core/Code/IO/mitkIOUtil.cpp index 910227eef7..7b1f2165c6 100644 --- a/Core/Code/IO/mitkIOUtil.cpp +++ b/Core/Code/IO/mitkIOUtil.cpp @@ -1,769 +1,955 @@ /*=================================================================== 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 "mitkIOUtil.h" #include #include #include #include #include #include #include #include #include +#include +#include //ITK #include //VTK #include #include #include #include #include static std::string GetLastErrorStr() { #ifdef US_PLATFORM_POSIX return std::string(strerror(errno)); #else // Retrieve the system error message for the last-error code LPVOID lpMsgBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); std::string errMsg((LPCTSTR)lpMsgBuf); LocalFree(lpMsgBuf); return errMsg; #endif } #ifdef US_PLATFORM_WINDOWS #include #include // make the posix flags point to the obsolte bsd types on windows #define S_IRUSR S_IREAD #define S_IWUSR S_IWRITE #else #include #include #include #endif #include #include static const char validLetters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // A cross-platform version of the mkstemps function static int mkstemps_compat(char* tmpl, int suffixlen) { static unsigned long long value = 0; int savedErrno = errno; // Lower bound on the number of temporary files to attempt to generate. #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary file. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX const unsigned int attempts = TMP_MAX; #else const unsigned int attempts = ATTEMPTS_MIN; #endif const int len = strlen(tmpl); if ((len - suffixlen) < 6 || strncmp(&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) { errno = EINVAL; return -1; } /* This is where the Xs start. */ char* XXXXXX = &tmpl[len - 6 - suffixlen]; /* Get some more or less random data. */ #ifdef US_PLATFORM_WINDOWS { SYSTEMTIME stNow; FILETIME ftNow; // get system time GetSystemTime(&stNow); stNow.wMilliseconds = 500; if (!SystemTimeToFileTime(&stNow, &ftNow)) { errno = -1; return -1; } unsigned long long randomTimeBits = ((static_cast(ftNow.dwHighDateTime) << 32) | static_cast(ftNow.dwLowDateTime)); value = randomTimeBits ^ static_cast(GetCurrentThreadId()); } #else { struct timeval tv; gettimeofday(&tv, NULL); unsigned long long randomTimeBits = ((static_cast(tv.tv_usec) << 32) | static_cast(tv.tv_sec)); value = randomTimeBits ^ static_cast(getpid()); } #endif for (unsigned int count = 0; count < attempts; value += 7777, ++count) { unsigned long long v = value; /* Fill in the random bits. */ XXXXXX[0] = validLetters[v % 62]; v /= 62; XXXXXX[1] = validLetters[v % 62]; v /= 62; XXXXXX[2] = validLetters[v % 62]; v /= 62; XXXXXX[3] = validLetters[v % 62]; v /= 62; XXXXXX[4] = validLetters[v % 62]; v /= 62; XXXXXX[5] = validLetters[v % 62]; int fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); if (fd >= 0) { errno = savedErrno; return fd; } else if (errno != EEXIST) { return -1; } } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return -1; } // A cross-platform version of the POSIX mkdtemp function static char* mkdtemps_compat(char* tmpl, int suffixlen) { static unsigned long long value = 0; int savedErrno = errno; // Lower bound on the number of temporary dirs to attempt to generate. #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary dir. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX const unsigned int attempts = TMP_MAX; #else const unsigned int attempts = ATTEMPTS_MIN; #endif const int len = strlen(tmpl); if ((len - suffixlen) < 6 || strncmp(&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) { errno = EINVAL; return NULL; } /* This is where the Xs start. */ char* XXXXXX = &tmpl[len - 6 - suffixlen]; /* Get some more or less random data. */ #ifdef US_PLATFORM_WINDOWS { SYSTEMTIME stNow; FILETIME ftNow; // get system time GetSystemTime(&stNow); stNow.wMilliseconds = 500; if (!SystemTimeToFileTime(&stNow, &ftNow)) { errno = -1; return NULL; } unsigned long long randomTimeBits = ((static_cast(ftNow.dwHighDateTime) << 32) | static_cast(ftNow.dwLowDateTime)); value = randomTimeBits ^ static_cast(GetCurrentThreadId()); } #else { struct timeval tv; gettimeofday(&tv, NULL); unsigned long long randomTimeBits = ((static_cast(tv.tv_usec) << 32) | static_cast(tv.tv_sec)); value = randomTimeBits ^ static_cast(getpid()); } #endif unsigned int count = 0; for (; count < attempts; value += 7777, ++count) { unsigned long long v = value; /* Fill in the random bits. */ XXXXXX[0] = validLetters[v % 62]; v /= 62; XXXXXX[1] = validLetters[v % 62]; v /= 62; XXXXXX[2] = validLetters[v % 62]; v /= 62; XXXXXX[3] = validLetters[v % 62]; v /= 62; XXXXXX[4] = validLetters[v % 62]; v /= 62; XXXXXX[5] = validLetters[v % 62]; #ifdef US_PLATFORM_WINDOWS int fd = _mkdir (tmpl); //, _S_IREAD | _S_IWRITE | _S_IEXEC); #else int fd = mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); #endif if (fd >= 0) { errno = savedErrno; return tmpl; } else if (errno != EEXIST) { return NULL; } } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return NULL; } //#endif +// ***************************************************************** +// Utility code + +US_HASH_FUNCTION_NAMESPACE_BEGIN +US_HASH_FUNCTION_BEGIN(std::vector) + std::string imploded; + imploded.reserve(256); + for(std::vector::const_iterator iter = arg.begin(), + iterEnd = arg.end(); iter != iterEnd; ++iter) + { + imploded += *iter; + } + return US_HASH_FUNCTION(std::string, imploded); +US_HASH_FUNCTION_END +US_HASH_FUNCTION_NAMESPACE_END + +namespace { + +class FileSorter +{ + +public: + + typedef std::vector MimeTypeVector; + typedef std::vector FileVector; + + FileSorter() + {} + +private: + + FileSorter(const FileSorter&); + FileSorter& operator=(const FileSorter&); + + typedef US_UNORDERED_MAP_TYPE HashMapType; + + HashMapType m_MimeTypesToFiles; + +public: + + typedef HashMapType::const_iterator Iterator; + + void AddFile(const std::string& file, const std::string& mimeType) + { + MimeTypeVector mimeTypes; + mimeTypes.push_back(mimeType); + m_MimeTypesToFiles[mimeTypes].push_back(file); + } + + void AddFile(const std::string& file, const MimeTypeVector& mimeTypes) + { + m_MimeTypesToFiles[mimeTypes].push_back(file); + } + + Iterator Begin() const + { + return m_MimeTypesToFiles.begin(); + } + + Iterator End() const + { + return m_MimeTypesToFiles.end(); + } + +}; + +} + +//************************************************************** +// mitk::IOUtil method definitions + namespace mitk { const std::string IOUtil::DEFAULTIMAGEEXTENSION = ".nrrd"; const std::string IOUtil::DEFAULTSURFACEEXTENSION = ".stl"; const std::string IOUtil::DEFAULTPOINTSETEXTENSION = ".mps"; +struct IOUtil::Impl +{ + struct FixedOptionsFunctor : public OptionsFunctorBase + { + FixedOptionsFunctor(const IFileReader::Options& options) + : m_Options(options) + {} + + virtual bool operator()(const std::string& /*path*/, const std::vector& /*readerLabels*/, + const std::vector& readers, IFileReader*& selectedReader) + { + selectedReader = readers.front(); + selectedReader->SetOptions(m_Options); + return false; + } + + private: + const IFileReader::Options& m_Options; + }; + + static BaseData::Pointer LoadBaseDataFromFile(const std::string& path); + + static void SetDefaultDataNodeProperties(mitk::DataNode* node, const std::string& filePath = std::string()); +}; + #ifdef US_PLATFORM_WINDOWS std::string IOUtil::GetProgramPath() { char path[512]; std::size_t index = std::string(path, GetModuleFileName(NULL, path, 512)).find_last_of('\\'); return std::string(path, index); } #elif defined(US_PLATFORM_APPLE) #include std::string IOUtil::GetProgramPath() { char path[512]; uint32_t size = sizeof(path); if (_NSGetExecutablePath(path, &size) == 0) { std::size_t index = std::string(path).find_last_of('/'); std::string strPath = std::string(path, index); //const char* execPath = strPath.c_str(); //mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(execPath,false); return strPath; } return std::string(); } #else #include #include #include std::string IOUtil::GetProgramPath() { std::stringstream ss; ss << "/proc/" << getpid() << "/exe"; char proc[512] = {0}; ssize_t ch = readlink(ss.str().c_str(), proc, 512); if (ch == -1) return std::string(); std::size_t index = std::string(proc).find_last_of('/'); return std::string(proc, index); } #endif std::string IOUtil::GetTempPath() { static std::string result; if (result.empty()) { #ifdef US_PLATFORM_WINDOWS char tempPathTestBuffer[1]; DWORD bufferLength = ::GetTempPath(1, tempPathTestBuffer); if (bufferLength == 0) { mitkThrow() << GetLastErrorStr(); } std::vector tempPath(bufferLength); bufferLength = ::GetTempPath(bufferLength, &tempPath[0]); if (bufferLength == 0) { mitkThrow() << GetLastErrorStr(); } result.assign(tempPath.begin(), tempPath.begin() + static_cast(bufferLength)); #else result = "/tmp/"; #endif } return result; } std::string IOUtil::CreateTemporaryFile(const std::string& templateName, std::string path) { ofstream tmpOutputStream; std::string returnValue = CreateTemporaryFile(tmpOutputStream,templateName,path); tmpOutputStream.close(); return returnValue; } std::string IOUtil::CreateTemporaryFile(std::ofstream& f, const std::string& templateName, std::string path) { return CreateTemporaryFile(f, std::ios_base::out | std::ios_base::trunc, templateName, path); } std::string IOUtil::CreateTemporaryFile(std::ofstream& f, std::ios_base::openmode mode, const std::string& templateName, std::string path) { if (path.empty()) { path = GetTempPath(); } path += "/" + templateName; std::vector dst_path(path.begin(), path.end()); dst_path.push_back('\0'); std::size_t lastX = path.find_last_of('X'); std::size_t firstX = path.find_last_not_of('X', lastX); int firstNonX = firstX == std::string::npos ? - 1 : firstX - 1; while (lastX != std::string::npos && (lastX - firstNonX) < 6) { lastX = path.find_last_of('X', firstX); firstX = path.find_last_not_of('X', lastX); firstNonX = firstX == std::string::npos ? - 1 : firstX - 1; } std::size_t suffixlen = lastX == std::string::npos ? path.size() : path.size() - lastX - 1; int fd = mkstemps_compat(&dst_path[0], suffixlen); if(fd != -1) { path.assign(dst_path.begin(), dst_path.end() - 1); f.open(path.c_str(), mode | std::ios_base::out | std::ios_base::trunc); close(fd); } else { mitkThrow() << "Creating temporary file " << &dst_path[0] << " failed: " << GetLastErrorStr(); } return path; } std::string IOUtil::CreateTemporaryDirectory(const std::string& templateName, std::string path) { if (path.empty()) { path = GetTempPath(); } path += "/" + templateName; std::vector dst_path(path.begin(), path.end()); dst_path.push_back('\0'); std::size_t lastX = path.find_last_of('X'); std::size_t firstX = path.find_last_not_of('X', lastX); int firstNonX = firstX == std::string::npos ? - 1 : firstX - 1; while (lastX != std::string::npos && (lastX - firstNonX) < 6) { lastX = path.find_last_of('X', firstX); firstX = path.find_last_not_of('X', lastX); firstNonX = firstX == std::string::npos ? - 1 : firstX - 1; } std::size_t suffixlen = lastX == std::string::npos ? path.size() : path.size() - lastX - 1; if(mkdtemps_compat(&dst_path[0], suffixlen) == NULL) { mitkThrow() << "Creating temporary directory " << &dst_path[0] << " failed: " << GetLastErrorStr(); } path.assign(dst_path.begin(), dst_path.end() - 1); return path; } -int IOUtil::LoadFiles(const std::vector &fileNames, DataStorage &ds) +DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::string& path, DataStorage& storage) { - // Get the set of registered mitk::IDataNodeReader services - us::ModuleContext* context = us::GetModuleContext(); - const std::vector > refs = context->GetServiceReferences(); - std::vector services; - services.reserve(refs.size()); - for (std::vector >::const_iterator i = refs.begin(); - i != refs.end(); ++i) - { - IDataNodeReader* s = context->GetService(*i); - if (s != 0) - { - services.push_back(s); - } - } + std::vector paths; + paths.push_back(path); + return Load(paths, storage); +} - mitk::ProgressBar::GetInstance()->AddStepsToDo(2*fileNames.size()); +DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::string& path, + const IFileReader::Options& options, + DataStorage& storage) +{ + std::vector paths; + paths.push_back(path); + DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); + Impl::FixedOptionsFunctor optionsCallback(options); + std::string errMsg = Load(paths, NULL, nodeResult, &storage, &optionsCallback); + if (!errMsg.empty()) + { + mitkThrow() << errMsg; + } + return nodeResult; +} - // Iterate over all file names and use the IDataNodeReader services - // to load them. - int nodesRead = 0; - for (std::vector::const_iterator i = fileNames.begin(); - i != fileNames.end(); ++i) - { - for (std::vector::const_iterator readerIt = services.begin(); - readerIt != services.end(); ++readerIt) - { - try - { - int n = (*readerIt)->Read(*i, ds); - nodesRead += n; - if (n > 0) break; - } - catch (const std::exception& e) - { - MITK_WARN << e.what(); - } - } - mitk::ProgressBar::GetInstance()->Progress(2); - } +std::vector IOUtil::Load(const std::string& path) +{ + std::vector paths; + paths.push_back(path); + return Load(paths); +} - for (std::vector >::const_iterator i = refs.begin(); - i != refs.end(); ++i) - { - context->UngetService(*i); - } +std::vector IOUtil::Load(const std::string& path, const IFileReader::Options& options) +{ + std::vector paths; + paths.push_back(path); + std::vector result; + Impl::FixedOptionsFunctor optionsCallback(options); + std::string errMsg = Load(paths, &result, NULL, NULL, &optionsCallback); + if (!errMsg.empty()) + { + mitkThrow() << errMsg; + } + return result; +} + +DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::vector& paths, DataStorage& storage) +{ + DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); + std::string errMsg = Load(paths, NULL, nodeResult, &storage, NULL); + if (!errMsg.empty()) + { + mitkThrow() << errMsg; + } + return nodeResult; +} - return nodesRead; +std::vector IOUtil::Load(const std::vector& paths) +{ + std::vector result; + std::string errMsg = Load(paths, &result, NULL, NULL, NULL); + if (!errMsg.empty()) + { + mitkThrow() << errMsg; + } + return result; +} + +int IOUtil::LoadFiles(const std::vector &fileNames, DataStorage& ds) +{ + return static_cast(Load(fileNames, ds)->Size()); } DataStorage::Pointer IOUtil::LoadFiles(const std::vector& fileNames) { - mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); - LoadFiles(fileNames, *ds); - return ds.GetPointer(); + mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); + Load(fileNames, *ds); + return ds.GetPointer(); } BaseData::Pointer IOUtil::LoadBaseData(const std::string& path) { - return LoadDataNode(path)->GetData(); + return Impl::LoadBaseDataFromFile(path); } -DataNode::Pointer IOUtil::LoadDataNode(const std::string& path) +BaseData::Pointer IOUtil::Impl::LoadBaseDataFromFile(const std::string& path) { - try - { - mitk::FileReaderRegistry readerRegistry; - std::vector baseDataList = readerRegistry.Read(path); + std::vector baseDataList = Load(path); - BaseData::Pointer baseData; - if (!baseDataList.empty()) baseData = baseDataList.front(); + // The Load(path) call above should throw an exception if nothing could be loaded + assert(!baseDataList.empty()); + return baseDataList.front(); +} - if(baseData.IsNull()) - { - MITK_ERROR << "Could not find data '" << path << "'"; - mitkThrow() << "An exception occured during loading the file " << path << ". Exception says could not find data."; - } +DataNode::Pointer IOUtil::LoadDataNode(const std::string& path) +{ + BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); - mitk::DataNode::Pointer node = mitk::DataNode::New(); - node->SetData(baseData); - SetDefaultDataNodeProperties(node, path); + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(baseData); + Impl::SetDefaultDataNodeProperties(node, path); - return node; - } - catch (const std::exception& e) - { - MITK_ERROR << "Exception occured during load data of '" << path << "': Exception: " << e.what(); - mitkThrow() << "An exception occured during loading the file " << path << ". Exception says: " << e.what(); - } + return node; } Image::Pointer IOUtil::LoadImage(const std::string& path) { - mitk::DataNode::Pointer node = LoadDataNode(path); - mitk::Image::Pointer image = dynamic_cast(node->GetData()); - if(image.IsNull()) - { - MITK_ERROR << "Image is NULL '" << path << "'"; - mitkThrow() << "An exception occured during loading the image " << path << ". Exception says: Image is NULL."; - } - return image; + BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); + mitk::Image::Pointer image = dynamic_cast(baseData.GetPointer()); + if(image.IsNull()) + { + mitkThrow() << path << " is not a mitk::Image but a " << baseData->GetNameOfClass(); + } + return image; } Surface::Pointer IOUtil::LoadSurface(const std::string& path) { - mitk::DataNode::Pointer node = LoadDataNode(path); - mitk::Surface::Pointer surface = dynamic_cast(node->GetData()); - if(surface.IsNull()) - { - MITK_ERROR << "Surface is NULL '" << path << "'"; - mitkThrow() << "An exception occured during loading the file " << path << ". Exception says: Surface is NULL."; - } - return surface; + BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); + mitk::Surface::Pointer surface = dynamic_cast(baseData.GetPointer()); + if(surface.IsNull()) + { + mitkThrow() << path << " is not a mitk::Surface but a " << baseData->GetNameOfClass(); + } + return surface; } PointSet::Pointer IOUtil::LoadPointSet(const std::string& path) { - mitk::DataNode::Pointer node = LoadDataNode(path); - mitk::PointSet::Pointer pointset = dynamic_cast(node->GetData()); - if(pointset.IsNull()) - { - MITK_ERROR << "PointSet is NULL '" << path << "'"; - mitkThrow() << "An exception occured during loading the file " << path << ". Exception says: Pointset is NULL."; - } - return pointset; + BaseData::Pointer baseData = Impl::LoadBaseDataFromFile(path); + mitk::PointSet::Pointer pointset = dynamic_cast(baseData.GetPointer()); + if(pointset.IsNull()) + { + mitkThrow() << path << " is not a mitk::PointSet but a " << baseData->GetNameOfClass(); + } + return pointset; } -bool IOUtil::SaveImage(mitk::Image::Pointer image, const std::string& path) +std::string IOUtil::Load(const std::vector& paths, std::vector* result, + DataStorage::SetOfObjects* nodeResult, DataStorage* ds, + OptionsFunctorBase* optionsCallback) { - return SaveBaseData(image, path); - /* - std::string dir = itksys::SystemTools::GetFilenamePath( path ); - std::string baseFilename = itksys::SystemTools::GetFilenameWithoutExtension( path ); - std::string extension = itksys::SystemTools::GetFilenameExtension( path ); - if (dir == "") - dir = "."; - std::string finalFileName = dir + "/" + baseFilename; - - mitk::ImageWriter::Pointer imageWriter = mitk::ImageWriter::New(); - //check if an extension is given, else use the defaul extension - if( extension == "" ) - { - MITK_WARN << extension << " extension is not set. Extension set to default: " << finalFileName - << DEFAULTIMAGEEXTENSION; - extension = DEFAULTIMAGEEXTENSION; - } + if (paths.empty()) + { + return "No input files given"; + } - // check if extension is suitable for writing image data - if (!imageWriter->IsExtensionValid(extension)) - { - MITK_WARN << extension << " extension is unknown. Extension set to default: " << finalFileName - << DEFAULTIMAGEEXTENSION; - extension = DEFAULTIMAGEEXTENSION; - } + mitk::ProgressBar::GetInstance()->AddStepsToDo(2*paths.size()); - try + CoreServicePointer mimeTypeProvider(CoreServices::GetMimeTypeProvider()); + + std::string errMsg; + + // group the selected files by mime-type(s) + FileSorter fileSorter; + std::string noMimeTypeError; + for(std::vector::const_iterator selectedFileIter = paths.begin(), + iterEnd = paths.end(); selectedFileIter != iterEnd; ++selectedFileIter) + { + std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForFile(*selectedFileIter); + if (!mimeTypes.empty()) { - //write the data - imageWriter->SetInput(image); - imageWriter->SetFileName(finalFileName.c_str()); - imageWriter->SetExtension(extension.c_str()); - imageWriter->Write(); + fileSorter.AddFile(*selectedFileIter, mimeTypes); } - catch ( std::exception& e ) + else { - MITK_ERROR << " during attempt to write '" << finalFileName + extension << "' Exception says:"; - MITK_ERROR << e.what(); - mitkThrow() << "An exception occured during writing the file " << finalFileName << ". Exception says " << e.what(); + noMimeTypeError += " * " + *selectedFileIter + "\n"; } - return true; - */ -} + } -bool IOUtil::SaveSurface(Surface::Pointer surface, const std::string& path) -{ - return SaveBaseData(surface, path); - /* - std::string dir = itksys::SystemTools::GetFilenamePath( path ); - std::string baseFilename = itksys::SystemTools::GetFilenameWithoutLastExtension( path ); - std::string extension = itksys::SystemTools::GetFilenameLastExtension( path ); - if (dir == "") - dir = "."; - std::string finalFileName = dir + "/" + baseFilename; + if (!noMimeTypeError.empty()) + { + errMsg += "Unknown file format for\n\n" + noMimeTypeError + "\n\n"; + } + + FileReaderRegistry readerRegistry; - if (extension == "") // if no extension has been set we use the default extension + for(FileSorter::Iterator iter = fileSorter.Begin(), endIter = fileSorter.End(); + iter != endIter; ++iter) + { + std::vector finalReaders; + std::vector finalReaderLabels; + const FileSorter::FileVector& currentFiles = iter->second; + const FileSorter::MimeTypeVector& fileMimeTypes = iter->first; + for(FileSorter::MimeTypeVector::const_iterator mimeTypeIter = fileMimeTypes.begin(), + mimeTypeIterEnd = fileMimeTypes.end(); mimeTypeIter != mimeTypeIterEnd; ++mimeTypeIter) { - MITK_WARN << extension << " extension is not set. Extension set to default: " << finalFileName - << DEFAULTSURFACEEXTENSION; - extension = DEFAULTSURFACEEXTENSION; + // Get all IFileReader references for the given mime-type + std::vector readerRefs = readerRegistry.GetReferences(*mimeTypeIter); + // Sort according to priority (ascending) + std::sort(readerRefs.begin(), readerRefs.end()); + + // Loop over all readers, starting at the highest priority, and check if it + // really can read the file (well, the first in the list). + for (std::vector::reverse_iterator readerRef = readerRefs.rbegin(); + readerRef != readerRefs.rend(); ++readerRef) + { + mitk::IFileReader* reader = readerRegistry.GetReader(*readerRef); + try + { + if (reader->CanRead(currentFiles.front())) + { + finalReaders.push_back(reader); + finalReaderLabels.push_back(readerRef->GetProperty(mitk::IFileReader::PROP_DESCRIPTION()).ToString()); + } + } + catch (const std::exception& e) + { + MITK_ERROR << "Calling CanRead('" << currentFiles.front() << "') on " << typeid(reader).name() << "failed: " << e.what(); + } + } + } + + if (finalReaders.empty()) + { + errMsg += "No reader available for files\n\n"; + for(FileSorter::FileVector::const_iterator fileIter = currentFiles.begin(), + fileIterEnd = currentFiles.end(); fileIter != fileIterEnd; ++fileIter) + { + errMsg += " * " + *fileIter + "\n"; + } } - try + else { - finalFileName += extension; - if(extension == ".stl" ) + // TODO check if the reader can read a series of files and if yes, + // pass the complete file list to one "Read" call. + + bool callOptionsCallback = finalReaders.size() > 1 || !finalReaders.front()->GetOptions().empty(); + mitk::IFileReader* selectedReader = finalReaders.front(); + MITK_INFO << "******* USING READER " << typeid(*selectedReader).name() << "*********"; + for(FileSorter::FileVector::const_iterator fileIter = currentFiles.begin(), + fileIterEnd = currentFiles.end(); fileIter != fileIterEnd; ++fileIter) + { + if (callOptionsCallback && optionsCallback) { - mitk::SurfaceVtkWriter::Pointer surfaceWriter = mitk::SurfaceVtkWriter::New(); - - // check if surface actually consists of triangles; if not, the writer will not do anything; so, convert to triangles... - vtkPolyData* polys = surface->GetVtkPolyData(); - if( polys->GetNumberOfStrips() > 0 ) - { - vtkSmartPointer triangleFilter = vtkSmartPointer::New(); - triangleFilter->SetInputData(polys); - triangleFilter->Update(); - polys = triangleFilter->GetOutput(); - polys->Register(NULL); - surface->SetVtkPolyData(polys); - } - surfaceWriter->SetInput( surface ); - surfaceWriter->SetFileName( finalFileName.c_str() ); - surfaceWriter->GetVtkWriter()->SetFileTypeToBinary(); - surfaceWriter->Write(); + callOptionsCallback = (*optionsCallback)(*fileIter, finalReaderLabels, finalReaders, selectedReader); } - else if(extension == ".vtp") + if (selectedReader == NULL) { - mitk::SurfaceVtkWriter::Pointer surfaceWriter = mitk::SurfaceVtkWriter::New(); - surfaceWriter->SetInput( surface ); - surfaceWriter->SetFileName( finalFileName.c_str() ); - surfaceWriter->GetVtkWriter()->SetDataModeToBinary(); - surfaceWriter->Write(); + errMsg += "Reading operation(s) cancelled."; + break; } - else if(extension == ".vtk") + + // Do the actual reading + try { - mitk::SurfaceVtkWriter::Pointer surfaceWriter = mitk::SurfaceVtkWriter::New(); - surfaceWriter->SetInput( surface ); - surfaceWriter->SetFileName( finalFileName.c_str() ); - surfaceWriter->Write(); + // Correct conversion for File names.(BUG 12252) + const std::string& stdFile = *fileIter; + + DataStorage::SetOfObjects::Pointer nodes; + // Now do the actual reading + if (ds != NULL) + { + nodes = selectedReader->Read(stdFile, *ds); + } + else + { + nodes = DataStorage::SetOfObjects::New(); + std::vector baseData = selectedReader->Read(stdFile); + for (std::vector::iterator iter = baseData.begin(); + iter != baseData.end(); ++iter) + { + if (iter->IsNotNull()) + { + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(*iter); + nodes->InsertElement(nodes->Size(), node); + } + } + } + + for (DataStorage::SetOfObjects::ConstIterator nodeIter = nodes->Begin(), + nodeIterEnd = nodes->End(); nodeIter != nodeIterEnd; ++nodeIter) + { + const mitk::DataNode::Pointer& node = nodeIter->Value(); + mitk::BaseData::Pointer data = node->GetData(); + if (data.IsNull()) + { + continue; + } + + mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New(stdFile); + data->SetProperty("path", pathProp); + + if (result) + { + result->push_back(data); + } + if (nodeResult) + { + nodeResult->push_back(nodeIter->Value()); + } + } + + if ((result && result->empty()) || (nodeResult && nodeResult->Size() == 0)) + { + errMsg += "Unknown read error occurred reading " + stdFile; + } } - else + catch (const std::exception& e) { - // file extension not suitable for writing specified data type - MITK_ERROR << "File extension is not suitable for writing'" << finalFileName; - mitkThrow() << "An exception occured during writing the file " << finalFileName << - ". File extension " << extension << " is not suitable for writing."; + errMsg += "Exception occured when reading file " + *fileIter + ":\n" + e.what() + "\n\n"; } + mitk::ProgressBar::GetInstance()->Progress(2); + } } - catch(std::exception& e) + + for(std::vector::const_iterator readerIter = finalReaders.begin(), + readerIterEnd = finalReaders.end(); readerIter != readerIterEnd; ++readerIter) { - MITK_ERROR << " during attempt to write '" << finalFileName << "' Exception says:"; - MITK_ERROR << e.what(); - mitkThrow() << "An exception occured during writing the file " << finalFileName << ". Exception says " << e.what(); + readerRegistry.UngetReader(*readerIter); } - return true; - */ + } + + if (!errMsg.empty()) + { + MITK_ERROR << errMsg; + } + + return errMsg; } -bool IOUtil::SavePointSet(PointSet::Pointer pointset, const std::string& path) +void IOUtil::Save(BaseData* data, const std::string& path) { - return SaveBaseData(pointset, path); - /* - mitk::PointSetWriter::Pointer pointSetWriter = mitk::PointSetWriter::New(); + Save(data, path, IFileWriter::Options()); +} - std::string dir = itksys::SystemTools::GetFilenamePath( path ); - std::string baseFilename = itksys::SystemTools::GetFilenameWithoutLastExtension( path ); - std::string extension = itksys::SystemTools::GetFilenameLastExtension( path ); - if (dir == "") - dir = "."; - std::string finalFileName = dir + "/" + baseFilename; +void IOUtil::Save(BaseData* data, const std::string& path, const IFileWriter::Options& options) +{ + if (data == NULL) + { + mitkThrow() << "Cannot write a NULL" << data->GetNameOfClass() << " object."; + } + if (path.empty()) + { + mitkThrow() << "Cannot write a " << data->GetNameOfClass() << " object to an empty path."; + } - if (extension == "") // if no extension has been entered manually into the filename - { - MITK_WARN << extension << " extension is not set. Extension set to default: " << finalFileName - << DEFAULTPOINTSETEXTENSION; - extension = DEFAULTPOINTSETEXTENSION; - } + FileWriterRegistry writerRegistry; + us::ServiceReference writerRef = writerRegistry.GetReference(data); + // Throw exception if no compatible Writer was found + if (!writerRef) + { + mitkThrow() << "No writer for " << data->GetNameOfClass() << " available."; + } - // check if extension is valid - if (!pointSetWriter->IsExtensionValid(extension)) - { - MITK_WARN << extension << " extension is unknown. Extension set to default: " << finalFileName - << DEFAULTPOINTSETEXTENSION; - extension = DEFAULTPOINTSETEXTENSION; - } - try - { - pointSetWriter->SetInput( pointset ); - finalFileName += extension; - pointSetWriter->SetFileName( finalFileName.c_str() ); - pointSetWriter->Update(); - } - catch( std::exception& e ) - { - MITK_ERROR << " during attempt to write '" << finalFileName << "' Exception says:"; - MITK_ERROR << e.what(); - mitkThrow() << "An exception occured during writing the file " << finalFileName << ". Exception says " << e.what(); - } - return true; - */ -} +// std::string extension = itksys::SystemTools::GetFilenameExtension( path ); +// if(extension.empty()) +// { +// std::string defaultExtension = writerRegistry.GetDefaultExtension(writerRef); +// MITK_WARN << "Using default extension '" << defaultExtension << "' for writing to " << path; +// extension = "." + defaultExtension; +// } -bool IOUtil::SaveBaseData( mitk::BaseData* data, const std::string& path ) -{ - if (data == NULL || path.empty()) return false; + IFileWriter* writer = writerRegistry.GetWriter(writerRef); + if (writer == NULL) + { + mitkThrow() << "Got a NULL IFileWriter service for writing " << data->GetNameOfClass(); + } try { - mitk::FileWriterRegistry::Write(data, path); + if (!options.empty()) + { + writer->SetOptions(options); + } + writer->Write(data, path); } catch(const std::exception& e) { - MITK_ERROR << " Writing a " << data->GetNameOfClass() << " to " << path << " failed: " - << e.what(); - throw e; + mitkThrow() << " Writing a " << data->GetNameOfClass() << " to " << path << " failed: " + << e.what(); } +} + +bool IOUtil::SaveImage(mitk::Image::Pointer image, const std::string& path) +{ + Save(image, path); + return true; +} + +bool IOUtil::SaveSurface(Surface::Pointer surface, const std::string& path) +{ + Save(surface, path); + return true; +} +bool IOUtil::SavePointSet(PointSet::Pointer pointset, const std::string& path) +{ + Save(pointset, path); + return true; +} + +bool IOUtil::SaveBaseData( mitk::BaseData* data, const std::string& path) +{ + Save(data, path); return true; } -void IOUtil::SetDefaultDataNodeProperties(DataNode* node, const std::string& filePath) +void IOUtil::Impl::SetDefaultDataNodeProperties(DataNode* node, const std::string& filePath) { // path mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New( itksys::SystemTools::GetFilenamePath(filePath) ); node->SetProperty(StringProperty::PATH, pathProp); // name already defined? mitk::StringProperty::Pointer nameProp = dynamic_cast(node->GetProperty("name")); if(nameProp.IsNull() || (strcmp(nameProp->GetValue(),"No Name!")==0)) { // name already defined in BaseData mitk::StringProperty::Pointer baseDataNameProp = dynamic_cast(node->GetData()->GetProperty("name").GetPointer() ); if(baseDataNameProp.IsNull() || (strcmp(baseDataNameProp->GetValue(),"No Name!")==0)) { // name neither defined in node, nor in BaseData -> name = filename nameProp = mitk::StringProperty::New( itksys::SystemTools::GetFilenameWithoutExtension(filePath)); node->SetProperty("name", nameProp); } else { // name defined in BaseData! nameProp = mitk::StringProperty::New(baseDataNameProp->GetValue()); node->SetProperty("name", nameProp); } } // visibility if(!node->GetProperty("visible")) { node->SetVisibility(true); } } } diff --git a/Core/Code/IO/mitkIOUtil.h b/Core/Code/IO/mitkIOUtil.h index 127850d7b1..75d429e1bc 100644 --- a/Core/Code/IO/mitkIOUtil.h +++ b/Core/Code/IO/mitkIOUtil.h @@ -1,271 +1,365 @@ /*=================================================================== 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. ===================================================================*/ #ifndef MITKIOUTIL_H #define MITKIOUTIL_H #include #include #include #include #include +#include +#include + #include namespace mitk { /** * \ingroup IO * * \brief A utility class to load and save data from/to the local file system. * * This method LoadFiles queries the MITK Micro Services registry for registered mitk::IDataNodeReader service * instances. The service instance with the highest ranking will be asked first to load the * given file. On error (exception thrown) or if no mitk::DataNode was constructed, the next * service instance is used. * * The methods LoadImage, LoadSurface, and LoadPointSet are convenience methods for general loading of * the three main data types in MITK. They all use the more generic method LoadDataNode. * * The methods SaveImage, SaveSurface, and SurfacePointSet are also meant for convenience (e.g. during testing). * Currently, there is no generic way to save a generic DataNode with an appropriate format. Thus, every method * initializes the corresponding instance of the special writer for the data type. * * \see mitk::IDataNodeReader */ class MITK_CORE_EXPORT IOUtil { public: /** * Get the file system path where the running executable is located. * * @return The location of the currently running executable, without the filename. */ static std::string GetProgramPath(); /** * Get the default temporary path. * * @return The default path for temporary data. */ static std::string GetTempPath(); /** * Create and open a temporary file. * * This method generates a unique temporary filename from \c templateName, creates * and opens the file using the output stream \c tmpStream and returns the name of * the newly create file. * * The \c templateName argument must contain six consective 'X' characters ("XXXXXX") * and these are replaced with a string that makes the filename unique. * * The file is created with read and write permissions for owner only. * * @param tmpStream The output stream for writing to the temporary file. * @param templateName An optional template for the filename. * @param path An optional path where the temporary file should be created. Defaults * to the default temp path as returned by GetTempPath(). * @return The filename of the created temporary file. * * @throw mitk::Exception if the temporary file could not be created. */ static std::string CreateTemporaryFile(std::ofstream& tmpStream, const std::string& templateName = "XXXXXX", std::string path = std::string()); /** * Create and open a temporary file. * * This method generates a unique temporary filename from \c templateName, creates * and opens the file using the output stream \c tmpStream and the specified open * mode \c mode and returns the name of the newly create file. The open mode is always * OR'd with \begin{code}std::ios_base::out | std::ios_base::trunc\end{code}. * * The \c templateName argument must contain six consective 'X' characters ("XXXXXX") * and these are replaced with a string that makes the filename unique. * * The file is created with read and write permissions for owner only. * * @param tmpStream The output stream for writing to the temporary file. * @param mode The open mode for the temporary file stream. * @param templateName An optional template for the filename. * @param path An optional path where the temporary file should be created. Defaults * to the default temp path as returned by GetTempPath(). * @return The filename of the created temporary file. * * @throw mitk::Exception if the temporary file could not be created. */ static std::string CreateTemporaryFile(std::ofstream& tmpStream, std::ios_base::openmode mode, const std::string& templateName = "XXXXXX", std::string path = std::string()); /** * Creates an empty temporary file. * * This method generates a unique temporary filename from \c templateName and creates * this file. * * The file is created with read and write permissions for owner only. * * --- * This version is potentially unsafe because the created temporary file is not kept open * and could be used by another process between calling this method and opening the returned * file path for reading or writing. * --- * * @return The filename of the created temporary file. * @param templateName An optional template for the filename. * @param path An optional path where the temporary file should be created. Defaults * to the default temp path as returned by GetTempPath(). * @throw mitk::Exception if the temporary file could not be created. */ static std::string CreateTemporaryFile(const std::string& templateName = "XXXXXX", std::string path = std::string()); /** * Create a temporary directory. * * This method generates a uniquely named temporary directory from \c templateName. * The last set of six consecutive 'X' characters in \c templateName is replaced * with a string that makes the directory name unique. * * The directory is created with read, write and executable permissions for owner only. * * @param templateName An optional template for the directory name. * @param path An optional path where the temporary directory should be created. Defaults * to the default temp path as returned by GetTempPath(). * @return The filename of the created temporary file. * * @throw mitk::Exception if the temporary directory could not be created. */ static std::string CreateTemporaryDirectory(const std::string& templateName = "XXXXXX", std::string path = std::string()); + /** + * @brief Load a file into the given DataStorage. + * + * This method calls Load(const std::vector&, DataStorage&) with a + * one-element vector. + * + * @param path The absolute file name including the file extension. + * @param storage A DataStorage object to which the loaded data will be added. + * @return The set of added DataNode objects. + * @throws mitk::Exception if \c path could not be loaded. + * + * @sa Load(const std::vector&, DataStorage&) + */ + static DataStorage::SetOfObjects::Pointer Load(const std::string& path, DataStorage& storage); + + static DataStorage::SetOfObjects::Pointer Load(const std::string& path, + const IFileReader::Options& options, + DataStorage& storage); + + static std::vector Load(const std::string& path); + + static std::vector Load(const std::string& path, + const IFileReader::Options& options); + + /** + * @brief Loads a list of file paths into the given DataStorage. + * + * If an entry in \c paths cannot be loaded, this method will continue to load + * the remaining entries into \c storage and throw an exception afterwards. + * + * @param paths A list of absolute file names including the file extension. + * @param storage A DataStorage object to which the loaded data will be added. + * @return The set of added DataNode objects. + * @throws mitk::Exception if an entry in \c paths could not be loaded. + */ + static DataStorage::SetOfObjects::Pointer Load(const std::vector& paths, DataStorage& storage); + + static std::vector Load(const std::vector& paths); + /** * Load a files in fileNames and add the constructed mitk::DataNode instances * to the mitk::DataStorage storage * - * \param fileNames A list (vector) of absolute file name paths. - * \param storage The data storage to which the constructed data nodes are added. - * \return The number of added mitk::DataNode instances. + * @param fileNames A list (vector) of absolute file name paths. + * @param storage The data storage to which the constructed data nodes are added. + * @return The number of added mitk::DataNode instances. + * + * @deprecatedSince{2014_03} Use Load() instead */ - static int LoadFiles(const std::vector&fileNames, DataStorage& storage); + DEPRECATED(static int LoadFiles(const std::vector&fileNames, DataStorage& storage)); /** * This method will create a new mitk::DataStorage instance and pass it to * LoadFiles(std::vector,DataStorage). * - * \param fileNames A list (vector) of absolute file name paths. - * \return The new mitk::DataStorage containing the constructed data nodes. + * @param fileNames A list (vector) of absolute file name paths. + * @return The new mitk::DataStorage containing the constructed data nodes. + * + * @see LoadFiles(std::vector,DataStorage) * - * \see LoadFiles(std::vector,DataStorage) + * @deprecatedSince{2014_03} Use Load() instead */ - static DataStorage::Pointer LoadFiles(const std::vector& fileNames); + DEPRECATED(static DataStorage::Pointer LoadFiles(const std::vector& fileNames)); /** * @brief Create a BaseData object from the given file. * @param path The path to the file including file name and file extension. * @throws mitk::Exception In case of an error when reading the file. * @return Returns the created BaseData object. + * + * @deprecatedSince{2014_03} Use Load() or FileReaderRegistry::Read() instead. */ - static mitk::BaseData::Pointer LoadBaseData(const std::string& path); + DEPRECATED(static mitk::BaseData::Pointer LoadBaseData(const std::string& path)); /** * @brief LoadDataNode Method to load an arbitrary DataNode. * @param path The path to the file including file name and file extension. * @throws mitk::Exception This exception is thrown when the DataNodeFactory is not able to read/find the file * or the DataNode is NULL. * @return Returns the DataNode. + * + * @deprecatedSince{2014_03} Use Load() instead. */ - static mitk::DataNode::Pointer LoadDataNode(const std::string& path); + DEPRECATED(static mitk::DataNode::Pointer LoadDataNode(const std::string& path)); /** * @brief LoadImage Convenience method to load an arbitrary mitkImage. * @param path The path to the image including file name and file extension. * @throws mitk::Exception This exception is thrown when the Image is NULL. * @return Returns the mitkImage. */ static mitk::Image::Pointer LoadImage(const std::string& path); /** * @brief LoadSurface Convenience method to load an arbitrary mitkSurface. * @param path The path to the surface including file name and file extension. * @throws mitk::Exception This exception is thrown when the Surface is NULL. * @return Returns the mitkSurface. */ static mitk::Surface::Pointer LoadSurface(const std::string& path); /** * @brief LoadPointSet Convenience method to load an arbitrary mitkPointSet. * @param path The path to the pointset including file name and file extension (currently, only .mps is supported). * @throws mitk::Exception This exception is thrown when the PointSet is NULL. * @return Returns the mitkPointSet. */ static mitk::PointSet::Pointer LoadPointSet(const std::string& path); + + /** + * @brief Convenience method to save mitk::BaseData instances. + * @param path The path to the image including file name and file extension. + * If no extention is set, the default extension is used. + * @param data The data to save. + * @throws mitk::Exception if no writer for \c data is available or the writer + * is not able to write the image. + */ + static void Save(mitk::BaseData* data, const std::string& path); + + /** + * @brief Convenience method to save mitk::BaseData instances. + * @param path The path to the image including file name and file extension. + * If no extention is set, the default extension is used. + * @param data The data to save. + * @parma options Configuration data for the used IFileWriter instance. + * @throws mitk::Exception if no writer for \c data is available or the writer + * is not able to write the image. + */ + static void Save(mitk::BaseData* data, const std::string& path, const mitk::IFileWriter::Options& options); + /** * @brief SaveImage Convenience method to save an arbitrary mitkImage. * @param path The path to the image including file name and file extension. - * If not extention is set, the default value (defined in DEFAULTIMAGEEXTENSION) is used. + * If no extention is set, the default value (defined in DEFAULTIMAGEEXTENSION) is used. * @param image The image to save. * @throws mitk::Exception This exception is thrown when the writer is not able to write the image. * @return Returns true for success else false. + * + * @deprecatedSince{2014_03} Use Save() instead. */ - static bool SaveImage(mitk::Image::Pointer image, const std::string& path); + DEPRECATED(static bool SaveImage(mitk::Image::Pointer image, const std::string& path)); /** * @brief SaveBaseData Convenience method to save arbitrary baseData. * @param path The path to the image including file name and file extension. - * If not extention is set, the default value (defined in DEFAULTIMAGEEXTENSION) is used. + * If no extention is set, the default extension is used. * @param data The data to save. * @throws mitk::Exception This exception is thrown when the writer is not able to write the image. * @return Returns true for success else false. + * + * @deprecatedSince{2014_03} Use Save() instead. */ - static bool SaveBaseData(mitk::BaseData* data, const std::string& path); + DEPRECATED(static bool SaveBaseData(mitk::BaseData* data, const std::string& path)); /** * @brief SaveSurface Convenience method to save an arbitrary mitkSurface. * @param path The path to the surface including file name and file extension. - * If not extention is set, the default value (defined in DEFAULTSURFACEEXTENSION) is used. + * If no extention is set, the default extension is used. * @throws mitk::Exception This exception is thrown when the writer is not able to write the surface. * or if the fileextension is not suitable for writing. * @return Returns true for success else false. + * + * @deprecatedSince{2014_03} Use Save() instead. */ - static bool SaveSurface(mitk::Surface::Pointer surface, const std::string& path); + DEPRECATED(static bool SaveSurface(mitk::Surface::Pointer surface, const std::string& path)); /** * @brief SavePointSet Convenience method to save an mitkPointSet. - * @param path The path to the pointset including file name and file extension (currently, only .mps is supported). - * If not extention is set, the default value (defined in DEFAULTPOINTSETEXTENSION) is used. + * @param path The path to the pointset including file name and file extension. + * If no extention is set, the default extension is used. * @throws mitk::Exception This exception is thrown when the writer is not able to write the pointset. * @return Returns true for success else false. + * + * @deprecatedSince{2014_03} Use Save() instead. */ - static bool SavePointSet(mitk::PointSet::Pointer pointset, const std::string& path); + DEPRECATED(static bool SavePointSet(mitk::PointSet::Pointer pointset, const std::string& path)); + + /** @deprecatedSince{2014_03} Use GetDefaultWriteExtension() instead */ + DEPRECATED(static const std::string DEFAULTIMAGEEXTENSION); + /** @deprecatedSince{2014_03} Use GetDefaultWriteExtension() instead */ + DEPRECATED(static const std::string DEFAULTSURFACEEXTENSION); + /** @deprecatedSince{2014_03} Use GetDefaultWriteExtension() instead */ + DEPRECATED(static const std::string DEFAULTPOINTSETEXTENSION); + +protected: + + struct OptionsFunctorBase + { + virtual bool operator()(const std::string& path, const std::vector& readerLabels, + const std::vector& readers, IFileReader*& selectedReader) = 0; + }; - static const std::string DEFAULTIMAGEEXTENSION; - static const std::string DEFAULTSURFACEEXTENSION; - static const std::string DEFAULTPOINTSETEXTENSION; + static std::string Load(const std::vector& paths, std::vector* result, + DataStorage::SetOfObjects* nodeResult, DataStorage* ds, OptionsFunctorBase* optionsCallback); private: - static void SetDefaultDataNodeProperties(mitk::DataNode* node, const std::string& filePath = std::string()); + struct Impl; }; } #endif // MITKIOUTIL_H diff --git a/Core/Code/Interfaces/mitkIFileReader.h b/Core/Code/Interfaces/mitkIFileReader.h index 3f0e6e97c1..d60a0eeaf4 100644 --- a/Core/Code/Interfaces/mitkIFileReader.h +++ b/Core/Code/Interfaces/mitkIFileReader.h @@ -1,157 +1,159 @@ /*=================================================================== 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. ===================================================================*/ #ifndef IFileReader_H_HEADER_INCLUDED_C1E7E521 #define IFileReader_H_HEADER_INCLUDED_C1E7E521 // Macro #include // Microservices #include +#include // MITK #include +#include namespace mitk { class BaseData; - class DataStorage; } namespace itk { template class SmartPointer; } namespace mitk { /** * \brief The common interface for all MITK file readers. * * Implementations of this interface must be registered as a service * to make themselve available via the service registry. If the * implementation is state-full, the service should be registered using * a PrototypeServiceFactory. * * The file reader implementation is associated with a mime-type, specified * in the service property PROP_MIMETYPE(). The specified mime-type should * have a corresponding IMimeType service object, registered by the reader * or some other party. * * It is recommended to derive new implementations from AbstractFileReader, * which provides correct service registration semantics. * * \sa AbstractFileReader * \sa IMimeType * \sa FileReaderRegistry * \sa IFileWriter */ struct MITK_CORE_EXPORT IFileReader { virtual ~IFileReader(); - typedef std::pair Option; - typedef std::vector OptionNames; - typedef std::vector