diff --git a/Core/Code/CppMicroServices/CMake/usFunctionCheckCompilerFlags.cmake b/Core/Code/CppMicroServices/CMake/usFunctionCheckCompilerFlags.cmake index 8a3d1407d9..8e7e806576 100644 --- a/Core/Code/CppMicroServices/CMake/usFunctionCheckCompilerFlags.cmake +++ b/Core/Code/CppMicroServices/CMake/usFunctionCheckCompilerFlags.cmake @@ -1,53 +1,53 @@ # # Helper macro allowing to check if the given flags are supported # by the underlying build tool # # If the flag(s) is/are supported, they will be appended to the string identified by RESULT_VAR # # Usage: # usFunctionCheckCompilerFlags(FLAGS_TO_CHECK VALID_FLAGS_VAR) # # Example: # # set(myflags) # usFunctionCheckCompilerFlags("-fprofile-arcs" myflags) # message(1-myflags:${myflags}) # usFunctionCheckCompilerFlags("-fauto-bugfix" myflags) # message(2-myflags:${myflags}) # usFunctionCheckCompilerFlags("-Wall" myflags) # message(1-myflags:${myflags}) # # The output will be: # 1-myflags: -fprofile-arcs # 2-myflags: -fprofile-arcs # 3-myflags: -fprofile-arcs -Wall include(TestCXXAcceptsFlag) function(usFunctionCheckCompilerFlags CXX_FLAG_TO_TEST RESULT_VAR) if(CXX_FLAG_TO_TEST STREQUAL "") message(FATAL_ERROR "CXX_FLAG_TO_TEST shouldn't be empty") endif() set(_test_flag ${CXX_FLAG_TO_TEST}) CHECK_CXX_ACCEPTS_FLAG("-Werror=unknown-warning-option" HAS_FLAG_unknown-warning-option) if(HAS_FLAG_unknown-warning-option) set(_test_flag "-Werror=unknown-warning-option ${CXX_FLAG_TO_TEST}") endif() # Internally, the macro CMAKE_CXX_ACCEPTS_FLAG calls TRY_COMPILE. To avoid # the cost of compiling the test each time the project is configured, the variable set by # the macro is added to the cache so that following invocation of the macro with # the same variable name skip the compilation step. - # For that same reason, ctkFunctionCheckCompilerFlags function appends a unique suffix to + # For that same reason, usFunctionCheckCompilerFlags function appends a unique suffix to # the HAS_FLAG variable. This suffix is created using a 'clean version' of the flag to test. string(REGEX REPLACE "-\\s\\$\\+\\*\\{\\}\\(\\)\\#" "" suffix ${CXX_FLAG_TO_TEST}) CHECK_CXX_ACCEPTS_FLAG(${_test_flag} HAS_FLAG_${suffix}) if(HAS_FLAG_${suffix}) set(${RESULT_VAR} "${${RESULT_VAR}} ${CXX_FLAG_TO_TEST}" PARENT_SCOPE) endif() endfunction() diff --git a/Core/Code/CppMicroServices/CMake/usFunctionCreateTestModule.cmake b/Core/Code/CppMicroServices/CMake/usFunctionCreateTestModule.cmake index edae38c466..3158dc6de9 100644 --- a/Core/Code/CppMicroServices/CMake/usFunctionCreateTestModule.cmake +++ b/Core/Code/CppMicroServices/CMake/usFunctionCreateTestModule.cmake @@ -1,33 +1,46 @@ macro(_us_create_test_module_helper) + if(_res_files) + usFunctionEmbedResources(_srcs LIBRARY_NAME ${name} ROOT_DIR resources FILES ${_res_files}) + endif() + add_library(${name} ${_srcs}) if(NOT US_BUILD_SHARED_LIBS) set_property(TARGET ${name} APPEND PROPERTY COMPILE_DEFINITIONS US_STATIC_MODULE) endif() if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") get_property(_compile_flags TARGET ${name} PROPERTY COMPILE_FLAGS) set_property(TARGET ${name} PROPERTY COMPILE_FLAGS "${_compile_flags} -fPIC") endif() target_link_libraries(${name} ${US_LINK_LIBRARIES}) if(NOT US_ENABLE_SERVICE_FACTORY_SUPPORT) target_link_libraries(${name} ${US_BASECLASS_LIBRARIES}) endif() set(_us_test_module_libs "${_us_test_module_libs};${name}" CACHE INTERNAL "" FORCE) endmacro() function(usFunctionCreateTestModuleWithAutoLoadDir name autoload_dir) set(_srcs ${ARGN}) usFunctionGenerateModuleInit(_srcs NAME "${name} Module" LIBRARY_NAME ${name} AUTOLOAD_DIR ${autoload_dir}) _us_create_test_module_helper() endfunction() function(usFunctionCreateTestModule name) set(_srcs ${ARGN}) + set(_res_files ) + usFunctionGenerateModuleInit(_srcs NAME "${name} Module" LIBRARY_NAME ${name}) + _us_create_test_module_helper() +endfunction() + +function(usFunctionCreateTestModuleWithResources name) + MACRO_PARSE_ARGUMENTS(US_TEST "SOURCES;RESOURCES" "" ${ARGN}) + set(_srcs ${US_TEST_SOURCES}) + set(_res_files ${US_TEST_RESOURCES}) usFunctionGenerateModuleInit(_srcs NAME "${name} Module" LIBRARY_NAME ${name}) _us_create_test_module_helper() endfunction() diff --git a/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake b/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake new file mode 100644 index 0000000000..b19976ce66 --- /dev/null +++ b/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake @@ -0,0 +1,52 @@ +function(usFunctionEmbedResources src_var) + + MACRO_PARSE_ARGUMENTS(US_RESOURCE "LIBRARY_NAME;ROOT_DIR;FILES" "" ${ARGN}) + + if(NOT src_var) + message(SEND_ERROR "Output variable name not specified.") + endif() + + if(NOT US_RESOURCE_LIBRARY_NAME) + message(SEND_ERROR "LIBRARY_NAME argument not specified.") + endif() + + if(NOT US_RESOURCE_FILES) + message(WARNING "No FILES argument given. Skipping resource processing.") + return() + endif() + + if(NOT US_RESOURCE_ROOT_DIR) + set(US_RESOURCE_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + if(NOT IS_ABSOLUTE ${US_RESOURCE_ROOT_DIR}) + set(US_RESOURCE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${US_RESOURCE_ROOT_DIR}") + endif() + if(NOT IS_DIRECTORY ${US_RESOURCE_ROOT_DIR}) + message(SEND_ERROR "The ROOT_DIR argument is not a directory: ${US_RESOURCE_ROOT_DIR}") + endif() + + set(absolute_res_files) + foreach(res_file ${US_RESOURCE_FILES}) + set(res_file "${US_RESOURCE_ROOT_DIR}/${res_file}") + if(IS_DIRECTORY ${res_file}) + message(SEND_ERROR "A resource cannot be a directory: ${res_file}") + endif() + if(NOT EXISTS ${res_file}) + message(SEND_ERROR "Resource does not exists: ${res_file}") + endif() + file(TO_NATIVE_PATH "${res_file}" res_file) + list(APPEND absolute_res_files ${res_file}) + endforeach() + + set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_LIBRARY_NAME}_resources.cpp") + add_custom_command( + OUTPUT ${us_cpp_resource_file} + COMMAND ${US_RCC_EXECUTABLE_NAME} ${US_RESOURCE_LIBRARY_NAME} ${us_cpp_resource_file} ${absolute_res_files} + WORKING_DIRECTORY ${US_RESOURCE_ROOT_DIR} + DEPENDS ${absolute_res_files} + COMMENT "Generating embedded resource file ${us_cpp_resource_name}" + ) + + set(${src_var} "${${src_var}};${us_cpp_resource_file}" PARENT_SCOPE) + +endfunction() diff --git a/Core/Code/CppMicroServices/CMakeLists.txt b/Core/Code/CppMicroServices/CMakeLists.txt index ae8ccf7a1f..8fd305999b 100644 --- a/Core/Code/CppMicroServices/CMakeLists.txt +++ b/Core/Code/CppMicroServices/CMakeLists.txt @@ -1,340 +1,355 @@ project(CppMicroServices) set(${PROJECT_NAME}_MAJOR_VERSION 0) set(${PROJECT_NAME}_MINOR_VERSION 99) set(${PROJECT_NAME}_PATCH_VERSION 0) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) cmake_minimum_required(VERSION 2.8) #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(MacroParseArguments) include(CheckCXXSourceCompiles) include(usFunctionCheckCompilerFlags) +include(usFunctionEmbedResources) include(usFunctionGetGccVersion) include(usFunctionGenerateModuleInit) #----------------------------------------------------------------------------- # Init output directories #----------------------------------------------------------------------------- set(US_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") foreach(_type ARCHIVE LIBRARY RUNTIME) if(NOT CMAKE_${_type}_OUTPUT_DIRECTORY) set(CMAKE_${_type}_OUTPUT_DIRECTORY ${US_${_type}_OUTPUT_DIRECTORY}) endif() endforeach() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # CMake options #----------------------------------------------------------------------------- function(us_cache_var _var_name _var_default _var_type _var_help) set(_advanced 0) set(_force) foreach(_argn ${ARGN}) if(_argn STREQUAL ADVANCED) set(_advanced 1) elseif(_argn STREQUAL FORCE) set(_force FORCE) endif() endforeach() if(US_IS_EMBEDDED) if(NOT DEFINED ${_var_name} OR _force) set(${_var_name} ${_var_default} PARENT_SCOPE) endif() else() set(${_var_name} ${_var_default} CACHE ${_var_type} "${_var_help}" ${_force}) if(_advanced) mark_as_advanced(${_var_name}) endif() endif() endfunction() # Determine if we are being build inside a larger project if(NOT DEFINED US_IS_EMBEDDED) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(US_IS_EMBEDDED 0) else() set(US_IS_EMBEDDED 1) set(CppMicroServices_EXPORTS 1) endif() endif() us_cache_var(US_ENABLE_AUTOLOADING_SUPPORT OFF BOOL "Enable module auto-loading support") us_cache_var(US_ENABLE_SERVICE_FACTORY_SUPPORT ON BOOL "Enable Service Factory support" ADVANCED) us_cache_var(US_ENABLE_THREADING_SUPPORT OFF BOOL "Enable threading support") us_cache_var(US_BUILD_SHARED_LIBS ON BOOL "Build shared libraries") us_cache_var(US_BUILD_TESTING OFF BOOL "Build tests") if(MSVC10 OR MSVC11) # Visual Studio 2010 and newer have support for C++11 enabled by default set(US_USE_C++11 1) else() us_cache_var(US_USE_C++11 OFF BOOL "Enable the use of C++11 features" ADVANCED) endif() us_cache_var(US_NAMESPACE "us" STRING "The namespace for the C++ micro services entities") us_cache_var(US_HEADER_PREFIX "" STRING "The file name prefix for the public C++ micro services header files") us_cache_var(US_BASECLASS_NAME "" STRING "The fully-qualified name of the base class") if(US_ENABLE_SERVICE_FACTORY_SUPPORT) us_cache_var(US_BASECLASS_PACKAGE "" STRING "The name of the package providing the base class definition" ADVANCED) set(bc_inc_d_doc "A list of include directories containing the header files for the base class") us_cache_var(US_BASECLASS_INCLUDE_DIRS "" STRING "${bc_inc_d_doc}" ADVANCED) set(bc_lib_d_doc "A list of library directories for the base class") us_cache_var(US_BASECLASS_LIBRARY_DIRS "" STRING "${bc_lib_d_doc}" ADVANCED) set(bc_lib_doc "A list of libraries needed for the base class") us_cache_var(US_BASECLASS_LIBRARIES "" STRING "${bc_lib_doc}" ADVANCED) us_cache_var(US_BASECLASS_HEADER "" STRING "The name of the header file containing the base class declaration" ADVANCED) endif() set(BUILD_SHARED_LIBS ${US_BUILD_SHARED_LIBS}) # Sanity checks if(US_ENABLE_SERVICE_FACTORY_SUPPORT OR US_BUILD_TESTING) if(US_BASECLASS_PACKAGE) find_package(${US_BASECLASS_PACKAGE} REQUIRED) # Try to get the include dirs foreach(_suffix DIRECTORIES DIRS DIRECTORY DIR) if(${US_BASECLASS_PACKAGE}_INCLUDE_${_suffix} AND NOT US_BASECLASS_INCLUDE_DIRS) us_cache_var(US_BASECLASS_INCLUDE_DIRS "${${US_BASECLASS_PACKAGE}_INCLUDE_${_suffix}}" STRING "${bc_inc_d_doc}" FORCE) break() endif() endforeach() # Try to get the library dirs foreach(_suffix DIRECTORIES DIRS DIRECTORY DIR) if(${US_BASECLASS_PACKAGE}_LIBRARY_${_suffix} AND NOT US_BASECLASS_LIBRARY_DIRS) us_cache_var(US_BASECLASS_LIBRARY_DIRS "${${US_BASECLASS_PACKAGE}_LIBRARY_${_suffix}}" STRING "${bc_lib_d_doc}" FORCE) break() endif() endforeach() # Try to get the libraries foreach(_suffix LIBRARIES LIBS LIBRARY LIB) if(${US_BASECLASS_PACKAGE}_${_suffix} AND NOT US_BASECLASS_LIBRARIES) us_cache_var(US_BASECLASS_LIBRARIES "${${US_BASECLASS_PACKAGE}_${_suffix}}" STRING "${bc_lib_doc}" FORCE) break() endif() endforeach() if(NOT US_BASECLASS_NAME) message(FATAL_ERROR "US_BASECLASS_NAME not set") elseif(NOT US_BASECLASS_HEADER) message(FATAL_ERROR "US_BASECLASS_HEADER not set") endif() endif() if(US_ENABLE_SERVICE_FACTORY_SUPPORT AND US_BASECLASS_NAME AND NOT US_BASECLASS_HEADER) message(FATAL_ERROR "US_ENABLE_SERVICE_FACTORY_SUPPORT requires a US_BASECLASS_HEADER value") endif() endif() set(_us_baseclass_default 0) if(NOT US_BASECLASS_NAME) message(WARNING "Using build in base class \"::${US_NAMESPACE}::Base\"") set(_us_baseclass_default 1) set(US_BASECLASS_NAME "${US_NAMESPACE}::Base") set(US_BASECLASS_HEADER "usBase.h") endif() if(US_BUILD_TESTING AND US_BASECLASS_NAME AND NOT US_BASECLASS_HEADER) message(FATAL_ERROR "US_BUILD_TESTING requires a US_BASECLASS_HEADER value") endif() set(US_BASECLASS_INCLUDE "#include <${US_BASECLASS_HEADER}>") string(REPLACE "::" ";" _bc_token "${US_BASECLASS_NAME}") list(GET _bc_token -1 _bc_name) list(REMOVE_AT _bc_token -1) set(US_BASECLASS_FORWARD_DECLARATION "") foreach(_namespace_tok ${_bc_token}) if(_namespace_tok) set(US_BASECLASS_FORWARD_DECLARATION "${US_BASECLASS_FORWARD_DECLARATION}namespace ${_namespace_tok} { ") endif() endforeach() set(US_BASECLASS_FORWARD_DECLARATION "${US_BASECLASS_FORWARD_DECLARATION}class ${_bc_name}; ") foreach(_namespace_tok ${_bc_token}) if(_namespace_tok) set(US_BASECLASS_FORWARD_DECLARATION "${US_BASECLASS_FORWARD_DECLARATION}}") endif() endforeach() #----------------------------------------------------------------------------- # US C/CXX Flags #----------------------------------------------------------------------------- set(US_C_FLAGS "${COVERAGE_C_FLAGS} ${ADDITIONAL_C_FLAGS}") set(US_CXX_FLAGS "${COVERAGE_CXX_FLAGS} ${ADDITIONAL_CXX_FLAGS}") # This is used as a preprocessor define set(US_USE_CXX11 ${US_USE_C++11}) # Set C++ compiler flags if(NOT MSVC) foreach(_cxxflag -Werror -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast -Wstrict-null-sentinel -Wsign-promo -fdiagnostics-show-option -D_FORTIFY_SOURCE=2) usFunctionCheckCompilerFlags(${_cxxflag} US_CXX_FLAGS) endforeach() if(US_USE_C++11) usFunctionCheckCompilerFlags("-std=c++0x" US_CXX_FLAGS) endif() endif() if(CMAKE_COMPILER_IS_GNUCXX) usFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) # With older versions of gcc the flag -fstack-protector-all requires an extra dependency to libssp.so. # If the gcc version is lower than 4.4.0 and the build type is Release let's not include the flag. if(${GCC_VERSION} VERSION_GREATER "4.4.0" OR (CMAKE_BUILD_TYPE STREQUAL "Debug" AND ${GCC_VERSION} VERSION_LESS "4.4.0")) usFunctionCheckCompilerFlags("-fstack-protector-all" US_CXX_FLAGS) endif() if(MINGW) # suppress warnings about auto imported symbols set(US_CXX_FLAGS "-Wl,--enable-auto-import ${US_CXX_FLAGS}") # we need to define a Windows version set(US_CXX_FLAGS "-D_WIN32_WINNT=0x0500 ${US_CXX_FLAGS}") else() # Enable visibility support if(NOT ${GCC_VERSION} VERSION_LESS "4.5") usFunctionCheckCompilerFlags("-fvisibility=hidden -fvisibility-inlines-hidden" US_CXX_FLAGS) endif() endif() -elseif(MSVC90 OR MSVC10 OR MSVC11) - set(US_CXX_FLAGS "/MP ${US_CXX_FLAGS}") +elseif(MSVC) + set(US_CXX_FLAGS "/MP /wd4996 ${US_CXX_FLAGS}") endif() if(NOT US_IS_EMBEDDED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${US_CXX_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${US_C_FLAGS}") endif() #----------------------------------------------------------------------------- # US Link Flags #----------------------------------------------------------------------------- set(US_LINK_FLAGS ) if(NOT MSVC) foreach(_linkflag -Wl,--no-undefined) set(_add_flag) usFunctionCheckCompilerFlags("${_linkflag}" _add_flag) if(_add_flag) set(US_LINK_FLAGS "${US_LINK_FLAGS} ${_linkflag}") endif() endforeach() endif() +#----------------------------------------------------------------------------- +# US Header Checks +#----------------------------------------------------------------------------- + +include(CheckIncludeFile) + +CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT) + #----------------------------------------------------------------------------- # US include dirs and libraries #----------------------------------------------------------------------------- set(US_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/include ) set(US_INTERNAL_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src/util ${CMAKE_CURRENT_SOURCE_DIR}/src/service ${CMAKE_CURRENT_SOURCE_DIR}/src/module ) if(US_ENABLE_SERVICE_FACTORY_SUPPORT) list(APPEND US_INTERNAL_INCLUDE_DIRS ${US_BASECLASS_INCLUDE_DIRS}) endif() # link libraries for third party libs if(US_IS_EMBEDDED) set(US_LINK_LIBRARIES ${US_EMBEDDING_LIBRARY}) else() set(US_LINK_LIBRARIES ${PROJECT_NAME}) endif() # link libraries for the CppMicroServices lib set(_link_libraries ) if(UNIX) list(APPEND _link_libraries dl) endif() list(APPEND US_LINK_LIBRARIES ${_link_libraries}) if(US_ENABLE_SERVICE_FACTORY_SUPPORT) list(APPEND US_LINK_LIBRARIES ${US_BASECLASS_LIBRARIES}) endif() set(US_LINK_DIRS ) if(US_ENABLE_SERVICE_FACTORY_SUPPORT) list(APPEND US_LINK_DIRS ${US_BASECLASS_LIBRARY_DIRS}) endif() #----------------------------------------------------------------------------- # Source directory #----------------------------------------------------------------------------- set(us_config_h_file "${PROJECT_BINARY_DIR}/include/usConfig.h") configure_file(usConfig.h.in ${us_config_h_file}) +set(US_RCC_EXECUTABLE_NAME usResourceCompiler) +set(US_RCC_EXECUTABLE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${US_RCC_EXECUTABLE_NAME}") + +add_subdirectory(tools) + add_subdirectory(src) + #----------------------------------------------------------------------------- # US testing #----------------------------------------------------------------------------- if(US_BUILD_TESTING) enable_testing() add_subdirectory(test) endif() #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- add_subdirectory(documentation) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- configure_file(${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY) diff --git a/Core/Code/CppMicroServices/src/CMakeLists.txt b/Core/Code/CppMicroServices/src/CMakeLists.txt index a30ce07ecc..12959997e7 100644 --- a/Core/Code/CppMicroServices/src/CMakeLists.txt +++ b/Core/Code/CppMicroServices/src/CMakeLists.txt @@ -1,169 +1,181 @@ #----------------------------------------------------------------------------- # US source files #----------------------------------------------------------------------------- set(_srcs util/usAny.cpp util/usThreads.cpp util/usUtils.cpp service/usLDAPExpr.cpp service/usLDAPFilter.cpp service/usServiceException.cpp service/usServiceEvent.cpp service/usServiceListenerEntry.cpp service/usServiceListenerEntry_p.h service/usServiceListeners.cpp service/usServiceListeners_p.h service/usServiceProperties.cpp service/usServiceReference.cpp service/usServiceReferencePrivate.cpp service/usServiceRegistration.cpp service/usServiceRegistrationPrivate.cpp service/usServiceRegistry.cpp service/usServiceRegistry_p.h module/usCoreModuleContext_p.h module/usCoreModuleContext.cpp module/usModuleContext.cpp module/usModule.cpp module/usModuleEvent.cpp module/usModuleInfo.cpp module/usModulePrivate.cpp module/usModuleRegistry.cpp + module/usModuleResource.cpp + module/usModuleResourceBuffer.cpp + module/usModuleResourceStream.cpp + module/usModuleResourceTree.cpp module/usModuleSettings.cpp module/usModuleUtils.cpp module/usModuleVersion.cpp ) set(_private_headers util/usAtomicInt_p.h util/usFunctor_p.h util/usStaticInit_p.h util/usThreads_p.h util/usUtils_p.h - + + util/dirent_win32_p.h + util/stdint_p.h + util/stdint_vc_p.h + service/usServiceTracker.tpp service/usServiceTrackerPrivate.h service/usServiceTrackerPrivate.tpp service/usTrackedService_p.h service/usTrackedServiceListener_p.h service/usTrackedService.tpp - + module/usModuleAbstractTracked_p.h module/usModuleAbstractTracked.tpp + module/usModuleResourceBuffer_p.h + module/usModuleResourceTree_p.h module/usModuleUtils_p.h ) set(_public_headers util/usAny.h util/usSharedData.h - + service/usLDAPFilter.h service/usServiceEvent.h service/usServiceException.h service/usServiceInterface.h service/usServiceProperties.h service/usServiceReference.h service/usServiceRegistration.h service/usServiceTracker.h service/usServiceTrackerCustomizer.h - + module/usGetModuleContext.h module/usModule.h module/usModuleActivator.h module/usModuleContext.h module/usModuleEvent.h module/usModuleImport.h module/usModuleInfo.h module/usModuleInitialization.h module/usModuleRegistry.h + module/usModuleResource.h + module/usModuleResourceStream.h module/usModuleSettings.h module/usModuleVersion.h ) if(_us_baseclass_default) list(APPEND _public_headers util/usBase.h) endif() if(US_ENABLE_SERVICE_FACTORY_SUPPORT) list(APPEND _public_headers service/usServiceFactory.h) endif() if(US_IS_EMBEDDED) set(US_SOURCES ) get_filename_component(_path_prefix "${PROJECT_SOURCE_DIR}" NAME) set(_path_prefix "${_path_prefix}/src") foreach(_src ${_srcs} ${_public_headers} ${_private_headers}) list(APPEND US_SOURCES ${_path_prefix}/${_src}) endforeach() set(US_SOURCES ${US_SOURCES} PARENT_SCOPE) endif() #----------------------------------------------------------------------------- # Create library (only if not in embedded mode) #----------------------------------------------------------------------------- if(NOT US_IS_EMBEDDED) include_directories(${US_INTERNAL_INCLUDE_DIRS}) if(US_LINK_DIRS) link_directories(${US_LINK_DIRS}) endif() usFunctionGenerateModuleInit(_srcs NAME ${PROJECT_NAME} VERSION "0.9.0") add_library(${PROJECT_NAME} ${_srcs} ${_public_headers} ${_private_headers} ${us_config_h_file}) if(NOT US_IS_EMBEDDED AND US_LINK_FLAGS) set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "${US_LINK_FLAGS}") endif() set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY COMPILE_DEFINITIONS US_FORCE_MODULE_INIT) set_property(TARGET ${PROJECT_NAME} PROPERTY FRAMEWORK 1) if(US_LINK_LIBRARIES) target_link_libraries(${PROJECT_NAME} ${US_LINK_LIBRARIES}) endif() endif() #----------------------------------------------------------------------------- # Configure public header wrappers #----------------------------------------------------------------------------- set(US_PUBLIC_HEADERS ${_public_headers}) if(US_HEADER_PREFIX) set(US_PUBLIC_HEADERS ) foreach(_public_header ${_public_headers}) get_filename_component(_public_header_basename ${_public_header} NAME_WE) set(_us_public_header ${_public_header_basename}.h) string(SUBSTRING "${_public_header_basename}" 2 -1 _public_header_basename) set(_header_wrapper "${PROJECT_BINARY_DIR}/include/${US_HEADER_PREFIX}${_public_header_basename}.h") configure_file(${PROJECT_SOURCE_DIR}/CMake/usPublicHeaderWrapper.h.in ${_header_wrapper} @ONLY) list(APPEND US_PUBLIC_HEADERS ${_header_wrapper}) endforeach() endif() foreach(_header ${_public_headers} ${_private_headers}) get_filename_component(_header_name "${_header}" NAME) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${_header} "${PROJECT_BINARY_DIR}/include/${_header_name}") endforeach() if(NOT US_IS_EMBEDDED) set_property(TARGET ${PROJECT_NAME} PROPERTY PUBLIC_HEADER ${US_PUBLIC_HEADERS}) set_property(TARGET ${PROJECT_NAME} PROPERTY PRIVATE_HEADER ${_private_headers} ${us_config_h_file}) else() set(US_PUBLIC_HEADERS ${US_PUBLIC_HEADERS} PARENT_SCOPE) set(US_PRIVATE_HEADERS ${US_PRIVATE_HEADERS} PARENT_SCOPE) endif() #----------------------------------------------------------------------------- # Install support (only if not in embedded mode) #----------------------------------------------------------------------------- if(NOT US_IS_EMBEDDED) install(TARGETS ${PROJECT_NAME} FRAMEWORK DESTINATION . RUNTIME DESTINATION bin LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib + ARCHIVE DESTINATION lib PUBLIC_HEADER DESTINATION include PRIVATE_HEADER DESTINATION include) endif() diff --git a/Core/Code/CppMicroServices/src/module/usModule.cpp b/Core/Code/CppMicroServices/src/module/usModule.cpp index 84da72f744..4d53927e5c 100644 --- a/Core/Code/CppMicroServices/src/module/usModule.cpp +++ b/Core/Code/CppMicroServices/src/module/usModule.cpp @@ -1,243 +1,262 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include "usModule.h" #include "usModuleContext.h" #include "usModuleActivator.h" #include "usModulePrivate.h" +#include "usModuleResource.h" #include "usModuleSettings.h" #include "usCoreModuleContext_p.h" US_BEGIN_NAMESPACE const std::string& Module::PROP_ID() { static const std::string s("module.id"); return s; } const std::string& Module::PROP_NAME() { static const std::string s("module.name"); return s; } const std::string& Module::PROP_LOCATION() { static const std::string s("module.location"); return s; } const std::string& Module::PROP_MODULE_DEPENDS() { static const std::string s("module.module_depends"); return s; } const std::string& Module::PROP_LIB_DEPENDS() { static const std::string s("module.lib_depends"); return s; } const std::string& Module::PROP_VERSION() { static const std::string s("module.version"); return s; } Module::Module() : d(0) { } Module::~Module() { delete d; } void Module::Init(CoreModuleContext* coreCtx, ModuleInfo* info) { ModulePrivate* mp = new ModulePrivate(this, coreCtx, info); std::swap(mp, d); delete mp; } void Module::Uninit() { if (d->moduleContext) { delete d->moduleContext; d->moduleContext = 0; } d->moduleActivator = 0; } bool Module::IsLoaded() const { return d->moduleContext != 0; } void Module::Start() { if (d->moduleContext) { US_WARN << "Module " << d->info.name << " already started."; return; } d->moduleContext = new ModuleContext(this->d); // try // { d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADING, this)); // try to get a ModuleActivator instance if (d->info.activatorHook) { try { d->moduleActivator = d->info.activatorHook(); } catch (...) { US_ERROR << "Creating the module activator of " << d->info.name << " failed"; throw; } d->moduleActivator->Load(d->moduleContext); } d->StartStaticModules(); #ifdef US_ENABLE_AUTOLOADING_SUPPORT if (ModuleSettings::IsAutoLoadingEnabled()) { AutoLoadModules(d->info); } #endif d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::LOADED, this)); // } // catch (...) // { // d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADING, this)); // d->RemoveModuleResources(); // delete d->moduleContext; // d->moduleContext = 0; // d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); // US_ERROR << "Calling the module activator Load() method of " << d->info.name << " failed!"; // throw; // } } void Module::Stop() { if (d->moduleContext == 0) { US_WARN << "Module " << d->info.name << " already stopped."; return; } try { d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADING, this)); d->StopStaticModules(); if (d->moduleActivator) { d->moduleActivator->Unload(d->moduleContext); } } catch (...) { US_WARN << "Calling the module activator Unload() method of " << d->info.name << " failed!"; try { d->RemoveModuleResources(); } catch (...) {} delete d->moduleContext; d->moduleContext = 0; d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); throw; } d->RemoveModuleResources(); delete d->moduleContext; d->moduleContext = 0; d->coreCtx->listeners.ModuleChanged(ModuleEvent(ModuleEvent::UNLOADED, this)); } ModuleContext* Module::GetModuleContext() const { return d->moduleContext; } long Module::GetModuleId() const { return d->info.id; } std::string Module::GetLocation() const { return d->info.location; } std::string Module::GetName() const { return d->info.name; } ModuleVersion Module::GetVersion() const { return d->version; } std::string Module::GetProperty(const std::string& key) const { if (d->properties.count(key) == 0) return ""; return d->properties[key]; } +ModuleResource Module::GetResource(const std::string &name) const +{ + if (!d->resourceTree.IsValid()) return ModuleResource(); + + return ModuleResource(name, &d->resourceTree); +} + +std::vector Module::FindResources(const std::string& path, const std::string& filePattern, + bool recurse) const +{ + std::vector result; + if (d->resourceTree.IsValid()) + { + d->resourceTree.FindNodes(path, filePattern, recurse, result); + } + return result; +} + US_END_NAMESPACE US_USE_NAMESPACE std::ostream& operator<<(std::ostream& os, const Module& module) { os << "Module[" << "id=" << module.GetModuleId() << ", loc=" << module.GetLocation() << ", name=" << module.GetName() << "]"; return os; } std::ostream& operator<<(std::ostream& os, Module const * module) { return operator<<(os, *module); } diff --git a/Core/Code/CppMicroServices/src/module/usModule.h b/Core/Code/CppMicroServices/src/module/usModule.h index b0ef8c003f..9568bc2b55 100644 --- a/Core/Code/CppMicroServices/src/module/usModule.h +++ b/Core/Code/CppMicroServices/src/module/usModule.h @@ -1,214 +1,221 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USMODULE_H #define USMODULE_H #include "usModuleVersion.h" +#include + US_BEGIN_NAMESPACE class CoreModuleContext; struct ModuleInfo; class ModuleContext; +class ModuleResource; class ModulePrivate; /** * \ingroup MicroServices * * Represents a CppMicroServices module. * *

