# HG changeset patch # User Sebastien Jodogne # Date 1591886434 -7200 # Node ID e00f3d089991aa5804b175e0ce6ba79c0b90571c # Parent 0953b3dc32614498de06c95d06e897998562aa46 shared library of orthanc framework diff -r 0953b3dc3261 -r e00f3d089991 CMakeLists.txt --- a/CMakeLists.txt Thu Jun 11 14:38:31 2020 +0200 +++ b/CMakeLists.txt Thu Jun 11 16:40:34 2020 +0200 @@ -248,6 +248,13 @@ ## Configuration of the C/C++ macros ##################################################################### +if (STATIC_BUILD) + add_definitions(-DORTHANC_STATIC=1) +else() + add_definitions(-DORTHANC_STATIC=0) +endif() + + if (ENABLE_PLUGINS) add_definitions(-DORTHANC_ENABLE_PLUGINS=1) else() diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Resources/CMake/Compiler.cmake --- a/OrthancFramework/Resources/CMake/Compiler.cmake Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Resources/CMake/Compiler.cmake Thu Jun 11 16:40:34 2020 +0200 @@ -1,5 +1,11 @@ # This file sets all the compiler-related flags + +# Save the current compiler flags to the cache every time cmake configures the project +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "compiler flags" FORCE) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "compiler flags" FORCE) + + include(CheckLibraryExists) if ((CMAKE_CROSSCOMPILING AND NOT @@ -206,19 +212,7 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") message("Building using Emscripten (for WebAssembly or asm.js targets)") - - # The BINARYEN_TRAP_MODE specifies what to do when divisions per - # zero (and similar conditions like integer overflows) are - # encountered: The "clamp" mode avoids throwing errors, as they - # cannot be properly catched by "try {} catch (...)" constructions. - # Setting this option to "ON" fixes error: "shared:ERROR: - # BINARYEN_TRAP_MODE is not supported by the LLVM wasm backend" if - # using the "upstream" backend of Emscripten. - if (NOT EMSCRIPTEN_SET_LLVM_WASM_BACKEND) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s BINARYEN_TRAP_MODE='\"clamp\"'") - endif() - - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'") + include(EmscriptenParameters.cmake) elseif (CMAKE_SYSTEM_NAME STREQUAL "Android") @@ -254,10 +248,3 @@ # preceding batches. https://cmake.org/Bug/view.php?id=14874 set(CMAKE_CXX_ARCHIVE_APPEND " q ") endif() - - -if (STATIC_BUILD) - add_definitions(-DORTHANC_STATIC=1) -else() - add_definitions(-DORTHANC_STATIC=0) -endif() diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Resources/CMake/DownloadOrthancFramework.cmake --- a/OrthancFramework/Resources/CMake/DownloadOrthancFramework.cmake Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Resources/CMake/DownloadOrthancFramework.cmake Thu Jun 11 16:40:34 2020 +0200 @@ -399,8 +399,10 @@ include(${CMAKE_CURRENT_LIST_DIR}/AutoGeneratedCode.cmake) set(EMBED_RESOURCES_PYTHON ${CMAKE_CURRENT_LIST_DIR}/EmbedResources.py) - if (NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows" AND - NOT ORTHANC_FRAMEWORK_STATIC) + if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows" OR + ORTHANC_FRAMEWORK_STATIC) + include_directories(${ORTHANC_FRAMEWORK_ROOT}/..) + else() # Look for mandatory dependency JsonCpp (cf. JsonCppConfiguration.cmake) find_path(JSONCPP_INCLUDE_DIR json/reader.h /usr/include/jsoncpp @@ -447,6 +449,22 @@ endif() link_libraries(sqlite3) endif() + + # Optional component - Pugixml + if (ENABLE_PUGIXML) + CHECK_INCLUDE_FILE_CXX(pugixml.hpp HAVE_PUGIXML_H) + if (NOT HAVE_PUGIXML_H) + message(FATAL_ERROR "Please install the libpugixml-dev package") + endif() + link_libraries(pugixml) + endif() + + # Optional component - DCMTK + if (ENABLE_DCMTK) + include(FindDCMTK) + include_directories(${DCMTK_INCLUDE_DIRS}) + link_libraries(${DCMTK_LIBRARIES}) + endif() endif() # Optional component - Google Test @@ -462,7 +480,6 @@ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") set(ORTHANC_FRAMEWORK_INCLUDE_DIR ${ORTHANC_FRAMEWORK_ROOT}) - include_directories(${ORTHANC_FRAMEWORK_ROOT}/..) else() find_path(ORTHANC_FRAMEWORK_INCLUDE_DIR OrthancFramework.h /usr/include/orthanc-framework diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Resources/CMake/EmscriptenParameters.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/CMake/EmscriptenParameters.cmake Thu Jun 11 16:40:34 2020 +0200 @@ -0,0 +1,24 @@ +if (NOT "${EMSCRIPTEN_TRAP_MODE}" STREQUAL "") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s BINARYEN_TRAP_MODE='\"${EMSCRIPTEN_TRAP_MODE}\"'") +endif() + +set(WASM_FLAGS "-s SIDE_MODULE=1 -s EXPORT_ALL=1") + +if (EMSCRIPTEN_TARGET_MODE STREQUAL "wasm") + # WebAssembly + set(WASM_FLAGS "${WASM_FLAGS} -s WASM=1 -s FETCH=1") + +elseif (EMSCRIPTEN_TARGET_MODE STREQUAL "asm.js") + # asm.js targeting IE 11 + set(WASM_FLAGS "-s WASM=0 -s ASM_JS=2 -s FETCH=1 -s LEGACY_VM_SUPPORT=1") + +else() + message(FATAL_ERROR "Bad value for EMSCRIPTEN_TARGET_MODE: ${EMSCRIPTEN_TARGET_MODE}") +endif() + +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(WASM_FLAGS "${WASM_FLAGS} -s SAFE_HEAP=1") +endif() + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WASM_FLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WASM_FLAGS}") diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake --- a/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake Thu Jun 11 16:40:34 2020 +0200 @@ -71,13 +71,16 @@ set(USE_LEGACY_JSONCPP OFF CACHE BOOL "Use the old branch 0.x.y of JsonCpp, that does not require a C++11 compiler (for LSB and old versions of Visual Studio)") set(USE_LEGACY_LIBICU OFF CACHE BOOL "Use icu icu4c-58_2, latest version not requiring a C++11 compiler (for LSB and old versions of Visual Studio)") set(MSVC_MULTIPLE_PROCESSES OFF CACHE BOOL "Add the /MP option to build with multiple processes if using Visual Studio") -set(EMSCRIPTEN_SET_LLVM_WASM_BACKEND OFF CACHE BOOL "Sets the compiler flags required to use the LLVM Web Assembly backend in emscripten") +set(EMSCRIPTEN_TARGET_MODE "wasm" CACHE STRING "Sets the target mode for Emscripten (can be \"wasm\" or \"asm.js\")") +set(EMSCRIPTEN_TRAP_MODE "" CACHE STRING "Sets the trap mode for Emscripten for numeric errors (can notably be empty, or \"clamp\")") set(OPENSSL_STATIC_VERSION "1.1.1" CACHE STRING "Version of OpenSSL to be used in static builds (can be \"1.0.2\", or \"1.1.1\")") -mark_as_advanced(USE_GOOGLE_TEST_DEBIAN_PACKAGE) +mark_as_advanced(EMSCRIPTEN_TARGET_MODE) +mark_as_advanced(EMSCRIPTEN_TRAP_MODE) mark_as_advanced(SYSTEM_MONGOOSE_USE_CALLBACKS) +mark_as_advanced(USE_DCMTK_362_PRIVATE_DIC) +mark_as_advanced(USE_GOOGLE_TEST_DEBIAN_PACKAGE) mark_as_advanced(USE_PUGIXML) -mark_as_advanced(USE_DCMTK_362_PRIVATE_DIC) ##################################################################### diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Resources/WebAssembly.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/WebAssembly.txt Thu Jun 11 16:40:34 2020 +0200 @@ -0,0 +1,58 @@ + +====================================== +== Notes about WebAssembly =========== +====================================== + + + +Trap mode +========= + +The BINARYEN_TRAP_MODE specifies what to do when divisions per zero +(and similar conditions like integer overflows) are encountered. This +can be set through the option "EMSCRIPTEN_TRAP_MODE" in Orthanc. + + + +Previous versions (<= 1.7.1) +---------------------------- + +The "clamp" mode avoids throwing errors, as they cannot be properly +catched by "try {} catch (...)" constructions. HOWEVER, the "upstream" +backend of Emscripten (which is now the default) doesn't support this +option. + +In Orthanc <= 1.7.1, the "clamp" mode was used by default. As a +consequence, there was an old flag "EMSCRIPTEN_SET_LLVM_WASM_BACKEND" +to setting BINARYEN_TRAP_MODE. + +Here is the definition of the parameter that was in +"OrthancFrameworkParameters.cmake": + +>>>>> +set(EMSCRIPTEN_SET_LLVM_WASM_BACKEND OFF CACHE BOOL "Sets the compiler flags required to use the LLVM Web Assembly backend in emscripten") +<<<<< + +Setting this option to "ON" fixes error: "shared:ERROR: +BINARYEN_TRAP_MODE is not supported by the LLVM wasm backend" if using +the "upstream" backend of Emscripten. Here is the corresponding +implementation that was in "Compiler.cmake": + +>>>>> +if (NOT EMSCRIPTEN_SET_LLVM_WASM_BACKEND) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s BINARYEN_TRAP_MODE='\"clamp\"'") +endif() +<<<<< + + + + +Linker flags +============ + +Since Orthanc 1.7.2, "Compiler.cmake" doesn't set any linking option +for Emscripten. In Orthanc <= 1.7.1, the following was done: + +>>>>> +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'") +<<<<< diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/SharedLibrary/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/SharedLibrary/CMakeLists.txt Thu Jun 11 16:40:34 2020 +0200 @@ -0,0 +1,421 @@ + +## To see all the exported symbols in the DLL: +## +## $ i686-w64-mingw32-objdump -p ./libOrthancFramework.dll +## +## IMPORTANT: "-static-libgcc" prevents catching exception in the +## .EXE, which makes throwing exceptions crash the software! +## + + +cmake_minimum_required(VERSION 2.8) +project(OrthancFramework) + +# *Do not* use CMAKE_INSTALL_PREFIX, otherwise CMake automatically +# *adds CMAKE_INSTALL_PREFIX to the include_directories()! +set(ORTHANC_INSTALL_DIR "/tmp/install" CACHE PATH "") +SET(UNIT_TESTS_WITH_HTTP_CONNEXIONS ON CACHE BOOL "Allow unit tests to make HTTP requests") + + +# This must be before inclusion of "OrthancFrameworkParameters.cmake" to take effect +if (CMAKE_SYSTEM_NAME STREQUAL "Windows" AND + CMAKE_COMPILER_IS_GNUCXX) # MinGW + set(DYNAMIC_MINGW_STDLIB ON) # Disable static linking against libc (to throw exceptions) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libstdc++") +endif() + +include(${CMAKE_SOURCE_DIR}/../Resources/CMake/OrthancFrameworkParameters.cmake) + +set(ENABLE_DCMTK ON) +set(ENABLE_DCMTK_TRANSCODING ON) +set(ENABLE_GOOGLE_TEST ON) +set(ENABLE_JPEG ON) +set(ENABLE_LOCALE ON) +set(ENABLE_LUA ON) +set(ENABLE_PNG ON) +set(ENABLE_PUGIXML ON) +set(ENABLE_ZLIB ON) + +if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + # WebAssembly or asm.js + set(BOOST_LOCALE_BACKEND "libiconv") + set(ORTHANC_SANDBOXED ON) + +else() + # Enable all the remaining modules for other targets + set(ENABLE_CRYPTO_OPTIONS ON) + set(ENABLE_DCMTK_NETWORKING ON) + set(ENABLE_OPENSSL_ENGINES ON) + set(ENABLE_SQLITE ON) + set(ENABLE_WEB_CLIENT ON) + set(ENABLE_WEB_SERVER ON) + + set(BOOST_LOCALE_BACKEND "icu") +endif() + + +set(ORTHANC_BUILDING_FRAMEWORK_LIBRARY ON) + +# Don't use the version script that is reserved for plugins +set(ENABLE_PLUGINS_VERSION_SCRIPT OFF) + +include(${CMAKE_SOURCE_DIR}/../Resources/CMake/OrthancFrameworkConfiguration.cmake) + +if (STATIC_BUILD OR NOT USE_SYSTEM_JSONCPP) + set(ORTHANC_STATIC_JSONCPP ON) +else() + set(ORTHANC_STATIC_JSONCPP OFF) +endif() + +if (STATIC_BUILD OR NOT USE_SYSTEM_BOOST) + set(ORTHANC_STATIC_BOOST ON) +else() + set(ORTHANC_STATIC_BOOST OFF) +endif() + +if (STATIC_BUILD OR NOT USE_SYSTEM_SQLITE) + set(ORTHANC_STATIC_SQLITE ON) +else() + set(ORTHANC_STATIC_SQLITE OFF) +endif() + +if (STATIC_BUILD OR NOT USE_SYSTEM_PUGIXML) + set(ORTHANC_STATIC_PUGIXML ON) +else() + set(ORTHANC_STATIC_PUGIXML OFF) +endif() + + +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR + CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + + # Control the visibility of JsonCpp + if (ORTHANC_STATIC_JSONCPP) + if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + set_source_files_properties(${JSONCPP_SOURCES} + PROPERTIES COMPILE_DEFINITIONS "JSON_API=__declspec(dllexport)" + ) + set(ORTHANC_JSON_API "__declspec(dllimport)") + else() + set(ORTHANC_JSON_API "__attribute__((visibility(\"default\")))") + set_source_files_properties(${JSONCPP_SOURCES} + PROPERTIES COMPILE_DEFINITIONS "JSON_API=${ORTHANC_JSON_API}" + ) + endif() + endif() + + # Control the visibility of SQLite + if (ORTHANC_STATIC_SQLITE) + if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + set_source_files_properties(${SQLITE_SOURCES} + PROPERTIES COMPILE_DEFINITIONS "SQLITE_API=__declspec(dllexport)" + ) + set(ORTHANC_SQLITE_API "__declspec(dllimport)") + else() + set(ORTHANC_SQLITE_API "__attribute__((visibility(\"default\")))") + set_source_files_properties(${SQLITE_SOURCES} + PROPERTIES COMPILE_DEFINITIONS "SQLITE_API=${ORTHANC_SQLITE_API}" + ) + endif() + endif() + + # Control the visibility of Boost + if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows" AND + ORTHANC_STATIC_BOOST) + set_source_files_properties(${ORTHANC_CORE_SOURCES_INTERNAL} + PROPERTIES COMPILE_DEFINITIONS "BOOST_DATE_TIME_SOURCE;BOOST_FILESYSTEM_SOURCE;BOOST_LOCALE_SOURCE;BOOST_REGEX_SOURCE" + ) + endif() + + # Control the visibility of Pugixml + if (ORTHANC_STATIC_PUGIXML) + if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + set_source_files_properties(${PUGIXML_SOURCES} + PROPERTIES COMPILE_DEFINITIONS "PUGIXML_API=__declspec(dllexport)" + ) + set(ORTHANC_PUGIXML_API "__declspec(dllimport)") + else() + set(ORTHANC_PUGIXML_API "__attribute__((visibility(\"default\")))") + set_source_files_properties(${PUGIXML_SOURCES} + PROPERTIES COMPILE_DEFINITIONS "PUGIXML_API=${ORTHANC_PUGIXML_API}" + ) + endif() + endif() +endif() + + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + execute_process( + COMMAND + ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/../Resources/WindowsResources.py + ${ORTHANC_VERSION} "OrthancFramework" OrthancFramework.dll "Shared library containing the Orthanc framework" + ERROR_VARIABLE Failure + OUTPUT_FILE ${AUTOGENERATED_DIR}/Version.rc + ) + + if (Failure) + message(FATAL_ERROR "Error while computing the version information: ${Failure}") + endif() + + list(APPEND AUTOGENERATED_SOURCES ${AUTOGENERATED_DIR}/Version.rc) +endif() + + +add_definitions( + -DCIVETWEB_API= # Don't export the public symbols from CivetWeb + ) + +# Those two files collided with each other, and thus are merged into a +# single "DllMain.cpp" +list(REMOVE_ITEM ORTHANC_CORE_SOURCES + ${BOOST_SOURCES_DIR}/libs/thread/src/win32/tss_dll.cpp + ${OPENSSL_SOURCES_DIR}/crypto/dllmain.c + ) + +if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + # In WebAssembly, a SIDE_MODULE is an executable + add_executable(OrthancFramework + ${AUTOGENERATED_SOURCES} + ${ORTHANC_CORE_SOURCES} + ${ORTHANC_DICOM_SOURCES} + DllMain.cpp + ) + + # CMake does not natively handle SIDE_MODULE, and believes that + # Emscripten produces a ".js" file (whereas it creates only the + # ".wasm"). Create a dummy ".js" for target to work. + add_custom_command( + TARGET OrthancFramework POST_BUILD + COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/OrthancFramework.js + ) +else() + add_library(OrthancFramework SHARED + ${AUTOGENERATED_SOURCES} + ${ORTHANC_CORE_SOURCES} + ${ORTHANC_DICOM_SOURCES} + DllMain.cpp + ) +endif() + +# By default, hide all the symbols +set_target_properties(OrthancFramework PROPERTIES C_VISIBILITY_PRESET hidden) +set_target_properties(OrthancFramework PROPERTIES CXX_VISIBILITY_PRESET hidden) + +target_link_libraries(OrthancFramework ${DCMTK_LIBRARIES}) + +if (LIBICU_LIBRARIES) + target_link_libraries(OrthancFramework ${LIBICU_LIBRARIES}) +endif() + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + target_link_libraries(OrthancFramework winpthread) +endif() + + +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + set_target_properties( + OrthancFramework PROPERTIES + VERSION ${ORTHANC_VERSION} + SOVERSION ${ORTHANC_VERSION} + ) +endif() + + +file( + COPY ${CMAKE_SOURCE_DIR}/../Sources/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/orthanc-framework + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + PATTERN OrthancFramework.h EXCLUDE + ) + +configure_file( + ${CMAKE_SOURCE_DIR}/OrthancFramework.h.in + ${CMAKE_CURRENT_BINARY_DIR}/Include/orthanc-framework/OrthancFramework.h + ) + + +if (ORTHANC_STATIC_BOOST) + file( + COPY ${BOOST_SOURCES_DIR}/boost/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/boost/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + PATTERN "*.hpp" + PATTERN "*.ipp" + ) +endif() + + +if (ENABLE_SQLITE AND ORTHANC_STATIC_SQLITE) + file( + COPY ${SQLITE_SOURCES_DIR}/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + ) +endif() + + +if (ORTHANC_STATIC_JSONCPP) + file( + COPY ${JSONCPP_SOURCES_DIR}/include/json/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/json/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + ) +endif() + + +if (ENABLE_DCMTK AND (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)) + file( + COPY ${DCMTK_SOURCES_DIR}/dcmdata/include/dcmtk/dcmdata/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/dcmtk/dcmdata/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + ) + + file( + COPY ${DCMTK_SOURCES_DIR}/config/include/dcmtk/config/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/dcmtk/config/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + ) + + file( + COPY ${DCMTK_SOURCES_DIR}/ofstd/include/dcmtk/ofstd/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/dcmtk/ofstd/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + ) + + file( + COPY ${DCMTK_SOURCES_DIR}/oflog/include/dcmtk/oflog/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/dcmtk/oflog/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + ) +endif() + + +if (ENABLE_PUGIXML AND (STATIC_BUILD OR NOT USE_SYSTEM_PUGIXML)) + file( + COPY ${PUGIXML_SOURCES_DIR}/src/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.hpp" + ) +endif() + + +if (ENABLE_LUA AND (STATIC_BUILD OR NOT USE_SYSTEM_LUA)) + file( + COPY ${LUA_SOURCES_DIR}/src/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + ) +endif() + + +if (OFF) + # These files are fully abstracted by the Orthanc Framework classes + if (ENABLE_PNG AND (STATIC_BUILD OR NOT USE_SYSTEM_LIBPNG)) + file( + COPY ${LIBPNG_SOURCES_DIR}/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + ) + endif() + + if (ENABLE_ZLIB AND (STATIC_BUILD OR NOT USE_SYSTEM_ZLIB)) + file( + COPY ${ZLIB_SOURCES_DIR}/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + ) + endif() + + if (ENABLE_JPEG AND (STATIC_BUILD OR NOT USE_SYSTEM_LIBJPEG)) + file( + COPY ${LIBJPEG_SOURCES_DIR}/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + ) + endif() + + if (ENABLE_WEB_CLIENT AND (STATIC_BUILD OR NOT USE_SYSTEM_CURL)) + file( + COPY ${CURL_SOURCES_DIR}/include/curl/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/Include/curl/ + NO_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.h" + ) + endif() +endif() + + + + + +include(ExternalProject) + +if (CMAKE_TOOLCHAIN_FILE) + # Take absolute path to the toolchain + get_filename_component(TMP ${CMAKE_TOOLCHAIN_FILE} REALPATH BASE ${CMAKE_SOURCE_DIR}/..) + list(APPEND Flags -DCMAKE_TOOLCHAIN_FILE=${TMP}) +endif() + +# Build the unit tests, linking them against the just-created +# "OrthancFramework" library +externalproject_add(UnitTests + SOURCE_DIR "${CMAKE_SOURCE_DIR}/../UnitTestsSources" + CMAKE_ARGS + -DALLOW_DOWNLOADS:BOOL=ON + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DORTHANC_FRAMEWORK_LIBDIR:PATH=${CMAKE_CURRENT_BINARY_DIR} + -DORTHANC_FRAMEWORK_ROOT:PATH=${CMAKE_CURRENT_BINARY_DIR}/Include/orthanc-framework + -DORTHANC_FRAMEWORK_SOURCE:STRING=system + -DORTHANC_FRAMEWORK_STATIC:BOOL=${STATIC_BUILD} + -DUNIT_TESTS_WITH_HTTP_CONNEXIONS:BOOL=${UNIT_TESTS_WITH_HTTP_CONNEXIONS} + -DUSE_SYSTEM_GOOGLE_TEST:BOOL=OFF + ${Flags} + ) + +add_dependencies(UnitTests OrthancFramework) + + +install( + TARGETS OrthancFramework + RUNTIME DESTINATION ${ORTHANC_INSTALL_DIR}/lib # Destination for Windows + LIBRARY DESTINATION ${ORTHANC_INSTALL_DIR}/lib # Destination for Linux + ) + +if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/OrthancFramework.wasm + LIBRARY DESTINATION ${ORTHANC_INSTALL_DIR}/lib + ) +endif() + +install( + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Include/orthanc-framework + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/orthanc-framework + ) diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/SharedLibrary/DllMain.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/SharedLibrary/DllMain.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -0,0 +1,61 @@ +/** + + This file merges 2 files: + ${BOOST_SOURCES_DIR}/libs/thread/src/win32/tss_dll.cpp + ${OPENSSL_SOURCES_DIR}/crypto/dllmain.c + + **/ + +#if defined(_WIN32) || defined(__CYGWIN__) +# ifdef __CYGWIN__ +# include +# endif + +#include "e_os.h" +#include "crypto/cryptlib.h" + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + //OPENSSL_cpuid_setup(); // TODO - Is this necessary? + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + OPENSSL_thread_stop(); + break; + + case DLL_PROCESS_DETACH: + break; + } + + return TRUE; +} + +#endif + + +namespace boost +{ + void tss_cleanup_implemented() + { + /* + This function's sole purpose is to cause a link error in cases where + automatic tss cleanup is not implemented by Boost.Threads as a + reminder that user code is responsible for calling the necessary + functions at the appropriate times (and for implementing an a + tss_cleanup_implemented() function to eliminate the linker's + missing symbol error). + + If Boost.Threads later implements automatic tss cleanup in cases + where it currently doesn't (which is the plan), the duplicate + symbol error will warn the user that their custom solution is no + longer needed and can be removed. + */ + } +} + diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/SharedLibrary/OrthancFramework.h.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/SharedLibrary/OrthancFramework.h.in Thu Jun 11 16:40:34 2020 +0200 @@ -0,0 +1,283 @@ +#pragma once + +/** + * Besides the "pragma once" above that only protects this file, + * define a macro to prevent including different versions of + * "OrthancFramework.h" + **/ +#ifndef __ORTHANC_FRAMEWORK_H +#define __ORTHANC_FRAMEWORK_H + + +#if defined(_WIN32) || defined (__CYGWIN__) +# define ORTHANC_PUBLIC __declspec(dllimport) +# define ORTHANC_LOCAL +#else +# if __GNUC__ >= 4 +# define ORTHANC_PUBLIC __attribute__ ((visibility ("default"))) +# define ORTHANC_LOCAL __attribute__ ((visibility ("hidden"))) +# else +# define ORTHANC_PUBLIC +# define ORTHANC_LOCAL +# pragma warning Unknown dynamic link import/export semantics +# endif +#endif + + +/** + * Configuration macros that are always set to the same value if using + * "OrthancFrameworkConfiguration.cmake" + **/ + +#define ORTHANC_ENABLE_BASE64 1 +#define ORTHANC_ENABLE_MD5 1 + + + +/** + * Configuration macros that needn't to be renamed + **/ + +#define ORTHANC_SQLITE_VERSION @ORTHANC_SQLITE_VERSION@ +#define ORTHANC_VERSION "@ORTHANC_VERSION@" +#define ORTHANC_VERSION_MAJOR @ORTHANC_VERSION_MAJOR@ +#define ORTHANC_VERSION_MINOR @ORTHANC_VERSION_MINOR@ +#define ORTHANC_VERSION_REVISION @ORTHANC_VERSION_REVISION@ + +#cmakedefine01 ORTHANC_ENABLE_CIVETWEB +#cmakedefine01 ORTHANC_ENABLE_LOGGING +#cmakedefine01 ORTHANC_ENABLE_LOGGING_STDIO +#cmakedefine01 ORTHANC_ENABLE_MONGOOSE +#cmakedefine01 ORTHANC_SANDBOXED +#cmakedefine01 ORTHANC_STATIC_BOOST +#cmakedefine01 ORTHANC_STATIC_JSONCPP +#cmakedefine01 ORTHANC_STATIC_SQLITE + +#if ORTHANC_STATIC_BOOST == 1 && !defined(BOOST_LEXICAL_CAST_ASSUME_C_LOCALE) +# define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE +#endif + +#if ORTHANC_STATIC_JSONCPP == 1 +# if defined(JSON_API) +# error JSON_API should not be defined +# else +# define JSON_API @ORTHANC_JSON_API@ +# endif +#endif + +#if ORTHANC_STATIC_SQLITE == 1 +# if defined(SQLITE_API) +# error SQLITE_API should not be defined +# else +# define SQLITE_API @ORTHANC_SQLITE_API@ +# endif +#endif + +#if ORTHANC_STATIC_PUGIXML == 1 +# if defined(PUGIXML_API) +# error PUGIXML_API should not be defined +# else +# define PUGIXML_API @ORTHANC_PUGIXML_API@ +# endif +#endif + + +#define ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(major, minor, revision) \ + (ORTHANC_VERSION_MAJOR > major || \ + (ORTHANC_VERSION_MAJOR == major && \ + (ORTHANC_VERSION_MINOR > minor || \ + (ORTHANC_VERSION_MINOR == minor && \ + ORTHANC_VERSION_REVISION >= revision)))) + + +/** + * Configuration macros that must be renamed, prefixing them by + * "ORTHANC_" + **/ + +#cmakedefine01 ENABLE_DCMTK +#if !defined(ENABLE_DCMTK) +# error CMake error +#elif ENABLE_DCMTK == 1 +# define ORTHANC_ENABLE_DCMTK 1 +#else +# define ORTHANC_ENABLE_DCMTK 0 +#endif +#undef ENABLE_DCMTK + + +#cmakedefine01 ENABLE_DCMTK_NETWORKING +#if !defined(ENABLE_DCMTK_NETWORKING) +# error CMake error +#elif ENABLE_DCMTK_NETWORKING == 1 +# define ORTHANC_ENABLE_DCMTK_NETWORKING 1 +#else +# define ORTHANC_ENABLE_DCMTK_NETWORKING 0 +#endif +#undef ENABLE_DCMTK_NETWORKING + + +#cmakedefine01 ENABLE_DCMTK_JPEG +#if !defined(ENABLE_DCMTK_JPEG) +# error CMake error +#elif ENABLE_DCMTK_JPEG == 1 +# define ORTHANC_ENABLE_DCMTK_JPEG 1 +#else +# define ORTHANC_ENABLE_DCMTK_JPEG 0 +#endif +#undef ENABLE_DCMTK_JPEG + + +#cmakedefine01 ENABLE_DCMTK_JPEG_LOSSLESS +#if !defined(ENABLE_DCMTK_JPEG_LOSSLESS) +# error CMake error +#elif ENABLE_DCMTK_JPEG_LOSSLESS == 1 +# define ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS 1 +#else +# define ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS 0 +#endif +#undef ENABLE_DCMTK_JPEG_LOSSLESS + + +#cmakedefine01 ENABLE_DCMTK_TRANSCODING +#if !defined(ENABLE_DCMTK_TRANSCODING) +# error CMake error +#elif ENABLE_DCMTK_TRANSCODING == 1 +# define ORTHANC_ENABLE_DCMTK_TRANSCODING 1 +#else +# define ORTHANC_ENABLE_DCMTK_TRANSCODING 0 +#endif +#undef ENABLE_DCMTK_TRANSCODING + + +#cmakedefine01 ENABLE_JPEG +#if !defined(ENABLE_JPEG) +# error CMake error +#elif ENABLE_JPEG == 1 +# define ORTHANC_ENABLE_JPEG 1 +#else +# define ORTHANC_ENABLE_JPEG 0 +#endif +#undef ENABLE_JPEG + + +#cmakedefine01 ENABLE_LOCALE +#if !defined(ENABLE_LOCALE) +# error CMake error +#elif ENABLE_LOCALE == 1 +# define ORTHANC_ENABLE_LOCALE 1 +#else +# define ORTHANC_ENABLE_LOCALE 0 +#endif +#undef ENABLE_LOCALE + + +#cmakedefine01 ENABLE_LUA +#if !defined(ENABLE_LUA) +# error CMake error +#elif ENABLE_LUA == 1 +# define ORTHANC_ENABLE_LUA 1 +#else +# define ORTHANC_ENABLE_LUA 0 +#endif +#undef ENABLE_LUA + + +#cmakedefine01 ENABLE_PKCS11 +#if !defined(ENABLE_PKCS11) +# error CMake error +#elif ENABLE_PKCS11 == 1 +# define ORTHANC_ENABLE_PKCS11 1 +#else +# define ORTHANC_ENABLE_PKCS11 0 +#endif +#undef ENABLE_PKCS11 + + +#cmakedefine01 ENABLE_PNG +#if !defined(ENABLE_PNG) +# error CMake error +#elif ENABLE_PNG == 1 +# define ORTHANC_ENABLE_PNG 1 +#else +# define ORTHANC_ENABLE_PNG 0 +#endif +#undef ENABLE_PNG + + +#cmakedefine01 ENABLE_PUGIXML +#if !defined(ENABLE_PUGIXML) +# error CMake error +#elif ENABLE_PUGIXML == 1 +# define ORTHANC_ENABLE_PUGIXML 1 +#else +# define ORTHANC_ENABLE_PUGIXML 0 +#endif +#undef ENABLE_PUGIXML + + +#cmakedefine01 ENABLE_SQLITE +#if !defined(ENABLE_SQLITE) +# error CMake error +#elif ENABLE_SQLITE == 1 +# define ORTHANC_ENABLE_SQLITE 1 +#else +# define ORTHANC_ENABLE_SQLITE 0 +#endif +#undef ENABLE_SQLITE + + +#cmakedefine01 ENABLE_SSL +#if !defined(ENABLE_SSL) +# error CMake error +#elif ENABLE_SSL == 1 +# define ORTHANC_ENABLE_SSL 1 +#else +# define ORTHANC_ENABLE_SSL 0 +#endif +#undef ENABLE_SSL + + +#cmakedefine01 ENABLE_WEB_CLIENT +#if !defined(ENABLE_WEB_CLIENT) +# error CMake error +#elif ENABLE_WEB_CLIENT == 1 +# define ORTHANC_ENABLE_CURL 1 +#else +# define ORTHANC_ENABLE_CURL 0 +#endif +#undef ENABLE_WEB_CLIENT + + +#cmakedefine01 ENABLE_ZLIB +#if !defined(ENABLE_ZLIB) +# error CMake error +#elif ENABLE_ZLIB == 1 +# define ORTHANC_ENABLE_ZLIB 1 +#else +# define ORTHANC_ENABLE_ZLIB 0 +#endif +#undef ENABLE_ZLIB + + +#if ORTHANC_ENABLE_DCMTK == 1 +# define DCMTK_VERSION_NUMBER @DCMTK_VERSION_NUMBER@ +#endif + + +/** + * Initialization functions. + **/ + +#include + +namespace Orthanc +{ + ORTHANC_PUBLIC void InitializeFramework(const std::string& locale, + bool loadPrivateDictionary); + + ORTHANC_PUBLIC void FinalizeFramework(); +} + + +#endif /* __ORTHANC_FRAMEWORK_H */ diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/Cache/MemoryCache.h --- a/OrthancFramework/Sources/Cache/MemoryCache.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryCache.h Thu Jun 11 16:40:34 2020 +0200 @@ -46,7 +46,7 @@ /** * WARNING: This class is NOT thread-safe. **/ - class MemoryCache + class ORTHANC_PUBLIC MemoryCache : public boost::noncopyable { private: struct Page diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/Cache/MemoryObjectCache.h --- a/OrthancFramework/Sources/Cache/MemoryObjectCache.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryObjectCache.h Thu Jun 11 16:40:34 2020 +0200 @@ -33,6 +33,7 @@ #pragma once +#include "../OrthancFramework.h" #include "ICacheable.h" #include "LeastRecentlyUsedIndex.h" @@ -47,7 +48,7 @@ namespace Orthanc { - class MemoryObjectCache : public boost::noncopyable + class ORTHANC_PUBLIC MemoryObjectCache : public boost::noncopyable { private: class Item; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/Cache/MemoryStringCache.h --- a/OrthancFramework/Sources/Cache/MemoryStringCache.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryStringCache.h Thu Jun 11 16:40:34 2020 +0200 @@ -41,7 +41,7 @@ * Facade object around "MemoryObjectCache" that caches a dictionary * of strings, using the "fetch/add" paradigm of memcached. **/ - class MemoryStringCache : public boost::noncopyable + class ORTHANC_PUBLIC MemoryStringCache : public boost::noncopyable { private: class StringValue; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/Cache/SharedArchive.h --- a/OrthancFramework/Sources/Cache/SharedArchive.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/Cache/SharedArchive.h Thu Jun 11 16:40:34 2020 +0200 @@ -49,7 +49,7 @@ namespace Orthanc { - class SharedArchive : public boost::noncopyable + class ORTHANC_PUBLIC SharedArchive : public boost::noncopyable { private: typedef std::map Archive; @@ -62,7 +62,7 @@ void RemoveInternal(const std::string& id); public: - class Accessor : public boost::noncopyable + class ORTHANC_PUBLIC Accessor : public boost::noncopyable { private: boost::mutex::scoped_lock lock_; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/DicomFormat/DicomTag.h --- a/OrthancFramework/Sources/DicomFormat/DicomTag.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomTag.h Thu Jun 11 16:40:34 2020 +0200 @@ -91,7 +91,7 @@ static bool ParseHexadecimal(DicomTag& tag, const char* value); - friend std::ostream& operator<< (std::ostream& o, const DicomTag& tag); + ORTHANC_PUBLIC friend std::ostream& operator<< (std::ostream& o, const DicomTag& tag); static void AddTagsForModule(std::set& target, DicomModule module); diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.h --- a/OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.h Thu Jun 11 16:40:34 2020 +0200 @@ -41,7 +41,7 @@ namespace Orthanc { - class DicomAssociationParameters + class ORTHANC_PUBLIC DicomAssociationParameters { private: std::string localAet_; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.h --- a/OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.h Thu Jun 11 16:40:34 2020 +0200 @@ -37,7 +37,7 @@ namespace Orthanc { - class DicomFindAnswers : public boost::noncopyable + class ORTHANC_PUBLIC DicomFindAnswers : public boost::noncopyable { private: Encoding encoding_; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.h --- a/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.h Thu Jun 11 16:40:34 2020 +0200 @@ -73,7 +73,7 @@ class DicomAssociation; // Forward declaration for PImpl design pattern - class DicomStoreUserConnection : public boost::noncopyable + class ORTHANC_PUBLIC DicomStoreUserConnection : public boost::noncopyable { private: typedef std::map > RegisteredClasses; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.h --- a/OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.h Thu Jun 11 16:40:34 2020 +0200 @@ -41,7 +41,7 @@ namespace Orthanc { - class RemoteModalityParameters + class ORTHANC_PUBLIC RemoteModalityParameters { private: std::string aet_; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/DicomParsing/DicomModification.h --- a/OrthancFramework/Sources/DicomParsing/DicomModification.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification.h Thu Jun 11 16:40:34 2020 +0200 @@ -37,7 +37,7 @@ namespace Orthanc { - class DicomModification : public boost::noncopyable + class ORTHANC_PUBLIC DicomModification : public boost::noncopyable { /** * Process: diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.h --- a/OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.h Thu Jun 11 16:40:34 2020 +0200 @@ -44,7 +44,7 @@ namespace Orthanc { - class DicomWebJsonVisitor : public ITagVisitor + class ORTHANC_PUBLIC DicomWebJsonVisitor : public ITagVisitor { public: enum BinaryMode diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/DicomParsing/IDicomTranscoder.h --- a/OrthancFramework/Sources/DicomParsing/IDicomTranscoder.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/DicomParsing/IDicomTranscoder.h Thu Jun 11 16:40:34 2020 +0200 @@ -52,7 +52,7 @@ class ORTHANC_PUBLIC IDicomTranscoder : public boost::noncopyable { public: - class DicomImage : public boost::noncopyable + class ORTHANC_PUBLIC DicomImage : public boost::noncopyable { private: std::unique_ptr parsed_; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.h --- a/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.h Thu Jun 11 16:40:34 2020 +0200 @@ -64,7 +64,7 @@ { class ParsedDicomFile; - class DicomImageDecoder : public boost::noncopyable + class ORTHANC_PUBLIC DicomImageDecoder : public boost::noncopyable { private: class ImageSource; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h --- a/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h Thu Jun 11 16:40:34 2020 +0200 @@ -120,8 +120,7 @@ Encoding defaultEncoding, bool permissive, const std::string& defaultPrivateCreator, - const std::map& privateCreators - ); + const std::map& privateCreators); ParsedDicomFile(const void* content, size_t size); diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/FileStorage/StorageAccessor.h --- a/OrthancFramework/Sources/FileStorage/StorageAccessor.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/FileStorage/StorageAccessor.h Thu Jun 11 16:40:34 2020 +0200 @@ -71,7 +71,7 @@ * contained in the storage area, and monitors timing metrics (if * enabled). **/ - class StorageAccessor : boost::noncopyable + class ORTHANC_PUBLIC StorageAccessor : boost::noncopyable { private: class MetricsTimer; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/Images/IImageWriter.h --- a/OrthancFramework/Sources/Images/IImageWriter.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/Images/IImageWriter.h Thu Jun 11 16:40:34 2020 +0200 @@ -43,7 +43,7 @@ namespace Orthanc { - class IImageWriter : public boost::noncopyable + class ORTHANC_PUBLIC IImageWriter : public boost::noncopyable { protected: virtual void WriteToMemoryInternal(std::string& compressed, diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/Images/JpegReader.h --- a/OrthancFramework/Sources/Images/JpegReader.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/Images/JpegReader.h Thu Jun 11 16:40:34 2020 +0200 @@ -51,7 +51,7 @@ namespace Orthanc { - class JpegReader : public ImageAccessor + class ORTHANC_PUBLIC JpegReader : public ImageAccessor { private: std::string content_; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/Images/JpegWriter.h --- a/OrthancFramework/Sources/Images/JpegWriter.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/Images/JpegWriter.h Thu Jun 11 16:40:34 2020 +0200 @@ -45,7 +45,7 @@ namespace Orthanc { - class JpegWriter : public IImageWriter + class ORTHANC_PUBLIC JpegWriter : public IImageWriter { protected: #if ORTHANC_SANDBOXED == 0 diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/Images/PamReader.h --- a/OrthancFramework/Sources/Images/PamReader.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/Images/PamReader.h Thu Jun 11 16:40:34 2020 +0200 @@ -41,7 +41,7 @@ namespace Orthanc { - class PamReader : public ImageAccessor + class ORTHANC_PUBLIC PamReader : public ImageAccessor { private: void ParseContent(); diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/Images/PamWriter.h --- a/OrthancFramework/Sources/Images/PamWriter.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/Images/PamWriter.h Thu Jun 11 16:40:34 2020 +0200 @@ -38,7 +38,7 @@ namespace Orthanc { // https://en.wikipedia.org/wiki/Netpbm#PAM_graphics_format - class PamWriter : public IImageWriter + class ORTHANC_PUBLIC PamWriter : public IImageWriter { protected: virtual void WriteToMemoryInternal(std::string& target, diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/Images/PngReader.h --- a/OrthancFramework/Sources/Images/PngReader.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/Images/PngReader.h Thu Jun 11 16:40:34 2020 +0200 @@ -55,7 +55,7 @@ namespace Orthanc { - class PngReader : public ImageAccessor + class ORTHANC_PUBLIC PngReader : public ImageAccessor { private: struct PngRabi; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/Images/PngWriter.h --- a/OrthancFramework/Sources/Images/PngWriter.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/Images/PngWriter.h Thu Jun 11 16:40:34 2020 +0200 @@ -47,7 +47,7 @@ namespace Orthanc { - class PngWriter : public IImageWriter + class ORTHANC_PUBLIC PngWriter : public IImageWriter { protected: #if ORTHANC_SANDBOXED == 0 diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.h --- a/OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.h Thu Jun 11 16:40:34 2020 +0200 @@ -37,7 +37,7 @@ namespace Orthanc { - class GenericJobUnserializer : public IJobUnserializer + class ORTHANC_PUBLIC GenericJobUnserializer : public IJobUnserializer { public: virtual IJob* UnserializeJob(const Json::Value& value); diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/IJob.h --- a/OrthancFramework/Sources/JobsEngine/IJob.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/IJob.h Thu Jun 11 16:40:34 2020 +0200 @@ -40,7 +40,7 @@ namespace Orthanc { - class IJob : public boost::noncopyable + class ORTHANC_PUBLIC IJob : public boost::noncopyable { public: virtual ~IJob() diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/IJobUnserializer.h --- a/OrthancFramework/Sources/JobsEngine/IJobUnserializer.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/IJobUnserializer.h Thu Jun 11 16:40:34 2020 +0200 @@ -41,7 +41,7 @@ namespace Orthanc { - class IJobUnserializer : public boost::noncopyable + class ORTHANC_PUBLIC IJobUnserializer : public boost::noncopyable { public: virtual ~IJobUnserializer() diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/JobInfo.h --- a/OrthancFramework/Sources/JobsEngine/JobInfo.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobInfo.h Thu Jun 11 16:40:34 2020 +0200 @@ -39,7 +39,7 @@ namespace Orthanc { - class JobInfo + class ORTHANC_PUBLIC JobInfo { private: std::string id_; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/JobStepResult.h --- a/OrthancFramework/Sources/JobsEngine/JobStepResult.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobStepResult.h Thu Jun 11 16:40:34 2020 +0200 @@ -39,7 +39,7 @@ { class OrthancException; - class JobStepResult + class ORTHANC_PUBLIC JobStepResult { private: JobStepCode code_; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/JobsEngine.h --- a/OrthancFramework/Sources/JobsEngine/JobsEngine.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobsEngine.h Thu Jun 11 16:40:34 2020 +0200 @@ -41,7 +41,7 @@ namespace Orthanc { - class JobsEngine : public boost::noncopyable + class ORTHANC_PUBLIC JobsEngine : public boost::noncopyable { private: enum State diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/JobsRegistry.h --- a/OrthancFramework/Sources/JobsEngine/JobsRegistry.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobsRegistry.h Thu Jun 11 16:40:34 2020 +0200 @@ -53,10 +53,10 @@ namespace Orthanc { // This class handles the state machine of the jobs engine - class JobsRegistry : public boost::noncopyable + class ORTHANC_PUBLIC JobsRegistry : public boost::noncopyable { public: - class IObserver : public boost::noncopyable + class ORTHANC_PUBLIC IObserver : public boost::noncopyable { public: virtual ~IObserver() @@ -204,7 +204,7 @@ unsigned int& success, unsigned int& errors); - class RunningJob : public boost::noncopyable + class ORTHANC_PUBLIC RunningJob : public boost::noncopyable { private: JobsRegistry& registry_; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/Operations/IJobOperation.h --- a/OrthancFramework/Sources/JobsEngine/Operations/IJobOperation.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/IJobOperation.h Thu Jun 11 16:40:34 2020 +0200 @@ -37,7 +37,7 @@ namespace Orthanc { - class IJobOperation : public boost::noncopyable + class ORTHANC_PUBLIC IJobOperation : public boost::noncopyable { public: virtual ~IJobOperation() diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/Operations/JobOperationValue.h --- a/OrthancFramework/Sources/JobsEngine/Operations/JobOperationValue.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/JobOperationValue.h Thu Jun 11 16:40:34 2020 +0200 @@ -33,12 +33,14 @@ #pragma once +#include "../../OrthancFramework.h" + #include #include namespace Orthanc { - class JobOperationValue : public boost::noncopyable + class ORTHANC_PUBLIC JobOperationValue : public boost::noncopyable { public: enum Type diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.h --- a/OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.h Thu Jun 11 16:40:34 2020 +0200 @@ -41,7 +41,7 @@ { class IJobUnserializer; - class JobOperationValues : public boost::noncopyable + class ORTHANC_PUBLIC JobOperationValues : public boost::noncopyable { private: std::vector values_; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.h --- a/OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.h Thu Jun 11 16:40:34 2020 +0200 @@ -37,7 +37,7 @@ namespace Orthanc { - class LogJobOperation : public IJobOperation + class ORTHANC_PUBLIC LogJobOperation : public IJobOperation { public: virtual void Apply(JobOperationValues& outputs, diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.h --- a/OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.h Thu Jun 11 16:40:34 2020 +0200 @@ -37,7 +37,7 @@ namespace Orthanc { - class NullOperationValue : public JobOperationValue + class ORTHANC_PUBLIC NullOperationValue : public JobOperationValue { public: NullOperationValue() : diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h --- a/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h Thu Jun 11 16:40:34 2020 +0200 @@ -43,10 +43,10 @@ namespace Orthanc { - class SequenceOfOperationsJob : public IJob + class ORTHANC_PUBLIC SequenceOfOperationsJob : public IJob { public: - class IObserver : public boost::noncopyable + class ORTHANC_PUBLIC IObserver : public boost::noncopyable { public: virtual ~IObserver() @@ -87,7 +87,7 @@ // This lock allows adding new operations to the end of the job, // from another thread than the worker thread, after the job has // been submitted for processing - class Lock : public boost::noncopyable + class ORTHANC_PUBLIC Lock : public boost::noncopyable { private: SequenceOfOperationsJob& that_; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.h --- a/OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.h Thu Jun 11 16:40:34 2020 +0200 @@ -39,7 +39,7 @@ namespace Orthanc { - class StringOperationValue : public JobOperationValue + class ORTHANC_PUBLIC StringOperationValue : public JobOperationValue { private: std::string content_; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h --- a/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h Thu Jun 11 16:40:34 2020 +0200 @@ -39,7 +39,7 @@ namespace Orthanc { - class SetOfCommandsJob : public IJob + class ORTHANC_PUBLIC SetOfCommandsJob : public IJob { public: class ICommand : public boost::noncopyable diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.h --- a/OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.h Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.h Thu Jun 11 16:40:34 2020 +0200 @@ -40,7 +40,7 @@ namespace Orthanc { - class SetOfInstancesJob : public SetOfCommandsJob + class ORTHANC_PUBLIC SetOfInstancesJob : public SetOfCommandsJob { private: class InstanceCommand; diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/UnitTestsSources/CMakeLists.txt Thu Jun 11 16:40:34 2020 +0200 @@ -0,0 +1,62 @@ +## +## This file is meant to be used only by ../SharedLibrary/CMakeLists.txt +## + +cmake_minimum_required(VERSION 2.8) +project(UnitTestsProject) + +SET(UNIT_TESTS_WITH_HTTP_CONNEXIONS ON CACHE BOOL "Allow unit tests to make HTTP requests") + +if (UNIT_TESTS_WITH_HTTP_CONNEXIONS) + add_definitions(-DUNIT_TESTS_WITH_HTTP_CONNEXIONS=1) +else() + add_definitions(-DUNIT_TESTS_WITH_HTTP_CONNEXIONS=0) +endif() + +if (NOT ORTHANC_FRAMEWORK_STATIC) + set(ENABLE_DCMTK ON) + set(ENABLE_LUA ON) + set(ENABLE_PUGIXML ON) + set(ENABLE_SQLITE ON) +endif() + +set(ENABLE_GOOGLE_TEST ON) +include(${CMAKE_SOURCE_DIR}/../Resources/CMake/DownloadOrthancFramework.cmake) + +add_definitions( + -DORTHANC_UNIT_TESTS_LINK_FRAMEWORK=1 + -DORTHANC_BUILD_UNIT_TESTS=1 # For "HierarchicalZipWriter" tests + ) + +add_executable(UnitTests + ${CMAKE_SOURCE_DIR}/SharedLibraryUnitTests.cpp + + ${CMAKE_SOURCE_DIR}/DicomMapTests.cpp + ${CMAKE_SOURCE_DIR}/FileStorageTests.cpp + ${CMAKE_SOURCE_DIR}/FrameworkTests.cpp + ${CMAKE_SOURCE_DIR}/FromDcmtkTests.cpp + ${CMAKE_SOURCE_DIR}/ImageProcessingTests.cpp + ${CMAKE_SOURCE_DIR}/ImageTests.cpp + ${CMAKE_SOURCE_DIR}/JobsTests.cpp + ${CMAKE_SOURCE_DIR}/JpegLosslessTests.cpp + ${CMAKE_SOURCE_DIR}/LoggingTests.cpp + ${CMAKE_SOURCE_DIR}/LuaTests.cpp + ${CMAKE_SOURCE_DIR}/MemoryCacheTests.cpp + ${CMAKE_SOURCE_DIR}/RestApiTests.cpp + ${CMAKE_SOURCE_DIR}/SQLiteChromiumTests.cpp + ${CMAKE_SOURCE_DIR}/SQLiteTests.cpp + ${CMAKE_SOURCE_DIR}/StreamTests.cpp + ${CMAKE_SOURCE_DIR}/ToolboxTests.cpp + ${CMAKE_SOURCE_DIR}/ZipTests.cpp + + ${AUTOGENERATED_SOURCES} + ${GOOGLE_TEST_SOURCES} + ) + +target_link_libraries(UnitTests OrthancFramework) +set_target_properties(UnitTests PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE) +set_target_properties(UnitTests PROPERTIES INSTALL_RPATH ${ORTHANC_FRAMEWORK_LIBDIR}) + +install(TARGETS UnitTests + DESTINATION ${ORTHANC_FRAMEWORK_LIBDIR} + ) diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/DicomMapTests.cpp --- a/OrthancFramework/UnitTestsSources/DicomMapTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/DicomMapTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,9 +32,14 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif +#if !defined(DCMTK_VERSION_NUMBER) +# error DCMTK_VERSION_NUMBER is not defined +#endif + #include #include "../Sources/Compatibility.h" @@ -45,9 +50,6 @@ #include "../Sources/DicomParsing/ParsedDicomFile.h" #include "../Sources/DicomParsing/DicomWebJsonVisitor.h" -#include -#include -#include using namespace Orthanc; @@ -597,302 +599,6 @@ } -static void SetTagKey(ParsedDicomFile& dicom, - const DicomTag& tag, - const DicomTag& value) -{ - // This function emulates a call to function - // "dicom.GetDcmtkObject().getDataset()->putAndInsertTagKey(tag, - // value)" that was not available in DCMTK 3.6.0 - - std::unique_ptr element(new DcmAttributeTag(ToDcmtkBridge::Convert(tag))); - - DcmTagKey v = ToDcmtkBridge::Convert(value); - if (!element->putTagVal(v).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - - dicom.GetDcmtkObject().getDataset()->insert(element.release()); -} - - -TEST(DicomWebJson, ValueRepresentation) -{ - // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.2.3.html - - ParsedDicomFile dicom(false); - dicom.ReplacePlainString(DicomTag(0x0040, 0x0241), "AE"); - dicom.ReplacePlainString(DicomTag(0x0010, 0x1010), "AS"); - SetTagKey(dicom, DicomTag(0x0020, 0x9165), DicomTag(0x0010, 0x0020)); - dicom.ReplacePlainString(DicomTag(0x0008, 0x0052), "CS"); - dicom.ReplacePlainString(DicomTag(0x0008, 0x0012), "DA"); - dicom.ReplacePlainString(DicomTag(0x0010, 0x1020), "42"); // DS - dicom.ReplacePlainString(DicomTag(0x0008, 0x002a), "DT"); - dicom.ReplacePlainString(DicomTag(0x0010, 0x9431), "43"); // FL - dicom.ReplacePlainString(DicomTag(0x0008, 0x1163), "44"); // FD - dicom.ReplacePlainString(DicomTag(0x0008, 0x1160), "45"); // IS - dicom.ReplacePlainString(DicomTag(0x0008, 0x0070), "LO"); - dicom.ReplacePlainString(DicomTag(0x0010, 0x4000), "LT"); - dicom.ReplacePlainString(DicomTag(0x0028, 0x2000), "OB"); - dicom.ReplacePlainString(DicomTag(0x7fe0, 0x0009), "3.14159"); // OD (other double) - dicom.ReplacePlainString(DicomTag(0x0064, 0x0009), "2.71828"); // OF (other float) - dicom.ReplacePlainString(DicomTag(0x0066, 0x0040), "46"); // OL (other long) - ASSERT_THROW(dicom.ReplacePlainString(DicomTag(0x0028, 0x1201), "O"), OrthancException); - dicom.ReplacePlainString(DicomTag(0x0028, 0x1201), "OWOW"); - dicom.ReplacePlainString(DicomTag(0x0010, 0x0010), "PN"); - dicom.ReplacePlainString(DicomTag(0x0008, 0x0050), "SH"); - dicom.ReplacePlainString(DicomTag(0x0018, 0x6020), "-15"); // SL - dicom.ReplacePlainString(DicomTag(0x0018, 0x9219), "-16"); // SS - dicom.ReplacePlainString(DicomTag(0x0008, 0x0081), "ST"); - dicom.ReplacePlainString(DicomTag(0x0008, 0x0013), "TM"); - dicom.ReplacePlainString(DicomTag(0x0008, 0x0119), "UC"); - dicom.ReplacePlainString(DicomTag(0x0008, 0x0016), "UI"); - dicom.ReplacePlainString(DicomTag(0x0008, 0x1161), "128"); // UL - dicom.ReplacePlainString(DicomTag(0x4342, 0x1234), "UN"); // Inexistent tag - dicom.ReplacePlainString(DicomTag(0x0008, 0x0120), "UR"); - dicom.ReplacePlainString(DicomTag(0x0008, 0x0301), "17"); // US - dicom.ReplacePlainString(DicomTag(0x0040, 0x0031), "UT"); - - DicomWebJsonVisitor visitor; - dicom.Apply(visitor); - - std::string s; - - // The tag (0002,0002) is "Media Storage SOP Class UID" and is - // automatically copied by DCMTK from tag (0008,0016) - ASSERT_EQ("UI", visitor.GetResult() ["00020002"]["vr"].asString()); - ASSERT_EQ("UI", visitor.GetResult() ["00020002"]["Value"][0].asString()); - ASSERT_EQ("AE", visitor.GetResult() ["00400241"]["vr"].asString()); - ASSERT_EQ("AE", visitor.GetResult() ["00400241"]["Value"][0].asString()); - ASSERT_EQ("AS", visitor.GetResult() ["00101010"]["vr"].asString()); - ASSERT_EQ("AS", visitor.GetResult() ["00101010"]["Value"][0].asString()); - ASSERT_EQ("AT", visitor.GetResult() ["00209165"]["vr"].asString()); - ASSERT_EQ("00100020", visitor.GetResult() ["00209165"]["Value"][0].asString()); - ASSERT_EQ("CS", visitor.GetResult() ["00080052"]["vr"].asString()); - ASSERT_EQ("CS", visitor.GetResult() ["00080052"]["Value"][0].asString()); - ASSERT_EQ("DA", visitor.GetResult() ["00080012"]["vr"].asString()); - ASSERT_EQ("DA", visitor.GetResult() ["00080012"]["Value"][0].asString()); - ASSERT_EQ("DS", visitor.GetResult() ["00101020"]["vr"].asString()); - ASSERT_FLOAT_EQ(42.0f, visitor.GetResult() ["00101020"]["Value"][0].asFloat()); - ASSERT_EQ("DT", visitor.GetResult() ["0008002A"]["vr"].asString()); - ASSERT_EQ("DT", visitor.GetResult() ["0008002A"]["Value"][0].asString()); - ASSERT_EQ("FL", visitor.GetResult() ["00109431"]["vr"].asString()); - ASSERT_FLOAT_EQ(43.0f, visitor.GetResult() ["00109431"]["Value"][0].asFloat()); - ASSERT_EQ("FD", visitor.GetResult() ["00081163"]["vr"].asString()); - ASSERT_FLOAT_EQ(44.0f, visitor.GetResult() ["00081163"]["Value"][0].asFloat()); - ASSERT_EQ("IS", visitor.GetResult() ["00081160"]["vr"].asString()); - ASSERT_FLOAT_EQ(45.0f, visitor.GetResult() ["00081160"]["Value"][0].asFloat()); - ASSERT_EQ("LO", visitor.GetResult() ["00080070"]["vr"].asString()); - ASSERT_EQ("LO", visitor.GetResult() ["00080070"]["Value"][0].asString()); - ASSERT_EQ("LT", visitor.GetResult() ["00104000"]["vr"].asString()); - ASSERT_EQ("LT", visitor.GetResult() ["00104000"]["Value"][0].asString()); - - ASSERT_EQ("OB", visitor.GetResult() ["00282000"]["vr"].asString()); - Toolbox::DecodeBase64(s, visitor.GetResult() ["00282000"]["InlineBinary"].asString()); - ASSERT_EQ("OB", s); - -#if DCMTK_VERSION_NUMBER >= 361 - ASSERT_EQ("OD", visitor.GetResult() ["7FE00009"]["vr"].asString()); - ASSERT_FLOAT_EQ(3.14159f, boost::lexical_cast(visitor.GetResult() ["7FE00009"]["Value"][0].asString())); -#else - ASSERT_EQ("UN", visitor.GetResult() ["7FE00009"]["vr"].asString()); - Toolbox::DecodeBase64(s, visitor.GetResult() ["7FE00009"]["InlineBinary"].asString()); - ASSERT_EQ(8u, s.size()); // Because of padding - ASSERT_EQ(0, s[7]); - ASSERT_EQ("3.14159", s.substr(0, 7)); -#endif - - ASSERT_EQ("OF", visitor.GetResult() ["00640009"]["vr"].asString()); - ASSERT_FLOAT_EQ(2.71828f, boost::lexical_cast(visitor.GetResult() ["00640009"]["Value"][0].asString())); - -#if DCMTK_VERSION_NUMBER < 361 - ASSERT_EQ("UN", visitor.GetResult() ["00660040"]["vr"].asString()); - Toolbox::DecodeBase64(s, visitor.GetResult() ["00660040"]["InlineBinary"].asString()); - ASSERT_EQ("46", s); -#elif DCMTK_VERSION_NUMBER == 361 - ASSERT_EQ("UL", visitor.GetResult() ["00660040"]["vr"].asString()); - ASSERT_EQ(46, visitor.GetResult() ["00660040"]["Value"][0].asInt()); -#else - ASSERT_EQ("OL", visitor.GetResult() ["00660040"]["vr"].asString()); - ASSERT_EQ(46, visitor.GetResult() ["00660040"]["Value"][0].asInt()); -#endif - - ASSERT_EQ("OW", visitor.GetResult() ["00281201"]["vr"].asString()); - Toolbox::DecodeBase64(s, visitor.GetResult() ["00281201"]["InlineBinary"].asString()); - ASSERT_EQ("OWOW", s); - - ASSERT_EQ("PN", visitor.GetResult() ["00100010"]["vr"].asString()); - ASSERT_EQ("PN", visitor.GetResult() ["00100010"]["Value"][0]["Alphabetic"].asString()); - - ASSERT_EQ("SH", visitor.GetResult() ["00080050"]["vr"].asString()); - ASSERT_EQ("SH", visitor.GetResult() ["00080050"]["Value"][0].asString()); - - ASSERT_EQ("SL", visitor.GetResult() ["00186020"]["vr"].asString()); - ASSERT_EQ(-15, visitor.GetResult() ["00186020"]["Value"][0].asInt()); - - ASSERT_EQ("SS", visitor.GetResult() ["00189219"]["vr"].asString()); - ASSERT_EQ(-16, visitor.GetResult() ["00189219"]["Value"][0].asInt()); - - ASSERT_EQ("ST", visitor.GetResult() ["00080081"]["vr"].asString()); - ASSERT_EQ("ST", visitor.GetResult() ["00080081"]["Value"][0].asString()); - - ASSERT_EQ("TM", visitor.GetResult() ["00080013"]["vr"].asString()); - ASSERT_EQ("TM", visitor.GetResult() ["00080013"]["Value"][0].asString()); - -#if DCMTK_VERSION_NUMBER >= 361 - ASSERT_EQ("UC", visitor.GetResult() ["00080119"]["vr"].asString()); - ASSERT_EQ("UC", visitor.GetResult() ["00080119"]["Value"][0].asString()); -#else - ASSERT_EQ("UN", visitor.GetResult() ["00080119"]["vr"].asString()); - Toolbox::DecodeBase64(s, visitor.GetResult() ["00080119"]["InlineBinary"].asString()); - ASSERT_EQ("UC", s); -#endif - - ASSERT_EQ("UI", visitor.GetResult() ["00080016"]["vr"].asString()); - ASSERT_EQ("UI", visitor.GetResult() ["00080016"]["Value"][0].asString()); - - ASSERT_EQ("UL", visitor.GetResult() ["00081161"]["vr"].asString()); - ASSERT_EQ(128u, visitor.GetResult() ["00081161"]["Value"][0].asUInt()); - - ASSERT_EQ("UN", visitor.GetResult() ["43421234"]["vr"].asString()); - Toolbox::DecodeBase64(s, visitor.GetResult() ["43421234"]["InlineBinary"].asString()); - ASSERT_EQ("UN", s); - -#if DCMTK_VERSION_NUMBER >= 361 - ASSERT_EQ("UR", visitor.GetResult() ["00080120"]["vr"].asString()); - ASSERT_EQ("UR", visitor.GetResult() ["00080120"]["Value"][0].asString()); -#else - ASSERT_EQ("UN", visitor.GetResult() ["00080120"]["vr"].asString()); - Toolbox::DecodeBase64(s, visitor.GetResult() ["00080120"]["InlineBinary"].asString()); - ASSERT_EQ("UR", s); -#endif - -#if DCMTK_VERSION_NUMBER >= 361 - ASSERT_EQ("US", visitor.GetResult() ["00080301"]["vr"].asString()); - ASSERT_EQ(17u, visitor.GetResult() ["00080301"]["Value"][0].asUInt()); -#else - ASSERT_EQ("UN", visitor.GetResult() ["00080301"]["vr"].asString()); - Toolbox::DecodeBase64(s, visitor.GetResult() ["00080301"]["InlineBinary"].asString()); - ASSERT_EQ("17", s); -#endif - - ASSERT_EQ("UT", visitor.GetResult() ["00400031"]["vr"].asString()); - ASSERT_EQ("UT", visitor.GetResult() ["00400031"]["Value"][0].asString()); - - std::string xml; - visitor.FormatXml(xml); - - { - DicomMap m; - m.FromDicomWeb(visitor.GetResult()); - ASSERT_EQ(31u, m.GetSize()); - - std::string s; - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0002, 0x0002), false)); ASSERT_EQ("UI", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0040, 0x0241), false)); ASSERT_EQ("AE", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x1010), false)); ASSERT_EQ("AS", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0020, 0x9165), false)); ASSERT_EQ("00100020", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0052), false)); ASSERT_EQ("CS", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0012), false)); ASSERT_EQ("DA", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x1020), false)); ASSERT_EQ("42", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x002a), false)); ASSERT_EQ("DT", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x9431), false)); ASSERT_EQ("43", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1163), false)); ASSERT_EQ("44", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1160), false)); ASSERT_EQ("45", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0070), false)); ASSERT_EQ("LO", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x4000), false)); ASSERT_EQ("LT", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0028, 0x2000), true)); ASSERT_EQ("OB", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x7fe0, 0x0009), true)); - -#if DCMTK_VERSION_NUMBER >= 361 - ASSERT_FLOAT_EQ(3.14159f, boost::lexical_cast(s)); -#else - ASSERT_EQ(8u, s.size()); // Because of padding - ASSERT_EQ(0, s[7]); - ASSERT_EQ("3.14159", s.substr(0, 7)); -#endif - - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0064, 0x0009), true)); - ASSERT_FLOAT_EQ(2.71828f, boost::lexical_cast(s)); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0028, 0x1201), true)); ASSERT_EQ("OWOW", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x0010), false)); ASSERT_EQ("PN", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0050), false)); ASSERT_EQ("SH", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0018, 0x6020), false)); ASSERT_EQ("-15", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0018, 0x9219), false)); ASSERT_EQ("-16", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0081), false)); ASSERT_EQ("ST", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0013), false)); ASSERT_EQ("TM", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0016), false)); ASSERT_EQ("UI", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1161), false)); ASSERT_EQ("128", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x4342, 0x1234), true)); ASSERT_EQ("UN", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0040, 0x0031), false)); ASSERT_EQ("UT", s); - -#if DCMTK_VERSION_NUMBER >= 361 - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), false)); ASSERT_EQ("46", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0119), false)); ASSERT_EQ("UC", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0120), false)); ASSERT_EQ("UR", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0301), false)); ASSERT_EQ("17", s); -#else - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), true)); ASSERT_EQ("46", s); // OL - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0119), true)); ASSERT_EQ("UC", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0120), true)); ASSERT_EQ("UR", s); - ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0301), true)); ASSERT_EQ("17", s); // US (but tag unknown to DCMTK 3.6.0) -#endif - - } -} - - -TEST(DicomWebJson, Sequence) -{ - ParsedDicomFile dicom(false); - - { - std::unique_ptr sequence(new DcmSequenceOfItems(DCM_ReferencedSeriesSequence)); - - for (unsigned int i = 0; i < 3; i++) - { - std::unique_ptr item(new DcmItem); - std::string s = "item" + boost::lexical_cast(i); - item->putAndInsertString(DCM_ReferencedSOPInstanceUID, s.c_str(), OFFalse); - ASSERT_TRUE(sequence->insert(item.release(), false, false).good()); - } - - ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->insert(sequence.release(), false, false).good()); - } - - DicomWebJsonVisitor visitor; - dicom.Apply(visitor); - - ASSERT_EQ("SQ", visitor.GetResult() ["00081115"]["vr"].asString()); - ASSERT_EQ(3u, visitor.GetResult() ["00081115"]["Value"].size()); - - std::set items; - - for (Json::Value::ArrayIndex i = 0; i < 3; i++) - { - ASSERT_EQ(1u, visitor.GetResult() ["00081115"]["Value"][i].size()); - ASSERT_EQ(1u, visitor.GetResult() ["00081115"]["Value"][i]["00081155"]["Value"].size()); - ASSERT_EQ("UI", visitor.GetResult() ["00081115"]["Value"][i]["00081155"]["vr"].asString()); - items.insert(visitor.GetResult() ["00081115"]["Value"][i]["00081155"]["Value"][0].asString()); - } - - ASSERT_EQ(3u, items.size()); - ASSERT_TRUE(items.find("item0") != items.end()); - ASSERT_TRUE(items.find("item1") != items.end()); - ASSERT_TRUE(items.find("item2") != items.end()); - - std::string xml; - visitor.FormatXml(xml); - - { - DicomMap m; - m.FromDicomWeb(visitor.GetResult()); - ASSERT_EQ(0u, m.GetSize()); // Sequences are not handled by DicomMap - } -} - - TEST(DicomWebJson, PixelSpacing) { // Test related to locales: Make sure that decimal separator is diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/FileStorageTests.cpp --- a/OrthancFramework/UnitTestsSources/FileStorageTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/FileStorageTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/FrameworkTests.cpp --- a/OrthancFramework/UnitTestsSources/FrameworkTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/FrameworkTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,9 +32,14 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif +#if !defined(ORTHANC_ENABLE_PUGIXML) +# error ORTHANC_ENABLE_PUGIXML is not defined +#endif + #include "../Sources/EnumerationDictionary.h" #include diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp --- a/OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,9 +32,18 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif +#if !defined(ORTHANC_ENABLE_DCMTK_TRANSCODING) +# error ORTHANC_ENABLE_DCMTK_TRANSCODING is not defined +#endif + +#if !defined(ORTHANC_ENABLE_PUGIXML) +# error ORTHANC_ENABLE_PUGIXML is not defined +#endif + #include #include "../Sources/Compatibility.h" @@ -54,12 +63,17 @@ #include "../Sources/SystemToolbox.h" #include "../Resources/CodeGeneration/EncodingTests.h" +#include #include -#include +#include + #include #if ORTHANC_ENABLE_PUGIXML == 1 # include +# if !defined(PUGIXML_VERSION) +# error PUGIXML_VERSION is not available +# endif #endif using namespace Orthanc; @@ -1776,6 +1790,302 @@ } +static void SetTagKey(ParsedDicomFile& dicom, + const DicomTag& tag, + const DicomTag& value) +{ + // This function emulates a call to function + // "dicom.GetDcmtkObject().getDataset()->putAndInsertTagKey(tag, + // value)" that was not available in DCMTK 3.6.0 + + std::unique_ptr element(new DcmAttributeTag(ToDcmtkBridge::Convert(tag))); + + DcmTagKey v = ToDcmtkBridge::Convert(value); + if (!element->putTagVal(v).good()) + { + throw OrthancException(ErrorCode_InternalError); + } + + dicom.GetDcmtkObject().getDataset()->insert(element.release()); +} + + +TEST(DicomWebJson, ValueRepresentation) +{ + // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.2.3.html + + ParsedDicomFile dicom(false); + dicom.ReplacePlainString(DicomTag(0x0040, 0x0241), "AE"); + dicom.ReplacePlainString(DicomTag(0x0010, 0x1010), "AS"); + SetTagKey(dicom, DicomTag(0x0020, 0x9165), DicomTag(0x0010, 0x0020)); + dicom.ReplacePlainString(DicomTag(0x0008, 0x0052), "CS"); + dicom.ReplacePlainString(DicomTag(0x0008, 0x0012), "DA"); + dicom.ReplacePlainString(DicomTag(0x0010, 0x1020), "42"); // DS + dicom.ReplacePlainString(DicomTag(0x0008, 0x002a), "DT"); + dicom.ReplacePlainString(DicomTag(0x0010, 0x9431), "43"); // FL + dicom.ReplacePlainString(DicomTag(0x0008, 0x1163), "44"); // FD + dicom.ReplacePlainString(DicomTag(0x0008, 0x1160), "45"); // IS + dicom.ReplacePlainString(DicomTag(0x0008, 0x0070), "LO"); + dicom.ReplacePlainString(DicomTag(0x0010, 0x4000), "LT"); + dicom.ReplacePlainString(DicomTag(0x0028, 0x2000), "OB"); + dicom.ReplacePlainString(DicomTag(0x7fe0, 0x0009), "3.14159"); // OD (other double) + dicom.ReplacePlainString(DicomTag(0x0064, 0x0009), "2.71828"); // OF (other float) + dicom.ReplacePlainString(DicomTag(0x0066, 0x0040), "46"); // OL (other long) + ASSERT_THROW(dicom.ReplacePlainString(DicomTag(0x0028, 0x1201), "O"), OrthancException); + dicom.ReplacePlainString(DicomTag(0x0028, 0x1201), "OWOW"); + dicom.ReplacePlainString(DicomTag(0x0010, 0x0010), "PN"); + dicom.ReplacePlainString(DicomTag(0x0008, 0x0050), "SH"); + dicom.ReplacePlainString(DicomTag(0x0018, 0x6020), "-15"); // SL + dicom.ReplacePlainString(DicomTag(0x0018, 0x9219), "-16"); // SS + dicom.ReplacePlainString(DicomTag(0x0008, 0x0081), "ST"); + dicom.ReplacePlainString(DicomTag(0x0008, 0x0013), "TM"); + dicom.ReplacePlainString(DicomTag(0x0008, 0x0119), "UC"); + dicom.ReplacePlainString(DicomTag(0x0008, 0x0016), "UI"); + dicom.ReplacePlainString(DicomTag(0x0008, 0x1161), "128"); // UL + dicom.ReplacePlainString(DicomTag(0x4342, 0x1234), "UN"); // Inexistent tag + dicom.ReplacePlainString(DicomTag(0x0008, 0x0120), "UR"); + dicom.ReplacePlainString(DicomTag(0x0008, 0x0301), "17"); // US + dicom.ReplacePlainString(DicomTag(0x0040, 0x0031), "UT"); + + DicomWebJsonVisitor visitor; + dicom.Apply(visitor); + + std::string s; + + // The tag (0002,0002) is "Media Storage SOP Class UID" and is + // automatically copied by DCMTK from tag (0008,0016) + ASSERT_EQ("UI", visitor.GetResult() ["00020002"]["vr"].asString()); + ASSERT_EQ("UI", visitor.GetResult() ["00020002"]["Value"][0].asString()); + ASSERT_EQ("AE", visitor.GetResult() ["00400241"]["vr"].asString()); + ASSERT_EQ("AE", visitor.GetResult() ["00400241"]["Value"][0].asString()); + ASSERT_EQ("AS", visitor.GetResult() ["00101010"]["vr"].asString()); + ASSERT_EQ("AS", visitor.GetResult() ["00101010"]["Value"][0].asString()); + ASSERT_EQ("AT", visitor.GetResult() ["00209165"]["vr"].asString()); + ASSERT_EQ("00100020", visitor.GetResult() ["00209165"]["Value"][0].asString()); + ASSERT_EQ("CS", visitor.GetResult() ["00080052"]["vr"].asString()); + ASSERT_EQ("CS", visitor.GetResult() ["00080052"]["Value"][0].asString()); + ASSERT_EQ("DA", visitor.GetResult() ["00080012"]["vr"].asString()); + ASSERT_EQ("DA", visitor.GetResult() ["00080012"]["Value"][0].asString()); + ASSERT_EQ("DS", visitor.GetResult() ["00101020"]["vr"].asString()); + ASSERT_FLOAT_EQ(42.0f, visitor.GetResult() ["00101020"]["Value"][0].asFloat()); + ASSERT_EQ("DT", visitor.GetResult() ["0008002A"]["vr"].asString()); + ASSERT_EQ("DT", visitor.GetResult() ["0008002A"]["Value"][0].asString()); + ASSERT_EQ("FL", visitor.GetResult() ["00109431"]["vr"].asString()); + ASSERT_FLOAT_EQ(43.0f, visitor.GetResult() ["00109431"]["Value"][0].asFloat()); + ASSERT_EQ("FD", visitor.GetResult() ["00081163"]["vr"].asString()); + ASSERT_FLOAT_EQ(44.0f, visitor.GetResult() ["00081163"]["Value"][0].asFloat()); + ASSERT_EQ("IS", visitor.GetResult() ["00081160"]["vr"].asString()); + ASSERT_FLOAT_EQ(45.0f, visitor.GetResult() ["00081160"]["Value"][0].asFloat()); + ASSERT_EQ("LO", visitor.GetResult() ["00080070"]["vr"].asString()); + ASSERT_EQ("LO", visitor.GetResult() ["00080070"]["Value"][0].asString()); + ASSERT_EQ("LT", visitor.GetResult() ["00104000"]["vr"].asString()); + ASSERT_EQ("LT", visitor.GetResult() ["00104000"]["Value"][0].asString()); + + ASSERT_EQ("OB", visitor.GetResult() ["00282000"]["vr"].asString()); + Toolbox::DecodeBase64(s, visitor.GetResult() ["00282000"]["InlineBinary"].asString()); + ASSERT_EQ("OB", s); + +#if DCMTK_VERSION_NUMBER >= 361 + ASSERT_EQ("OD", visitor.GetResult() ["7FE00009"]["vr"].asString()); + ASSERT_FLOAT_EQ(3.14159f, boost::lexical_cast(visitor.GetResult() ["7FE00009"]["Value"][0].asString())); +#else + ASSERT_EQ("UN", visitor.GetResult() ["7FE00009"]["vr"].asString()); + Toolbox::DecodeBase64(s, visitor.GetResult() ["7FE00009"]["InlineBinary"].asString()); + ASSERT_EQ(8u, s.size()); // Because of padding + ASSERT_EQ(0, s[7]); + ASSERT_EQ("3.14159", s.substr(0, 7)); +#endif + + ASSERT_EQ("OF", visitor.GetResult() ["00640009"]["vr"].asString()); + ASSERT_FLOAT_EQ(2.71828f, boost::lexical_cast(visitor.GetResult() ["00640009"]["Value"][0].asString())); + +#if DCMTK_VERSION_NUMBER < 361 + ASSERT_EQ("UN", visitor.GetResult() ["00660040"]["vr"].asString()); + Toolbox::DecodeBase64(s, visitor.GetResult() ["00660040"]["InlineBinary"].asString()); + ASSERT_EQ("46", s); +#elif DCMTK_VERSION_NUMBER == 361 + ASSERT_EQ("UL", visitor.GetResult() ["00660040"]["vr"].asString()); + ASSERT_EQ(46, visitor.GetResult() ["00660040"]["Value"][0].asInt()); +#else + ASSERT_EQ("OL", visitor.GetResult() ["00660040"]["vr"].asString()); + ASSERT_EQ(46, visitor.GetResult() ["00660040"]["Value"][0].asInt()); +#endif + + ASSERT_EQ("OW", visitor.GetResult() ["00281201"]["vr"].asString()); + Toolbox::DecodeBase64(s, visitor.GetResult() ["00281201"]["InlineBinary"].asString()); + ASSERT_EQ("OWOW", s); + + ASSERT_EQ("PN", visitor.GetResult() ["00100010"]["vr"].asString()); + ASSERT_EQ("PN", visitor.GetResult() ["00100010"]["Value"][0]["Alphabetic"].asString()); + + ASSERT_EQ("SH", visitor.GetResult() ["00080050"]["vr"].asString()); + ASSERT_EQ("SH", visitor.GetResult() ["00080050"]["Value"][0].asString()); + + ASSERT_EQ("SL", visitor.GetResult() ["00186020"]["vr"].asString()); + ASSERT_EQ(-15, visitor.GetResult() ["00186020"]["Value"][0].asInt()); + + ASSERT_EQ("SS", visitor.GetResult() ["00189219"]["vr"].asString()); + ASSERT_EQ(-16, visitor.GetResult() ["00189219"]["Value"][0].asInt()); + + ASSERT_EQ("ST", visitor.GetResult() ["00080081"]["vr"].asString()); + ASSERT_EQ("ST", visitor.GetResult() ["00080081"]["Value"][0].asString()); + + ASSERT_EQ("TM", visitor.GetResult() ["00080013"]["vr"].asString()); + ASSERT_EQ("TM", visitor.GetResult() ["00080013"]["Value"][0].asString()); + +#if DCMTK_VERSION_NUMBER >= 361 + ASSERT_EQ("UC", visitor.GetResult() ["00080119"]["vr"].asString()); + ASSERT_EQ("UC", visitor.GetResult() ["00080119"]["Value"][0].asString()); +#else + ASSERT_EQ("UN", visitor.GetResult() ["00080119"]["vr"].asString()); + Toolbox::DecodeBase64(s, visitor.GetResult() ["00080119"]["InlineBinary"].asString()); + ASSERT_EQ("UC", s); +#endif + + ASSERT_EQ("UI", visitor.GetResult() ["00080016"]["vr"].asString()); + ASSERT_EQ("UI", visitor.GetResult() ["00080016"]["Value"][0].asString()); + + ASSERT_EQ("UL", visitor.GetResult() ["00081161"]["vr"].asString()); + ASSERT_EQ(128u, visitor.GetResult() ["00081161"]["Value"][0].asUInt()); + + ASSERT_EQ("UN", visitor.GetResult() ["43421234"]["vr"].asString()); + Toolbox::DecodeBase64(s, visitor.GetResult() ["43421234"]["InlineBinary"].asString()); + ASSERT_EQ("UN", s); + +#if DCMTK_VERSION_NUMBER >= 361 + ASSERT_EQ("UR", visitor.GetResult() ["00080120"]["vr"].asString()); + ASSERT_EQ("UR", visitor.GetResult() ["00080120"]["Value"][0].asString()); +#else + ASSERT_EQ("UN", visitor.GetResult() ["00080120"]["vr"].asString()); + Toolbox::DecodeBase64(s, visitor.GetResult() ["00080120"]["InlineBinary"].asString()); + ASSERT_EQ("UR", s); +#endif + +#if DCMTK_VERSION_NUMBER >= 361 + ASSERT_EQ("US", visitor.GetResult() ["00080301"]["vr"].asString()); + ASSERT_EQ(17u, visitor.GetResult() ["00080301"]["Value"][0].asUInt()); +#else + ASSERT_EQ("UN", visitor.GetResult() ["00080301"]["vr"].asString()); + Toolbox::DecodeBase64(s, visitor.GetResult() ["00080301"]["InlineBinary"].asString()); + ASSERT_EQ("17", s); +#endif + + ASSERT_EQ("UT", visitor.GetResult() ["00400031"]["vr"].asString()); + ASSERT_EQ("UT", visitor.GetResult() ["00400031"]["Value"][0].asString()); + + std::string xml; + visitor.FormatXml(xml); + + { + DicomMap m; + m.FromDicomWeb(visitor.GetResult()); + ASSERT_EQ(31u, m.GetSize()); + + std::string s; + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0002, 0x0002), false)); ASSERT_EQ("UI", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0040, 0x0241), false)); ASSERT_EQ("AE", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x1010), false)); ASSERT_EQ("AS", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0020, 0x9165), false)); ASSERT_EQ("00100020", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0052), false)); ASSERT_EQ("CS", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0012), false)); ASSERT_EQ("DA", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x1020), false)); ASSERT_EQ("42", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x002a), false)); ASSERT_EQ("DT", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x9431), false)); ASSERT_EQ("43", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1163), false)); ASSERT_EQ("44", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1160), false)); ASSERT_EQ("45", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0070), false)); ASSERT_EQ("LO", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x4000), false)); ASSERT_EQ("LT", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0028, 0x2000), true)); ASSERT_EQ("OB", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x7fe0, 0x0009), true)); + +#if DCMTK_VERSION_NUMBER >= 361 + ASSERT_FLOAT_EQ(3.14159f, boost::lexical_cast(s)); +#else + ASSERT_EQ(8u, s.size()); // Because of padding + ASSERT_EQ(0, s[7]); + ASSERT_EQ("3.14159", s.substr(0, 7)); +#endif + + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0064, 0x0009), true)); + ASSERT_FLOAT_EQ(2.71828f, boost::lexical_cast(s)); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0028, 0x1201), true)); ASSERT_EQ("OWOW", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x0010), false)); ASSERT_EQ("PN", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0050), false)); ASSERT_EQ("SH", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0018, 0x6020), false)); ASSERT_EQ("-15", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0018, 0x9219), false)); ASSERT_EQ("-16", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0081), false)); ASSERT_EQ("ST", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0013), false)); ASSERT_EQ("TM", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0016), false)); ASSERT_EQ("UI", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1161), false)); ASSERT_EQ("128", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x4342, 0x1234), true)); ASSERT_EQ("UN", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0040, 0x0031), false)); ASSERT_EQ("UT", s); + +#if DCMTK_VERSION_NUMBER >= 361 + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), false)); ASSERT_EQ("46", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0119), false)); ASSERT_EQ("UC", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0120), false)); ASSERT_EQ("UR", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0301), false)); ASSERT_EQ("17", s); +#else + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), true)); ASSERT_EQ("46", s); // OL + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0119), true)); ASSERT_EQ("UC", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0120), true)); ASSERT_EQ("UR", s); + ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0301), true)); ASSERT_EQ("17", s); // US (but tag unknown to DCMTK 3.6.0) +#endif + + } +} + + +TEST(DicomWebJson, Sequence) +{ + ParsedDicomFile dicom(false); + + { + std::unique_ptr sequence(new DcmSequenceOfItems(DCM_ReferencedSeriesSequence)); + + for (unsigned int i = 0; i < 3; i++) + { + std::unique_ptr item(new DcmItem); + std::string s = "item" + boost::lexical_cast(i); + item->putAndInsertString(DCM_ReferencedSOPInstanceUID, s.c_str(), OFFalse); + ASSERT_TRUE(sequence->insert(item.release(), false, false).good()); + } + + ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->insert(sequence.release(), false, false).good()); + } + + DicomWebJsonVisitor visitor; + dicom.Apply(visitor); + + ASSERT_EQ("SQ", visitor.GetResult() ["00081115"]["vr"].asString()); + ASSERT_EQ(3u, visitor.GetResult() ["00081115"]["Value"].size()); + + std::set items; + + for (Json::Value::ArrayIndex i = 0; i < 3; i++) + { + ASSERT_EQ(1u, visitor.GetResult() ["00081115"]["Value"][i].size()); + ASSERT_EQ(1u, visitor.GetResult() ["00081115"]["Value"][i]["00081155"]["Value"].size()); + ASSERT_EQ("UI", visitor.GetResult() ["00081115"]["Value"][i]["00081155"]["vr"].asString()); + items.insert(visitor.GetResult() ["00081115"]["Value"][i]["00081155"]["Value"][0].asString()); + } + + ASSERT_EQ(3u, items.size()); + ASSERT_TRUE(items.find("item0") != items.end()); + ASSERT_TRUE(items.find("item1") != items.end()); + ASSERT_TRUE(items.find("item2") != items.end()); + + std::string xml; + visitor.FormatXml(xml); + + { + DicomMap m; + m.FromDicomWeb(visitor.GetResult()); + ASSERT_EQ(0u, m.GetSize()); // Sequences are not handled by DicomMap + } +} + + #if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/ImageProcessingTests.cpp --- a/OrthancFramework/UnitTestsSources/ImageProcessingTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/ImageProcessingTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/ImageTests.cpp --- a/OrthancFramework/UnitTestsSources/ImageTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/ImageTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/JobsTests.cpp --- a/OrthancFramework/UnitTestsSources/JobsTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/JobsTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/JpegLosslessTests.cpp --- a/OrthancFramework/UnitTestsSources/JpegLosslessTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/JpegLosslessTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,12 +32,17 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif +#if !defined(ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS) +# error ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS is not defined +#endif + #include -#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1 +#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 #include "../Sources/DicomParsing/Internals/DicomImageDecoder.h" #include "../Sources/DicomParsing/ParsedDicomFile.h" diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/LoggingTests.cpp --- a/OrthancFramework/UnitTestsSources/LoggingTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/LoggingTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/LuaTests.cpp --- a/OrthancFramework/UnitTestsSources/LuaTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/LuaTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/MemoryCacheTests.cpp --- a/OrthancFramework/UnitTestsSources/MemoryCacheTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/MemoryCacheTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/RestApiTests.cpp --- a/OrthancFramework/UnitTestsSources/RestApiTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/RestApiTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif @@ -56,7 +57,11 @@ using namespace Orthanc; #if !defined(UNIT_TESTS_WITH_HTTP_CONNEXIONS) -#error "Please set UNIT_TESTS_WITH_HTTP_CONNEXIONS" +# error UNIT_TESTS_WITH_HTTP_CONNEXIONS is not defined +#endif + +#if !defined(ORTHANC_ENABLE_SSL) +# error ORTHANC_ENABLE_SSL is not defined #endif diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/SQLiteChromiumTests.cpp --- a/OrthancFramework/UnitTestsSources/SQLiteChromiumTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/SQLiteChromiumTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/SQLiteTests.cpp --- a/OrthancFramework/UnitTestsSources/SQLiteTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/SQLiteTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/SharedLibraryUnitTests.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/UnitTestsSources/SharedLibraryUnitTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -0,0 +1,63 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +// This file is meant to be used only by ../SharedLibrary/CMakeLists.txt + +#if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library +# include +#else +# error This file must only be used if testing the Orthanc framework shared library +#endif + +#include "../Sources/Logging.h" +#include "../Sources/Toolbox.h" +#include "../Sources/SystemToolbox.h" + +#include + +int main(int argc, char **argv) +{ + Orthanc::InitializeFramework("", true); + + Orthanc::Logging::EnableInfoLevel(true); + Orthanc::Toolbox::DetectEndianness(); + Orthanc::SystemToolbox::MakeDirectory("UnitTestsResults"); + + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + + Orthanc::FinalizeFramework(); + + return result; +} diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/StreamTests.cpp --- a/OrthancFramework/UnitTestsSources/StreamTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/StreamTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/ToolboxTests.cpp --- a/OrthancFramework/UnitTestsSources/ToolboxTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/ToolboxTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif diff -r 0953b3dc3261 -r e00f3d089991 OrthancFramework/UnitTestsSources/ZipTests.cpp --- a/OrthancFramework/UnitTestsSources/ZipTests.cpp Thu Jun 11 14:38:31 2020 +0200 +++ b/OrthancFramework/UnitTestsSources/ZipTests.cpp Thu Jun 11 16:40:34 2020 +0200 @@ -32,6 +32,7 @@ #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 +// Must be the first to be sure to use the Orthanc framework shared library # include #endif