* A %Module object is the access point to a CppMicroServices module. * Each CppMicroServices module has an associated %Module object. * *

* A module has unique identity, a long, chosen by the * framework. This identity does not change during the lifecycle of a module. * *

* A module can be in one of two states: *

    *
  • LOADED *
  • UNLOADED *
*

* You can determine the current state by using IsLoaded(). * *

* A module can only execute code when its state is LOADED. * An UNLOADED module is a * zombie and can only be reached because it was loaded before. However, * unloaded modules can be loaded again. * *

* The framework is the only entity that is allowed to create * %Module objects. * * @remarks This class is thread safe. */ class US_EXPORT Module { public: static const std::string& PROP_ID(); static const std::string& PROP_NAME(); static const std::string& PROP_LOCATION(); static const std::string& PROP_MODULE_DEPENDS(); static const std::string& PROP_LIB_DEPENDS(); static const std::string& PROP_VERSION(); ~Module(); /** * Returns this module's current state. * *

* A module can be in only one state at any time. * * @return true if the module is LOADED * false if it is UNLOADED */ bool IsLoaded() const; /** * Returns this module's {@link ModuleContext}. The returned * ModuleContext can be used by the caller to act on behalf * of this module. * *

* If this module is not in the LOADED state, then this * module has no valid ModuleContext. This method will * return 0 if this module has no valid * ModuleContext. * * @return A ModuleContext for this module or * 0 if this module has no valid * ModuleContext. */ ModuleContext* GetModuleContext() const; /** * Returns this module's unique identifier. This module is assigned a unique * identifier by the framework when it was loaded. * *

* A module's unique identifier has the following attributes: *

    *
  • Is unique. *
  • Is a long. *
  • Its value is not reused for another module, even after a module is * unloaded. *
  • Does not change while a module remains loaded. *
  • Does not change when a module is reloaded. *
* *

* This method continues to return this module's unique identifier while * this module is in the UNLOADED state. * * @return The unique identifier of this module. */ long GetModuleId() const; /** * Returns this module's location. * *

* The location is the full path to the module's shared library. * This method continues to return this module's location * while this module is in the UNLOADED state. * * @return The string representation of this module's location. */ std::string GetLocation() const; /** * Returns the name of this module as specified by the * US_CREATE_MODULE CMake macro. The module * name together with a version must identify a unique module. * *

* This method continues to return this module's name while * this module is in the UNLOADED state. * * @return The name of this module. */ std::string GetName() const; /** * Returns the version of this module as specified by the * US_INITIALIZE_MODULE CMake macro. If this module does not have a * specified version then {@link ModuleVersion::EmptyVersion} is returned. * *

* This method continues to return this module's version while * this module is in the UNLOADED state. * * @return The version of this module. */ ModuleVersion GetVersion() const; /** * Returns the value of the specified property for this module. The * method returns an empty string if the property is not found. * * @param key The name of the requested property. * @return The value of the requested property, or an empty string * if the property is undefined. */ std::string GetProperty(const std::string& key) const; + ModuleResource GetResource(const std::string& name) const; + + std::vector FindResources(const std::string& path, const std::string& filePattern, bool recurse) const; + private: friend class ModuleRegistry; friend class ServiceReferencePrivate; ModulePrivate* d; Module(); void Init(CoreModuleContext* coreCtx, ModuleInfo* info); void Uninit(); void Start(); void Stop(); // purposely not implemented Module(const Module &); Module& operator=(const Module&); }; US_END_NAMESPACE /** * \ingroup MicroServices */ US_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(Module)& module); /** * \ingroup MicroServices */ US_EXPORT std::ostream& operator<<(std::ostream& os, US_PREPEND_NAMESPACE(Module) const * module); #endif // USMODULE_H diff --git a/Core/Code/CppMicroServices/src/module/usModuleInfo.cpp b/Core/Code/CppMicroServices/src/module/usModuleInfo.cpp index 810b2cc98f..d3c0314cf3 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleInfo.cpp +++ b/Core/Code/CppMicroServices/src/module/usModuleInfo.cpp @@ -1,35 +1,42 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include "usModuleInfo.h" US_BEGIN_NAMESPACE ModuleInfo::ModuleInfo(const std::string& name, const std::string& libName, const std::string& autoLoadDir, const std::string& moduleDeps, const std::string& version) - : name(name), libName(libName), moduleDeps(moduleDeps), - version(version), autoLoadDir(autoLoadDir), id(0), - activatorHook(0) + : name(name) + , libName(libName) + , moduleDeps(moduleDeps) + , version(version) + , autoLoadDir(autoLoadDir) + , id(0) + , activatorHook(NULL) + , resourceData(NULL) + , resourceNames(NULL) + , resourceTree(NULL) {} US_END_NAMESPACE diff --git a/Core/Code/CppMicroServices/src/module/usModuleInfo.h b/Core/Code/CppMicroServices/src/module/usModuleInfo.h index c6dd8a5ea9..4c81954fb4 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleInfo.h +++ b/Core/Code/CppMicroServices/src/module/usModuleInfo.h @@ -1,70 +1,75 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USMODULEINFO_H #define USMODULEINFO_H #include #include #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4251) #endif US_BEGIN_NAMESPACE struct ModuleActivator; /** * This class is not intended to be used directly. It is exported to support * the CppMicroServices module system. */ struct US_EXPORT ModuleInfo { ModuleInfo(const std::string& name, const std::string& libName, const std::string& autoLoadDir, const std::string& moduleDeps, const std::string& version); typedef ModuleActivator*(*ModuleActivatorHook)(void); + typedef int(*InitResourcesHook)(ModuleInfo*); + typedef const unsigned char* ModuleResourceData; std::string name; std::string libName; std::string moduleDeps; std::string version; std::string location; std::string autoLoadDir; long id; ModuleActivatorHook activatorHook; + ModuleResourceData resourceData; + ModuleResourceData resourceNames; + ModuleResourceData resourceTree; }; US_END_NAMESPACE #ifdef _MSC_VER # pragma warning(pop) #endif #endif // USMODULEINFO_H diff --git a/Core/Code/CppMicroServices/src/module/usModuleInitialization.h b/Core/Code/CppMicroServices/src/module/usModuleInitialization.h index 96b9a60b8f..c73cceea35 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleInitialization.h +++ b/Core/Code/CppMicroServices/src/module/usModuleInitialization.h @@ -1,170 +1,178 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include #include #include #include #include #ifndef USMODULEINITIALIZATION_H #define USMODULEINITIALIZATION_H /** * \ingroup MicroServices * * \brief Creates initialization code for a module. * * Each module which wants to register itself with the CppMicroServices library * has to put a call to this macro (or to #US_INITIALIZE_MODULE_WITH_CUSTOM_AUTOLOADDIR) * in one of its source files. * * Example call for a module with file-name "libmylibname.so". * \code * US_INITIALIZE_MODULE("My Service Implementation", "mylibname", "", "1.0.0") * \endcode * * This will initialize the module for use with the CppMicroServices library, using a default * auto-load directory named after the provided library name in \c _module_libname. * * \sa US_INITIALIZE_MODULE_WITH_CUSTOM_AUTOLOADDIR * * \remarks If you are using CMake, consider using the provided CMake macro * usFunctionGenerateModuleInit(). * * \param _module_name A human-readable name for the module. * If you use this macro in a source file for an executable, the module name must * be a valid C-identifier (no spaces etc.). * \param _module_libname The physical name of the module, withou prefix or suffix. * \param _module_depends A list of module dependencies. This is meta-data only. * \param _module_version A version string in the form of "...". * * \note If you use this macro in a source file compiled into an executable, additional * requirements for the macro arguments apply: * - The \c _module_name argument must be a valid C-identifier (no spaces etc.). * - The \c _module_libname argument must be an empty string. * */ #define US_INITIALIZE_MODULE(_module_name, _module_libname, _module_depends, _module_version) \ US_INITIALIZE_MODULE_WITH_CUSTOM_AUTOLOADDIR(_module_name, _module_libname, _module_libname, _module_depends, _module_version) /** * \ingroup MicroServices * * \brief Creates initialization code for a module using a custom auto-load directory. * * Each module which wants to register itself with the CppMicroServices library * has to put a call to this macro (or to #US_INITIALIZE_MODULE) in one of its source files. * * Example call for a module with file-name "libmylibname.so". * \code * US_INITIALIZE_MODULE_WITH_CUSTOM_AUTOLOADDIR("My Service Implementation", "mylibname", "autoload_mysublibs", "", "1.0.0") * \endcode * * \remarks If you are using CMake, consider using the provided CMake macro * usFunctionGenerateModuleInit(). * * \param _module_name A human-readable name for the module. * If you use this macro in a source file for an executable, the module name must * be a valid C-identifier (no spaces etc.). * \param _module_libname The physical name of the module, withou prefix or suffix. * \param _module_autoload_dir A directory name relative to this modules library location from which * modules will be auto-loaded during activation of this module. Provide an empty string to * disable auto-loading for this module. * \param _module_depends A list of module dependencies. This is meta-data only. * \param _module_version A version string in the form of "...". */ #define US_INITIALIZE_MODULE_WITH_CUSTOM_AUTOLOADDIR(_module_name, _module_libname, _module_autoload_dir, _module_depends, _module_version) \ US_BEGIN_NAMESPACE \ \ /* Declare a file scoped ModuleInfo object */ \ US_GLOBAL_STATIC_WITH_ARGS(ModuleInfo, moduleInfo, (_module_name, _module_libname, _module_autoload_dir, _module_depends, _module_version)) \ \ /* This class is used to statically initialize the library within the C++ Micro services \ library. It looks up a library specific C-style function returning an instance \ of the ModuleActivator interface. */ \ class US_ABI_LOCAL ModuleInitializer { \ \ public: \ \ ModuleInitializer() \ { \ std::string location = ModuleUtils::GetLibraryPath(moduleInfo()->libName, \ reinterpret_cast(moduleInfo)); \ std::string activator_func = "_us_module_activator_instance_"; \ if(moduleInfo()->libName.empty()) \ { \ activator_func.append(moduleInfo()->name); \ } \ else \ { \ activator_func.append(moduleInfo()->libName); \ } \ \ moduleInfo()->location = location; \ \ if (moduleInfo()->libName.empty()) \ { \ /* make sure we retrieve symbols from the executable, if "libName" is empty */ \ location.clear(); \ } \ moduleInfo()->activatorHook = reinterpret_cast(ModuleUtils::GetSymbol(location, activator_func.c_str())); \ \ + std::string init_res_func = "us_init_resources_"; \ + init_res_func.append(moduleInfo()->libName); \ + ModuleInfo::InitResourcesHook initResourcesHook = reinterpret_cast(ModuleUtils::GetSymbol(location, init_res_func.c_str())); \ + if (initResourcesHook) \ + { \ + initResourcesHook(moduleInfo()); \ + } \ + \ Register(); \ } \ \ static void Register() \ { \ ModuleRegistry::Register(moduleInfo()); \ } \ \ ~ModuleInitializer() \ { \ ModuleRegistry::UnRegister(moduleInfo()); \ } \ \ }; \ \ US_ABI_LOCAL ModuleContext* GetModuleContext() \ { \ /* make sure the module is registered */ \ if (moduleInfo()->id == 0) \ { \ ModuleInitializer::Register(); \ } \ \ return ModuleRegistry::GetModule(moduleInfo()->id)->GetModuleContext(); \ } \ \ US_END_NAMESPACE \ \ static US_PREPEND_NAMESPACE(ModuleInitializer) _InitializeModule; // Static modules usually don't get initialization code. They are initialized within the // module importing the static module(s). #if defined(US_STATIC_MODULE) && !defined(US_FORCE_MODULE_INIT) #undef US_INITIALIZE_MODULE_WITH_CUSTOM_AUTOLOADDIR #define US_INITIALIZE_MODULE_WITH_CUSTOM_AUTOLOADDIR(_a,_b,_c,_d,_e) #endif #endif // USMODULEINITIALIZATION_H diff --git a/Core/Code/CppMicroServices/src/module/usModulePrivate.cpp b/Core/Code/CppMicroServices/src/module/usModulePrivate.cpp index d13a5f3ecf..817213f08b 100644 --- a/Core/Code/CppMicroServices/src/module/usModulePrivate.cpp +++ b/Core/Code/CppMicroServices/src/module/usModulePrivate.cpp @@ -1,192 +1,195 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include "usModulePrivate.h" #include "usModule.h" #include "usModuleActivator.h" #include "usModuleUtils_p.h" #include "usCoreModuleContext_p.h" #include "usServiceRegistration.h" #include "usServiceReferencePrivate.h" #include #include US_BEGIN_NAMESPACE AtomicInt ModulePrivate::idCounter; ModulePrivate::ModulePrivate(Module* qq, CoreModuleContext* coreCtx, ModuleInfo* info) - : coreCtx(coreCtx), info(*info), moduleContext(0), moduleActivator(0), q(qq) + : coreCtx(coreCtx), info(*info), resourceTree(info), + moduleContext(0), moduleActivator(0), q(qq) { std::stringstream propId; propId << this->info.id; properties[Module::PROP_ID()] = propId.str(); std::stringstream propModuleDepends; std::stringstream propLibDepends; std::stringstream propPackageDepends; int counter = 0; int counter2 = 0; std::stringstream ss(this->info.moduleDeps); while (ss) { std::string moduleDep; ss >> moduleDep; if (!moduleDep.empty()) { Module* dep = ModuleRegistry::GetModule(moduleDep); if (dep) { requiresIds.push_back(dep->GetModuleId()); if (counter > 0) propModuleDepends << ", "; propModuleDepends << moduleDep; ++counter; } else { requiresLibs.push_back(moduleDep); if (counter2 > 0) propLibDepends << ", "; propLibDepends << moduleDep; ++counter2; } } } properties[Module::PROP_MODULE_DEPENDS()] = propModuleDepends.str(); properties[Module::PROP_LIB_DEPENDS()] = propLibDepends.str(); if (!this->info.version.empty()) { try { version = ModuleVersion(this->info.version); properties[Module::PROP_VERSION()] = this->info.version; } catch (const std::exception& e) { throw std::invalid_argument(std::string("CppMicroServices module does not specify a valid version identifier. Got exception: ") + e.what()); } } properties[Module::PROP_LOCATION()] = this->info.location; properties[Module::PROP_NAME()] = this->info.name; } ModulePrivate::~ModulePrivate() { delete moduleContext; } void ModulePrivate::RemoveModuleResources() { coreCtx->listeners.RemoveAllListeners(moduleContext); std::list srs; coreCtx->services.GetRegisteredByModule(this, srs); for (std::list::iterator i = srs.begin(); i != srs.end(); ++i) { try { i->Unregister(); } catch (const std::logic_error& /*ignore*/) { // Someone has unregistered the service after stop completed. // This should not occur, but we don't want get stuck in // an illegal state so we catch it. } } srs.clear(); coreCtx->services.GetUsedByModule(q, srs); for (std::list::const_iterator i = srs.begin(); i != srs.end(); ++i) { i->GetReference().d->UngetService(q, false); } + + resourceTree.Invalidate(); } void ModulePrivate::StartStaticModules() { typedef const char*(*GetImportedModulesFunc)(void); std::string getImportedModulesSymbol("_us_get_imported_modules_for_"); getImportedModulesSymbol += info.libName; std::string location = info.location; if (info.libName.empty()) { /* make sure we retrieve symbols from the executable, if "libName" is empty */ location.clear(); } GetImportedModulesFunc getImportedModulesFunc = reinterpret_cast(ModuleUtils::GetSymbol(location,getImportedModulesSymbol.c_str())); if (getImportedModulesFunc == NULL) return; std::string importedStaticModuleLibNames = getImportedModulesFunc(); std::vector staticModuleLibNames; std::istringstream iss(importedStaticModuleLibNames); std::copy(std::istream_iterator(iss), std::istream_iterator(), std::back_inserter >(staticModuleLibNames)); for (std::vector::iterator i = staticModuleLibNames.begin(); i != staticModuleLibNames.end(); ++i) { std::string staticActivatorSymbol = "_us_module_activator_instance_"; staticActivatorSymbol += *i; ModuleInfo::ModuleActivatorHook staticActivator = reinterpret_cast(ModuleUtils::GetSymbol(location, staticActivatorSymbol.c_str())); if (staticActivator) { US_DEBUG << "Loading static activator " << *i; staticActivators.push_back(staticActivator); staticActivator()->Load(moduleContext); } else { US_WARN << "Could not find an activator for the static module " << (*i) << ". You either forgot a US_IMPORT_MODULE macro call in " << info.libName << " or to link " << (*i) << " to " << info.libName << "."; } } } void ModulePrivate::StopStaticModules() { for (std::list::iterator i = staticActivators.begin(); i != staticActivators.end(); ++i) { (*i)()->Unload(moduleContext); } } US_END_NAMESPACE diff --git a/Core/Code/CppMicroServices/src/module/usModulePrivate.h b/Core/Code/CppMicroServices/src/module/usModulePrivate.h index 99c02469a7..4fa545e92a 100644 --- a/Core/Code/CppMicroServices/src/module/usModulePrivate.h +++ b/Core/Code/CppMicroServices/src/module/usModulePrivate.h @@ -1,98 +1,101 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USMODULEPRIVATE_H #define USMODULEPRIVATE_H #include #include #include "usModuleRegistry.h" #include "usModuleVersion.h" #include "usModuleInfo.h" +#include "usModuleResourceTree_p.h" #include "usAtomicInt_p.h" US_BEGIN_NAMESPACE class CoreModuleContext; class ModuleContext; struct ModuleActivator; /** * \ingroup MicroServices */ class ModulePrivate { public: /** * Construct a new module based on a ModuleInfo object. */ ModulePrivate(Module* qq, CoreModuleContext* coreCtx, ModuleInfo* info); virtual ~ModulePrivate(); void RemoveModuleResources(); void StartStaticModules(); void StopStaticModules(); CoreModuleContext* const coreCtx; std::vector requiresIds; std::vector requiresLibs; /** * Module version */ ModuleVersion version; ModuleInfo info; + ModuleResourceTree resourceTree; + /** * ModuleContext for the module */ ModuleContext* moduleContext; ModuleActivator* moduleActivator; std::map properties; Module* const q; private: std::list staticActivators; static AtomicInt idCounter; // purposely not implemented ModulePrivate(const ModulePrivate&); ModulePrivate& operator=(const ModulePrivate&); }; US_END_NAMESPACE #endif // USMODULEPRIVATE_H diff --git a/Core/Code/CppMicroServices/src/module/usModuleResource.cpp b/Core/Code/CppMicroServices/src/module/usModuleResource.cpp new file mode 100644 index 0000000000..74ab8e2eec --- /dev/null +++ b/Core/Code/CppMicroServices/src/module/usModuleResource.cpp @@ -0,0 +1,236 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=============================================================================*/ + + +#include "usModuleResource.h" + +#include "usAtomicInt_p.h" +#include "usModuleResourceTree_p.h" + +#include + +US_BEGIN_NAMESPACE + +class ModuleResourcePrivate +{ + +public: + + ModuleResourcePrivate() + : resourceTree(NULL) + , node(-1) + , size(0) + , data(NULL) + , isFile(false) + , ref(1) + {} + + std::string fileName; + std::string path; + std::string filePath; + + ModuleResourceTree* resourceTree; + + int node; + int32_t size; + const unsigned char* data; + + mutable std::vector children; + + bool isFile; + + /** + * Reference count for implicitly shared private implementation. + */ + AtomicInt ref; +}; + +ModuleResource::ModuleResource() + : d(new ModuleResourcePrivate) +{ +} + +ModuleResource::ModuleResource(const ModuleResource &resource) + : d(resource.d) +{ + d->ref.Ref(); +} + +ModuleResource::ModuleResource(const std::string& _file, ModuleResourceTree* resourceTree) + : d(new ModuleResourcePrivate) +{ + d->resourceTree = resourceTree; + + std::string file = _file; + if (file.empty()) file = "/"; + if (file[0] != '/') file = std::string("/") + file; + + std::size_t index = file.find_last_of('/'); + if (index < file.size()-1) + { + d->fileName = file.substr(index+1); + } + std::string rawPath = file.substr(0,index+1); + + // remove duplicate / + std::string::value_type lastChar = 0; + for (std::size_t i = 0; i < rawPath.size(); ++i) + { + if (rawPath[i] == '/' && lastChar == '/') + { + continue; + } + lastChar = rawPath[i]; + d->path.push_back(lastChar); + } + + d->filePath = d->path + d->fileName; + + d->node = d->resourceTree->FindNode(GetFilePath()); + if (d->node != -1) + { + d->isFile = !resourceTree->IsDir(d->node); + if (d->isFile) + { + d->data = d->resourceTree->GetData(d->node, &d->size); + } + } +} + +ModuleResource::~ModuleResource() +{ + if (!d->ref.Deref()) + delete d; +} + +ModuleResource& ModuleResource::operator =(const ModuleResource& resource) +{ + ModuleResourcePrivate* curr_d = d; + d = resource.d; + d->ref.Ref(); + + if (!curr_d->ref.Deref()) + delete curr_d; + + return *this; +} + +bool ModuleResource::operator <(const ModuleResource& resource) const +{ + return this->GetFilePath() < resource.GetFilePath(); +} + +bool ModuleResource::operator ==(const ModuleResource& resource) const +{ + return this->GetFilePath() == resource.GetFilePath(); +} + +bool ModuleResource::operator !=(const ModuleResource &resource) const +{ + return !(*this == resource); +} + +bool ModuleResource::IsValid() const +{ + return d->resourceTree->IsValid() && d->node > -1; +} + +us::ModuleResource::operator bool() const +{ + return IsValid(); +} + +std::string ModuleResource::GetFileName() const +{ + return d->fileName; +} + +std::string ModuleResource::GetPath() const +{ + return d->path; +} + +std::string ModuleResource::GetFilePath() const +{ + return d->filePath; +} + +std::string ModuleResource::GetBaseName() const +{ + return d->fileName.substr(0, d->fileName.find_first_of('.')); +} + +std::string ModuleResource::GetCompleteBaseName() const +{ + return d->fileName.substr(0, d->fileName.find_last_of('.')); +} + +std::string ModuleResource::GetSuffix() const +{ + std::size_t index = d->fileName.find_last_of('.'); + return index < d->fileName.size()-1 ? d->fileName.substr(index+1) : std::string(""); +} + +bool ModuleResource::IsDir() const +{ + return !d->isFile; +} + +bool ModuleResource::IsFile() const +{ + return d->isFile; +} + +std::vector ModuleResource::GetChildren() const +{ + if (d->isFile || !IsValid()) return d->children; + + if (!d->children.empty()) return d->children; + + d->resourceTree->GetChildren(d->node, d->children); + return d->children; +} + +int ModuleResource::GetSize() const +{ + return d->size; +} + +const unsigned char* ModuleResource::GetData() const +{ + if (!IsValid()) return NULL; + return d->data; +} + +std::size_t ModuleResource::Hash() const +{ + using namespace US_HASH_FUNCTION_NAMESPACE; + return US_HASH_FUNCTION(std::string, this->GetFilePath()); +} + +US_END_NAMESPACE + +US_USE_NAMESPACE + +std::ostream& operator<<(std::ostream& os, const ModuleResource& resource) +{ + return os << resource.GetFilePath(); +} diff --git a/Core/Code/CppMicroServices/src/module/usModuleResource.h b/Core/Code/CppMicroServices/src/module/usModuleResource.h new file mode 100644 index 0000000000..d15ccad560 --- /dev/null +++ b/Core/Code/CppMicroServices/src/module/usModuleResource.h @@ -0,0 +1,99 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=============================================================================*/ + + +#ifndef USMODULERESOURCE_H +#define USMODULERESOURCE_H + +#include + +#include +#include + +US_MSVC_PUSH_DISABLE_WARNING(4396) + +US_BEGIN_NAMESPACE + +class ModuleResourcePrivate; +class ModuleResourceTree; + +class US_EXPORT ModuleResource +{ + +public: + + ModuleResource(); + ModuleResource(const ModuleResource& resource); + + ~ModuleResource(); + + ModuleResource& operator=(const ModuleResource& resource); + + bool operator<(const ModuleResource& resource) const; + bool operator==(const ModuleResource& resource) const; + bool operator!=(const ModuleResource& resource) const; + + bool IsValid() const; + operator bool() const; + + std::string GetFileName() const; + std::string GetPath() const; + std::string GetFilePath() const; + + std::string GetBaseName() const; + std::string GetCompleteBaseName() const; + std::string GetSuffix() const; + + bool IsDir() const; + bool IsFile() const; + + std::vector GetChildren() const; + + int GetSize() const; + const unsigned char* GetData() const; + +private: + + ModuleResource(const std::string& file, ModuleResourceTree* resourceTree); + + friend class Module; + + US_HASH_FUNCTION_FRIEND(ModuleResource); + + std::size_t Hash() const; + + ModuleResourcePrivate* d; + +}; + +US_END_NAMESPACE + +US_MSVC_POP_WARNING + +US_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ModuleResource)& resource); + +US_HASH_FUNCTION_NAMESPACE_BEGIN +US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ModuleResource)) + return arg.Hash(); +US_HASH_FUNCTION_END +US_HASH_FUNCTION_NAMESPACE_END + +#endif // USMODULERESOURCE_H diff --git a/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer.cpp b/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer.cpp new file mode 100644 index 0000000000..c3f15278b6 --- /dev/null +++ b/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer.cpp @@ -0,0 +1,275 @@ +/*=================================================================== + +BlueBerry Platform + +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 "usModuleResourceBuffer_p.h" + +#include "stdint_p.h" + +#include +#include + +#ifdef US_PLATFORM_WINDOWS +#define DATA_NEEDS_NEWLINE_CONVERSION 1 +#undef REMOVE_LAST_NEWLINE_IN_TEXT_MODE +#else +#undef DATA_NEEDS_NEWLINE_CONVERSION +#define REMOVE_LAST_NEWLINE_IN_TEXT_MODE 1 +#endif + +US_BEGIN_NAMESPACE + +static const std::size_t BUFFER_SIZE = 1024; + +class ModuleResourceBufferPrivate +{ +public: + + ModuleResourceBufferPrivate(const char* begin, std::size_t size, std::ios_base::openmode mode) + : begin(begin) + , end(begin + size) + , current(begin) + , mode(mode) + #ifdef DATA_NEEDS_NEWLINE_CONVERSION + , pos(0) + #endif + { + } + + const char* const begin; + const char* const end; + const char* current; + + const std::ios_base::openmode mode; + +#ifdef DATA_NEEDS_NEWLINE_CONVERSION + // records the stream position ignoring CR characters + std::streambuf::pos_type pos; +#endif + +}; + +ModuleResourceBuffer::ModuleResourceBuffer(const unsigned char* data, std::size_t _size, + std::ios_base::openmode mode) + : d(NULL) +{ + assert(_size < static_cast(std::numeric_limits::max())); + assert(data != NULL); + + const char* begin = reinterpret_cast(data); + std::size_t size = _size; + +#ifdef DATA_NEEDS_NEWLINE_CONVERSION + if (!(mode & std::ios_base::binary) && begin[0] == '\r') + { + ++begin; + --size; + } +#endif + +#ifdef REMOVE_LAST_NEWLINE_IN_TEXT_MODE + if(!(mode & std::ios_base::binary) && begin[size-1] == '\n') + { + --size; + } +#endif + + d = new ModuleResourceBufferPrivate(begin, size, mode); +} + +ModuleResourceBuffer::~ModuleResourceBuffer() +{ + delete d; +} + +ModuleResourceBuffer::int_type ModuleResourceBuffer::underflow() +{ + if (d->current == d->end) + return traits_type::eof(); + +#ifdef DATA_NEEDS_NEWLINE_CONVERSION + char c = *d->current; + if (!(d->mode & std::ios_base::binary)) + { + if (c == '\r') + { + if (d->current + 1 == d->end) + { + return traits_type::eof(); + } + c = d->current[1]; + } + } + return traits_type::to_int_type(c); +#else + return traits_type::to_int_type(*d->current); +#endif +} + +ModuleResourceBuffer::int_type ModuleResourceBuffer::uflow() +{ + if (d->current == d->end) + return traits_type::eof(); + +#ifdef DATA_NEEDS_NEWLINE_CONVERSION + char c = *d->current++; + if (!(d->mode & std::ios_base::binary)) + { + if (c == '\r') + { + if (d->current == d->end) + { + return traits_type::eof(); + } + c = *d->current++; + } + } + return traits_type::to_int_type(c); +#else + return traits_type::to_int_type(*d->current++); +#endif +} + +ModuleResourceBuffer::int_type ModuleResourceBuffer::pbackfail(int_type ch) +{ + int backOffset = -1; +#ifdef DATA_NEEDS_NEWLINE_CONVERSION + if (!(d->mode & std::ios_base::binary)) + { + while ((d->current - backOffset) >= d->begin && d->current[backOffset] == '\r') + { + --backOffset; + } + // d->begin always points to a character != '\r' + } +#endif + if (d->current == d->begin || (ch != traits_type::eof() && ch != d->current[backOffset])) + { + return traits_type::eof(); + } + + d->current += backOffset; + return traits_type::to_int_type(*d->current); +} + +std::streamsize ModuleResourceBuffer::showmanyc() +{ + assert(std::less_equal()(d->current, d->end)); + +#ifdef DATA_NEEDS_NEWLINE_CONVERSION + std::streamsize ssize = 0; + std::size_t chunkSize = d->end - d->current; + for (std::size_t i = 0; i < chunkSize; ++i) + { + if (d->current[i] != '\r') + { + ++ssize; + } + } + return ssize; +#else + return d->end - d->current; +#endif +} + +std::streambuf::pos_type ModuleResourceBuffer::seekoff(std::streambuf::off_type off, + std::ios_base::seekdir way, + std::ios_base::openmode /*which*/) +{ +#ifdef DATA_NEEDS_NEWLINE_CONVERSION + std::streambuf::off_type step = 1; + if (way == std::ios_base::beg) + { + d->current = d->begin; + } + else if (way == std::ios_base::end) + { + d->current = d->end; + step = -1; + } + + if (!(d->mode & std::ios_base::binary)) + { + if (way == std::ios_base::beg) + { + d->pos = 0; + } + else if (way == std::ios_base::end) + { + d->current -= 1; + } + + std::streambuf::off_type i = 0; + // scan through off amount of characters excluding '\r' + while (i != off) + { + if (*d->current != '\r') + { + i += step; + d->pos += step; + } + d->current += step; + } + + // adjust the position in case of a "backwards" seek + if (way == std::ios_base::end) + { + // fix pointer from previous while loop + d->current += 1; + d->pos = 0; + i = 0; + const std::streampos currInternalPos = d->current - d->begin; + while (i != currInternalPos) + { + if (d->begin[i] != '\r') + { + d->pos += 1; + } + ++i; + } + } + } + else + { + d->current += off; + d->pos = d->current - d->begin; + } + return d->pos; +#else + if (way == std::ios_base::beg) + { + d->current = d->begin + off; + return off; + } + else if (way == std::ios_base::cur) + { + d->current += off; + return d->current - d->begin; + } + else + { + d->current = d->end + off; + return d->current - d->begin; + } +#endif +} + +std::streambuf::pos_type ModuleResourceBuffer::seekpos(std::streambuf::pos_type sp, + std::ios_base::openmode /*which*/) +{ + return this->seekoff(sp, std::ios_base::beg); +} + +US_END_NAMESPACE diff --git a/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer_p.h b/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer_p.h new file mode 100644 index 0000000000..8432a5ab23 --- /dev/null +++ b/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer_p.h @@ -0,0 +1,63 @@ +/*=================================================================== + +BlueBerry Platform + +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 USMODULERESOURCEBUFFER_P_H +#define USMODULERESOURCEBUFFER_P_H + +#include + +#include + +US_BEGIN_NAMESPACE + +class ModuleResourceBufferPrivate; + +class US_EXPORT ModuleResourceBuffer: public std::streambuf +{ + +public: + + explicit ModuleResourceBuffer(const unsigned char* data, std::size_t size, + std::ios_base::openmode mode); + + ~ModuleResourceBuffer(); + +private: + + int_type underflow(); + + int_type uflow(); + + int_type pbackfail(int_type ch); + + std::streamsize showmanyc(); + + pos_type seekoff (off_type off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out); + pos_type seekpos (pos_type sp, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out); + + // purposely not implemented + ModuleResourceBuffer(const ModuleResourceBuffer&); + ModuleResourceBuffer& operator=(const ModuleResourceBuffer&); + +private: + + ModuleResourceBufferPrivate* d; + +}; + +US_END_NAMESPACE + +#endif // USMODULERESOURCEBUFFER_P_H diff --git a/Core/Code/CppMicroServices/src/module/usModuleResourceStream.cpp b/Core/Code/CppMicroServices/src/module/usModuleResourceStream.cpp new file mode 100644 index 0000000000..3288e4c463 --- /dev/null +++ b/Core/Code/CppMicroServices/src/module/usModuleResourceStream.cpp @@ -0,0 +1,34 @@ +/*=================================================================== + +BlueBerry Platform + +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 "usModuleResourceStream.h" + +#include "usModuleResource.h" + +// 'this' used in base member initializer list +US_MSVC_PUSH_DISABLE_WARNING(4355) + +US_BEGIN_NAMESPACE + +ModuleResourceStream::ModuleResourceStream(const ModuleResource& resource, std::ios_base::openmode mode) + : ModuleResourceBuffer(resource.GetData(), resource.GetSize(), mode | std::ios_base::in) + , std::istream(this) +{ +} + +US_END_NAMESPACE + +US_MSVC_POP_WARNING \ No newline at end of file diff --git a/Core/Code/CppMicroServices/src/module/usModuleResourceStream.h b/Core/Code/CppMicroServices/src/module/usModuleResourceStream.h new file mode 100644 index 0000000000..d8c0e73922 --- /dev/null +++ b/Core/Code/CppMicroServices/src/module/usModuleResourceStream.h @@ -0,0 +1,45 @@ +/*=================================================================== + +BlueBerry Platform + +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 USMODULERESOURCESTREAM_H +#define USMODULERESOURCESTREAM_H + +#include "usModuleResourceBuffer_p.h" + +#include + +US_BEGIN_NAMESPACE + +class ModuleResource; + +class US_EXPORT ModuleResourceStream : private ModuleResourceBuffer, public std::istream +{ + +public: + + ModuleResourceStream(const ModuleResource& resource, + std::ios_base::openmode mode = std::ios_base::in); + +private: + + // purposely not implemented + ModuleResourceStream(const ModuleResourceStream&); + ModuleResourceStream& operator=(const ModuleResourceStream&); +}; + +US_END_NAMESPACE + +#endif // USMODULERESOURCESTREAM_H diff --git a/Core/Code/CppMicroServices/src/module/usModuleResourceTree.cpp b/Core/Code/CppMicroServices/src/module/usModuleResourceTree.cpp new file mode 100644 index 0000000000..30e79d0ef0 --- /dev/null +++ b/Core/Code/CppMicroServices/src/module/usModuleResourceTree.cpp @@ -0,0 +1,344 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=============================================================================*/ + + +#include "usModuleResourceTree_p.h" + +#include "usModuleInfo.h" +#include "usUtils_p.h" +#include "stdint_p.h" + +#include +#include + +//#define DEBUG_RESOURCE_MATCH + +US_BEGIN_NAMESPACE + +US_EXPORT bool RegisterResourceData(int, ModuleInfo* moduleInfo, + const unsigned char* resourceTree, + const unsigned char* resourceName, + const unsigned char* resourceData) +{ + moduleInfo->resourceTree = resourceTree; + moduleInfo->resourceNames = resourceName; + moduleInfo->resourceData = resourceData; + return true; +} + + +ModuleResourceTree::ModuleResourceTree(const ModuleInfo* moduleInfo) + : isValid(moduleInfo->resourceTree && moduleInfo->resourceNames && moduleInfo->resourceData) + , tree(moduleInfo->resourceTree) + , names(moduleInfo->resourceNames) + , payloads(moduleInfo->resourceData) +{ +} + +bool ModuleResourceTree::IsValid() const +{ + return isValid; +} + +void ModuleResourceTree::Invalidate() +{ + isValid = false; +} + +inline std::string ModuleResourceTree::GetName(int node) const +{ + if(!node) // root + return std::string(); + + const int offset = FindOffset(node); + + std::string ret; + int nameOffset = (tree[offset+0] << 24) + (tree[offset+1] << 16) + + (tree[offset+2] << 8) + (tree[offset+3] << 0); + const int16_t nameLength = (names[nameOffset+0] << 8) + + (names[nameOffset+1] << 0); + nameOffset += 2; // jump past name length + nameOffset += 4; // jump past hash + + ret.resize(nameLength); + for(int i = 0; i < nameLength; ++i) + { + ret[i] = names[nameOffset+i]; + } + return ret; +} + +int ModuleResourceTree::FindNode(const std::string& _path) const +{ + std::string path = _path.empty() ? "/" : _path; + +#ifdef DEBUG_RESOURCE_MATCH + US_DEBUG << "***" << " START " << path; +#endif + + if(path == "/") + return 0; + + // the root node is always first + int childCount = (tree[6] << 24) + (tree[7] << 16) + + (tree[8] << 8) + (tree[9] << 0); + int child = (tree[10] << 24) + (tree[11] << 16) + + (tree[12] << 8) + (tree[13] << 0); + + int node = -1; + + // split the full path into segments + std::vector segments; + { + std::stringstream ss(path); + std::string item; + while(std::getline(ss, item, '/')) + { + if (item.empty()) continue; + segments.push_back(item); + } + } + + //now iterate up the path hierarchy + for (std::size_t i = 0; i < segments.size() && childCount; ++i) + { + const std::string& segment = segments[i]; + +#ifdef DEBUG_RESOURCE_MATCH + US_DEBUG << " CHILDREN " << segment; + for(int j = 0; j < childCount; ++j) + { + US_DEBUG << " " << child+j << " :: " << GetName(child+j); + } +#endif + + // get the hash value for the current segment + const uint32_t currHash = static_cast(US_HASH_FUNCTION_NAMESPACE::US_HASH_FUNCTION(std::string,segment)); + + // do a binary search for the hash + int l = 0; + int r = childCount-1; + int subNode = (l+r+1)/2; + while(r != l) + { + const uint32_t subNodeHash = GetHash(child+subNode); + if(currHash == subNodeHash) + break; + else if(currHash < subNodeHash) + r = subNode - 1; + else + l = subNode; + subNode = (l+r+1) / 2; + } + subNode += child; + + // now check fo collisions and do compare using equality + bool found = false; + if(GetHash(subNode) == currHash) + { + while(subNode > child && GetHash(subNode-1) == currHash) // walk up to include all collisions + --subNode; + for(; subNode < child+childCount && GetHash(subNode) == currHash; ++subNode) + { + // now test using name comparison + if(GetName(subNode) == segment) + { + found = true; + int offset = FindOffset(subNode); +#ifdef DEBUG_RESOURCE_MATCH + US_DEBUG << " TRY " << subNode << " " << GetName(subNode) << " " << offset; +#endif + offset += 4; // jump past name + + const short flags = (tree[offset+0] << 8) + (tree[offset+1] << 0); + offset += 2; + + if(i == segments.size()-1) + { +#ifdef DEBUG_RESOURCE_MATCH + US_DEBUG << "!!!!" << " FINISHED " << subNode; +#endif + return subNode; + } + + // if we are not at the end of the resource path and the current + // segment is not a directory, return "not found" (this shouldn't happen). + if(!(flags & Directory)) + return -1; + + childCount = (tree[offset+0] << 24) + (tree[offset+1] << 16) + + (tree[offset+2] << 8) + (tree[offset+3] << 0); + offset += 4; + child = (tree[offset+0] << 24) + (tree[offset+1] << 16) + + (tree[offset+2] << 8) + (tree[offset+3] << 0); + break; + } + } + } + if(!found) + { + break; + } + } +#ifdef DEBUG_RESOURCE_MATCH + US_DEBUG << "***" << " FINISHED " << node; +#endif + return node; +} + +void ModuleResourceTree::FindNodes(const std::string& _path, + const std::string& _filePattern, + bool recurse, std::vector& result) +{ + std::string path = _path.empty() ? std::string("/") : _path; + if (path[path.size()-1] != '/') path.append("/"); + + std::string filePattern = _filePattern.empty() ? std::string("*") : _filePattern; + + int rootNode = FindNode(path); + if (rootNode > -1) + { + this->FindNodes(result, path, rootNode, filePattern, recurse); + } +} + +short ModuleResourceTree::GetFlags(int node) const +{ + if(node == -1) + return 0; + const int offset = FindOffset(node) + 4; //jump past name + return (tree[offset+0] << 8) + (tree[offset+1] << 0); +} + +void ModuleResourceTree::FindNodes(std::vector &result, const std::string& path, + const int rootNode, + const std::string &filePattern, bool recurse) +{ + int offset = FindOffset(rootNode) + 6; // jump past name and type + + const int childCount = (tree[offset+0] << 24) + (tree[offset+1] << 16) + + (tree[offset+2] << 8) + (tree[offset+3] << 0); + offset += 4; + const int childNode = (tree[offset+0] << 24) + (tree[offset+1] << 16) + + (tree[offset+2] << 8) + (tree[offset+3] << 0); + + for(int i = childNode; i < childNode+childCount; ++i) + { + const int childOffset = FindOffset(i); + const short childFlags = (tree[childOffset+4] << 8) + (tree[childOffset+5] << 0); + if (!(childFlags & Directory)) + { + const std::string name = GetName(i); + if (this->Matches(name, filePattern)) + { + result.push_back(path + name); + } + } + else if (recurse) + { + this->FindNodes(result, path + GetName(i) + "/", i, filePattern, recurse); + } + } +} + +uint32_t ModuleResourceTree::GetHash(int node) const +{ + if(!node) // root node + return 0; + + const int offset = FindOffset(node); + int nameOffset = (tree[offset+0] << 24) + (tree[offset+1] << 16) + + (tree[offset+2] << 8) + (tree[offset+3] << 0); + nameOffset += 2; // jump past name length + return (names[nameOffset+0] << 24) + (names[nameOffset+1] << 16) + + (names[nameOffset+2] << 8) + (names[nameOffset+3] << 0); +} + +bool ModuleResourceTree::Matches(const std::string &name, const std::string &filePattern) +{ + // short-cut + if (filePattern == "*") return true; + + std::stringstream ss(filePattern); + std::string tok; + std::size_t pos = 0; + while(std::getline(ss, tok, '*')) + { + std::size_t index = name.find(tok, pos); + if (index == std::string::npos) return false; + pos = index + tok.size(); + } + return true; +} + +const unsigned char* ModuleResourceTree::GetData(int node, int32_t* size) const +{ + if(node == -1) + { + *size = 0; + return 0; + } + int offset = FindOffset(node) + 4; // jump past name + + const short flags = (tree[offset+0] << 8) + (tree[offset+1] << 0); + offset += 2; + + offset += 4; // jump past the padding + + if(!(flags & Directory)) + { + const int dataOffset = (tree[offset+0] << 24) + (tree[offset+1] << 16) + + (tree[offset+2] << 8) + (tree[offset+3] << 0); + const int32_t dataLength = (payloads[dataOffset+0] << 24) + (payloads[dataOffset+1] << 16) + + (payloads[dataOffset+2] << 8) + (payloads[dataOffset+3] << 0); + const unsigned char* ret = payloads+dataOffset+4; + *size = dataLength; + return ret; + } + *size = 0; + return 0; +} + +void ModuleResourceTree::GetChildren(int node, std::vector& ret) const +{ + if(node == -1) + return; + + int offset = FindOffset(node) + 4; // jump past name + + const short flags = (tree[offset+0] << 8) + (tree[offset+1] << 0); + offset += 2; + + if(flags & Directory) + { + const int childCount = (tree[offset+0] << 24) + (tree[offset+1] << 16) + + (tree[offset+2] << 8) + (tree[offset+3] << 0); + offset += 4; + const int childOffset = (tree[offset+0] << 24) + (tree[offset+1] << 16) + + (tree[offset+2] << 8) + (tree[offset+3] << 0); + for(int i = childOffset; i < childOffset+childCount; ++i) + { + ret.push_back(GetName(i)); + } + } +} + +US_END_NAMESPACE diff --git a/Core/Code/CppMicroServices/src/module/usModuleResourceTree_p.h b/Core/Code/CppMicroServices/src/module/usModuleResourceTree_p.h new file mode 100644 index 0000000000..d7643b7586 --- /dev/null +++ b/Core/Code/CppMicroServices/src/module/usModuleResourceTree_p.h @@ -0,0 +1,85 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=============================================================================*/ + + +#ifndef USMODULERESOURCETREE_H +#define USMODULERESOURCETREE_H + +#include + +#include "stdint_p.h" + +#include + +US_BEGIN_NAMESPACE + +struct ModuleInfo; + +class ModuleResourceTree +{ + +private: + + enum Flags + { + Directory = 0x01 + }; + + bool isValid; + const unsigned char *tree, *names, *payloads; + + // Returns the offset in the us_resource_tree array for a given node index + inline int FindOffset(int node) const { return node * 14; } // sizeof each tree element + + std::string GetName(int node) const; + short GetFlags(int node) const; + + void FindNodes(std::vector& result, const std::string& path, + const int rootNode, + const std::string& filePattern, bool recurse); + + uint32_t GetHash(int node) const; + + bool Matches(const std::string& name, const std::string& filePattern); + +public: + + ModuleResourceTree(const ModuleInfo* moduleInfo); + + bool IsValid() const; + void Invalidate(); + + // Returns an index enumerating the info entries in the us_resource_tree array for + // the given resource path. + int FindNode(const std::string& path) const; + + void FindNodes(const std::string& path, const std::string& filePattern, + bool recurse, std::vector& result); + + inline bool IsDir(int node) const { return GetFlags(node) & Directory; } + const unsigned char* GetData(int node, int32_t *size) const; + void GetChildren(int node, std::vector& children) const; + +}; + +US_END_NAMESPACE + +#endif // USMODULERESOURCETREE_H diff --git a/Core/Code/CppMicroServices/src/service/usServiceReference.h b/Core/Code/CppMicroServices/src/service/usServiceReference.h index 773b77b9cd..825784fd71 100644 --- a/Core/Code/CppMicroServices/src/service/usServiceReference.h +++ b/Core/Code/CppMicroServices/src/service/usServiceReference.h @@ -1,225 +1,220 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #ifndef USSERVICEREFERENCE_H #define USSERVICEREFERENCE_H #include -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4396) -#endif +US_MSVC_PUSH_DISABLE_WARNING(4396) US_BEGIN_NAMESPACE class Module; class ServiceRegistrationPrivate; class ServiceReferencePrivate; /** * \ingroup MicroServices * * A reference to a service. * *

* The framework returns ServiceReference objects from the * ModuleContext::GetServiceReference and * ModuleContext::GetServiceReferences methods. *

* A ServiceReference object may be shared between modules and * can be used to examine the properties of the service and to get the service * object. *

* Every service registered in the framework has a unique * ServiceRegistration object and may have multiple, distinct * ServiceReference objects referring to it. * ServiceReference objects associated with a * ServiceRegistration are considered equal * (more specifically, their operator==() * method will return true when compared). *

* If the same service object is registered multiple times, * ServiceReference objects associated with different * ServiceRegistration objects are not equal. * * @see ModuleContext::GetServiceReference * @see ModuleContext::GetServiceReferences * @see ModuleContext::GetService * @remarks This class is thread safe. */ class US_EXPORT ServiceReference { public: /** * Creates an invalid ServiceReference object. You can use * this object in boolean expressions and it will evaluate to * false. */ ServiceReference(); ServiceReference(const ServiceReference& ref); /** * Converts this ServiceReference instance into a boolean * expression. If this instance was default constructed or * the service it references has been unregistered, the conversion * returns false, otherwise it returns true. */ operator bool() const; /** * Releases any resources held or locked by this * ServiceReference and renders it invalid. */ ServiceReference& operator=(int null); ~ServiceReference(); /** * Returns the property value to which the specified property key is mapped * in the properties ServiceProperties object of the service * referenced by this ServiceReference object. * *

* Property keys are case-insensitive. * *

* This method continues to return property values after the service has * been unregistered. This is so references to unregistered services can * still be interrogated. * * @param key The property key. * @return The property value to which the key is mapped; an invalid Any * if there is no property named after the key. */ Any GetProperty(const std::string& key) const; /** * Returns a list of the keys in the ServiceProperties * object of the service referenced by this ServiceReference * object. * *

* This method will continue to return the keys after the service has been * unregistered. This is so references to unregistered services can * still be interrogated. * * @param keys A vector being filled with the property keys. */ void GetPropertyKeys(std::vector& keys) const; /** * Returns the module that registered the service referenced by this * ServiceReference object. * *

* This method must return 0 when the service has been * unregistered. This can be used to determine if the service has been * unregistered. * * @return The module that registered the service referenced by this * ServiceReference object; 0 if that * service has already been unregistered. * @see ModuleContext::RegisterService(const std::vector&, US_BASECLASS_NAME*, const ServiceProperties&) */ Module* GetModule() const; /** * Returns the modules that are using the service referenced by this * ServiceReference object. Specifically, this method returns * the modules whose usage count for that service is greater than zero. * * @param modules A list of modules whose usage count for the service referenced * by this ServiceReference object is greater than * zero. */ void GetUsingModules(std::vector& modules) const; /** * Compares this ServiceReference with the specified * ServiceReference for order. * *

* If this ServiceReference and the specified * ServiceReference have the same \link ServiceConstants::SERVICE_ID() * service id\endlink they are equal. This ServiceReference is less * than the specified ServiceReference if it has a lower * {@link ServiceConstants::SERVICE_RANKING service ranking} and greater if it has a * higher service ranking. Otherwise, if this ServiceReference * and the specified ServiceReference have the same * {@link ServiceConstants::SERVICE_RANKING service ranking}, this * ServiceReference is less than the specified * ServiceReference if it has a higher * {@link ServiceConstants::SERVICE_ID service id} and greater if it has a lower * service id. * * @param reference The ServiceReference to be compared. * @return Returns a false or true if this * ServiceReference is less than or greater * than the specified ServiceReference. */ bool operator<(const ServiceReference& reference) const; bool operator==(const ServiceReference& reference) const; ServiceReference& operator=(const ServiceReference& reference); private: friend class ModulePrivate; friend class ModuleContext; friend class ServiceFilter; friend class ServiceRegistrationPrivate; friend class ServiceListeners; friend class LDAPFilter; template friend class ServiceTracker; template friend class ServiceTrackerPrivate; template friend class ModuleAbstractTracked; US_HASH_FUNCTION_FRIEND(ServiceReference); std::size_t Hash() const; ServiceReference(ServiceRegistrationPrivate* reg); ServiceReferencePrivate* d; }; US_END_NAMESPACE -#ifdef _MSC_VER -#pragma warning(pop) -#endif +US_MSVC_POP_WARNING US_EXPORT std::ostream& operator<<(std::ostream& os, const US_PREPEND_NAMESPACE(ServiceReference)& serviceRef); US_HASH_FUNCTION_NAMESPACE_BEGIN US_HASH_FUNCTION_BEGIN(US_PREPEND_NAMESPACE(ServiceReference)) return arg.Hash(); US_HASH_FUNCTION_END US_HASH_FUNCTION_NAMESPACE_END #endif // USSERVICEREFERENCE_H diff --git a/Core/Code/CppMicroServices/src/module/usModuleInfo.cpp b/Core/Code/CppMicroServices/src/util/stdint_p.h similarity index 66% copy from Core/Code/CppMicroServices/src/module/usModuleInfo.cpp copy to Core/Code/CppMicroServices/src/util/stdint_p.h index 810b2cc98f..242332bac2 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleInfo.cpp +++ b/Core/Code/CppMicroServices/src/util/stdint_p.h @@ -1,35 +1,33 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ - -#include "usModuleInfo.h" - -US_BEGIN_NAMESPACE - -ModuleInfo::ModuleInfo(const std::string& name, const std::string& libName, - const std::string& autoLoadDir, const std::string& moduleDeps, - const std::string& version) - : name(name), libName(libName), moduleDeps(moduleDeps), - version(version), autoLoadDir(autoLoadDir), id(0), - activatorHook(0) -{} - -US_END_NAMESPACE +#ifndef USSTDINT_H +#define USSTDINT_H + +#ifdef HAVE_STDINT +#include +#elif defined(_MSC_VER) +#include "stdint_vc_p.h" +#else +#error The stdint.h header is not available +#endif + +#endif // USSTDINT_H diff --git a/Core/Code/CppMicroServices/src/util/stdint_vc_p.h b/Core/Code/CppMicroServices/src/util/stdint_vc_p.h new file mode 100644 index 0000000000..c660849c42 --- /dev/null +++ b/Core/Code/CppMicroServices/src/util/stdint_vc_p.h @@ -0,0 +1,235 @@ +/* ISO C9x 7.18 Integer types + * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * Contributor: Danny Smith + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Date: 2000-12-02 + * + * mwb: This was modified in the following ways: + * + * - make it compatible with Visual C++ 6 (which uses + * non-standard keywords and suffixes for 64-bit types) + * - some environments need stddef.h included (for wchar stuff?) + * - handle the fact that Microsoft's limits.h header defines + * SIZE_MAX + * - make corrections for SIZE_MAX, INTPTR_MIN, INTPTR_MAX, UINTPTR_MAX, + * PTRDIFF_MIN, PTRDIFF_MAX, SIG_ATOMIC_MIN, and SIG_ATOMIC_MAX + * to be 64-bit aware. + */ + + +#ifndef _STDINT_H +#define _STDINT_H +#define __need_wint_t +#define __need_wchar_t +#include +#include + +#if _MSC_VER && (_MSC_VER < 1300) +/* using MSVC 6 or earlier - no "long long" type, but might have _int64 type */ +#define __STDINT_LONGLONG __int64 +#define __STDINT_LONGLONG_SUFFIX i64 +#else +#define __STDINT_LONGLONG long long +#define __STDINT_LONGLONG_SUFFIX LL +#endif + +#if !defined( PASTE) +#define PASTE2( x, y) x##y +#define PASTE( x, y) PASTE2( x, y) +#endif /* PASTE */ + + +/* 7.18.1.1 Exact-width integer types */ +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned uint32_t; +typedef __STDINT_LONGLONG int64_t; +typedef unsigned __STDINT_LONGLONG uint64_t; + +/* 7.18.1.2 Minimum-width integer types */ +typedef signed char int_least8_t; +typedef unsigned char uint_least8_t; +typedef short int_least16_t; +typedef unsigned short uint_least16_t; +typedef int int_least32_t; +typedef unsigned uint_least32_t; +typedef __STDINT_LONGLONG int_least64_t; +typedef unsigned __STDINT_LONGLONG uint_least64_t; + +/* 7.18.1.3 Fastest minimum-width integer types + * Not actually guaranteed to be fastest for all purposes + * Here we use the exact-width types for 8 and 16-bit ints. + */ +typedef char int_fast8_t; +typedef unsigned char uint_fast8_t; +typedef short int_fast16_t; +typedef unsigned short uint_fast16_t; +typedef int int_fast32_t; +typedef unsigned int uint_fast32_t; +typedef __STDINT_LONGLONG int_fast64_t; +typedef unsigned __STDINT_LONGLONG uint_fast64_t; + +/* 7.18.1.4 Integer types capable of holding object pointers */ +#ifndef _INTPTR_T_DEFINED +#define _INTPTR_T_DEFINED +#ifdef _WIN64 +typedef __STDINT_LONGLONG intptr_t +#else +typedef int intptr_t; +#endif /* _WIN64 */ +#endif /* _INTPTR_T_DEFINED */ + +#ifndef _UINTPTR_T_DEFINED +#define _UINTPTR_T_DEFINED +#ifdef _WIN64 +typedef unsigned __STDINT_LONGLONG uintptr_t +#else +typedef unsigned int uintptr_t; +#endif /* _WIN64 */ +#endif /* _UINTPTR_T_DEFINED */ + +/* 7.18.1.5 Greatest-width integer types */ +typedef __STDINT_LONGLONG intmax_t; +typedef unsigned __STDINT_LONGLONG uintmax_t; + +/* 7.18.2 Limits of specified-width integer types */ +#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS) + +/* 7.18.2.1 Limits of exact-width integer types */ +#define INT8_MIN (-128) +#define INT16_MIN (-32768) +#define INT32_MIN (-2147483647 - 1) +#define INT64_MIN (PASTE( -9223372036854775807, __STDINT_LONGLONG_SUFFIX) - 1) + +#define INT8_MAX 127 +#define INT16_MAX 32767 +#define INT32_MAX 2147483647 +#define INT64_MAX (PASTE( 9223372036854775807, __STDINT_LONGLONG_SUFFIX)) + +#define UINT8_MAX 0xff /* 255U */ +#define UINT16_MAX 0xffff /* 65535U */ +#define UINT32_MAX 0xffffffff /* 4294967295U */ +#define UINT64_MAX (PASTE( 0xffffffffffffffffU, __STDINT_LONGLONG_SUFFIX)) /* 18446744073709551615ULL */ + +/* 7.18.2.2 Limits of minimum-width integer types */ +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN + +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +/* 7.18.2.3 Limits of fastest minimum-width integer types */ +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST64_MIN INT64_MIN + +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +/* 7.18.2.4 Limits of integer types capable of holding + object pointers */ +#ifdef _WIN64 +#define INTPTR_MIN INT64_MIN +#define INTPTR_MAX INT64_MAX +#define UINTPTR_MAX UINT64_MAX +#else +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX +#endif /* _WIN64 */ + +/* 7.18.2.5 Limits of greatest-width integer types */ +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +/* 7.18.3 Limits of other integer types */ +#define PTRDIFF_MIN INTPTR_MIN +#define PTRDIFF_MAX INTPTR_MAX + +#define SIG_ATOMIC_MIN INTPTR_MIN +#define SIG_ATOMIC_MAX INTPTR_MAX + +/* we need to check for SIZE_MAX already defined because MS defines it in limits.h */ +#ifndef SIZE_MAX +#define SIZE_MAX UINTPTR_MAX +#endif + +#ifndef WCHAR_MIN /* also in wchar.h */ +#define WCHAR_MIN 0 +#define WCHAR_MAX ((wchar_t)-1) /* UINT16_MAX */ +#endif + +/* + * wint_t is unsigned short for compatibility with MS runtime + */ +#define WINT_MIN 0 +#define WINT_MAX ((wint_t)-1) /* UINT16_MAX */ + +#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */ + + +/* 7.18.4 Macros for integer constants */ +#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS) + +/* 7.18.4.1 Macros for minimum-width integer constants + + Accoding to Douglas Gwyn : +"This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC +9899:1999 as initially published, the expansion was required +to be an integer constant of precisely matching type, which +is impossible to accomplish for the shorter types on most +platforms, because C99 provides no standard way to designate +an integer constant with width less than that of type int. +TC1 changed this to require just an integer constant +*expression* with *promoted* type." +*/ + +#define INT8_C(val) ((int8_t) + (val)) +#define UINT8_C(val) ((uint8_t) + (val##U)) +#define INT16_C(val) ((int16_t) + (val)) +#define UINT16_C(val) ((uint16_t) + (val##U)) + +#define INT32_C(val) val##L +#define UINT32_C(val) val##UL +#define INT64_C(val) (PASTE( val, __STDINT_LONGLONG_SUFFIX)) +#define UINT64_C(val)(PASTE( PASTE( val, U), __STDINT_LONGLONG_SUFFIX)) + +/* 7.18.4.2 Macros for greatest-width integer constants */ +#define INTMAX_C(val) INT64_C(val) +#define UINTMAX_C(val) UINT64_C(val) + +#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */ + +#endif diff --git a/Core/Code/CppMicroServices/test/CMakeLists.txt b/Core/Code/CppMicroServices/test/CMakeLists.txt index cd8bc207e6..3442dc7eff 100644 --- a/Core/Code/CppMicroServices/test/CMakeLists.txt +++ b/Core/Code/CppMicroServices/test/CMakeLists.txt @@ -1,98 +1,99 @@ #----------------------------------------------------------------------------- # Configure files, include dirs, etc. #----------------------------------------------------------------------------- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/usTestingConfig.h.in" "${PROJECT_BINARY_DIR}/include/usTestingConfig.h") include_directories(${US_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}) if(NOT US_ENABLE_SERVICE_FACTORY_SUPPORT) include_directories(${US_BASECLASS_INCLUDE_DIRS}) endif() link_directories(${US_LINK_DIRS}) if(NOT US_ENABLE_SERVICE_FACTORY_SUPPORT) link_directories(${US_BASECLASS_LIBRARY_DIRS}) endif() #----------------------------------------------------------------------------- # Create test modules #----------------------------------------------------------------------------- include(usFunctionCreateTestModule) set(_us_test_module_libs "" CACHE INTERNAL "" FORCE) add_subdirectory(modules) #----------------------------------------------------------------------------- # Add unit tests #----------------------------------------------------------------------------- set(_tests usDebugOutputTest usLDAPFilterTest usModuleTest + usModuleResourceTest usServiceRegistryTest usServiceTrackerTest usStaticModuleTest ) if(US_BUILD_SHARED_LIBS) list(APPEND _tests usServiceListenerTest) if(US_ENABLE_AUTOLOADING_SUPPORT) list(APPEND _tests usModuleAutoLoadTest) endif() endif() set(_additional_srcs usTestManager.cpp usTestUtilModuleListener.cpp usTestUtilSharedLibrary.cpp ) set(_test_driver ${PROJECT_NAME}TestDriver) set(_test_sourcelist_extra_args ) create_test_sourcelist(_srcs ${_test_driver}.cpp ${_tests} ${_test_sourcelist_extra_args}) # Generate a custom "module init" file for the test driver executable set(MODULE_DEPENDS_STR ) foreach(_dep ${US_LINK_LIBRARIES}) set(MODULE_DEPENDS_STR "${MODULE_DEPENDS_STR} ${_dep}") endforeach() if(US_BUILD_SHARED_LIBS) usFunctionGenerateModuleInit(_srcs NAME ${_test_driver} DEPENDS "${MODULE_DEPENDS_STR}" VERSION "0.1.0" EXECUTABLE ) endif() add_executable(${_test_driver} ${_srcs} ${_additional_srcs}) if(NOT US_BUILD_SHARED_LIBS) target_link_libraries(${_test_driver} ${_us_test_module_libs}) endif() target_link_libraries(${_test_driver} ${US_LINK_LIBRARIES}) if(NOT US_ENABLE_SERVICE_FACTORY_SUPPORT) target_link_libraries(${_test_driver} ${US_BASECLASS_LIBRARIES}) endif() # Register tests foreach(_test ${_tests}) add_test(NAME ${_test} COMMAND ${_test_driver} ${_test}) endforeach() if(US_TEST_LABELS) set_tests_properties(${_tests} PROPERTIES LABELS "${US_TEST_LABELS}") endif() #----------------------------------------------------------------------------- # Add dependencies for shared libraries #----------------------------------------------------------------------------- if(US_BUILD_SHARED_LIBS) foreach(_test_module ${_us_test_module_libs}) add_dependencies(${_test_driver} ${_test_module}) endforeach() endif() diff --git a/Core/Code/CppMicroServices/test/modules/CMakeLists.txt b/Core/Code/CppMicroServices/test/modules/CMakeLists.txt index 5ebdf2f5cd..6d02314c68 100644 --- a/Core/Code/CppMicroServices/test/modules/CMakeLists.txt +++ b/Core/Code/CppMicroServices/test/modules/CMakeLists.txt @@ -1,9 +1,11 @@ add_subdirectory(libA) add_subdirectory(libA2) add_subdirectory(libAL) add_subdirectory(libAL2) add_subdirectory(libBWithStatic) add_subdirectory(libS) add_subdirectory(libSL1) add_subdirectory(libSL3) add_subdirectory(libSL4) + +add_subdirectory(libRWithResources) diff --git a/Core/Code/CppMicroServices/test/modules/libRWithResources/CMakeLists.txt b/Core/Code/CppMicroServices/test/modules/libRWithResources/CMakeLists.txt new file mode 100644 index 0000000000..2b4880e3ca --- /dev/null +++ b/Core/Code/CppMicroServices/test/modules/libRWithResources/CMakeLists.txt @@ -0,0 +1,13 @@ + +set(resource_files + icons/cppmicroservices.png + icons/readme.txt + foo.txt + special_chars.dummy.txt + test.xml +) + +usFunctionCreateTestModuleWithResources(TestModuleR + SOURCES usTestModuleR.cpp + RESOURCES ${resource_files}) + diff --git a/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/foo.txt b/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/foo.txt new file mode 100644 index 0000000000..f004091c6b --- /dev/null +++ b/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/foo.txt @@ -0,0 +1,3 @@ +foo and +bar + diff --git a/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/icons/cppmicroservices.png b/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/icons/cppmicroservices.png new file mode 100644 index 0000000000..e115492256 Binary files /dev/null and b/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/icons/cppmicroservices.png differ diff --git a/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/icons/readme.txt b/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/icons/readme.txt new file mode 100644 index 0000000000..30af5fe09c --- /dev/null +++ b/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/icons/readme.txt @@ -0,0 +1 @@ +icons diff --git a/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/special_chars.dummy.txt b/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/special_chars.dummy.txt new file mode 100644 index 0000000000..47bfa90dd0 --- /dev/null +++ b/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/special_chars.dummy.txt @@ -0,0 +1,2 @@ +German Füße (feet) +French garçon de café (waiter) diff --git a/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/test.xml b/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/test.xml new file mode 100644 index 0000000000..23208713be --- /dev/null +++ b/Core/Code/CppMicroServices/test/modules/libRWithResources/resources/test.xml @@ -0,0 +1,4 @@ + + +hi + diff --git a/Core/Code/CppMicroServices/src/module/usModuleInfo.cpp b/Core/Code/CppMicroServices/test/modules/libRWithResources/usTestModuleR.cpp similarity index 69% copy from Core/Code/CppMicroServices/src/module/usModuleInfo.cpp copy to Core/Code/CppMicroServices/test/modules/libRWithResources/usTestModuleR.cpp index 810b2cc98f..602caaf82f 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleInfo.cpp +++ b/Core/Code/CppMicroServices/test/modules/libRWithResources/usTestModuleR.cpp @@ -1,35 +1,44 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ -#include "usModuleInfo.h" +#include US_BEGIN_NAMESPACE -ModuleInfo::ModuleInfo(const std::string& name, const std::string& libName, - const std::string& autoLoadDir, const std::string& moduleDeps, - const std::string& version) - : name(name), libName(libName), moduleDeps(moduleDeps), - version(version), autoLoadDir(autoLoadDir), id(0), - activatorHook(0) -{} +class TestModuleRActivator : public ModuleActivator +{ +public: + + void Load(ModuleContext*) + { + } + + void Unload(ModuleContext*) + { + } + +}; US_END_NAMESPACE + +US_EXPORT_MODULE_ACTIVATOR(TestModuleR, US_PREPEND_NAMESPACE(TestModuleRActivator)) + diff --git a/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp b/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp new file mode 100644 index 0000000000..e5da6561e1 --- /dev/null +++ b/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp @@ -0,0 +1,347 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=============================================================================*/ + +#include +#include +#include +#include +#include +#include + +#include + +#include "usTestUtilSharedLibrary.h" +#include "usTestingMacros.h" + +#include + +#include + +US_USE_NAMESPACE + +namespace { + +void checkResourceInfo(const ModuleResource& res, const std::string& path, + const std::string& baseName, + const std::string& completeBaseName, const std::string& suffix, + int size, bool children = false) +{ + US_TEST_CONDITION_REQUIRED(res.IsValid(), "Valid resource") + US_TEST_CONDITION(res.GetBaseName() == baseName, "GetBaseName()") + US_TEST_CONDITION(res.GetChildren().empty() == !children, "No children") + US_TEST_CONDITION(res.GetCompleteBaseName() == completeBaseName, "GetCompleteBaseName()") + US_TEST_CONDITION(res.GetFileName() == completeBaseName + "." + suffix, "GetFileName()") + US_TEST_CONDITION(res.GetFilePath() == path + completeBaseName + "." + suffix, "GetFilePath()") + US_TEST_CONDITION(res.GetPath() == path, "GetPath()") + US_TEST_CONDITION(res.GetSize() == size, "Data size") + US_TEST_CONDITION(res.GetSuffix() == suffix, "Suffix") +} + +void testTextResource(Module* module) +{ + ModuleResource res = module->GetResource("foo.txt"); +#ifdef US_PLATFORM_WINDOWS + checkResourceInfo(res, "/", "foo", "foo", "txt", 16, false); + const std::streampos ssize(13); + const std::string fileData = "foo and\nbar\n\n"; +#else + checkResourceInfo(res, "/", "foo", "foo", "txt", 13, false); + const std::streampos ssize(12); + const std::string fileData = "foo and\nbar\n"; +#endif + + ModuleResourceStream rs(res); + + rs.seekg(0, std::ios::end); + US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); + rs.seekg(0, std::ios::beg); + + std::string content; + content.reserve(res.GetSize()); + char buffer[1024]; + while (rs.read(buffer, sizeof(buffer))) + { + content.append(buffer, sizeof(buffer)); + } + content.append(buffer, rs.gcount()); + + US_TEST_CONDITION(rs.eof(), "EOF check"); + US_TEST_CONDITION(content == fileData, "Resource content"); + + rs.clear(); + rs.seekg(0); + + US_TEST_CONDITION_REQUIRED(rs.tellg() == std::streampos(0), "Move to start") + US_TEST_CONDITION_REQUIRED(rs.good(), "Start re-reading"); + + std::vector lines; + std::string line; + while (std::getline(rs, line)) + { + lines.push_back(line); + } + US_TEST_CONDITION_REQUIRED(lines.size() > 1, "Number of lines") + US_TEST_CONDITION(lines[0] == "foo and", "Check first line") + US_TEST_CONDITION(lines[1] == "bar", "Check second line") +} + +void testTextResourceAsBinary(Module* module) +{ + ModuleResource res = module->GetResource("foo.txt"); + +#ifdef US_PLATFORM_WINDOWS + checkResourceInfo(res, "/", "foo", "foo", "txt", 16, false); + const std::streampos ssize(16); + const std::string fileData = "foo and\r\nbar\r\n\r\n"; +#else + checkResourceInfo(res, "/", "foo", "foo", "txt", 13, false); + const std::streampos ssize(13); + const std::string fileData = "foo and\nbar\n\n"; +#endif + + + ModuleResourceStream rs(res, std::ios_base::binary); + + rs.seekg(0, std::ios::end); + US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); + rs.seekg(0, std::ios::beg); + + std::string content; + content.reserve(res.GetSize()); + char buffer[1024]; + while (rs.read(buffer, sizeof(buffer))) + { + content.append(buffer, sizeof(buffer)); + } + content.append(buffer, rs.gcount()); + + US_TEST_CONDITION(rs.eof(), "EOF check"); + US_TEST_CONDITION(content == fileData, "Resource content"); +} + +void testSpecialCharacters(Module* module) +{ + ModuleResource res = module->GetResource("special_chars.dummy.txt"); +#ifdef US_PLATFORM_WINDOWS + checkResourceInfo(res, "/", "special_chars", "special_chars.dummy", "txt", 56, false); + const std::streampos ssize(54); + const std::string fileData = "German Füße (feet)\nFrench garçon de café (waiter)\n"; +#else + checkResourceInfo(res, "/", "special_chars", "special_chars.dummy", "txt", 54, false); + const std::streampos ssize(53); + const std::string fileData = "German Füße (feet)\nFrench garçon de café (waiter)"; +#endif + + ModuleResourceStream rs(res); + + rs.seekg(0, std::ios_base::end); + US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); + rs.seekg(0, std::ios_base::beg); + + std::string content; + content.reserve(res.GetSize()); + char buffer[1024]; + while (rs.read(buffer, sizeof(buffer))) + { + content.append(buffer, sizeof(buffer)); + } + content.append(buffer, rs.gcount()); + + US_TEST_CONDITION(rs.eof(), "EOF check"); + US_TEST_CONDITION(content == fileData, "Resource content"); +} + +void testBinaryResource(Module* module) +{ + ModuleResource res = module->GetResource("/icons/cppmicroservices.png"); + checkResourceInfo(res, "/icons/", "cppmicroservices", "cppmicroservices", "png", 2424, false); + + ModuleResourceStream rs(res, std::ios_base::binary); + rs.seekg(0, std::ios_base::end); + std::streampos resLength = rs.tellg(); + rs.seekg(0); + + std::ifstream png(CppMicroServices_SOURCE_DIR "/test/modules/libRWithResources/resources/icons/cppmicroservices.png", + std::ifstream::in | std::ifstream::binary); + + US_TEST_CONDITION_REQUIRED(png.is_open(), "Open reference file") + + png.seekg(0, std::ios_base::end); + std::streampos pngLength = png.tellg(); + png.seekg(0); + US_TEST_CONDITION(resLength = res.GetSize(), "Check resource size") + US_TEST_CONDITION_REQUIRED(resLength == pngLength, "Compare sizes") + + char c1 = 0; + char c2 = 0; + bool isEqual = true; + int count = 0; + while (png.get(c1) && rs.get(c2)) + { + ++count; + if (c1 != c2) + { + isEqual = false; + break; + } + } + + US_TEST_CONDITION_REQUIRED(count == pngLength, "Check if everything was read"); + US_TEST_CONDITION_REQUIRED(isEqual, "Equal binary contents"); + US_TEST_CONDITION(png.eof(), "EOF check"); +} + +void testResourceTree(Module* module) +{ + ModuleResource res = module->GetResource(""); + US_TEST_CONDITION(res.GetFilePath() == "/", "Check root file path") + US_TEST_CONDITION(res.IsDir() == true, "Check type") + + std::vector children = res.GetChildren(); + std::sort(children.begin(), children.end()); + US_TEST_CONDITION_REQUIRED(children.size() == 4, "Check child count") + US_TEST_CONDITION(children[0] == "foo.txt", "Check child name") + US_TEST_CONDITION(children[1] == "icons", "Check child name") + US_TEST_CONDITION(children[2] == "special_chars.dummy.txt", "Check child name") + US_TEST_CONDITION(children[3] == "test.xml", "Check child name") + + + ModuleResource readme = module->GetResource("/icons/readme.txt"); + US_TEST_CONDITION(readme.IsFile() && readme.GetChildren().empty(), "Check file resource") + + ModuleResource icons = module->GetResource("icons"); + US_TEST_CONDITION(icons.IsDir() && !icons.IsFile() && !icons.GetChildren().empty(), "Check directory resource") + + children = icons.GetChildren(); + US_TEST_CONDITION_REQUIRED(children.size() == 2, "Check icons child count") + std::sort(children.begin(), children.end()); + US_TEST_CONDITION(children[0] == "cppmicroservices.png", "Check child name") + US_TEST_CONDITION(children[1] == "readme.txt", "Check child name") + + // find all .txt files + std::vector nodes = module->FindResources("", "*.txt", false); + std::sort(nodes.begin(), nodes.end()); + US_TEST_CONDITION_REQUIRED(nodes.size() == 2, "Found child count") + US_TEST_CONDITION(nodes[0] == "/foo.txt", "Check child name") + US_TEST_CONDITION(nodes[1] == "/special_chars.dummy.txt", "Check child name") + + nodes = module->FindResources("", "*.txt", true); + std::sort(nodes.begin(), nodes.end()); + US_TEST_CONDITION_REQUIRED(nodes.size() == 3, "Found child count") + US_TEST_CONDITION(nodes[0] == "/foo.txt", "Check child name") + US_TEST_CONDITION(nodes[1] == "/icons/readme.txt", "Check child name") + US_TEST_CONDITION(nodes[2] == "/special_chars.dummy.txt", "Check child name") + + // find all resources + nodes = module->FindResources("", "", true); + US_TEST_CONDITION(nodes.size() == 5, "Total resource number") + nodes = module->FindResources("", "**", true); + US_TEST_CONDITION(nodes.size() == 5, "Total resource number") + + + // test pattern matching + nodes.clear(); + nodes = module->FindResources("/icons", "*micro*.png", false); + US_TEST_CONDITION(nodes.size() == 1 && nodes[0] == "/icons/cppmicroservices.png", "Check file pattern matches") + + nodes.clear(); + nodes = module->FindResources("", "*.txt", true); + US_TEST_CONDITION(nodes.size() == 3, "Check recursive pattern matches") +} + +void testResourceOperators(Module* module) +{ + ModuleResource invalid = module->GetResource("invalid"); + ModuleResource foo = module->GetResource("foo.txt"); + US_TEST_CONDITION_REQUIRED(foo.IsValid() && foo, "Check valid resource") + ModuleResource foo2(foo); + US_TEST_CONDITION(foo == foo2, "Check copy constructor and equality operator") + US_TEST_CONDITION(foo != invalid, "Check inequality with invalid resource") + + ModuleResource xml = module->GetResource("/test.xml"); + US_TEST_CONDITION_REQUIRED(xml.IsValid() && xml, "Check valid resource") + US_TEST_CONDITION(foo != xml, "Check inequality") + US_TEST_CONDITION(foo < xml, "Check operator<") + + // check operator< by using a set + std::set resources; + resources.insert(foo); + resources.insert(foo); + resources.insert(xml); + US_TEST_CONDITION(resources.size() == 2, "Check operator< with set") + + // check hash function specialization + US_UNORDERED_SET_TYPE resources2; + resources2.insert(foo); + resources2.insert(foo); + resources2.insert(xml); + US_TEST_CONDITION(resources2.size() == 2, "Check operator< with unordered set") + + // check operator<< + std::ostringstream oss; + oss << foo; + US_TEST_CONDITION(oss.str() == foo.GetFilePath(), "Check operator<<") +} + +} // end unnamed namespace + + +int usModuleResourceTest(int /*argc*/, char* /*argv*/[]) +{ + US_TEST_BEGIN("ModuleResourceTest"); + + ModuleContext* mc = GetModuleContext(); + assert(mc); + + SharedLibraryHandle libR("TestModuleR"); + + try + { + libR.Load(); + } + catch (const std::exception& e) + { + US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) + } + + Module* moduleR = ModuleRegistry::GetModule("TestModuleR Module"); + US_TEST_CONDITION_REQUIRED(moduleR != NULL, "Test for existing module TestModuleR") + + US_TEST_CONDITION(moduleR->GetName() == "TestModuleR Module", "Test module name") + + testResourceTree(moduleR); + + testResourceOperators(moduleR); + + testTextResource(moduleR); + testTextResourceAsBinary(moduleR); + testSpecialCharacters(moduleR); + + testBinaryResource(moduleR); + + ModuleResource foo = moduleR->GetResource("foo.txt"); + US_TEST_CONDITION(foo.IsValid() == true, "Valid resource") + libR.Unload(); + US_TEST_CONDITION(foo.IsValid() == false, "Invalidated resource") + US_TEST_CONDITION(foo.GetData() == NULL, "NULL data") + + US_TEST_END() +} diff --git a/Core/Code/CppMicroServices/test/usServiceListenerTest.cpp b/Core/Code/CppMicroServices/test/usServiceListenerTest.cpp index 103befce2e..c49d2ca0d9 100644 --- a/Core/Code/CppMicroServices/test/usServiceListenerTest.cpp +++ b/Core/Code/CppMicroServices/test/usServiceListenerTest.cpp @@ -1,561 +1,561 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include #include #include #include #include US_BASECLASS_HEADER #include #include "usTestUtilSharedLibrary.h" US_USE_NAMESPACE class TestServiceListener { private: friend bool runLoadUnloadTest(const std::string&, int cnt, SharedLibraryHandle&, const std::vector&); const bool checkUsingModules; std::vector events; bool teststatus; ModuleContext* mc; public: TestServiceListener(ModuleContext* mc, bool checkUsingModules = true) : checkUsingModules(checkUsingModules), events(), teststatus(true), mc(mc) {} bool getTestStatus() const { return teststatus; } void clearEvents() { events.clear(); } bool checkEvents(const std::vector& eventTypes) { if (events.size() != eventTypes.size()) { dumpEvents(eventTypes); return false; } for (std::size_t i=0; i < eventTypes.size(); ++i) { if (eventTypes[i] != events[i].GetType()) { dumpEvents(eventTypes); return false; } } return true; } void serviceChanged(const ServiceEvent evt) { events.push_back(evt); US_TEST_OUTPUT( << "ServiceEvent: " << evt ); if (ServiceEvent::UNREGISTERING == evt.GetType()) { ServiceReference sr = evt.GetServiceReference(); // Validate that no module is marked as using the service std::vector usingModules; sr.GetUsingModules(usingModules); if (checkUsingModules && !usingModules.empty()) { teststatus = false; printUsingModules(sr, "*** Using modules (unreg) should be empty but is: "); } // Check if the service can be fetched US_BASECLASS_NAME* service = mc->GetService(sr); sr.GetUsingModules(usingModules); // if (UNREGISTERSERVICE_VALID_DURING_UNREGISTERING) { // In this mode the service shall be obtainable during // unregistration. if (service == 0) { teststatus = false; US_TEST_OUTPUT( << "*** Service should be available to ServiceListener " << "while handling unregistering event." ); } US_TEST_OUTPUT( << "Service (unreg): " << us_service_impl_name(service) ); if (checkUsingModules && usingModules.size() != 1) { teststatus = false; printUsingModules(sr, "*** One using module expected " "(unreg, after getService), found: "); } else { printUsingModules(sr, "Using modules (unreg, after getService): "); } // } else { // // In this mode the service shall NOT be obtainable during // // unregistration. // if (null!=service) { // teststatus = false; // out.print("*** Service should not be available to ServiceListener " // +"while handling unregistering event."); // } // if (checkUsingBundles && null!=usingBundles) { // teststatus = false; // printUsingBundles(sr, // "*** Using bundles (unreg, after getService), " // +"should be null but is: "); // } else { // printUsingBundles(sr, // "Using bundles (unreg, after getService): null"); // } // } mc->UngetService(sr); // Check that the UNREGISTERING service can not be looked up // using the service registry. try { long sid = any_cast(sr.GetProperty(ServiceConstants::SERVICE_ID())); std::stringstream ss; ss << "(" << ServiceConstants::SERVICE_ID() << "=" << sid << ")"; std::list srs = mc->GetServiceReferences("", ss.str()); if (srs.empty()) { US_TEST_OUTPUT( << "ServiceReference for UNREGISTERING service is not" " found in the service registry; ok." ); } else { teststatus = false; US_TEST_OUTPUT( << "*** ServiceReference for UNREGISTERING service," << sr << ", not found in the service registry; fail." ); US_TEST_OUTPUT( << "Found the following Service references:") ; for(std::list::const_iterator sr = srs.begin(); sr != srs.end(); ++sr) { US_TEST_OUTPUT( << (*sr) ); } } } catch (const std::exception& e) { teststatus = false; US_TEST_OUTPUT( << "*** Unexpected excpetion when trying to lookup a" " service while it is in state UNREGISTERING: " << e.what() ); } } } void printUsingModules(const ServiceReference& sr, const std::string& caption) { std::vector usingModules; sr.GetUsingModules(usingModules); US_TEST_OUTPUT( << (caption.empty() ? "Using modules: " : caption) ); for(std::vector::const_iterator module = usingModules.begin(); module != usingModules.end(); ++module) { US_TEST_OUTPUT( << " -" << (*module) ); } } // Print expected and actual service events. void dumpEvents(const std::vector& eventTypes) { std::size_t max = events.size() > eventTypes.size() ? events.size() : eventTypes.size(); US_TEST_OUTPUT( << "Expected event type -- Actual event" ); for (std::size_t i=0; i < max; ++i) { ServiceEvent evt = i < events.size() ? events[i] : ServiceEvent(); if (i < eventTypes.size()) { US_TEST_OUTPUT( << " " << eventTypes[i] << "--" << evt ); } else { US_TEST_OUTPUT( << " " << "- NONE - " << "--" << evt ); } } } }; // end of class ServiceListener bool runLoadUnloadTest(const std::string& name, int cnt, SharedLibraryHandle& target, const std::vector& events) { bool teststatus = true; ModuleContext* mc = GetModuleContext(); for (int i = 0; i < cnt && teststatus; ++i) { TestServiceListener sListen(mc); try { mc->AddServiceListener(&sListen, &TestServiceListener::serviceChanged); //mc->AddServiceListener(MessageDelegate1(&sListen, &ServiceListener::serviceChanged)); } catch (const std::logic_error& ise) { teststatus = false; US_TEST_FAILED_MSG( << "service listener registration failed " << ise.what() << " :" << name << ":FAIL" ); } // Start the test target to get a service published. try { target.Load(); } catch (const std::exception& e) { teststatus = false; US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what() << " + in " << name << ":FAIL" ); } // Stop the test target to get a service unpublished. try { target.Unload(); } catch (const std::exception& e) { teststatus = false; US_TEST_FAILED_MSG( << "Failed to unload module, got exception: " << e.what() << " + in " << name << ":FAIL" ); } if (teststatus && !sListen.checkEvents(events)) { teststatus = false; US_TEST_FAILED_MSG( << "Service listener event notification error :" << name << ":FAIL" ); } try { mc->RemoveServiceListener(&sListen, &TestServiceListener::serviceChanged); teststatus &= sListen.teststatus; sListen.clearEvents(); } catch (const std::logic_error& ise) { teststatus = false; US_TEST_FAILED_MSG( << "service listener removal failed " << ise.what() << " :" << name << ":FAIL" ); } } return teststatus; } void frameSL02a() { ModuleContext* mc = GetModuleContext(); TestServiceListener listener1(mc); TestServiceListener listener2(mc); try { mc->RemoveServiceListener(&listener1, &TestServiceListener::serviceChanged); mc->AddServiceListener(&listener1, &TestServiceListener::serviceChanged); mc->RemoveServiceListener(&listener2, &TestServiceListener::serviceChanged); mc->AddServiceListener(&listener2, &TestServiceListener::serviceChanged); } catch (const std::logic_error& ise) { US_TEST_FAILED_MSG( << "service listener registration failed " << ise.what() << " : frameSL02a:FAIL" ); } SharedLibraryHandle target("TestModuleA"); // Start the test target to get a service published. try { target.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG( << "Failed to load module, got exception: " << e.what() << " + in frameSL02a:FAIL" ); } std::vector events; events.push_back(ServiceEvent::REGISTERED); US_TEST_CONDITION(listener1.checkEvents(events), "Check first service listener") US_TEST_CONDITION(listener2.checkEvents(events), "Check second service listener") mc->RemoveServiceListener(&listener1, &TestServiceListener::serviceChanged); mc->RemoveServiceListener(&listener2, &TestServiceListener::serviceChanged); target.Unload(); } void frameSL05a() { std::vector events; events.push_back(ServiceEvent::REGISTERED); events.push_back(ServiceEvent::UNREGISTERING); SharedLibraryHandle libA("TestModuleA"); bool testStatus = runLoadUnloadTest("FrameSL05a", 1, libA, events); US_TEST_CONDITION(testStatus, "FrameSL05a") } void frameSL10a() { std::vector events; events.push_back(ServiceEvent::REGISTERED); events.push_back(ServiceEvent::UNREGISTERING); SharedLibraryHandle libA2("TestModuleA2"); bool testStatus = runLoadUnloadTest("FrameSL10a", 1, libA2, events); US_TEST_CONDITION(testStatus, "FrameSL10a") } void frameSL25a() { ModuleContext* mc = GetModuleContext(); TestServiceListener sListen(mc, false); try { mc->AddServiceListener(&sListen, &TestServiceListener::serviceChanged); } catch (const std::logic_error& ise) { US_TEST_OUTPUT( << "service listener registration failed " << ise.what() ); throw; } SharedLibraryHandle libSL1("TestModuleSL1"); SharedLibraryHandle libSL3("TestModuleSL3"); SharedLibraryHandle libSL4("TestModuleSL4"); std::vector expectedServiceEventTypes; // Startup expectedServiceEventTypes.push_back(ServiceEvent::REGISTERED); // at start of libSL1 expectedServiceEventTypes.push_back(ServiceEvent::REGISTERED); // FooService at start of libSL4 expectedServiceEventTypes.push_back(ServiceEvent::REGISTERED); // at start of libSL3 // Stop libSL4 expectedServiceEventTypes.push_back(ServiceEvent::UNREGISTERING); // FooService at first stop of libSL4 #ifdef US_BUILD_SHARED_LIBS // Shutdown expectedServiceEventTypes.push_back(ServiceEvent::UNREGISTERING); // at stop of libSL1 expectedServiceEventTypes.push_back(ServiceEvent::UNREGISTERING); // at stop of libSL3 #endif // Start libModuleTestSL1 to ensure that the Service interface is available. try { US_TEST_OUTPUT( << "Starting libModuleTestSL1: " << libSL1.GetAbsolutePath() ); libSL1.Load(); } catch (const std::exception& e) { US_TEST_OUTPUT( << "Failed to load module, got exception: " << e.what() ); throw; } // Start libModuleTestSL4 that will require the serivce interface and publish - // ctkFooService + // us::FooService try { US_TEST_OUTPUT( << "Starting libModuleTestSL4: " << libSL4.GetAbsolutePath() ); libSL4.Load(); } catch (const std::exception& e) { US_TEST_OUTPUT( << "Failed to load module, got exception: " << e.what() ); throw; } // Start libModuleTestSL3 that will require the serivce interface and get the service try { US_TEST_OUTPUT( << "Starting libModuleTestSL3: " << libSL3.GetAbsolutePath() ); libSL3.Load(); } catch (const std::exception& e) { US_TEST_OUTPUT( << "Failed to load module, got exception: " << e.what() ); throw; } // Check that libSL3 has been notified about the FooService. US_TEST_OUTPUT( << "Check that FooService is added to service tracker in libSL3" ); try { ServiceReference libSL3SR = mc->GetServiceReference("ActivatorSL3"); US_BASECLASS_NAME* libSL3Activator = mc->GetService(libSL3SR); US_TEST_CONDITION_REQUIRED(libSL3Activator, "ActivatorSL3 service != 0"); ModulePropsInterface* propsInterface = dynamic_cast(libSL3Activator); US_TEST_CONDITION_REQUIRED(propsInterface, "Cast to ModulePropsInterface"); ModulePropsInterface::Properties::const_iterator i = propsInterface->GetProperties().find("serviceAdded"); US_TEST_CONDITION_REQUIRED(i != propsInterface->GetProperties().end(), "Property serviceAdded"); Any serviceAddedField3 = i->second; US_TEST_CONDITION_REQUIRED(!serviceAddedField3.Empty() && any_cast(serviceAddedField3), "libSL3 notified about presence of FooService"); mc->UngetService(libSL3SR); } catch (const ServiceException& se) { US_TEST_FAILED_MSG( << "Failed to get service reference:" << se ); } // Check that libSL1 has been notified about the FooService. US_TEST_OUTPUT( << "Check that FooService is added to service tracker in libSL1" ); try { ServiceReference libSL1SR = mc->GetServiceReference("ActivatorSL1"); US_BASECLASS_NAME* libSL1Activator = mc->GetService(libSL1SR); US_TEST_CONDITION_REQUIRED(libSL1Activator, "ActivatorSL1 service != 0"); ModulePropsInterface* propsInterface = dynamic_cast(libSL1Activator); US_TEST_CONDITION_REQUIRED(propsInterface, "Cast to ModulePropsInterface"); ModulePropsInterface::Properties::const_iterator i = propsInterface->GetProperties().find("serviceAdded"); US_TEST_CONDITION_REQUIRED(i != propsInterface->GetProperties().end(), "Property serviceAdded"); Any serviceAddedField1 = i->second; US_TEST_CONDITION_REQUIRED(!serviceAddedField1.Empty() && any_cast(serviceAddedField1), "libSL1 notified about presence of FooService"); mc->UngetService(libSL1SR); } catch (const ServiceException& se) { US_TEST_FAILED_MSG( << "Failed to get service reference:" << se ); } // Stop the service provider: libSL4 try { US_TEST_OUTPUT( << "Stop libSL4: " << libSL4.GetAbsolutePath() ); libSL4.Unload(); } catch (const std::exception& e) { US_TEST_OUTPUT( << "Failed to unload module, got exception:" << e.what() ); throw; } // Check that libSL3 has been notified about the removal of FooService. US_TEST_OUTPUT( << "Check that FooService is removed from service tracker in libSL3" ); try { ServiceReference libSL3SR = mc->GetServiceReference("ActivatorSL3"); US_BASECLASS_NAME* libSL3Activator = mc->GetService(libSL3SR); US_TEST_CONDITION_REQUIRED(libSL3Activator, "ActivatorSL3 service != 0"); ModulePropsInterface* propsInterface = dynamic_cast(libSL3Activator); US_TEST_CONDITION_REQUIRED(propsInterface, "Cast to ModulePropsInterface"); ModulePropsInterface::Properties::const_iterator i = propsInterface->GetProperties().find("serviceRemoved"); US_TEST_CONDITION_REQUIRED(i != propsInterface->GetProperties().end(), "Property serviceRemoved"); Any serviceRemovedField3 = i->second; US_TEST_CONDITION(!serviceRemovedField3.Empty() && any_cast(serviceRemovedField3), "libSL3 notified about removal of FooService"); mc->UngetService(libSL3SR); } catch (const ServiceException& se) { US_TEST_FAILED_MSG( << "Failed to get service reference:" << se ); } // Stop libSL1 try { US_TEST_OUTPUT( << "Stop libSL1:" << libSL1.GetAbsolutePath() ); libSL1.Unload(); } catch (const std::exception& e) { US_TEST_OUTPUT( << "Failed to unload module got exception" << e.what() ); throw; } // Stop pSL3 try { US_TEST_OUTPUT( << "Stop libSL3:" << libSL3.GetAbsolutePath() ); libSL3.Unload(); } catch (const std::exception& e) { US_TEST_OUTPUT( << "Failed to unload module got exception" << e.what() ); throw; } // Check service events seen by this class US_TEST_OUTPUT( << "Checking ServiceEvents(ServiceListener):" ); if (!sListen.checkEvents(expectedServiceEventTypes)) { US_TEST_FAILED_MSG( << "Service listener event notification error" ); } US_TEST_CONDITION_REQUIRED(sListen.getTestStatus(), "Service listener checks"); try { mc->RemoveServiceListener(&sListen, &TestServiceListener::serviceChanged); sListen.clearEvents(); } catch (const std::logic_error& ise) { US_TEST_FAILED_MSG( << "service listener removal failed: " << ise.what() ); } } int usServiceListenerTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ServiceListenerTest"); frameSL02a(); frameSL05a(); frameSL10a(); frameSL25a(); US_TEST_END() } diff --git a/Core/Code/CppMicroServices/tools/CMakeLists.txt b/Core/Code/CppMicroServices/tools/CMakeLists.txt new file mode 100644 index 0000000000..b5913aa65b --- /dev/null +++ b/Core/Code/CppMicroServices/tools/CMakeLists.txt @@ -0,0 +1,8 @@ + +if(NOT US_IS_EMBEDDED) + include_directories(${US_INTERNAL_INCLUDE_DIRS}) +endif() + +add_definitions(-DUS_RCC_EXECUTABLE_NAME=\"${US_RCC_EXECUTABLE_NAME}\") + +add_executable(${US_RCC_EXECUTABLE_NAME} usResourceCompiler.cpp) diff --git a/Core/Code/CppMicroServices/tools/usResourceCompiler.cpp b/Core/Code/CppMicroServices/tools/usResourceCompiler.cpp new file mode 100644 index 0000000000..05b7dd3640 --- /dev/null +++ b/Core/Code/CppMicroServices/tools/usResourceCompiler.cpp @@ -0,0 +1,668 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=============================================================================*/ + +#include "usConfig.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stdint_p.h" + +#include "usConfig.h" + +#ifdef US_PLATFORM_WINDOWS +static const char DIR_SEP = '\\'; +#else +static const char DIR_SEP = '/'; +#endif + +class ResourceWriter; + +class Resource +{ + +public: + + enum Flags + { + NoFlags = 0x00, + Directory = 0x01 + }; + + Resource(const std::string& name, const std::string& path = std::string(), unsigned int flags = NoFlags); + ~Resource(); + + std::string GetResourcePath() const; + + int64_t WriteName(ResourceWriter& writer, int64_t offset); + void WriteTreeInfo(ResourceWriter& writer); + int64_t WritePayload(ResourceWriter& writer, int64_t offset, std::string* errorMessage); + + std::string name; + std::string path; + unsigned int flags; + Resource* parent; + std::map children; + std::map sortedChildren; + + int64_t nameOffset; + int64_t dataOffset; + int64_t childOffset; + +}; + +class ResourceWriter +{ + +public: + + ResourceWriter(const std::string& fileName, const std::string& libName); + ~ResourceWriter(); + + bool AddFiles(const std::vector& files, const std::string& basePath); + bool Write(); + +private: + + friend class Resource; + + bool AddFile(const std::string& alias, const Resource& file); + + bool WriteHeader(); + bool WritePayloads(); + bool WriteNames(); + bool WriteDataTree(); + bool WriteRegistrationCode(); + + void WriteString(const std::string& str); + void WriteChar(char c); + void WriteHex(uint8_t tmp); + void WriteNumber2(uint16_t number); + void WriteNumber4(uint32_t number); + + std::ofstream out; + std::vector files; + + std::string libName; + std::string fileName; + + Resource* root; +}; + +Resource::Resource(const std::string& name, const std::string& path, unsigned int flags) + : name(name) + , path(path) + , flags(flags) + , parent(NULL) + , nameOffset(0) + , dataOffset(0) + , childOffset(0) +{ +} + +Resource::~Resource() +{ + for (std::map::iterator i = children.begin(); + i != children.end(); ++i) + { + delete i->second; + } +} + +std::string Resource::GetResourcePath() const +{ + std::string resource = name; + for (Resource* p = parent; p; p = p->parent) + { + resource = resource.insert(0, p->name + '/'); + } + return resource; +} + +int64_t Resource::WriteName(ResourceWriter& writer, int64_t offset) +{ + // capture the offset + nameOffset = offset; + + // write the resource name as a comment + writer.WriteString(" // "); + writer.WriteString(name); + writer.WriteString("\n "); + + // write the length of the name + writer.WriteNumber2(name.size()); + writer.WriteString("\n "); + offset += 2; + + // write the hash value + writer.WriteNumber4(static_cast(US_HASH_FUNCTION_NAMESPACE::US_HASH_FUNCTION(std::string, name))); + writer.WriteString("\n "); + offset += 4; + + // write the name itself + for (std::size_t i = 0; i < name.length(); ++i) + { + writer.WriteHex(name[i]); + if (i != 0 && i % 32 == 0) + writer.WriteString("\n "); + } + offset += name.length(); + + // done + writer.WriteString("\n "); + return offset; +} + +void Resource::WriteTreeInfo(ResourceWriter& writer) +{ + // write the resource path as a comment + writer.WriteString(" // "); + writer.WriteString(GetResourcePath()); + writer.WriteString("\n "); + + if (flags & Directory) + { + // name offset (in the us_resource_name array) + writer.WriteNumber4(static_cast(nameOffset)); + + // flags + writer.WriteNumber2(flags); + + // child count + writer.WriteNumber4(children.size()); + + // first child offset (in the us_resource_tree array) + writer.WriteNumber4(static_cast(childOffset)); + } + else + { + // name offset + writer.WriteNumber4(static_cast(nameOffset)); + + // flags + writer.WriteNumber2(flags); + + // padding (not used) + writer.WriteNumber4(0); + + // data offset + writer.WriteNumber4(static_cast(dataOffset)); + } + writer.WriteChar('\n'); +} + +int64_t Resource::WritePayload(ResourceWriter& writer, int64_t offset, std::string* errorMessage) +{ + // capture the offset + dataOffset = offset; + + // open the resource file on the file system + std::ifstream file(path.c_str(), std::ifstream::in | std::ifstream::binary); + if (!file) + { + *errorMessage = "File could not be opened: " + path; + return 0; + } + + // write the full path of the resource in the file system as a comment + writer.WriteString(" // "); + writer.WriteString(path); + writer.WriteString("\n "); + + // write the length + file.seekg(0, std::ifstream::end); + std::ifstream::pos_type size = file.tellg(); + file.seekg(0); + writer.WriteNumber4(size); + writer.WriteString("\n "); + offset += 4; + + // write the actual payload + int charsLeft = 16; + char c = 0; + while (file.get(c)) + { + --charsLeft; + writer.WriteHex(static_cast(c)); + if (charsLeft == 0) + { + writer.WriteString("\n "); + charsLeft = 16; + } + } + + offset += size; + + // done + writer.WriteString("\n "); + return offset; +} + +ResourceWriter::ResourceWriter(const std::string& fileName, const std::string& libName) + : libName(libName) + , fileName(fileName) + , root(NULL) +{ + out.exceptions(std::ofstream::goodbit); + out.open(fileName.c_str()); +} + +ResourceWriter::~ResourceWriter() +{ + delete root; +} + +bool ResourceWriter::AddFiles(const std::vector& files, const std::string& basePath) +{ + bool success = true; + for (std::size_t i = 0; i < files.size(); ++i) + { + const std::string& file = files[i]; + if (file.size() <= basePath.size() || file.substr(0, basePath.size()) != basePath) + { + std::cerr << "File " << file << " is not an absolute path starting with " << basePath << std::endl; + success = false; + } + else + { + const std::string relativePath = file.substr(basePath.size()); + std::string name = relativePath; + std::size_t index = relativePath.find_last_of(DIR_SEP); + if (index != std::string::npos) + { + name = relativePath.substr(index+1); + } + success &= AddFile(relativePath, Resource(name, file)); + } + } + return success; +} + +bool ResourceWriter::Write() +{ + if (!WriteHeader()) + { + std::cerr << "Could not write header." << std::endl; + return false; + } + if (!WritePayloads()) + { + std::cerr << "Could not write data blobs." << std::endl; + return false; + } + if (!WriteNames()) + { + std::cerr << "Could not write file names." << std::endl; + return false; + } + if (!WriteDataTree()) + { + std::cerr << "Could not write data tree." << std::endl; + return false; + } + if (!WriteRegistrationCode()) + { + std::cerr << "Could not write footer" << std::endl; + return false; + } + + return true; +} + +bool ResourceWriter::AddFile(const std::string& alias, const Resource& file) +{ + std::ifstream in(file.path.c_str(), std::ifstream::in | std::ifstream::binary); + if (!in) + { + std::cerr << "File could not be opened: " << file.path << std::endl; + return false; + } + in.seekg(0, std::ifstream::end); + std::ifstream::pos_type size = in.tellg(); + in.close(); + + if (size > 0xffffffff) + { + std::cerr << "File too big: " << file.path << std::endl; + return false; + } + + if (!root) + { + root = new Resource(std::string(), std::string(), Resource::Directory); + } + + Resource* parent = root; + std::stringstream ss(alias); + std::vector nodes; + { + std::string node; + while (std::getline(ss, node, DIR_SEP)) + { + if (node.empty()) + continue; + nodes.push_back(node); + } + } + + for(std::size_t i = 0; i < nodes.size()-1; ++i) + { + const std::string& node = nodes[i]; + if (parent->children.find(node) == parent->children.end()) + { + Resource* s = new Resource(node, std::string(), Resource::Directory); + s->parent = parent; + parent->children.insert(std::make_pair(node, s)); + parent->sortedChildren.insert(std::make_pair(static_cast(US_HASH_FUNCTION_NAMESPACE::US_HASH_FUNCTION(std::string, node)), s)); + parent = s; + } + else + { + parent = parent->children[node]; + } + } + + const std::string filename = nodes.back(); + Resource* s = new Resource(file); + s->parent = parent; + parent->children.insert(std::make_pair(filename, s)); + parent->sortedChildren.insert(std::make_pair(static_cast(US_HASH_FUNCTION_NAMESPACE::US_HASH_FUNCTION(std::string, filename)), s)); + return true; +} + +bool ResourceWriter::WriteHeader() +{ + std::stringstream ss; + std::time_t now = time(0); + ss << std::ctime(&now); + + WriteString("/*=============================================================================\n"); + WriteString(" Resource object code\n"); + WriteString("\n"); + WriteString(" Created: "); + WriteString(ss.str()); + WriteString(" by: The Resource Compiler for CppMicroServices version "); + WriteString(CppMicroServices_VERSION_STR); + WriteString("\n\n"); + WriteString(" WARNING! All changes made in this file will be lost!\n"); + WriteString( "=============================================================================*/\n\n"); + WriteString("#include \n"); + WriteString("#include \n\n"); + return true; +} + +bool ResourceWriter::WritePayloads() +{ + if (!root) + return false; + + WriteString("static const unsigned char us_resource_data[] = {\n"); + std::stack pending; + + pending.push(root); + int64_t offset = 0; + std::string errorMessage; + while (!pending.empty()) + { + Resource* file = pending.top(); + pending.pop(); + for (std::map::iterator i = file->children.begin(); + i != file->children.end(); ++i) + { + Resource* child = i->second; + if (child->flags & Resource::Directory) + { + pending.push(child); + } + else + { + offset = child->WritePayload(*this, offset, &errorMessage); + if (offset == 0) + { + std::cerr << errorMessage << std::endl; + } + } + } + } + WriteString("\n};\n\n"); + return true; +} + +bool ResourceWriter::WriteNames() +{ + if (!root) + return false; + + WriteString("static const unsigned char us_resource_name[] = {\n"); + + std::map names; + std::stack pending; + + pending.push(root); + int64_t offset = 0; + while (!pending.empty()) + { + Resource* file = pending.top(); + pending.pop(); + for (std::map::iterator it = file->children.begin(); + it != file->children.end(); ++it) + { + Resource* child = it->second; + if (child->flags & Resource::Directory) + { + pending.push(child); + } + if (names.find(child->name) != names.end()) + { + child->nameOffset = names[child->name]; + } + else + { + names.insert(std::make_pair(child->name, offset)); + offset = child->WriteName(*this, offset); + } + } + } + WriteString("\n};\n\n"); + return true; +} + +bool ResourceWriter::WriteDataTree() +{ + if (!root) + return false; + + WriteString("static const unsigned char us_resource_tree[] = {\n"); + std::stack pending; + + // calculate the child offsets in the us_resource_tree array + pending.push(root); + int offset = 1; + while (!pending.empty()) + { + Resource* file = pending.top(); + pending.pop(); + file->childOffset = offset; + + // calculate the offset now + for (std::map::iterator i = file->sortedChildren.begin(); + i != file->sortedChildren.end(); ++i) + { + Resource* child = i->second; + ++offset; + if (child->flags & Resource::Directory) + { + pending.push(child); + } + } + } + + // write the tree structure + pending.push(root); + root->WriteTreeInfo(*this); + while (!pending.empty()) + { + Resource *file = pending.top(); + pending.pop(); + + // write the actual data now + for (std::map::iterator i = file->sortedChildren.begin(); + i != file->sortedChildren.end(); ++i) + { + Resource *child = i->second; + child->WriteTreeInfo(*this); + if (child->flags & Resource::Directory) + { + pending.push(child); + } + } + } + WriteString("\n};\n\n"); + + return true; +} + +bool ResourceWriter::WriteRegistrationCode() +{ + WriteString("US_BEGIN_NAMESPACE\n\n"); + WriteString("extern US_EXPORT bool RegisterResourceData(int, ModuleInfo*, const unsigned char*, const unsigned char*, const unsigned char*);\n\n"); + WriteString("US_END_NAMESPACE\n\n"); + + WriteString(std::string("extern \"C\" US_ABI_EXPORT int us_init_resources_") + libName + + "(US_PREPEND_NAMESPACE(ModuleInfo)* moduleInfo)\n"); + WriteString("{\n"); + WriteString(" US_PREPEND_NAMESPACE(RegisterResourceData)(0x01, moduleInfo, us_resource_tree, us_resource_name, us_resource_data);\n"); + WriteString(" return 1;\n"); + WriteString("}\n"); + + return true; +} + +void ResourceWriter::WriteString(const std::string& str) +{ + out << str; +} + +void ResourceWriter::WriteChar(char c) +{ + out << c; +} + +void ResourceWriter::WriteHex(uint8_t tmp) +{ + const char* const digits = "0123456789abcdef"; + WriteChar('0'); + WriteChar('x'); + if (tmp < 16) + { + WriteChar(digits[tmp]); + } + else + { + WriteChar(digits[tmp >> 4]); + WriteChar(digits[tmp & 0xf]); + } + WriteChar(','); +} + +void ResourceWriter::WriteNumber2(uint16_t number) +{ + WriteHex(number >> 8); + WriteHex(static_cast(number)); +} + +void ResourceWriter::WriteNumber4(uint32_t number) +{ + WriteHex(number >> 24); + WriteHex(number >> 16); + WriteHex(number >> 8); + WriteHex(number); +} + + +#ifdef US_PLATFORM_POSIX +#include +std::string GetCurrentDir() +{ + char currDir[512]; + if (!getcwd(currDir, sizeof(currDir))) + { + std::cerr << "Getting the current directory failed." << std::endl; + exit(EXIT_FAILURE); + } + return std::string(currDir); +} +#else +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +std::string GetCurrentDir() +{ + TCHAR currDir[512]; + DWORD dwRet; + dwRet = GetCurrentDirectory(sizeof(currDir), currDir); + + if( dwRet == 0 || dwRet > 512) + { + std::cerr << "Getting the current directory failed." << std::endl; + exit(EXIT_FAILURE); + } + return std::string(currDir); +} +#endif + +int main(int argc, char** argv) +{ + if (argc < 4) + { + std::cout << US_RCC_EXECUTABLE_NAME " - A resource compiler for C++ Micro Services modules\n" + "\n" + "Usage: " US_RCC_EXECUTABLE_NAME " LIBNAME OUTPUT INPUT [INPUT]...\n" + "Convert all INPUT files into hex code embedded in C funtions written to OUTPUT.\n"; + exit(EXIT_SUCCESS); + } + + std::string libName(argv[1]); + std::string fileName(argv[2]); + + std::vector inputFiles; + + for (int i = 3; i < argc; i++) + { + inputFiles.push_back(argv[i]); + } + + ResourceWriter writer(fileName, libName); + if (!writer.AddFiles(inputFiles, GetCurrentDir())) + { + return EXIT_FAILURE; + } + + return writer.Write() ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/Core/Code/CppMicroServices/usConfig.h.in b/Core/Code/CppMicroServices/usConfig.h.in index 05802cb127..59c59a4753 100644 --- a/Core/Code/CppMicroServices/usConfig.h.in +++ b/Core/Code/CppMicroServices/usConfig.h.in @@ -1,229 +1,253 @@ /* USCONFIG.h this file is generated. Do not change! */ #ifndef USCONFIG_H #define USCONFIG_H #cmakedefine US_BUILD_SHARED_LIBS #cmakedefine CppMicroServices_EXPORTS #cmakedefine US_ENABLE_AUTOLOADING_SUPPORT #cmakedefine US_ENABLE_THREADING_SUPPORT #cmakedefine US_ENABLE_SERVICE_FACTORY_SUPPORT #cmakedefine US_USE_CXX11 ///------------------------------------------------------------------- // Version information //------------------------------------------------------------------- #define CppMicroServices_VERSION_MAJOR @CppMicroServices_VERSION_MAJOR@ #define CppMicroServices_VERSION_MINOR @CppMicroServices_VERSION_MINOR@ #define CppMicroServices_VERSION_PATH @CppMicroServices_VERSION_PATCH@ #define CppMicroServices_VERSION @CppMicroServices_VERSION@ #define CppMicroServices_VERSION_STR "@CppMicroServices_VERSION@" +///------------------------------------------------------------------- +// Macros used by the unit tests +//------------------------------------------------------------------- + +#define CppMicroServices_SOURCE_DIR "@CppMicroServices_SOURCE_DIR@" + ///------------------------------------------------------------------- // Macros for import/export declarations //------------------------------------------------------------------- #if defined(WIN32) #define US_ABI_EXPORT __declspec(dllexport) #define US_ABI_IMPORT __declspec(dllimport) #define US_ABI_LOCAL #else #if __GNUC__ >= 4 #define US_ABI_EXPORT __attribute__ ((visibility ("default"))) #define US_ABI_IMPORT __attribute__ ((visibility ("default"))) #define US_ABI_LOCAL __attribute__ ((visibility ("hidden"))) #else #define US_ABI_EXPORT #define US_ABI_IMPORT #define US_ABI_LOCAL #endif #endif #ifdef US_BUILD_SHARED_LIBS // We are building a shared lib #ifdef CppMicroServices_EXPORTS #define US_EXPORT US_ABI_EXPORT #else #define US_EXPORT US_ABI_IMPORT #endif #else // We are building a static lib #if __GNUC__ >= 4 // Don't hide RTTI symbols of definitions in the C++ Micro Services // headers that are included in DSOs with hidden visibility #define US_EXPORT US_ABI_EXPORT #else #define US_EXPORT #endif #endif //------------------------------------------------------------------- // Namespace customization //------------------------------------------------------------------- #define US_NAMESPACE @US_NAMESPACE@ #ifndef US_NAMESPACE /* user namespace */ # define US_PREPEND_NAMESPACE(name) ::name # define US_USE_NAMESPACE # define US_BEGIN_NAMESPACE # define US_END_NAMESPACE # define US_FORWARD_DECLARE_CLASS(name) class name; # define US_FORWARD_DECLARE_STRUCT(name) struct name; #else /* user namespace */ # define US_PREPEND_NAMESPACE(name) ::US_NAMESPACE::name # define US_USE_NAMESPACE using namespace ::US_NAMESPACE; # define US_BEGIN_NAMESPACE namespace US_NAMESPACE { # define US_END_NAMESPACE } # define US_FORWARD_DECLARE_CLASS(name) \ US_BEGIN_NAMESPACE class name; US_END_NAMESPACE # define US_FORWARD_DECLARE_STRUCT(name) \ US_BEGIN_NAMESPACE struct name; US_END_NAMESPACE namespace US_NAMESPACE {} #endif /* user namespace */ #define US_BASECLASS_NAME @US_BASECLASS_NAME@ #define US_BASECLASS_HEADER <@US_BASECLASS_HEADER@> // base class forward declaration @US_BASECLASS_FORWARD_DECLARATION@ //------------------------------------------------------------------- // Platform defines //------------------------------------------------------------------- #if defined(__APPLE__) #define US_PLATFORM_APPLE #endif #if defined(__linux__) #define US_PLATFORM_LINUX #endif #if defined(_WIN32) || defined(_WIN64) #define US_PLATFORM_WINDOWS #else #define US_PLATFORM_POSIX #endif //------------------------------------------------------------------- -// Compiler defines +// Macros for suppressing warnings //------------------------------------------------------------------- -#if defined(_MSC_VER) && !defined(_SCL_SECURE_NO_WARNINGS) - #define _SCL_SECURE_NO_WARNINGS +#ifdef _MSC_VER +#define US_MSVC_PUSH_DISABLE_WARNING(wn) \ +__pragma(warning(push)) \ +__pragma(warning(disable:wn)) +#define US_MSVC_POP_WARNING \ +__pragma(warning(pop)) +#define US_MSVC_DISABLE_WARNING(wn) \ +__pragma(warning(disable:wn)) +#else +#define US_MSVC_PUSH_DISABLE_WARNING(wn) +#define US_MSVC_POP_WARNING +#define US_MSVC_DISABLE_WARNING(wn) #endif +// Do not warn about the usage of deprecated unsafe functions +US_MSVC_DISABLE_WARNING(4996) + //------------------------------------------------------------------- // Debuging & Logging //------------------------------------------------------------------- #if defined(NDEBUG) && !defined(US_NO_DEBUG_OUTPUT) #define US_NO_DEBUG_OUTPUT #endif US_BEGIN_NAMESPACE enum MsgType { DebugMsg = 0, InfoMsg = 1, WarningMsg = 2, ErrorMsg = 3 }; typedef void (*MsgHandler)(MsgType, const char *); US_EXPORT MsgHandler installMsgHandler(MsgHandler); US_END_NAMESPACE //------------------------------------------------------------------- // Hash Container //------------------------------------------------------------------- #ifdef US_USE_CXX11 #include #include #define US_HASH_FUNCTION_BEGIN(type) \ template<> \ struct hash : std::unary_function { \ std::size_t operator()(const type& arg) const { #define US_HASH_FUNCTION_END } }; #define US_HASH_FUNCTION(type, arg) hash()(arg) - + #if defined(US_PLATFORM_WINDOWS) && (_MSC_VER < 1700) #define US_HASH_FUNCTION_FRIEND(type) friend class ::std::hash #else #define US_HASH_FUNCTION_FRIEND(type) friend struct ::std::hash #endif #define US_UNORDERED_MAP_TYPE ::std::unordered_map #define US_UNORDERED_SET_TYPE ::std::unordered_set #define US_HASH_FUNCTION_NAMESPACE ::std #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace std { #define US_HASH_FUNCTION_NAMESPACE_END } #elif defined(__GNUC__) #include #include - + #define US_HASH_FUNCTION_BEGIN(type) \ template<> \ struct hash : std::unary_function { \ - std::size_t operator()(const type& arg) const { - + std::size_t operator()(const type& arg) const { + #define US_HASH_FUNCTION_END } }; - + #define US_HASH_FUNCTION(type, arg) hash()(arg) #define US_HASH_FUNCTION_FRIEND(type) friend struct ::std::tr1::hash #define US_UNORDERED_MAP_TYPE ::std::tr1::unordered_map #define US_UNORDERED_SET_TYPE ::std::tr1::unordered_set #define US_HASH_FUNCTION_NAMESPACE ::std::tr1 #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace std { namespace tr1 { #define US_HASH_FUNCTION_NAMESPACE_END }} #elif _MSC_VER <= 1500 // Visual Studio 2008 and lower #include #include - + #define US_HASH_FUNCTION_BEGIN(type) \ template<> \ - inline std::size_t hash_value(const type& arg) { - + inline std::size_t hash_value(const type& arg) { + #define US_HASH_FUNCTION_END } - + #define US_HASH_FUNCTION(type, arg) hash_value(arg) #define US_HASH_FUNCTION_FRIEND(type) friend std::size_t stdext::hash_value(const type&) #define US_UNORDERED_MAP_TYPE ::stdext::hash_map #define US_UNORDERED_SET_TYPE ::stdext::hash_set #define US_HASH_FUNCTION_NAMESPACE ::stdext #define US_HASH_FUNCTION_NAMESPACE_BEGIN namespace stdext { #define US_HASH_FUNCTION_NAMESPACE_END } #endif //------------------------------------------------------------------- // Threading Configuration //------------------------------------------------------------------- #ifdef US_ENABLE_THREADING_SUPPORT #define US_DEFAULT_THREADING US_PREPEND_NAMESPACE(MultiThreaded) #else #define US_DEFAULT_THREADING US_PREPEND_NAMESPACE(SingleThreaded) #endif +//------------------------------------------------------------------- +// Header Availability +//------------------------------------------------------------------- + +#cmakedefine HAVE_STDINT #endif // USCONFIG_H