[med-svn] [odil] 01/08: Imported Upstream version 0.8.0
Julien Lamy
lamy-guest at moszumanska.debian.org
Thu Apr 20 09:52:37 UTC 2017
This is an automated email from the git hooks/post-receive script.
lamy-guest pushed a commit to branch master
in repository odil.
commit 78d9019fab7e22a21c2fd22a4f9475acc43616ac
Author: root <root at 0081a9e9b04b>
Date: Wed Apr 19 10:31:24 2017 +0000
Imported Upstream version 0.8.0
---
.travis.yml | 18 +-
CMakeLists.txt | 22 +-
FindICU.cmake | 15 +-
FindLog4Cpp.cmake | 2 +-
README.md | 11 +-
applications/odil | 3 +-
applications/store.py | 68 ++++
appveyor.full.yml | 52 ---
appveyor.yml | 113 ++++--
ctest-to-junit.xsl | 64 ++++
examples/CMakeLists.txt | 6 +-
examples/find.cpp | 10 +-
examples/genericscp.cpp | 22 +-
src/CMakeLists.txt | 10 +-
src/odil/Association.cpp | 8 +-
src/odil/Association.h | 9 +-
src/odil/AssociationAcceptor.h | 4 +-
src/odil/AssociationParameters.cpp | 8 +-
src/odil/AssociationParameters.h | 7 +-
src/odil/BasicDirectoryCreator.h | 3 +-
src/odil/DataSet.cpp | 215 +++++------
src/odil/DataSet.h | 78 ++--
src/odil/EchoSCP.cpp | 14 +
src/odil/EchoSCP.h | 7 +-
src/odil/EchoSCU.h | 3 +-
src/odil/Element.cpp | 137 ++++---
src/odil/Element.h | 88 ++---
src/odil/ElementsDictionary.h | 76 ++--
src/odil/Exception.h | 4 +-
src/odil/FindSCP.cpp | 18 +-
src/odil/FindSCP.h | 9 +-
src/odil/FindSCU.cpp | 77 +++-
src/odil/FindSCU.h | 18 +-
src/odil/GetSCP.cpp | 18 +-
src/odil/GetSCP.h | 8 +-
src/odil/GetSCU.cpp | 96 +++--
src/odil/GetSCU.h | 25 +-
src/odil/MoveSCP.cpp | 20 +-
src/odil/MoveSCP.h | 7 +-
src/odil/MoveSCU.cpp | 72 +++-
src/odil/MoveSCU.h | 28 +-
src/odil/{StoreSCP.cpp => NCreateSCP.cpp} | 53 +--
src/odil/{EchoSCP.h => NCreateSCP.h} | 27 +-
src/odil/NSetSCP.cpp | 102 ++++++
src/odil/{EchoSCP.h => NSetSCP.h} | 28 +-
src/odil/NSetSCU.cpp | 74 ++++
src/odil/{StoreSCU.h => NSetSCU.h} | 20 +-
src/odil/Reader.cpp | 46 +--
src/odil/Reader.h | 3 +-
src/odil/SCP.cpp | 4 +-
src/odil/SCP.h | 8 +-
src/odil/SCPDispatcher.cpp | 27 +-
src/odil/SCPDispatcher.h | 7 +-
src/odil/SCU.h | 3 +-
src/odil/StoreSCP.cpp | 18 +-
src/odil/StoreSCP.h | 9 +-
src/odil/StoreSCU.cpp | 37 +-
src/odil/StoreSCU.h | 12 +-
src/odil/Tag.h | 16 +-
src/odil/UIDsDictionary.h | 4 +-
src/odil/VR.h | 16 +-
src/odil/VRFinder.h | 3 +-
src/odil/Value.cpp | 164 ++++++---
src/odil/Value.h | 69 ++--
src/odil/Value.txx | 12 +-
src/odil/Writer.h | 3 +-
src/odil/base64.h | 6 +-
src/odil/dcmtk/ElementAccessor.h | 5 +-
src/odil/dcmtk/Exception.h | 3 +-
src/odil/dcmtk/conversion.cpp | 48 +--
src/odil/dcmtk/conversion.h | 20 +-
src/odil/dul/EventData.h | 3 +-
src/odil/dul/StateMachine.h | 3 +-
src/odil/dul/Transport.h | 4 +-
src/odil/json_converter.cpp | 12 +-
src/odil/json_converter.h | 5 +-
src/odil/message/CEchoRequest.h | 3 +-
src/odil/message/CEchoResponse.h | 3 +-
src/odil/message/CFindRequest.cpp | 54 ++-
src/odil/message/CFindRequest.h | 24 +-
src/odil/message/CFindResponse.cpp | 47 ++-
src/odil/message/CFindResponse.h | 21 +-
src/odil/message/CGetRequest.cpp | 54 ++-
src/odil/message/CGetRequest.h | 24 +-
src/odil/message/CGetResponse.cpp | 51 ++-
src/odil/message/CGetResponse.h | 21 +-
src/odil/message/CMoveRequest.cpp | 56 ++-
src/odil/message/CMoveRequest.h | 26 +-
src/odil/message/CMoveResponse.cpp | 51 ++-
src/odil/message/CMoveResponse.h | 21 +-
src/odil/message/CStoreRequest.cpp | 64 +++-
src/odil/message/CStoreRequest.h | 31 +-
src/odil/message/CStoreResponse.h | 3 +-
src/odil/message/Cancellation.h | 3 +-
src/odil/message/Message.cpp | 41 +++
src/odil/message/Message.h | 18 +-
src/odil/message/NCreateRequest.cpp | 51 +++
src/odil/message/NCreateRequest.h | 63 ++++
src/odil/message/NCreateResponse.cpp | 53 +++
src/odil/message/NCreateResponse.h | 61 ++++
src/odil/message/NSetRequest.cpp | 93 +++++
src/odil/message/NSetRequest.h | 59 +++
src/odil/message/NSetResponse.cpp | 61 ++++
src/odil/message/NSetResponse.h | 58 +++
src/odil/message/Request.h | 3 +-
src/odil/message/Response.h | 3 +-
src/odil/odil.h | 7 +-
src/odil/pdu/AAbort.h | 3 +-
src/odil/pdu/AAssociate.h | 3 +-
src/odil/pdu/AAssociateAC.h | 3 +-
src/odil/pdu/AAssociateRJ.h | 3 +-
src/odil/pdu/AAssociateRQ.h | 3 +-
src/odil/pdu/AReleaseRP.h | 3 +-
src/odil/pdu/AReleaseRQ.h | 3 +-
src/odil/pdu/ApplicationContext.h | 3 +-
src/odil/pdu/AsynchronousOperationsWindow.h | 3 +-
src/odil/pdu/ImplementationClassUID.h | 3 +-
src/odil/pdu/ImplementationVersionName.h | 3 +-
src/odil/pdu/Item.h | 7 +-
src/odil/pdu/MaximumLength.h | 3 +-
src/odil/pdu/Object.h | 5 +-
src/odil/pdu/PDataTF.h | 5 +-
src/odil/pdu/PresentationContext.h | 3 +-
src/odil/pdu/PresentationContextAC.h | 3 +-
src/odil/pdu/PresentationContextRQ.h | 3 +-
src/odil/pdu/RoleSelection.h | 3 +-
src/odil/pdu/SOPClassCommonExtendedNegotiation.h | 3 +-
src/odil/pdu/SOPClassExtendedNegotiation.h | 3 +-
src/odil/pdu/UserIdentityAC.h | 3 +-
src/odil/pdu/UserIdentityRQ.h | 3 +-
src/odil/pdu/UserInformation.h | 3 +-
src/odil/registry.cpp | 59 ++-
src/odil/registry.h | 19 +-
src/odil/uid.h | 2 +-
src/odil/unicode.h | 6 +-
src/odil/write_ds.h | 4 +-
src/odil/xml_converter.cpp | 24 +-
src/odil/xml_converter.h | 5 +-
tests/CMakeLists.txt | 7 +-
tests/code/BasicDirectoryCreator.cpp | 15 +-
tests/code/DataSet.cpp | 445 +++++++++++------------
tests/code/Element.cpp | 353 ++++++++++++------
tests/code/FindSCP.cpp | 18 +-
tests/code/FindSCU.cpp | 27 ++
tests/code/GetSCP.cpp | 20 +-
tests/code/GetSCU.cpp | 40 ++
tests/code/MoveSCP.cpp | 18 +-
tests/code/MoveSCU.cpp | 48 +++
tests/code/NCreateSCP.cpp | 91 +++++
tests/code/Reader.cpp | 2 +-
tests/code/SCPDispatcher.cpp | 2 +-
tests/code/StoreSCU.cpp | 8 +
tests/code/Value.cpp | 379 ++++++++-----------
tests/run | 24 +-
tests/tools/CMakeLists.txt | 8 +-
tests/wrappers/test_association_parameters.py | 4 +-
tests/wrappers/test_data_set.py | 243 ++++++-------
tests/wrappers/test_element.py | 194 +++++++---
tests/wrappers/test_tag.py | 11 +
tests/wrappers/test_value.py | 150 ++++++--
tests/wrappers/test_vr.py | 20 +
wrappers/Assocation.cpp | 110 +++---
wrappers/AssocationParameters.cpp | 3 +-
wrappers/CEchoResponse.cpp | 30 ++
wrappers/CMakeLists.txt | 20 +
wrappers/CStoreResponse.cpp | 54 +++
wrappers/DataSet.cpp | 2 +
wrappers/EchoSCP.cpp | 32 +-
wrappers/Element.cpp | 12 +-
wrappers/FindSCP.cpp | 7 +-
wrappers/GetSCP.cpp | 7 +-
wrappers/Message.cpp | 65 +++-
wrappers/MoveSCP.cpp | 7 +-
wrappers/{EchoSCP.cpp => NCreateSCP.cpp} | 17 +-
wrappers/NSetRequest.cpp | 50 +++
wrappers/{EchoSCP.cpp => NSetSCP.cpp} | 27 +-
wrappers/{StoreSCU.cpp => NSetSCU.cpp} | 16 +-
wrappers/Response.cpp | 34 ++
wrappers/{EchoSCP.cpp => SCP.cpp} | 15 +-
wrappers/SCPDispatcher.cpp | 47 +++
wrappers/StoreSCP.cpp | 31 +-
wrappers/StoreSCU.cpp | 14 +-
wrappers/Tag.cpp | 6 +
wrappers/VR.cpp | 70 ++++
wrappers/Value.cpp | 6 +-
wrappers/odil.cpp | 19 +-
wrappers/value_constructor.cpp | 41 ++-
187 files changed, 4644 insertions(+), 1899 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 1c6a9ab..4c029d9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,8 +5,8 @@ matrix:
sudo: required
dist: trusty
compiler: gcc
-# - os: osx
-# compiler: clang
+ - os: osx
+ compiler: clang
addons:
apt:
packages:
@@ -16,6 +16,7 @@ addons:
- libicu-dev
- zlib1g-dev
- libboost-dev
+ - libboost-date-time-dev
- libboost-filesystem-dev
- libboost-python-dev
- libboost-regex-dev
@@ -27,7 +28,7 @@ addons:
before_install:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; fi
# JSONCpp conflicts with json-c
- - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew uninstall json-c; fi
+ - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew uninstall --ignore-dependencies json-c; fi
# Boost is already installed with another version
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew unlink boost; brew install boost boost-python; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install dcmtk icu4c jsoncpp log4cpp; fi
@@ -38,12 +39,15 @@ before_script:
- mkdir build
- cd build
- export BIN_DIR=$PWD
- - CMAKE_CXX_FLAGS="-std=c++11"
- - if [ "${CC}" = "gcc" ]; then CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} --coverage"; fi
+ - CMAKE_OPTIONS=""
+ - if [ "${CC}" = "gcc" ]; then CMAKE_OPTIONS='${CMAKE_OPTIONS} -DCMAKE_CXX_FLAGS="--coverage"'; fi
+ #- if [ "${CC}" = "gcc" ]; then CMAKE_OPTIONS='${CMAKE_OPTIONS} -DPYTHON_LIBRARY=/opt/python/2.7.12/lib/libpython2.7.so'; fi
+ #- if [ "$TRAVIS_OS_NAME" = "osx" ]; then CMAKE_OPTIONS='${CMAKE_OPTIONS} -DPYTHON_LIBRARY=/usr/local/Frameworks/Python.framework/Versions/2.7/lib/libpython2.7.dylib' ; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/opt/icu4c/lib/pkgconfig; fi
- - cmake -D CMAKE_CXX_FLAGS:STRING="${CMAKE_CXX_FLAGS}" -D CMAKE_BUILD_TYPE:STRING=Debug ../
+ # Travis has a weird Python environment. Disable the wrappers
+ - cmake ${CMAKE_OPTIONS} -DBUILD_WRAPPERS=OFF ../
script:
- make
- - ../tests/run --no-network
+ - ../tests/run --no-network -e ".*"
after_success:
- if [ "${CC}" = "gcc" ]; then coveralls --exclude examples --exclude tests --exclude-pattern '.*CMake[^/]+\.c(?:pp)?' --exclude-pattern "/usr/.*" --root=${SRC_DIR} --build-root ${BIN_DIR} > /dev/null; fi
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9c34df5..ce37237 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 2.8)
project("odil")
set(odil_MAJOR_VERSION 0)
-set(odil_MINOR_VERSION 7)
-set(odil_PATCH_VERSION 2)
+set(odil_MINOR_VERSION 8)
+set(odil_PATCH_VERSION 0)
set(odil_VERSION
${odil_MAJOR_VERSION}.${odil_MINOR_VERSION}.${odil_PATCH_VERSION})
@@ -12,19 +12,27 @@ option(BUILD_EXAMPLES "Build the examples directory." ON)
option(BUILD_WRAPPERS "Build the Python Wrappers." ON)
option(WITH_DCMTK "Build the DCMTK converter" ON)
+option(
+ USE_BUILTIN_DCMTK_GETSCU
+ "Compile a locally packaged version of getscu for old DCMTK versions" ON)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}" ${CMAKE_MODULE_PATH})
include(CTest)
include(cmake/functions.cmake)
+# Add the C++0x or C++11 flag
+include(CheckCXXCompilerFlag)
+CHECK_CXX_COMPILER_FLAG(-std=c++11 COMPILER_SUPPORTS_CXX11)
+CHECK_CXX_COMPILER_FLAG(-std=c++0x COMPILER_SUPPORTS_CXX0X)
+if(COMPILER_SUPPORTS_CXX11)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+elseif(COMPILER_SUPPORTS_CXX0X)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+endif()
+
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
if(WIN32)
- # Trying the automatic creation of .def files by CMake
- if(${BUILD_SHARED_LIBS})
- set(WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
- endif()
-
# We have to set _WIN32_WINNT for Asio
if(${CMAKE_SYSTEM_VERSION} EQUAL 10) # Windows 10
add_definitions(-D _WIN32_WINNT=0x0A00)
diff --git a/FindICU.cmake b/FindICU.cmake
index 61e9d72..f9ce7e2 100644
--- a/FindICU.cmake
+++ b/FindICU.cmake
@@ -10,7 +10,20 @@ pkg_check_modules(PC_ICU QUIET icu-uc)
set(ICU_DEFINITIONS ${PC_ICU_CFLAGS_OTHER})
find_path(ICU_INCLUDE_DIR "unicode/ucnv.h" HINTS ${PC_ICU_INCLUDE_DIRS})
-find_library(ICU_LIBRARY NAMES icuuc HINTS ${PC_ICU_LIBRARY_DIRS} )
+
+# Get version
+if(ICU_INCLUDE_DIR AND EXISTS "${ICU_INCLUDE_DIR}/unicode/uvernum.h")
+ file(STRINGS "${ICU_INCLUDE_DIR}/unicode/uvernum.h" icu_header_str
+ REGEX "^#define[\t ]+U_ICU_VERSION[\t ]+\".*\".*")
+
+ string(REGEX REPLACE "^#define[\t ]+U_ICU_VERSION[\t ]+\"([0-9]*).*"
+ "\\1" icu_version_string "${icu_header_str}")
+ set(ICU_VERSION "${icu_version_string}" )
+ unset(icu_header_str)
+ unset(icu_version_string)
+endif()
+
+find_library(ICU_LIBRARY NAMES icuuc icuuc${ICU_VERSION} icuuc${ICU_VERSION}d HINTS ${PC_ICU_LIBRARY_DIRS} )
set(ICU_LIBRARIES ${ICU_LIBRARY} )
set(ICU_INCLUDE_DIRS ${ICU_INCLUDE_DIR} )
diff --git a/FindLog4Cpp.cmake b/FindLog4Cpp.cmake
index 7f83da4..00c867c 100644
--- a/FindLog4Cpp.cmake
+++ b/FindLog4Cpp.cmake
@@ -10,7 +10,7 @@ pkg_check_modules(PC_Log4Cpp QUIET log4cpp)
set(Log4Cpp_DEFINITIONS ${PC_Log4Cpp_CFLAGS_OTHER})
find_path(Log4Cpp_INCLUDE_DIR "log4cpp/Category.hh" HINTS ${PC_Log4Cpp_INCLUDE_DIRS})
-find_library(Log4Cpp_LIBRARY NAMES log4cpp HINTS ${PC_Log4Cpp_LIBRARY_DIRS} )
+find_library(Log4Cpp_LIBRARY NAMES log4cpp log4cppD HINTS ${PC_Log4Cpp_LIBRARY_DIRS} )
set(Log4Cpp_LIBRARIES ${Log4Cpp_LIBRARY} )
set(Log4Cpp_INCLUDE_DIRS ${Log4Cpp_INCLUDE_DIR} )
diff --git a/README.md b/README.md
index 7de4d0a..7a1435a 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
-Odil
-=======
+# Odil
Odil is a C++11 library for the [DICOM](http://dicom.nema.org/) standard.
@@ -13,11 +12,13 @@ Odil also provides conversion to and from
[DCMTK](http://dicom.offis.de/dcmtk.php.en) data structures.
Odil builds and run on:
+
* Linux (Debian 7 and 8, Ubuntu 12.04, 14.04, and 16.04, all 32 and 64 bits).
Official packages are available ([Debian](https://packages.debian.org/search?keywords=odil&searchon=sourcenames&suite=all§ion=all), [Ubuntu](http://packages.ubuntu.com/search?keywords=odil&searchon=sourcenames&suite=all§ion=all)),
- as well as [unofficial backports](https://github.com/lamyj/packages).
-
+ as well as [unofficial backports](https://github.com/lamyj/packages).
* OS X
+* Windows
-[![Build Status](https://travis-ci.org/lamyj/odil.svg?branch=master)](https://travis-ci.org/lamyj/odil)
+[![Build Status (Travis)](https://travis-ci.org/lamyj/odil.svg?branch=master)](https://travis-ci.org/lamyj/odil)
+[![Build Status (Appveyor)](https://ci.appveyor.com/api/projects/status/github/lamyj/odil?svg=true)](https://ci.appveyor.com/project/lamyj/odil)
[![Coverage Status](https://coveralls.io/repos/lamyj/odil/badge.svg)](https://coveralls.io/r/lamyj/odil)
diff --git a/applications/odil b/applications/odil
index 97e4d6f..07c3cc5 100755
--- a/applications/odil
+++ b/applications/odil
@@ -9,6 +9,7 @@ import echo
import find
import get
import print_
+import store
import transcode
def main():
@@ -18,7 +19,7 @@ def main():
modules = [
print_, transcode, dicomdir,
- echo, find, get
+ echo, find, get, store
]
for module in modules:
sub_parser = module.add_subparser(subparsers)
diff --git a/applications/store.py b/applications/store.py
new file mode 100755
index 0000000..cd628f2
--- /dev/null
+++ b/applications/store.py
@@ -0,0 +1,68 @@
+from __future__ import print_function
+
+import argparse
+
+import odil
+
+def add_subparser(subparsers):
+ parser = subparsers.add_parser(
+ "store", help="DICOM store (C-STORE)",
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser.add_argument("host", help="Remote host address")
+ parser.add_argument("port", type=int, help="Remote host port")
+ parser.add_argument(
+ "calling_ae_title", help="AE title of the calling application")
+ parser.add_argument(
+ "called_ae_title", help="AE title of the called application")
+ parser.add_argument("filenames", nargs="+", help="File names")
+ parser.set_defaults(function=store)
+ return parser
+
+def store(host, port, calling_ae_title, called_ae_title, filenames):
+ transfer_syntaxes = [
+ odil.registry.ExplicitVRLittleEndian,
+ odil.registry.ImplicitVRLittleEndian,
+ ]
+
+ # Find all SOP classes to negotiate at association time. We don't need to
+ # read the whole data set for this
+ sop_classes = set()
+ for filename in filenames:
+ _, data_set = odil.read(
+ filename, halt_condition=lambda tag: tag>odil.registry.SOPClassUID)
+ sop_classes.update(data_set.as_string("SOPClassUID"))
+
+ print(sop_classes)
+ presentation_contexts = [
+ odil.AssociationParameters.PresentationContext(
+ 2*i+1, sop_class, transfer_syntaxes, True, False)
+ for i, sop_class in enumerate(sop_classes)
+ ]
+
+ # Create the association and the Store SCU
+ association = odil.Association()
+ association.set_peer_host(host)
+ association.set_peer_port(port)
+ association.update_parameters()\
+ .set_calling_ae_title(calling_ae_title)\
+ .set_called_ae_title(called_ae_title)\
+ .set_presentation_contexts(presentation_contexts)
+ association.associate()
+
+ negotiated_parameters = association.get_negotiated_parameters()
+ negotiated_pc = negotiated_parameters.get_presentation_contexts()
+ for pc in negotiated_pc:
+ print(pc.abstract_syntax, " ", pc.transfer_syntaxes[0])
+
+ store = odil.StoreSCU(association)
+
+ for filename in filenames:
+ _, data_set = odil.read(filename)
+
+ try:
+ store.set_affected_sop_class(data_set)
+ store.store(data_set)
+ except Exception as e:
+ print("Could not store {}: {}".format(filename, e))
+
+ association.release()
diff --git a/appveyor.full.yml b/appveyor.full.yml
deleted file mode 100644
index 092d607..0000000
--- a/appveyor.full.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-version: "{build}"
-
-os: Visual Studio 2015
-
-clone_folder: c:\projects\dcmtkpp
-
-environment:
- BOOST_ROOT: C:/Libraries/boost_1_59_0
- BOOST_LIBRARYDIR: C:/Libraries/boost_1_59_0/lib64-msvc-14.0
- ICU_INCLUDE_DIR: C:/Libraries/icu/include
- ICU_LIBRARY: C:/Libraries/icu/lib64/icuuc.lib
- JsonCpp_INCLUDE_DIR: c:/Libraries/jsoncpp_0_10_5/include
- JsonCpp_LIBRARY: c:/Libraries/jsoncpp_0_10_5/lib/jsoncpp.lib
- DCMTK_INCLUDE_DIR: C:/Libraries/dcmtk-3.6.1_20150924/include
- DCMTK_LIBRARY: C:/Libraries/dcmtk-3.6.1_20150924/lib/dcmdata.lib
-
-#init:
-#- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
-
-install:
- # ICU4C
-- ps: Start-FileDownload http://download.icu-project.org/files/icu4c/56.1/icu4c-56_1-Win64-msvc10.zip
-- 7z x -oC:\Libraries icu4c-56_1-Win64-msvc10.zip
- # JsonCpp
-- ps: Start-FileDownload https://github.com/open-source-parsers/jsoncpp/archive/0.10.5.zip
-- 7z x -oC:\projects 0.10.5.zip
-- cd C:\projects\jsoncpp-0.10.5
-- mkdir build
-- cd build
-- cmake -D CMAKE_INSTALL_PREFIX=c:\Libraries\jsoncpp_0_10_5 ..
-- cmake --build . --config release --target install
- # DCMTK
-- ps: Start-FileDownload http://dicom.offis.de/download/dcmtk/snapshot/dcmtk-3.6.1_20150924.tar.gz
-- 7z x -so dcmtk-3.6.1_20150924.tar.gz | 7z x -si -oC:\projects -ttar
-- cd C:\projects\dcmtk-3.6.1_20150924
-- mkdir build
-- cd build
-- cmake -D CMAKE_INSTALL_PREFIX=c:\Libraries\dcmtk-3.6.1_20150924 ..
-- cmake --build . --config release --target install
-
-before_build:
- - cd c:\projects\dcmtkpp
- - md build
- - cd build
- - set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH%
- - cmake -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%" -DICU_INCLUDE_DIR="%ICU_INCLUDE_DIR%" -DICU_LIBRARY="%ICU_LIBRARY%" -DJsonCpp_INCLUDE_DIR="%JsonCpp_INCLUDE_DIR%" -DJsonCpp_LIBRARY="%JsonCpp_LIBRARY%" -DDCMTK_INCLUDE_DIR="%DCMTK_INCLUDE_DIR%" -DDCMTK_LIBRARY="%DCMTK_LIBRARY%" ..
-
-build:
- project: C:\projects\dcmtkpp\build\dcmtkpp.sln
-
-#on_finish:
-#- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
diff --git a/appveyor.yml b/appveyor.yml
index edbf936..923006b 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,43 +1,86 @@
version: "{build}"
+image: Visual Studio 2015
+platform:
+ - x64
+configuration:
+ - Release
-os: Windows Server 2012 R2
+environment:
+ BOOST_ROOT: C:/Libraries/boost_1_62_0
+ DCMTK_ROOT: c:/Libraries/dcmtk
+ ICU_ROOT: C:/Libraries/icu
+ JsonCpp_ROOT: C:/Libraries/jsoncpp
+ Log4Cpp_ROOT: C:/Libraries/log4cpp
+ Python_ROOT: C:/Python27-x64
+ VERSION: 0.8.0-1
-clone_folder: c:\projects\odil
+install:
+ - ps: |
+ Start-FileDownload https://github.com/lamyj/appveyor-dcmtk/releases/download/v3.6.1-20161102-2/dcmtk_3.6.1-20161102-2_dynamic_x64.zip dcmtk.zip
+ 7z x -bd -oC:\Libraries dcmtk.zip
-environment:
- BOOST_ROOT: C:/Libraries/boost_1_59_0
- BOOST_LIBRARYDIR: C:/Libraries/boost_1_59_0/lib64-msvc-14.0
- ICU_INCLUDE_DIR: C:/Libraries/icu/include
- ICU_LIBRARY: C:/Libraries/icu/lib64/icuuc.lib
- JsonCpp_INCLUDE_DIR: c:/Libraries/jsoncpp_0_10_5/include
- JsonCpp_LIBRARY: c:/Libraries/jsoncpp_0_10_5/lib/jsoncpp.lib
- DCMTK_INCLUDE_DIR: C:/Libraries/dcmtk-3.6.1_20150924/include
- DCMTK_LIBRARY: C:/Libraries/dcmtk-3.6.1_20150924/lib/dcmdata.lib
+ Start-FileDownload http://download.icu-project.org/files/icu4c/58.2/icu4c-58_2-Win64-MSVC2015.zip
+ 7z x -bd -oC:\Libraries icu4c-58_2-Win64-MSVC2015.zip
-configuration:
- - Release
+ Start-FileDownload https://github.com/lamyj/appveyor-jsoncpp/releases/download/v1.8.0-2/jsoncpp_1.8.0-2_dynamic_x64.zip jsoncpp.zip
+ 7z x -bd -oC:\Libraries jsoncpp.zip
-install:
- # ICU4C
-- ps: Start-FileDownload http://download.icu-project.org/files/icu4c/56.1/icu4c-56_1-Win64-msvc10.zip
-- 7z x -bd -oC:\Libraries icu4c-56_1-Win64-msvc10.zip
- # JsonCpp
-- ps: Start-FileDownload https://github.com/lamyj/jsoncpp/releases/download/0.10.5/jsoncpp_0_10_5_Win64_msvc14.zip
-- 7z x -bd -oC:\Libraries jsoncpp_0_10_5_Win64_msvc14.zip
- # DCMTK
-- ps: Start-FileDownload https://github.com/lamyj/dcmtk/releases/download/DCMTK-3.6.1_20150924/dcmtk-3.6.1_20150924_Win64_msvc14_dynamic.zip
-- 7z x -bd -oC:\Libraries dcmtk-3.6.1_20150924_Win64_msvc14_dynamic.zip
+ Start-FileDownload https://github.com/lamyj/appveyor-log4cpp/releases/download/v1.1.1-1/log4cpp_1.1.1-dll_x64.zip log4cpp.zip
+ 7z x -bd -oC:\Libraries log4cpp.zip
before_build:
- - cd c:\projects\odil
- - md build
- - cd build
- - cmake
- -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%"
- -DICU_INCLUDE_DIR="%ICU_INCLUDE_DIR%" -DICU_LIBRARY="%ICU_LIBRARY%"
- -DJsonCpp_INCLUDE_DIR="%JsonCpp_INCLUDE_DIR%" -DJsonCpp_LIBRARY="%JsonCpp_LIBRARY%"
- -DDCMTK_INCLUDE_DIR="%DCMTK_INCLUDE_DIR%" -DDCMTK_LIBRARY="%DCMTK_LIBRARY%"
- ..
-
-build:
- project: C:\projects\odil\build\odil.sln
+ - ps: |
+ ${env:BUILD_DIRECTORY}="${env:APPVEYOR_BUILD_FOLDER}\build"
+ ${env:INSTALL_DIRECTORY}="${env:APPVEYOR_BUILD_FOLDER}\install\${env:APPVEYOR_PROJECT_NAME}"
+
+ New-Item -Path "${env:BUILD_DIRECTORY}" -ItemType "directory"
+ cd "${env:BUILD_DIRECTORY}"
+
+ ${generator} = "Visual Studio 14 2015"
+ if (${env:PLATFORM} -eq "x64") { ${generator} = "${generator} Win64" }
+ cmake `
+ -G "${generator}" -DCMAKE_INSTALL_PREFIX="${env:INSTALL_DIRECTORY}" `
+ -DBUILD_EXAMPLES=ON -DBUILD_WRAPPERS=OFF -DUSE_BUILTIN_DCMTK_GETSCU=OFF `
+ -DBUILD_SHARED_LIBS=ON -DBUILD_TESTING=ON -DWITH_DCMTK=ON `
+ -DBOOST_LIBRARYDIR="${env:BOOST_ROOT}/lib64-msvc-14.0" `
+ -DDCMTK_INCLUDE_DIR="${env:DCMTK_ROOT}/include" -DDCMTK_LIBRARY="${env:DCMTK_ROOT}/lib/dcmdata.lib" `
+ -DDCMDATA_LIBRARY="${env:DCMTK_ROOT}/lib/dcmdata.lib" -DDCMNET_LIBRARY="${env:DCMTK_ROOT}/lib/dcmnet.lib" `
+ -DOFLOG_LIBRARY="${env:DCMTK_ROOT}/lib/oflog.lib" -DOFSTD_LIBRARY="${env:DCMTK_ROOT}/lib/ofstd.lib" `
+ -DICU_INCLUDE_DIR="${env:ICU_ROOT}/include" -DICU_LIBRARY="${env:ICU_ROOT}/lib64/icuuc.lib" `
+ -DJsonCpp_INCLUDE_DIR="${env:JsonCpp_ROOT}/include" -DJsonCpp_LIBRARY="${env:JsonCpp_ROOT}/lib/jsoncpp.lib" `
+ -DLog4Cpp_INCLUDE_DIR="${env:Log4Cpp_ROOT}/include" -DLog4Cpp_LIBRARY="${env:Log4Cpp_ROOT}/lib/log4cpp.lib" `
+ "${env:APPVEYOR_BUILD_FOLDER}"
+
+build_script:
+ - ps: |
+ msbuild "${env:BUILD_DIRECTORY}\${env:APPVEYOR_PROJECT_NAME}.sln" `
+ /m /clp:Verbosity=minimal /p:Configuration=${env:CONFIGURATION}
+ msbuild "${env:BUILD_DIRECTORY}\INSTALL.vcxproj" `
+ /m /clp:Verbosity=minimal /p:Configuration=${env:CONFIGURATION}
+
+before_test:
+ - ps: |
+ & "${env:Python_ROOT}\Scripts\pip.exe" install nose
+
+# nosetests writes on stderr, and powershell treats this as an exception:
+# use cmd instead
+test_script:
+ - cmd: |
+ set PATH=%PATH%;%BOOST_ROOT%\lib64-msvc-14.0;%DCMTK_ROOT%\bin
+ set PATH=%PATH%;%ICU_ROOT%\bin64;%JsonCpp_ROOT%\bin;%Log4Cpp_ROOT%\bin
+ set PATH=%PATH%;%INSTALL_DIRECTORY%\bin
+ set PYTHONPATH=%BUILD_DIRECTORY%\wrappers\%CONFIGURATION%
+ cd %BUILD_DIRECTORY%
+ %Python_ROOT%\python.exe ..\tests\run --no-network -e ".*" --nose=%Python_ROOT%\Scripts\nosetests.exe
+
+after_test:
+ - ps: |
+ Start-FileDownload https://download.microsoft.com/download/f/2/6/f263ac46-1fe9-4ae9-8fd3-21102100ebf5/msxsl.exe
+ .\msxsl.exe `
+ "${env:BUILD_DIRECTORY}\Testing\$(Get-Content Testing\TAG -TotalCount 1)\Test.xml" `
+ "${env:APPVEYOR_BUILD_FOLDER}\ctest-to-junit.xsl" `
+ -o junit.xml
+ $wc = New-Object 'System.Net.WebClient'
+ $wc.UploadFile(
+ "https://ci.appveyor.com/api/testresults/junit/${env:APPVEYOR_JOB_ID}",
+ (Resolve-Path .\junit.xml))
diff --git a/ctest-to-junit.xsl b/ctest-to-junit.xsl
new file mode 100644
index 0000000..910d752
--- /dev/null
+++ b/ctest-to-junit.xsl
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+The MIT License (MIT)
+
+Copyright (c) 2014, Gregory Boissinot
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+-->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:output method="xml" indent="yes"/>
+ <xsl:template match="/">
+ <testsuites>
+ <xsl:variable name="buildName" select="//Site/@BuildName"/>
+ <xsl:variable name="numberOfTests" select="count(//Site/Testing/Test)"/>
+ <xsl:variable name="numberOfFailures" select="count(//Site/Testing/Test[@Status!='passed'])"/>
+ <testsuite name="CTest"
+ tests="{$numberOfTests}" time="0"
+ failures="{$numberOfFailures}" errors="0"
+ skipped="0">
+ <xsl:for-each select="//Site/Testing/Test">
+ <xsl:variable name="testName" select="translate(Name, '-', '_')"/>
+ <xsl:variable name="duration" select="Results/NamedMeasurement[@name='Execution Time']/Value"/>
+ <xsl:variable name="status" select="@Status"/>
+ <xsl:variable name="output" select="Results/Measurement/Value"/>
+ <xsl:variable name="className" select="translate(Path, '/.', '.')"/>
+ <testcase classname="projectroot{$className}"
+ name="{$testName}"
+ time="{$duration}">
+ <xsl:choose>
+ <xsl:when test="@Status='passed'"/>
+ <xsl:when test="@Status='notrun'">
+ <skipped/>
+ </xsl:when>
+ <xsl:otherwise>
+ <failure>
+ <xsl:value-of select="$output"/>
+ </failure>
+ </xsl:otherwise>
+ </xsl:choose>
+ <system-out>
+ <xsl:value-of select="$output"/>
+ </system-out>
+ </testcase>
+ </xsl:for-each>
+ </testsuite>
+ </testsuites>
+ </xsl:template>
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 491a8f7..b91c6f2 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -5,11 +5,15 @@ find_package(JsonCpp REQUIRED)
include_directories(
${CMAKE_SOURCE_DIR}/src ${Boost_INCLUDE_DIRS} ${DCMTK_INCLUDE_DIRS}
${JsonCpp_INCLUDE_DIRS})
+
add_definitions(
${DCMTK_DEFINITIONS}
- -D BOOST_ASIO_DYN_LINK
-D ODIL_MAJOR_VERSION=${odil_MAJOR_VERSION}
)
+if(BUILD_SHARED_LIBS)
+ add_definitions(-D BOOST_ALL_DYN_LINK)
+endif()
+
link_directories(${Boost_LIBRARY_DIRS} ${DCMTK_LIBRARY_DIRS})
file(GLOB_RECURSE examples *.cpp)
diff --git a/examples/find.cpp b/examples/find.cpp
index 7540efc..39458bc 100644
--- a/examples/find.cpp
+++ b/examples/find.cpp
@@ -8,11 +8,11 @@
void print_informations(odil::DataSet const & response)
{
- auto const name = response.has("PatientName")?
+ auto const name = (response.has("PatientName") && !response.empty("PatientName"))?
response.as_string("PatientName", 0):"(no name)";
- auto const study = response.has("StudyDescription")?
+ auto const study = (response.has("StudyDescription") && !response.empty("StudyDescription"))?
response.as_string("StudyDescription", 0):"(no description)";
- auto const date = response.has("StudyDate")?
+ auto const date = (response.has("StudyDate") && !response.empty("StudyDate"))?
response.as_string("StudyDate", 0):"(no date)";
std::cout
<< "\"" << name << "\": \"" << study << "\" on " << date << "\n";
@@ -56,6 +56,7 @@ int main()
std::cout << "Callback\n";
std::cout << "--------\n\n";
+ // We are re-using the query in the next call to "find", so do not move it.
scu.find(query, print_informations);
std::cout << "\n";
@@ -64,7 +65,8 @@ int main()
std::cout << "vector\n";
std::cout << "------\n\n";
- auto const result = scu.find(query);
+ // We are not re-using the query, so move it.
+ auto const result = scu.find(std::move(query));
for(auto const & dataset: result)
{
print_informations(dataset);
diff --git a/examples/genericscp.cpp b/examples/genericscp.cpp
index 3bd0a3c..05ad03d 100644
--- a/examples/genericscp.cpp
+++ b/examples/genericscp.cpp
@@ -5,6 +5,7 @@
#include "odil/EchoSCP.h"
#include "odil/FindSCP.h"
#include "odil/StoreSCP.h"
+#include "odil/NSetSCP.h"
#include "odil/registry.h"
#include "odil/SCPDispatcher.h"
#include "odil/SCP.h"
@@ -13,6 +14,7 @@
#include "odil/message/CFindRequest.h"
#include "odil/message/CFindResponse.h"
#include "odil/message/CStoreRequest.h"
+#include "odil/message/NSetRequest.h"
class FindGenerator: public odil::SCP::DataSetGenerator
{
@@ -79,15 +81,27 @@ odil::Value::Integer store(odil::message::CStoreRequest const & request)
return odil::message::Response::Success;
}
+odil::Value::Integer nset(odil::message::NSetRequest const & request)
+{
+ std::cout << "NSetRequest message ID: " << request.get_message_id() <<"\n";
+ std::cout << "NSetRequest requested SOP Class UID: " << request.get_requested_sop_class_uid()<<"\n";
+
+ return odil::message::Response::Success;
+}
+
int main()
{
odil::Association association;
+ while (true)
+ {
+ std::cout << "Waiting for an association on port : 11112..." << std::endl;
+
association.receive_association(boost::asio::ip::tcp::v4(), 11112);
std::cout
<< "Received association from "
<< association.get_peer_host() << ":" << association.get_peer_port()
- << "\n";
+ << std::endl ;
auto const & contexts =
association.get_negotiated_parameters().get_presentation_contexts();
@@ -95,7 +109,7 @@ int main()
for(auto const & context: contexts)
{
std::cout
- << " "
+ << "\t"
<< odil::registry::uids_dictionary.at(context.abstract_syntax).name
<< ": "
<< odil::registry::uids_dictionary.at(context.transfer_syntaxes[0]).name
@@ -110,12 +124,15 @@ int main()
auto find_scp = std::make_shared<odil::FindSCP>(
association, std::make_shared<FindGenerator>());
auto store_scp = std::make_shared<odil::StoreSCP>(association, store);
+ auto nset_scp = std::make_shared<odil::NSetSCP>(association, nset);
odil::SCPDispatcher dispatcher(association);
dispatcher.set_scp(odil::message::Message::Command::C_ECHO_RQ, echo_scp);
dispatcher.set_scp(odil::message::Message::Command::C_FIND_RQ, find_scp);
dispatcher.set_scp(
odil::message::Message::Command::C_STORE_RQ, store_scp);
+ dispatcher.set_scp(
+ odil::message::Message::Command::N_SET_RQ, nset_scp);
bool done = false;
while(!done)
@@ -139,4 +156,5 @@ int main()
done = true;
}
}
+ }
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e17e565..0ebd955 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,4 +1,4 @@
-find_package(Boost REQUIRED COMPONENTS filesystem system)
+find_package(Boost REQUIRED COMPONENTS date_time filesystem system)
find_package(ICU REQUIRED)
find_package(JsonCpp REQUIRED)
find_package(Log4Cpp REQUIRED)
@@ -9,6 +9,9 @@ endif()
file(GLOB_RECURSE Header_Files "*.h")
file(GLOB_RECURSE Source_Files "*.cpp")
file(GLOB_RECURSE templates "*.txx")
+list(SORT Header_Files)
+list(SORT Source_Files)
+list(SORT templates)
if(NOT WITH_DCMTK)
set(pattern "${CMAKE_CURRENT_SOURCE_DIR}/odil/dcmtk/[^;]+[;$]")
@@ -24,11 +27,16 @@ GroupFiles(Source_Files)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR} ${Boost_INCLUDE_DIRS} ${DCMTK_INCLUDE_DIRS}
${ICU_INCLUDE_DIRS} ${Log4Cpp_INCLUDE_DIRS} ${JsonCpp_INCLUDE_DIRS})
+
add_definitions(
${DCMTK_DEFINITIONS}
-D BOOST_ASIO_SEPARATE_COMPILATION
-D ODIL_MAJOR_VERSION=${odil_MAJOR_VERSION}
)
+if(BUILD_SHARED_LIBS)
+ add_definitions(-D BOOST_ALL_DYN_LINK)
+endif()
+
link_directories(${Boost_LIBRARY_DIRS} ${DCMTK_LIBRARY_DIRS})
add_library(libodil ${Source_Files} ${Header_Files} ${templates})
diff --git a/src/odil/Association.cpp b/src/odil/Association.cpp
index 001ab87..b4dd53f 100644
--- a/src/odil/Association.cpp
+++ b/src/odil/Association.cpp
@@ -195,7 +195,7 @@ bool
Association
::is_associated() const
{
- return this->_state_machine.get_transport().is_open();
+ return this->_state_machine.get_transport().is_open() && this->_state_machine.get_state() == odil::dul::StateMachine::State::Sta6 ;
}
void
@@ -442,13 +442,13 @@ Association
}
Reader reader(data_stream, transfer_syntax_it->second);
- auto const data_set = reader.read_data_set();
+ auto data_set = reader.read_data_set();
- return message::Message(command_set, data_set);
+ return message::Message(std::move(command_set), std::move(data_set));
}
else
{
- return message::Message(command_set);
+ return message::Message(std::move(command_set));
}
}
diff --git a/src/odil/Association.h b/src/odil/Association.h
index b49ca25..81ce872 100644
--- a/src/odil/Association.h
+++ b/src/odil/Association.h
@@ -19,6 +19,7 @@
#include "odil/AssociationParameters.h"
#include "odil/dul/StateMachine.h"
#include "odil/message/Message.h"
+#include "odil/odil.h"
namespace odil
{
@@ -26,7 +27,7 @@ namespace odil
/**
* @brief Association.
*/
-class Association
+class ODIL_API Association
{
public:
/// @brief Association result (ITU-T X.227, PS 3.8, 7.1.1.7 and PS 3.8, 9.3.4).
@@ -142,7 +143,7 @@ public:
/// @brief Test whether the object is currently associated to its peer.
bool is_associated() const;
- /// @brief Request an association with the peer.
+ /// @brief Request an association with the peer. Throws an exception if the endpoint can not be reached.
void associate();
/// @brief Receive an association from a peer.
@@ -200,7 +201,7 @@ private:
* @brief Exception reported when receiving a message after the association was
* released.
*/
-class AssociationReleased: public Exception
+class ODIL_API AssociationReleased: public Exception
{
public:
AssociationReleased()
@@ -214,7 +215,7 @@ public:
* @brief Exception reported when receiving a message after the association was
* aborted.
*/
-class AssociationAborted: public Exception
+class ODIL_API AssociationAborted: public Exception
{
public:
/// @brief Source of the error.
diff --git a/src/odil/AssociationAcceptor.h b/src/odil/AssociationAcceptor.h
index 815136c..c032431 100644
--- a/src/odil/AssociationAcceptor.h
+++ b/src/odil/AssociationAcceptor.h
@@ -14,6 +14,7 @@
#include "odil/AssociationParameters.h"
#include "odil/Exception.h"
+#include "odil/odil.h"
namespace odil
{
@@ -35,11 +36,12 @@ typedef
* and the roles of each presentation context, do not check identity,
* keep maximum length.
*/
+ODIL_API
AssociationParameters
default_association_acceptor(AssociationParameters const & input);
/// @brief Exception reported when an incoming association is rejected.
-struct AssociationRejected: public Exception
+struct ODIL_API AssociationRejected: public Exception
{
public:
/// @brief Constructor.
diff --git a/src/odil/AssociationParameters.cpp b/src/odil/AssociationParameters.cpp
index 6d9d605..aabb590 100644
--- a/src/odil/AssociationParameters.cpp
+++ b/src/odil/AssociationParameters.cpp
@@ -115,7 +115,9 @@ AssociationParameters
AssociationParameters
::AssociationParameters(pdu::AAssociateRQ const & pdu)
: _called_ae_title(""), _calling_ae_title(""), _presentation_contexts(),
- _user_identity(), _maximum_length(16384)
+ _user_identity({UserIdentity::Type::None, "", ""}), _maximum_length(16384),
+ _maximum_number_operations_invoked(1), _maximum_number_operations_performed(1),
+ _sop_class_extended_negotiation(), _sop_class_common_extended_negotiation()
{
this->set_called_ae_title(pdu.get_called_ae_title());
this->set_calling_ae_title(pdu.get_calling_ae_title());
@@ -202,6 +204,10 @@ AssociationParameters
AssociationParameters
::AssociationParameters(
pdu::AAssociateAC const & pdu, AssociationParameters const & request)
+: _called_ae_title(""), _calling_ae_title(""), _presentation_contexts(),
+ _user_identity({UserIdentity::Type::None, "", ""}), _maximum_length(16384),
+ _maximum_number_operations_invoked(1), _maximum_number_operations_performed(1),
+ _sop_class_extended_negotiation(), _sop_class_common_extended_negotiation()
{
// Calling and Called AE titles are not meaningful in A-ASSOCIATE-AC
this->set_called_ae_title(request.get_called_ae_title());
diff --git a/src/odil/AssociationParameters.h b/src/odil/AssociationParameters.h
index d11d582..bb53944 100644
--- a/src/odil/AssociationParameters.h
+++ b/src/odil/AssociationParameters.h
@@ -13,6 +13,7 @@
#include <string>
#include <vector>
+#include "odil/odil.h"
#include "odil/pdu/AAssociateAC.h"
#include "odil/pdu/AAssociateRQ.h"
#include "odil/pdu/SOPClassCommonExtendedNegotiation.h"
@@ -22,14 +23,14 @@ namespace odil
{
/// @brief Encapsulate association parameters
-class AssociationParameters
+class ODIL_API AssociationParameters
{
public:
/**
* @brief Presentation Context, cf. PS 3.8, 9.3.2.2, PS 3.8, 9.3.3.2,
* PS 3.7, D.3.3.4.1 and PS 3.7 D.3.3.4.2.
*/
- struct PresentationContext
+ struct ODIL_API PresentationContext
{
/// @brief Result of the presentation context negotiation.
enum class Result
@@ -71,7 +72,7 @@ public:
};
/// @brief User Identity, cf. PS3.8 D.3.3.7
- struct UserIdentity
+ struct ODIL_API UserIdentity
{
/// @brief User identity type.
enum class Type
diff --git a/src/odil/BasicDirectoryCreator.h b/src/odil/BasicDirectoryCreator.h
index e84354f..26eab26 100644
--- a/src/odil/BasicDirectoryCreator.h
+++ b/src/odil/BasicDirectoryCreator.h
@@ -16,6 +16,7 @@
#include <vector>
#include "odil/DataSet.h"
+#include "odil/odil.h"
#include "odil/Tag.h"
#include "odil/Writer.h"
@@ -23,7 +24,7 @@ namespace odil
{
/// @brief Write a Basic Directory (i.e. DICOMDIR) object to the disk.
-class BasicDirectoryCreator
+class ODIL_API BasicDirectoryCreator
{
public:
/// @brief The tag and its associated type in the record.
diff --git a/src/odil/DataSet.cpp b/src/odil/DataSet.cpp
index 493c788..91d2650 100644
--- a/src/odil/DataSet.cpp
+++ b/src/odil/DataSet.cpp
@@ -32,103 +32,96 @@ void
DataSet
::add(Tag const & tag, Element const & element)
{
- this->_elements[tag] = element;
-}
-
-
-void
-DataSet
-::add(Tag const & tag, VR vr)
-{
- Value value;
-
- if(vr == VR::UNKNOWN)
- {
- vr = as_vr(tag);
- }
-
- if(::odil::is_int(vr))
- {
- value = Value::Integers();
- }
- else if(::odil::is_real(vr))
- {
- value = Value::Reals();
- }
- else if(::odil::is_string(vr))
- {
- value = Value::Strings();
- }
- else if(::odil::is_binary(vr))
- {
- value = Value::Binary();
- }
- else if(vr == VR::SQ)
+ auto const iterator = this->_elements.find(tag);
+ if(iterator == this->_elements.end())
{
- value = Value::DataSets();
+ // WARNING: std::map<K,V>::emplace does not exist on old compilers.
+ // This is however a case of non-mandatory copy elision, so the copy
+ // constructor of element should only be called once.
+ this->_elements.insert(std::make_pair(tag, element));
+ //this->_elements.emplace(tag, element);
}
else
{
- throw Exception("Unknown VR: "+::odil::as_string(vr));
- }
-
- this->add(tag, Element(value, vr));
-}
-
-void
-DataSet
-::add(Tag const & tag, Value::Integers const & value, VR vr)
-{
- if(vr == VR::UNKNOWN)
- {
- vr = as_vr(tag);
+ iterator->second = element;
}
- this->add(tag, Element(value, vr));
}
void
DataSet
-::add(Tag const & tag, Value::Reals const & value, VR vr)
+::add(Tag const & tag, Element && element)
{
- if(vr == VR::UNKNOWN)
+ auto const iterator = this->_elements.find(tag);
+ if(iterator == this->_elements.end())
{
- vr = as_vr(tag);
+ // WARNING: std::map<K,V>::emplace does not exist on old compilers.
+ this->_elements.insert(std::make_pair(tag, std::move(element)));
+ //this->_elements.emplace(tag, std::move(element));
}
- this->add(tag, Element(value, vr));
-}
-
-void
-DataSet
-::add(Tag const & tag, Value::Strings const & value, VR vr)
-{
- if(vr == VR::UNKNOWN)
+ else
{
- vr = as_vr(tag);
+ iterator->second = element;
}
- this->add(tag, Element(value, vr));
}
void
DataSet
-::add(Tag const & tag, Value::DataSets const & value, VR vr)
+::add(Tag const & tag, VR vr)
{
if(vr == VR::UNKNOWN)
{
vr = as_vr(tag);
}
- this->add(tag, Element(value, vr));
-}
-void
-DataSet
-::add(Tag const & tag, Value::Binary const & value, VR vr)
-{
- if(vr == VR::UNKNOWN)
- {
- vr = as_vr(tag);
+ this->add(tag, Element(vr));
+}
+
+#define ODIL_DATASET_ADD(type) \
+ void\
+ DataSet\
+ ::add(\
+ Tag const & tag, Value::type const & value, VR vr)\
+ { \
+ if(vr == VR::UNKNOWN)\
+ {\
+ vr = as_vr(tag);\
+ }\
+ this->add(tag, Element(value, vr));\
+ }\
+ void\
+ DataSet\
+ ::add(\
+ Tag const & tag, Value::type && value, VR vr)\
+ { \
+ if(vr == VR::UNKNOWN)\
+ {\
+ vr = as_vr(tag);\
+ }\
+ this->add(tag, Element(std::move(value), vr));\
+ }\
+ void\
+ DataSet\
+ ::add(\
+ Tag const & tag, \
+ std::initializer_list<Value::type::value_type> const & value, VR vr)\
+ { \
+ if(vr == VR::UNKNOWN)\
+ {\
+ vr = as_vr(tag);\
+ }\
+ this->add(tag, Element(value, vr));\
}
- this->add(tag, Element(value, vr));
-}
+ /*
+ * No need for for a rvalue reference version of std::initializer_list:
+ * copying a std::initializer_list does not copy the underlying objects.
+ */
+
+ ODIL_DATASET_ADD(Integers);
+ ODIL_DATASET_ADD(Reals);
+ ODIL_DATASET_ADD(Strings);
+ ODIL_DATASET_ADD(DataSets);
+ ODIL_DATASET_ADD(Binary);
+#undef ODIL_DATASET_ADD
void
DataSet
@@ -144,43 +137,8 @@ DataSet
void
DataSet
::add(
- Tag const & tag, std::initializer_list<Value::Integer> const & value, VR vr)
-{
- if(vr == VR::UNKNOWN)
- {
- vr = as_vr(tag);
- }
- this->add(tag, Element(value, vr));
-}
-
-void
-DataSet
-::add(
- Tag const & tag, std::initializer_list<Value::Real> const & value, VR vr)
-{
- if(vr == VR::UNKNOWN)
- {
- vr = as_vr(tag);
- }
- this->add(tag, Element(value, vr));
-}
-
-void
-DataSet
-::add(
- Tag const & tag, std::initializer_list<Value::String> const & value, VR vr)
-{
- if(vr == VR::UNKNOWN)
- {
- vr = as_vr(tag);
- }
- this->add(tag, Element(value, vr));
-}
-
-void
-DataSet
-::add(
- Tag const & tag, std::initializer_list<DataSet> const & value, VR vr)
+ Tag const & tag,
+ std::initializer_list<std::initializer_list<uint8_t>> const & value, VR vr)
{
if(vr == VR::UNKNOWN)
{
@@ -195,7 +153,7 @@ DataSet
{
if(!this->has(tag))
{
- throw Exception("No such element");
+ throw Exception("No such element " + std::string( tag ));
}
this->_elements.erase(tag);
@@ -222,7 +180,7 @@ DataSet
ElementMap::const_iterator const it = this->_elements.find(tag);
if(it == this->_elements.end())
{
- throw Exception("No such element");
+ throw Exception("No such element " + std::string( tag ));
}
return it->second;
@@ -235,7 +193,7 @@ DataSet
ElementMap::iterator it = this->_elements.find(tag);
if(it == this->_elements.end())
{
- throw Exception("No such element");
+ throw Exception("No such element " + std::string( tag ));
}
return it->second;
@@ -406,7 +364,7 @@ DataSet
ElementMap::const_iterator const it = this->_elements.find(tag);
if(it == this->_elements.end())
{
- throw Exception("No such element");
+ throw Exception("No such element "+ std::string(tag) );
}
return it->second.vr;
@@ -419,7 +377,7 @@ DataSet
ElementMap::const_iterator const it = this->_elements.find(tag);
if(it == this->_elements.end())
{
- throw Exception("No such element");
+ throw Exception("No such element " + std::string( tag ) );
}
return it->second.empty();
@@ -432,12 +390,26 @@ DataSet
ElementMap::const_iterator const it = this->_elements.find(tag);
if(it == this->_elements.end())
{
- throw Exception("No such element");
+ throw Exception("No such element " + std::string( tag ));
}
return it->second.size();
}
+DataSet::const_iterator
+DataSet
+::begin() const
+{
+ return this->_elements.begin();
+}
+
+DataSet::const_iterator
+DataSet
+::end() const
+{
+ return this->_elements.end();
+}
+
bool
DataSet
::operator==(DataSet const & other) const
@@ -452,6 +424,19 @@ DataSet
return !(*this == other);
}
+void
+DataSet
+::clear(Tag const & tag)
+{
+ ElementMap::iterator const it = this->_elements.find(tag);
+ if(it == this->_elements.end())
+ {
+ throw Exception("No such element: "+std::string(tag));
+ }
+
+ it->second.clear();
+}
+
std::string const &
DataSet
::get_transfer_syntax() const
diff --git a/src/odil/DataSet.h b/src/odil/DataSet.h
index ff59454..c49c1c7 100644
--- a/src/odil/DataSet.h
+++ b/src/odil/DataSet.h
@@ -17,6 +17,7 @@
#include <vector>
#include "odil/Element.h"
+#include "odil/odil.h"
#include "odil/Value.h"
namespace odil
@@ -25,61 +26,61 @@ namespace odil
/**
* @brief DICOM Data set.
*/
-class DataSet
+class ODIL_API DataSet
{
public:
/// @brief Create an empty data set.
explicit DataSet(std::string const & transfer_syntax="");
- /// @brief Add an element to the dataset.
- void add(Tag const & tag, Element const & element);
-
- /// @brief Add an empty element to the dataset.
- void add(Tag const & tag, VR vr=VR::UNKNOWN);
-
- /// @brief Add an element to the dataset.
- void add(
- Tag const & tag, Value::Integers const & value, VR vr=VR::UNKNOWN);
-
- /// @brief Add an element to the dataset.
- void add(
- Tag const & tag, Value::Reals const & value, VR vr=VR::UNKNOWN);
-
- /// @brief Add an element to the dataset.
- void add(
- Tag const & tag, Value::Strings const & value, VR vr=VR::UNKNOWN);
+ /** @addtogroup default_operations Default class operations
+ * @{
+ */
+ ~DataSet() =default;
+ DataSet(DataSet const &) =default;
+ DataSet(DataSet &&) =default;
+ DataSet & operator=(DataSet const &) =default;
+ DataSet & operator=(DataSet &&) =default;
+ /// @}
/// @brief Add an element to the dataset.
- void add(
- Tag const & tag, Value::DataSets const & value, VR vr=VR::UNKNOWN);
+ void add(Tag const & tag, Element const & element);
/// @brief Add an element to the dataset.
- void add(
- Tag const & tag, Value::Binary const & value, VR vr=VR::UNKNOWN);
+ void add(Tag const & tag, Element && element);
- /// @brief Add an element to the dataset.
- void add(
- Tag const & tag, std::initializer_list<int> const & value,
- VR vr=VR::UNKNOWN);
+ /// @brief Add an empty element to the dataset.
+ void add(Tag const & tag, VR vr=VR::UNKNOWN);
- /// @brief Add an element to the dataset.
- void add(
- Tag const & tag, std::initializer_list<Value::Integer> const & value,
+#define ODIL_DATASET_ADD(type) \
+ void add(\
+ Tag const & tag, Value::type const & value, VR vr=VR::UNKNOWN);\
+ void add(\
+ Tag const & tag, Value::type && value, VR vr=VR::UNKNOWN); \
+ void add(\
+ Tag const & tag, \
+ std::initializer_list<Value::type::value_type> const & value, \
VR vr=VR::UNKNOWN);
+ /*
+ * No need for for a rvalue reference version of std::initializer_list:
+ * copying a std::initializer_list does not copy the underlying objects.
+ */
- /// @brief Add an element to the dataset.
- void add(
- Tag const & tag, std::initializer_list<Value::Real> const & value,
- VR vr=VR::UNKNOWN);
+ ODIL_DATASET_ADD(Integers);
+ ODIL_DATASET_ADD(Reals);
+ ODIL_DATASET_ADD(Strings);
+ ODIL_DATASET_ADD(DataSets);
+ ODIL_DATASET_ADD(Binary);
+#undef ODIL_DATASET_ADD
/// @brief Add an element to the dataset.
void add(
- Tag const & tag, std::initializer_list<Value::String> const & value,
+ Tag const & tag, std::initializer_list<int> const & value,
VR vr=VR::UNKNOWN);
/// @brief Add an element to the dataset.
void add(
- Tag const & tag, std::initializer_list<DataSet> const & value,
+ Tag const & tag,
+ std::initializer_list<std::initializer_list<uint8_t>> const & value,
VR vr=VR::UNKNOWN);
/**
@@ -198,10 +199,10 @@ public:
typedef std::map<Tag, Element>::const_iterator const_iterator;
/// @brief Return an iterator to the start of the elements.
- const_iterator begin() const { return this->_elements.begin(); }
+ const_iterator begin() const;
/// @brief Return an iterator to the end of the elements.
- const_iterator end() const { return this->_elements.end(); }
+ const_iterator end() const;
/// @brief Equality test.
bool operator==(DataSet const & other) const;
@@ -209,6 +210,9 @@ public:
/// @brief Difference test.
bool operator!=(DataSet const & other) const;
+ /// @brief Clear the element (data_set.empty(tag) will be true).
+ void clear(Tag const & tag);
+
/// @brief Return the current transfer syntax.
std::string const & get_transfer_syntax() const;
diff --git a/src/odil/EchoSCP.cpp b/src/odil/EchoSCP.cpp
index e80e24b..e9872fc 100644
--- a/src/odil/EchoSCP.cpp
+++ b/src/odil/EchoSCP.cpp
@@ -58,7 +58,21 @@ EchoSCP
::operator()(message::Message const & message)
{
message::CEchoRequest const request(message);
+ this->operator()(request);
+}
+void
+EchoSCP
+::operator()(message::Message && message)
+{
+ message::CEchoRequest const request(std::move(message));
+ this->operator()(request);
+}
+
+void
+EchoSCP
+::operator()(message::CEchoRequest const & request)
+{
Value::Integer status=message::CEchoResponse::Success;
DataSet status_fields;
diff --git a/src/odil/EchoSCP.h b/src/odil/EchoSCP.h
index 5fa0433..b5e30aa 100644
--- a/src/odil/EchoSCP.h
+++ b/src/odil/EchoSCP.h
@@ -12,6 +12,7 @@
#include <functional>
#include "odil/Association.h"
+#include "odil/odil.h"
#include "odil/SCP.h"
#include "odil/Value.h"
#include "odil/message/CEchoRequest.h"
@@ -21,7 +22,7 @@ namespace odil
{
/// @brief SCP for C-Echo services.
-class EchoSCP: public SCP
+class ODIL_API EchoSCP: public SCP
{
public:
/**
@@ -48,8 +49,12 @@ public:
/// @brief Process a C-Echo request.
virtual void operator()(message::Message const & message);
+ /// @brief Process a C-Echo request.
+ virtual void operator()(message::Message && message);
+
private:
Callback _callback;
+ void operator()(message::CEchoRequest const & request);
};
}
diff --git a/src/odil/EchoSCU.h b/src/odil/EchoSCU.h
index 5ad96d8..a912924 100644
--- a/src/odil/EchoSCU.h
+++ b/src/odil/EchoSCU.h
@@ -10,13 +10,14 @@
#define _94f3b347_1f95_49ab_83f6_8710f5a3ad67
#include "odil/Association.h"
+#include "odil/odil.h"
#include "odil/SCU.h"
namespace odil
{
/// @brief SCU for the C-ECHO services.
-class EchoSCU: public SCU
+class ODIL_API EchoSCU: public SCU
{
public:
/// @brief Constructor
diff --git a/src/odil/Element.cpp b/src/odil/Element.cpp
index 4ac0d7d..eb749bc 100644
--- a/src/odil/Element.cpp
+++ b/src/odil/Element.cpp
@@ -8,6 +8,10 @@
#include "odil/Element.h"
+#include <initializer_list>
+#include <utility>
+
+#include "odil/Exception.h"
#include "odil/Value.h"
#include "odil/DataSet.h"
@@ -15,78 +19,93 @@ namespace odil
{
Element
-::Element(Value const & value, VR const & vr)
-: _value(value), vr(vr)
-{
- // Nothing else
+::Element(VR const & vr)
+: _value(Value::Integers()), vr(vr)
+{
+ if(odil::is_int(vr))
+ {
+ this->_value = Value::Integers();
+ }
+ else if(odil::is_real(vr))
+ {
+ this->_value = Value::Reals();
+ }
+ else if(odil::is_string(vr))
+ {
+ this->_value = Value::Strings();
+ }
+ else if(vr == VR::SQ)
+ {
+ this->_value = Value::DataSets();
+ }
+ else if(odil::is_binary(vr))
+ {
+ this->_value = Value::Binary();
+ }
+ else
+ {
+ throw Exception("Unknown VR type");
+ }
}
Element
-::Element(Value::Integers const & value, VR const & vr)
-: _value(value), vr(vr)
-{
- // Nothing else
-}
-
-Element
-::Element(Value::Reals const & value, VR const & vr)
-: _value(value), vr(vr)
-{
- // Nothing else
-}
-
-Element
-::Element(Value::Strings const & value, VR const & vr)
+::Element(Value const & value, VR const & vr)
: _value(value), vr(vr)
{
// Nothing else
}
Element
-::Element(Value::DataSets const & value, VR const & vr)
-: _value(value), vr(vr)
+::Element(Value && value, VR const & vr)
+: _value(std::move(value)), vr(vr)
{
// Nothing else
}
-Element
-::Element(Value::Binary const & value, VR const & vr)
-: _value(value), vr(vr)
-{
- // Nothing else
-}
+#define ODIL_ELEMENT_CONSTRUCTORS(type) \
+ Element\
+ ::Element(Value::type const & value, VR const & vr)\
+ : vr(vr), _value(value)\
+ {\
+ }\
+ \
+ Element\
+ ::Element(Value::type && value, VR const & vr)\
+ : vr(vr), _value(std::move(value))\
+ {\
+ }\
+ \
+ Element\
+ ::Element(\
+ std::initializer_list<Value::type::value_type> const & value, \
+ VR const & vr)\
+ : vr(vr), _value(value)\
+ {\
+ }
+ /*
+ * No need for for a rvalue reference version of std::initializer_list:
+ * copying a std::initializer_list does not copy the underlying objects.
+ */
+
+ ODIL_ELEMENT_CONSTRUCTORS(Integers);
+ ODIL_ELEMENT_CONSTRUCTORS(Reals);
+ ODIL_ELEMENT_CONSTRUCTORS(Strings);
+ ODIL_ELEMENT_CONSTRUCTORS(DataSets);
+ ODIL_ELEMENT_CONSTRUCTORS(Binary);
+#undef ODIL_ELEMENT_CONSTRUCTORS
Element
::Element(std::initializer_list<int> const & value, VR const & vr)
-: _value(value), vr(vr)
+: vr(vr), _value(value)
{
// Nothing else
}
Element
-::Element(std::initializer_list<Value::Integer> const & value, VR const & vr)
-: _value(value), vr(vr)
-{
- // Nothing else
-}
-
-Element
-::Element(std::initializer_list<Value::Real> const & value, VR const & vr)
-: _value(value), vr(vr)
-{
- // Nothing else
-}
-
-Element
-::Element(std::initializer_list<Value::String> const & value, VR const & vr)
-: _value(value), vr(vr)
-{
- // Nothing else
-}
-
-Element
-::Element(std::initializer_list<DataSet> const & value, VR const & vr)
-: _value(value), vr(vr)
+::Element(
+ std::initializer_list<std::initializer_list<uint8_t>> const & value,
+ VR const & vr)
+: vr(vr), _value(value)
{
// Nothing else
}
@@ -95,18 +114,14 @@ bool
Element
::empty() const
{
- return (
- (this->_value.get_type() == Value::Type::Empty) ||
- apply_visitor(Empty(), this->_value));
+ return this->_value.empty();
}
std::size_t
Element
::size() const
{
- return (
- (this->_value.get_type() == Value::Type::Empty)?0:
- apply_visitor(Size(), this->_value));
+ return this->_value.size();
}
Value const &
@@ -233,4 +248,12 @@ Element
return !(*this == other);
}
+void
+Element
+::clear()
+{
+ this->_value.clear();
+}
+
}
+
diff --git a/src/odil/Element.h b/src/odil/Element.h
index 917cab2..3b0ccfb 100644
--- a/src/odil/Element.h
+++ b/src/odil/Element.h
@@ -12,6 +12,7 @@
#include <cstddef>
#include <initializer_list>
+#include "odil/odil.h"
#include "odil/Tag.h"
#include "odil/Value.h"
#include "odil/VR.h"
@@ -22,54 +23,56 @@ namespace odil
/**
* @brief Element of a DICOM data set.
*/
-class Element
+class ODIL_API Element
{
public:
/// @brief VR of the element.
VR vr;
- /// @brief Constructor.
- Element(Value const & value=Value(), VR const & vr=VR::INVALID);
-
- /// @brief Constructor.
- Element(Value::Integers const & value, VR const & vr=VR::INVALID);
+ /// @brief Constructor using the VR to create an according empty container.
+ Element(VR const & vr);
/// @brief Constructor.
- Element(Value::Reals const & value, VR const & vr=VR::INVALID);
+ Element(Value const & value, VR const & vr);
/// @brief Constructor.
- Element(Value::Strings const & value, VR const & vr=VR::INVALID);
+ Element(Value && value, VR const & vr);
- /// @brief Constructor.
- Element(Value::DataSets const & value, VR const & vr=VR::INVALID);
+#define ODIL_ELEMENT_CONSTRUCTORS(type) \
+ Element(Value::type const & value, VR const & vr=VR::INVALID); \
+ Element(Value::type && value, VR const & vr=VR::INVALID); \
+ Element(\
+ std::initializer_list<Value::type::value_type> const & value, \
+ VR const & vr=VR::INVALID);
+ /*
+ * No need for for a rvalue reference version of std::initializer_list:
+ * copying a std::initializer_list does not copy the underlying objects.
+ */
- /// @brief Constructor.
- Element(Value::Binary const & value, VR const & vr=VR::INVALID);
+ ODIL_ELEMENT_CONSTRUCTORS(Integers);
+ ODIL_ELEMENT_CONSTRUCTORS(Reals);
+ ODIL_ELEMENT_CONSTRUCTORS(Strings);
+ ODIL_ELEMENT_CONSTRUCTORS(DataSets);
+ ODIL_ELEMENT_CONSTRUCTORS(Binary);
+#undef ODIL_ELEMENT_CONSTRUCTORS
- /// @brief Constructor.
Element(
std::initializer_list<int> const & value, VR const & vr=VR::INVALID);
- /// @brief Constructor.
Element(
- std::initializer_list<Value::Integer> const & value,
+ std::initializer_list<std::initializer_list<uint8_t>> const & value,
VR const & vr=VR::INVALID);
- /// @brief Constructor.
- Element(
- std::initializer_list<Value::Real> const & value,
- VR const & vr=VR::INVALID);
-
- /// @brief Constructor.
- Element(
- std::initializer_list<Value::String> const & value,
- VR const & vr=VR::INVALID);
-
- /// @brief Constructor.
- Element(
- std::initializer_list<DataSet> const & value,
- VR const & vr=VR::INVALID);
+ /** @addtogroup default_operations Default class operations
+ * @{
+ */
+ ~Element() =default;
+ Element(Element const &) =default;
+ Element(Element &&) =default;
+ Element & operator=(Element const &) =default;
+ Element & operator=(Element &&) =default;
+ /// @}
/// @brief Test whether the element is empty.
bool empty() const;
@@ -170,31 +173,11 @@ public:
/// @brief Difference test
bool operator!=(Element const & other) const;
+
+ /// @brief Clear the element (element.empty() will be true).
+ void clear();
private:
- struct Empty
- {
- typedef bool result_type;
-
- template<typename T>
- bool operator()(T const & container) const
- {
- return container.empty();
- }
- };
-
- struct Size
- {
- typedef std::size_t result_type;
-
- template<typename T>
- std::size_t operator()(T const & container) const
- {
- return container.size();
- }
- };
-
-
Value _value;
};
@@ -211,3 +194,4 @@ apply_visitor(TVisitor const & visitor, Element const & element);
#include "odil/Element.txx"
#endif // _9c3d8f32_0310_4e3a_b5d2_6d69f229a2cf
+
diff --git a/src/odil/ElementsDictionary.h b/src/odil/ElementsDictionary.h
index 0179767..929b622 100644
--- a/src/odil/ElementsDictionary.h
+++ b/src/odil/ElementsDictionary.h
@@ -12,63 +12,64 @@
#include <map>
#include <string>
-#include <odil/Tag.h>
+#include "odil/odil.h"
+#include "odil/Tag.h"
namespace odil
{
- /// @brief Key of a dictionary of DICOM elements.
- class ElementsDictionaryKey
+/// @brief Key of a dictionary of DICOM elements.
+class ODIL_API ElementsDictionaryKey
+{
+public:
+ /// @brief Type of the key.
+ enum class Type
{
- public:
- /// @brief Type of the key.
- enum class Type
- {
- Tag,
- String,
- None
- };
+ Tag,
+ String,
+ None
+ };
- /// @brief Create a key with type equal to None.
- ElementsDictionaryKey();
+ /// @brief Create a key with type equal to None.
+ ElementsDictionaryKey();
- /// @brief Create a key with type equal to Tag.
- ElementsDictionaryKey(Tag const & value);
+ /// @brief Create a key with type equal to Tag.
+ ElementsDictionaryKey(Tag const & value);
- /// @brief Create a key with type equal to String.
- ElementsDictionaryKey(std::string const & value);
+ /// @brief Create a key with type equal to String.
+ ElementsDictionaryKey(std::string const & value);
- /// @brief Return the type.
- Type const & get_type() const;
+ /// @brief Return the type.
+ Type const & get_type() const;
- /// @brief Return the tag value or raise an exception if type is not Tag.
- Tag const & get_tag() const;
+ /// @brief Return the tag value or raise an exception if type is not Tag.
+ Tag const & get_tag() const;
- /// @brief Return the string value or raise an exception if type is not String.
- std::string const & get_string() const;
+ /// @brief Return the string value or raise an exception if type is not String.
+ std::string const & get_string() const;
- /// @brief Set the type to Tag.
- void set(Tag const value);
+ /// @brief Set the type to Tag.
+ void set(Tag const value);
- /// @brief Set the type to String.
- void set(std::string const & value);
+ /// @brief Set the type to String.
+ void set(std::string const & value);
- /// @brief Comparator.
- bool operator<(ElementsDictionaryKey const & other) const;
+ /// @brief Comparator.
+ bool operator<(ElementsDictionaryKey const & other) const;
- /// @brief Comparator.
- bool operator==(ElementsDictionaryKey const & other) const;
+ /// @brief Comparator.
+ bool operator==(ElementsDictionaryKey const & other) const;
- private:
- Type _type;
- Tag _tag;
- std::string _string;
- };
+private:
+ Type _type;
+ Tag _tag;
+ std::string _string;
+};
/**
* @brief Entry in a dictionary of DICOM elements.
*/
-struct ElementsDictionaryEntry
+struct ODIL_API ElementsDictionaryEntry
{
/// @brief Full name.
std::string name;
@@ -91,6 +92,7 @@ struct ElementsDictionaryEntry
typedef
std::map<ElementsDictionaryKey, ElementsDictionaryEntry> ElementsDictionary;
+ODIL_API
ElementsDictionary::const_iterator
find(ElementsDictionary const & dictionary, Tag const & tag);
diff --git a/src/odil/Exception.h b/src/odil/Exception.h
index 89583d6..12e347d 100644
--- a/src/odil/Exception.h
+++ b/src/odil/Exception.h
@@ -12,11 +12,13 @@
#include <exception>
#include <string>
+#include "odil/odil.h"
+
namespace odil
{
/// @brief Base class for odil exceptions.
-class Exception: public std::exception
+class ODIL_API Exception: public std::exception
{
public:
/// @brief Message string constructor.
diff --git a/src/odil/FindSCP.cpp b/src/odil/FindSCP.cpp
index b45e2b8..b7d9696 100644
--- a/src/odil/FindSCP.cpp
+++ b/src/odil/FindSCP.cpp
@@ -61,7 +61,21 @@ FindSCP
::operator()(message::Message const & message)
{
message::CFindRequest const request(message);
+ this->operator()(request);
+}
+void
+FindSCP
+::operator()(message::Message && message)
+{
+ message::CFindRequest request(std::move(message));
+ this->operator()(request);
+}
+
+void
+FindSCP
+::operator()(message::CFindRequest const & request)
+{
Value::Integer final_status = message::CFindResponse::Success;
DataSet status_fields;
@@ -70,10 +84,10 @@ FindSCP
this->_generator->initialize(request);
while(!this->_generator->done())
{
- auto const data_set = this->_generator->get();
+ auto data_set = this->_generator->get();
message::CFindResponse const response(
request.get_message_id(), message::CFindResponse::Pending,
- data_set);
+ std::move(data_set));
this->_association.send_message(
response, request.get_affected_sop_class_uid());
this->_generator->next();
diff --git a/src/odil/FindSCP.h b/src/odil/FindSCP.h
index eb61994..7e416fc 100644
--- a/src/odil/FindSCP.h
+++ b/src/odil/FindSCP.h
@@ -12,14 +12,16 @@
#include <memory>
#include "odil/Association.h"
+#include "odil/odil.h"
#include "odil/SCP.h"
+#include "odil/message/CFindRequest.h"
#include "odil/message/Message.h"
namespace odil
{
/// @brief SCP for C-Find services.
-class FindSCP: public SCP
+class ODIL_API FindSCP: public SCP
{
public:
@@ -43,8 +45,13 @@ public:
/// @brief Process a C-Find request.
virtual void operator()(message::Message const & message);
+ /// @brief Process a C-Find request.
+ virtual void operator()(message::Message && message);
+
private:
std::shared_ptr<DataSetGenerator> _generator;
+
+ void operator()(message::CFindRequest const & request);
};
}
diff --git a/src/odil/FindSCU.cpp b/src/odil/FindSCU.cpp
index 1c928ae..8b11681 100644
--- a/src/odil/FindSCU.cpp
+++ b/src/odil/FindSCU.cpp
@@ -10,11 +10,13 @@
#include <functional>
#include <sstream>
+#include <utility>
#include <vector>
#include "odil/Association.h"
#include "odil/DataSet.h"
#include "odil/Exception.h"
+#include "odil/logging.h"
#include "odil/message/CFindRequest.h"
#include "odil/message/CFindResponse.h"
@@ -41,6 +43,55 @@ FindSCU
message::CFindRequest request(
this->_association.next_message_id(),
this->_affected_sop_class, message::Message::Priority::MEDIUM, query);
+ this->_find(request, callback);
+}
+
+void
+FindSCU
+::find(DataSet && query, Callback callback) const
+{
+ message::CFindRequest request(
+ this->_association.next_message_id(),
+ this->_affected_sop_class, message::Message::Priority::MEDIUM,
+ std::move(query));
+ this->_find(request, callback);
+}
+
+void _accumulate(std::vector<DataSet> & data_sets, DataSet && data_set)
+{
+ data_sets.push_back(std::move(data_set));
+}
+
+std::vector<DataSet>
+FindSCU
+::find(DataSet const & query) const
+{
+ std::vector<DataSet> result;
+ auto callback = [&result](DataSet && dataset) {
+ result.push_back(std::move(dataset));
+ };
+ this->find(query, callback);
+
+ return result;
+}
+
+std::vector<DataSet>
+FindSCU
+::find(DataSet && query) const
+{
+ std::vector<DataSet> result;
+ auto callback = [&result](DataSet && dataset) {
+ result.push_back(std::move(dataset));
+ };
+ this->find(std::move(query), callback);
+
+ return result;
+}
+
+void
+FindSCU
+::_find(message::CFindRequest const & request, Callback callback) const
+{
this->_association.send_message(request, this->_affected_sop_class);
// Receive the responses
@@ -48,7 +99,7 @@ FindSCU
while(!done)
{
// FIXME: include progress callback
- message::CFindResponse const response =
+ message::CFindResponse response =
this->_association.receive_message();
if(response.get_message_id_being_responded_to() != request.get_message_id())
@@ -69,25 +120,21 @@ FindSCU
throw Exception(message.str());
}
+ if(message::Response::is_warning(response.get_status()))
+ {
+ ODIL_LOG(WARN) << "C-FIND response status: " << response.get_status();
+ }
+ else if(message::Response::is_failure(response.get_status()))
+ {
+ ODIL_LOG(ERROR) << "C-FIND response status: " << response.get_status();
+ }
+
done = !response.is_pending();
if(!done)
{
- callback(response.get_data_set());
+ callback(std::move(response.get_data_set()));
}
}
}
-std::vector<DataSet>
-FindSCU
-::find(DataSet const & query) const
-{
- std::vector<DataSet> result;
- auto callback = [&result](DataSet const & dataset) {
- result.push_back(dataset);
- };
- this->find(query, callback);
-
- return result;
-}
-
}
diff --git a/src/odil/FindSCU.h b/src/odil/FindSCU.h
index 7bb6bd3..e209cf8 100644
--- a/src/odil/FindSCU.h
+++ b/src/odil/FindSCU.h
@@ -13,17 +13,19 @@
#include "odil/Association.h"
#include "odil/DataSet.h"
+#include "odil/message/CFindRequest.h"
+#include "odil/odil.h"
#include "odil/SCU.h"
namespace odil
{
/// @brief SCU for C-FIND services.
-class FindSCU: public SCU
+class ODIL_API FindSCU: public SCU
{
public:
/// @brief Callback called when a response is received.
- typedef std::function<void(DataSet const &)> Callback;
+ typedef std::function<void(DataSet &&)> Callback;
/// @brief Constructor.
FindSCU(Association & association);
@@ -33,12 +35,24 @@ public:
/// @brief Perform the C-FIND using an optional callback.
void find(DataSet const & query, Callback callback) const;
+
+ /// @brief Perform the C-FIND using an optional callback.
+ void find(DataSet && query, Callback callback) const;
/**
* @brief Return a list of datasets matching the query. The user is
* responsible for the de-allocation of the matches.
*/
std::vector<DataSet> find(DataSet const & query) const;
+
+ /**
+ * @brief Return a list of datasets matching the query. The user is
+ * responsible for the de-allocation of the matches.
+ */
+ std::vector<DataSet> find(DataSet && query) const;
+
+private:
+ void _find(message::CFindRequest const & request, Callback callback) const;
};
}
diff --git a/src/odil/GetSCP.cpp b/src/odil/GetSCP.cpp
index 38508b9..875db32 100644
--- a/src/odil/GetSCP.cpp
+++ b/src/odil/GetSCP.cpp
@@ -62,7 +62,21 @@ GetSCP
::operator()(message::Message const & message)
{
message::CGetRequest const request(message);
+ this->operator()(request);
+}
+void
+GetSCP
+::operator()(message::Message && message)
+{
+ message::CGetRequest request(std::move(message));
+ this->operator()(request);
+}
+
+void
+GetSCP
+::operator()(message::CGetRequest const & request)
+{
StoreSCU store_scu(this->_association);
Value::Integer final_status = message::CGetResponse::Success;
@@ -92,11 +106,11 @@ GetSCP
this->_association.send_message(
response, request.get_affected_sop_class_uid());
- auto const data_set = this->_generator->get();
+ auto data_set = this->_generator->get();
store_scu.set_affected_sop_class(data_set);
try
{
- store_scu.store(data_set);
+ store_scu.store(std::move(data_set));
--remaining_sub_operations;
++completed_sub_operations;
diff --git a/src/odil/GetSCP.h b/src/odil/GetSCP.h
index bdc8eb0..1da7d7e 100644
--- a/src/odil/GetSCP.h
+++ b/src/odil/GetSCP.h
@@ -12,14 +12,16 @@
#include <memory>
#include "odil/Association.h"
+#include "odil/odil.h"
#include "odil/SCP.h"
+#include "odil/message/CGetRequest.h"
#include "odil/message/Message.h"
namespace odil
{
/// @brief SCP for C-Get services.
-class GetSCP: public SCP
+class ODIL_API GetSCP: public SCP
{
public:
@@ -51,8 +53,12 @@ public:
/// @brief Process a C-Get request.
virtual void operator()(message::Message const & message);
+ /// @brief Process a C-Get request.
+ virtual void operator()(message::Message && message);
+
private:
std::shared_ptr<DataSetGenerator> _generator;
+ void operator()(message::CGetRequest const & request);
};
}
diff --git a/src/odil/GetSCU.cpp b/src/odil/GetSCU.cpp
index 750a345..73bf329 100644
--- a/src/odil/GetSCU.cpp
+++ b/src/odil/GetSCU.cpp
@@ -15,6 +15,7 @@
#include "odil/Association.h"
#include "odil/DataSet.h"
#include "odil/Exception.h"
+#include "odil/logging.h"
#include "odil/StoreSCP.h"
#include "odil/message/CGetRequest.h"
#include "odil/message/CGetResponse.h"
@@ -46,25 +47,74 @@ GetSCU
message::CGetRequest request(
this->_association.next_message_id(),
this->_affected_sop_class, message::Message::Priority::MEDIUM, query);
+ this->_get(request, store_callback, get_callback);
+}
+
+void
+GetSCU
+::get(
+ DataSet && query, StoreCallback store_callback,
+ GetCallback get_callback) const
+{
+ // Send the request
+ message::CGetRequest request(
+ this->_association.next_message_id(),
+ this->_affected_sop_class, message::Message::Priority::MEDIUM,
+ std::move(query));
+ this->_get(request, store_callback, get_callback);
+}
+
+std::vector<DataSet>
+GetSCU
+::get(DataSet const & query) const
+{
+ std::vector<DataSet> result;
+ auto callback = [&result](DataSet && data_set) {
+ result.push_back(data_set);
+ };
+ this->get(query, callback);
+
+ return result;
+}
+
+std::vector<DataSet>
+GetSCU
+::get(DataSet && query) const
+{
+ std::vector<DataSet> result;
+ auto callback = [&result](DataSet && data_set) {
+ result.push_back(std::move(data_set));
+ };
+ this->get(std::move(query), callback);
+
+ return result;
+}
+
+void
+GetSCU
+::_get(
+ message::CGetRequest const & request,
+ StoreCallback store_callback, GetCallback get_callback) const
+{
this->_association.send_message(request, this->_affected_sop_class);
// Receive the responses
bool done = false;
while(!done)
{
- message::Message const message = this->_association.receive_message();
+ message::Message message = this->_association.receive_message();
if(message.get_command_field() == message::Message::Command::C_GET_RSP)
{
done = this->_handle_get_response(
- message::CGetResponse(message), get_callback);
+ message::CGetResponse(std::move(message)), get_callback);
}
else if(message.get_command_field() == message::Message::Command::C_STORE_RQ)
{
try
{
this->_handle_store_request(
- message::CStoreRequest(message), store_callback);
+ message::CStoreRequest(std::move(message)), store_callback);
}
catch(...)
{
@@ -82,45 +132,45 @@ GetSCU
}
}
-std::vector<DataSet>
-GetSCU
-::get(DataSet const & query) const
-{
- std::vector<DataSet> result;
- auto callback = [&result](DataSet const & data_set) {
- result.push_back(data_set);
- };
- this->get(query, callback);
-
- return result;
-}
-
bool
GetSCU
::_handle_get_response(
- message::CGetResponse const & response, GetCallback callback) const
+ message::CGetResponse && response, GetCallback callback) const
{
+ if(message::Response::is_warning(response.get_status()))
+ {
+ ODIL_LOG(WARN) << "C-GET response status: " << response.get_status();
+ }
+ else if(message::Response::is_failure(response.get_status()))
+ {
+ ODIL_LOG(ERROR) << "C-GET response status: " << response.get_status();
+ }
+
+ // Store status before moving the response.
+ auto const done = !response.is_pending();
+
if(callback)
{
- callback(response);
+ callback(std::move(response));
}
- return !response.is_pending();
+
+ return done;
}
void
GetSCU
::_handle_store_request(
- message::CStoreRequest const & request, StoreCallback callback) const
+ message::CStoreRequest && request, StoreCallback callback) const
{
- auto const store_callback = [&callback](message::CStoreRequest const & request) {
+ auto const store_callback = [&callback](message::CStoreRequest && request) {
if(callback)
{
- callback(request.get_data_set());
+ callback(std::move(request.get_data_set()));
}
return message::Response::Success;
};
StoreSCP scp(this->_association, store_callback);
- scp(request);
+ scp(std::move(request));
}
}
diff --git a/src/odil/GetSCU.h b/src/odil/GetSCU.h
index 292f974..9b19088 100644
--- a/src/odil/GetSCU.h
+++ b/src/odil/GetSCU.h
@@ -14,7 +14,9 @@
#include "odil/Association.h"
#include "odil/DataSet.h"
+#include "odil/odil.h"
#include "odil/SCU.h"
+#include "odil/message/CGetRequest.h"
#include "odil/message/CGetResponse.h"
#include "odil/message/CStoreRequest.h"
@@ -22,11 +24,11 @@ namespace odil
{
/// @brief SCU for C-GET services.
-class GetSCU: public SCU
+class ODIL_API GetSCU: public SCU
{
public:
/// @brief Callback called when a C-STORE request is received.
- typedef std::function<void(DataSet const &)> StoreCallback;
+ typedef std::function<void(DataSet &&)> StoreCallback;
/**
* @brief Typedef to keep compatibility with previous versions.
@@ -35,7 +37,7 @@ public:
typedef StoreCallback Callback;
/// @brief Callback called when a C-GET response is received.
- typedef std::function<void(message::CGetResponse const &)> GetCallback;
+ typedef std::function<void(message::CGetResponse &&)> GetCallback;
/// @brief Constructor.
GetSCU(Association & association);
@@ -47,17 +49,30 @@ public:
void get(
DataSet const & query, StoreCallback store_callback,
GetCallback get_callback=GetCallback()) const;
+
+ /// @brief Perform the C-GET using callbacks.
+ void get(
+ DataSet && query, StoreCallback store_callback,
+ GetCallback get_callback=GetCallback()) const;
/**
* @brief Return a list of datasets matching the query.
*/
std::vector<DataSet> get(DataSet const & query) const;
+ /**
+ * @brief Return a list of datasets matching the query.
+ */
+ std::vector<DataSet> get(DataSet && query) const;
+
private:
+ void _get(
+ message::CGetRequest const & request,
+ StoreCallback store_callback, GetCallback get_callback) const;
bool _handle_get_response(
- message::CGetResponse const & response, GetCallback callback) const;
+ message::CGetResponse && response, GetCallback callback) const;
void _handle_store_request(
- message::CStoreRequest const & request, StoreCallback callback) const;
+ message::CStoreRequest && request, StoreCallback callback) const;
};
}
diff --git a/src/odil/MoveSCP.cpp b/src/odil/MoveSCP.cpp
index 785492a..c52edc7 100644
--- a/src/odil/MoveSCP.cpp
+++ b/src/odil/MoveSCP.cpp
@@ -65,7 +65,21 @@ MoveSCP
::operator()(message::Message const & message)
{
message::CMoveRequest const request(message);
+ this->operator()(request);
+}
+void
+MoveSCP
+::operator()(message::Message && message)
+{
+ message::CMoveRequest const request(std::move(message));
+ this->operator()(request);
+}
+
+void
+MoveSCP
+::operator()(message::CMoveRequest const & request)
+{
Association move_association;
try
{
@@ -114,11 +128,13 @@ MoveSCP
this->_association.send_message(
response, request.get_affected_sop_class_uid());
- auto const data_set = this->_generator->get();
+ auto data_set = this->_generator->get();
store_scu.set_affected_sop_class(data_set);
try
{
- store_scu.store(data_set, move_originator_aet, move_originator_message_id);
+ store_scu.store(
+ std::move(data_set), move_originator_aet,
+ move_originator_message_id);
--remaining_sub_operations;
++completed_sub_operations;
diff --git a/src/odil/MoveSCP.h b/src/odil/MoveSCP.h
index 63004fd..b5bebe2 100644
--- a/src/odil/MoveSCP.h
+++ b/src/odil/MoveSCP.h
@@ -15,6 +15,7 @@
#include <utility>
#include "odil/Association.h"
+#include "odil/odil.h"
#include "odil/SCP.h"
#include "odil/message/CMoveRequest.h"
#include "odil/message/Message.h"
@@ -23,7 +24,7 @@ namespace odil
{
/// @brief SCP for C-Move services.
-class MoveSCP: public SCP
+class ODIL_API MoveSCP: public SCP
{
public:
@@ -63,8 +64,12 @@ public:
/// @brief Process a C-Get request.
virtual void operator()(message::Message const & message);
+ /// @brief Process a C-Get request.
+ virtual void operator()(message::Message && message);
+
private:
std::shared_ptr<DataSetGenerator> _generator;
+ void operator()(message::CMoveRequest const & request);
};
}
diff --git a/src/odil/MoveSCU.cpp b/src/odil/MoveSCU.cpp
index f39a151..64528a1 100644
--- a/src/odil/MoveSCU.cpp
+++ b/src/odil/MoveSCU.cpp
@@ -16,6 +16,7 @@
#include "odil/Association.h"
#include "odil/DataSet.h"
#include "odil/Exception.h"
+#include "odil/logging.h"
#include "odil/StoreSCP.h"
#include "odil/message/CMoveRequest.h"
#include "odil/message/CMoveResponse.h"
@@ -74,11 +75,24 @@ MoveSCU
void
MoveSCU
+::move(DataSet && query, StoreCallback store_callback) const
+{
+ this->move(std::move(query), store_callback, MoveCallback());
+}
+
+void
+MoveSCU
::move(DataSet const & query, MoveCallback move_callback) const
{
this->move(query, StoreCallback(), move_callback);
}
+void
+MoveSCU
+::move(DataSet && query, MoveCallback move_callback) const
+{
+ this->move(std::move(query), StoreCallback(), move_callback);
+}
void
MoveSCU
@@ -91,6 +105,29 @@ MoveSCU
this->_association.next_message_id(),
this->_affected_sop_class, message::Message::Priority::MEDIUM,
this->_move_destination, query);
+ this->_move(request, store_callback, move_callback);
+}
+
+void
+MoveSCU
+::move(
+ DataSet && query, StoreCallback store_callback,
+ MoveCallback move_callback) const
+{
+ // Send the request
+ message::CMoveRequest const request(
+ this->_association.next_message_id(),
+ this->_affected_sop_class, message::Message::Priority::MEDIUM,
+ this->_move_destination, std::move(query));
+ this->_move(request, store_callback, move_callback);
+}
+
+void
+MoveSCU
+::_move(
+ message::CMoveRequest const & request, StoreCallback store_callback,
+ MoveCallback move_callback) const
+{
this->_association.send_message(request, this->_affected_sop_class);
// Receive the responses
@@ -145,6 +182,19 @@ MoveSCU
return result;
}
+std::vector<DataSet>
+MoveSCU
+::move(DataSet && query) const
+{
+ std::vector<DataSet> result;
+ auto callback = [&result](DataSet && data_set) {
+ result.push_back(std::move(data_set));
+ };
+ this->move(std::move(query), callback, MoveCallback());
+
+ return result;
+}
+
void
MoveSCU
::_dispatch(
@@ -174,12 +224,24 @@ bool
MoveSCU
::_handle_main_association(MoveCallback callback) const
{
- message::CMoveResponse const response = this->_association.receive_message();
+ message::CMoveResponse response = this->_association.receive_message();
+ if(message::Response::is_warning(response.get_status()))
+ {
+ ODIL_LOG(WARN) << "C-MOVE response status: " << response.get_status();
+ }
+ else if(message::Response::is_failure(response.get_status()))
+ {
+ ODIL_LOG(ERROR) << "C-MOVE response status: " << response.get_status();
+ }
+
+ // Store status before moving the response.
+ auto const done = !response.is_pending();
+
if(callback)
{
- callback(response);
+ callback(std::move(response));
}
- return !response.is_pending();
+ return done;
}
bool
@@ -190,10 +252,10 @@ MoveSCU
bool result = false;
try
{
- auto const store_callback = [&callback](message::CStoreRequest const & request) {
+ auto const store_callback = [&callback](message::CStoreRequest && request) {
if(callback)
{
- callback(request.get_data_set());
+ callback(std::move(request.get_data_set()));
}
return message::Response::Success;
};
diff --git a/src/odil/MoveSCU.h b/src/odil/MoveSCU.h
index 76be7f5..e4f3b40 100644
--- a/src/odil/MoveSCU.h
+++ b/src/odil/MoveSCU.h
@@ -15,18 +15,20 @@
#include "odil/Association.h"
#include "odil/DataSet.h"
+#include "odil/message/CMoveRequest.h"
#include "odil/message/CMoveResponse.h"
+#include "odil/odil.h"
#include "odil/SCU.h"
namespace odil
{
/// @brief SCU for C-MOVE services.
-class MoveSCU: public SCU
+class ODIL_API MoveSCU: public SCU
{
public:
/// @brief Callback called when a C-STORE request is received.
- typedef std::function<void(DataSet const &)> StoreCallback;
+ typedef std::function<void(DataSet &&)> StoreCallback;
/**
* @brief Typedef to keep compatibility with previous versions.
@@ -35,7 +37,7 @@ public:
typedef StoreCallback Callback;
/// @brief Callback called when a C-MOVE response is received.
- typedef std::function<void(message::CMoveResponse const &)> MoveCallback;
+ typedef std::function<void(message::CMoveResponse &&)> MoveCallback;
/// @brief Constructor.
MoveSCU(Association & association);
@@ -56,23 +58,43 @@ public:
/// @brief Perform the C-MOVE using callbacks.
void move(DataSet const & query, StoreCallback store_callback) const;
+
+ /// @brief Perform the C-MOVE using callbacks.
+ void move(DataSet && query, StoreCallback store_callback) const;
/// @brief Perform the C-MOVE using callbacks.
void move(DataSet const & query, MoveCallback move_callback) const;
/// @brief Perform the C-MOVE using callbacks.
+ void move(DataSet && query, MoveCallback move_callback) const;
+
+ /// @brief Perform the C-MOVE using callbacks.
void move(
DataSet const & query, StoreCallback store_callback,
MoveCallback move_callback) const;
+
+ /// @brief Perform the C-MOVE using callbacks.
+ void move(
+ DataSet && query, StoreCallback store_callback,
+ MoveCallback move_callback) const;
/**
* @brief Return a list of datasets matching the query.
*/
std::vector<DataSet> move(DataSet const & query) const;
+ /**
+ * @brief Return a list of datasets matching the query.
+ */
+ std::vector<DataSet> move(DataSet && query) const;
+
private:
std::string _move_destination;
uint16_t _incoming_port;
+
+ void _move(
+ message::CMoveRequest const & request, StoreCallback store_callback,
+ MoveCallback move_callback) const;
void _dispatch(
Association & store_association, StoreCallback store_callback,
diff --git a/src/odil/StoreSCP.cpp b/src/odil/NCreateSCP.cpp
similarity index 58%
copy from src/odil/StoreSCP.cpp
copy to src/odil/NCreateSCP.cpp
index ae1a3a9..67004e8 100644
--- a/src/odil/StoreSCP.cpp
+++ b/src/odil/NCreateSCP.cpp
@@ -6,63 +6,72 @@
* for details.
************************************************************************/
-#include "odil/StoreSCP.h"
+#include "odil/NCreateSCP.h"
#include <functional>
#include "odil/Association.h"
-#include "odil/Exception.h"
#include "odil/SCP.h"
#include "odil/Value.h"
-#include "odil/message/CStoreRequest.h"
-#include "odil/message/CStoreResponse.h"
-#include "odil/message/CStoreRequest.h"
-#include "odil/message/CStoreResponse.h"
+#include "odil/message/NCreateResponse.h"
namespace odil
{
-StoreSCP
-::StoreSCP(Association & association)
+NCreateSCP
+::NCreateSCP(Association & association)
: SCP(association), _callback()
{
// Nothing else.
}
-StoreSCP
-::StoreSCP(Association & association, Callback const & callback)
+NCreateSCP
+::NCreateSCP(Association & association, Callback const & callback)
: SCP(association), _callback()
{
this->set_callback(callback);
}
-StoreSCP
-::~StoreSCP()
+NCreateSCP
+::~NCreateSCP()
{
// Nothing to do.
}
-StoreSCP::Callback const &
-StoreSCP
-::get_callback() const
+NCreateSCP::Callback const &
+NCreateSCP::get_callback() const
{
return this->_callback;
}
void
-StoreSCP
+NCreateSCP
::set_callback(Callback const & callback)
{
this->_callback = callback;
}
void
-StoreSCP
+NCreateSCP
::operator()(message::Message const & message)
{
- message::CStoreRequest const request(message);
+ message::NCreateRequest const request(message);
+ this->operator()(request);
+}
- Value::Integer status=message::CStoreResponse::Success;
+void
+NCreateSCP
+::operator()(message::Message && message)
+{
+ message::NCreateRequest const request(std::move(message));
+ this->operator()(request);
+}
+
+void
+NCreateSCP
+::operator()(message::NCreateRequest const & request)
+{
+ Value::Integer status=message::NCreateResponse::Success;
DataSet status_fields;
try
@@ -76,10 +85,12 @@ StoreSCP
}
catch(odil::Exception const &)
{
- status = message::CStoreResponse::ProcessingFailure;
+ status = message::NCreateResponse::ProcessingFailure;
}
- message::CStoreResponse response(request.get_message_id(), status);
+ message::NCreateResponse response(
+ request.get_message_id()
+ , status, request.get_affected_sop_class_uid());
response.set_status_fields(status_fields);
this->_association.send_message(
response, request.get_affected_sop_class_uid());
diff --git a/src/odil/EchoSCP.h b/src/odil/NCreateSCP.h
similarity index 59%
copy from src/odil/EchoSCP.h
copy to src/odil/NCreateSCP.h
index 5fa0433..20940fb 100644
--- a/src/odil/EchoSCP.h
+++ b/src/odil/NCreateSCP.h
@@ -6,38 +6,39 @@
* for details.
************************************************************************/
-#ifndef _1a61d976_ba12_4dba_af34_67f064d38506
-#define _1a61d976_ba12_4dba_af34_67f064d38506
+#ifndef _918ce553_d774_44c0_9cbf_56f32584a1ab
+#define _918ce553_d774_44c0_9cbf_56f32584a1ab
#include <functional>
#include "odil/Association.h"
+#include "odil/odil.h"
#include "odil/SCP.h"
#include "odil/Value.h"
-#include "odil/message/CEchoRequest.h"
+#include "odil/message/NCreateRequest.h"
#include "odil/message/Message.h"
namespace odil
{
-/// @brief SCP for C-Echo services.
-class EchoSCP: public SCP
+/// @brief SCP for N-Create services.
+class ODIL_API NCreateSCP: public SCP
{
public:
/**
* @brief Callback called when a request is received, shall throw an
* SCP::Exception on error.
*/
- typedef std::function<Value::Integer(message::CEchoRequest const &)> Callback;
+ typedef std::function<Value::Integer(message::NCreateRequest const &)> Callback;
/// @brief Constructor.
- EchoSCP(Association & association);
+ NCreateSCP(Association & association);
/// @brief Constructor.
- EchoSCP(Association & association, Callback const & callback);
+ NCreateSCP(Association & association, Callback const & callback);
/// @brief Destructor.
- virtual ~EchoSCP();
+ virtual ~NCreateSCP();
/// @brief Return the callback.
Callback const & get_callback() const;
@@ -45,13 +46,17 @@ public:
/// @brief Set the callback.
void set_callback(Callback const & callback);
- /// @brief Process a C-Echo request.
+ /// @brief Process a N-Create request.
virtual void operator()(message::Message const & message);
+ /// @brief Process a N-Create request.
+ virtual void operator()(message::Message && message);
+
private:
Callback _callback;
+ void operator()(message::NCreateRequest const & message);
};
}
-#endif // _1a61d976_ba12_4dba_af34_67f064d38506
+#endif // _918ce553_d774_44c0_9cbf_56f32584a1ab
diff --git a/src/odil/NSetSCP.cpp b/src/odil/NSetSCP.cpp
new file mode 100644
index 0000000..5bce0d2
--- /dev/null
+++ b/src/odil/NSetSCP.cpp
@@ -0,0 +1,102 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#include "odil/Association.h"
+#include "odil/NSetSCP.h"
+#include "odil/SCP.h"
+#include "odil/Value.h"
+#include "odil/message/NSetResponse.h"
+
+#include <functional>
+
+namespace odil
+{
+
+NSetSCP
+::NSetSCP(Association& association)
+ : SCP(association), _callback()
+{
+ // Nothing else.
+}
+
+NSetSCP
+::NSetSCP(Association& association, Callback const& callback)
+ : SCP(association), _callback()
+{
+ this->set_callback(callback);
+}
+
+NSetSCP
+::~NSetSCP()
+{
+ // Nothing to do.
+}
+
+NSetSCP::Callback const&
+NSetSCP::get_callback() const
+{
+ return this->_callback;
+}
+
+void
+NSetSCP
+::set_callback(Callback const& callback)
+{
+ this->_callback = callback;
+}
+
+void
+NSetSCP
+::operator()(message::Message const & message)
+{
+ message::NSetRequest const request(message);
+ this->operator()(request);
+}
+
+void
+NSetSCP
+::operator()(message::Message && message)
+{
+ message::NSetRequest const request(std::move(message));
+ this->operator()(request);
+}
+
+void
+NSetSCP
+::operator()(message::NSetRequest const & request)
+{
+ Value::Integer status = message::NSetResponse::Success;
+ DataSet status_fields;
+
+ try
+ {
+ status = this->_callback(request);
+ }
+ catch(SCP::Exception const& e)
+ {
+ status = e.status;
+ status_fields = e.status_fields;
+ }
+ catch(odil::Exception const&)
+ {
+ status = message::NSetResponse::ProcessingFailure;
+ }
+
+ message::NSetResponse response(
+ request.get_message_id(),
+ status,
+ request.get_requested_sop_class_uid(),
+ request.get_requested_sop_instance_uid() );
+
+ response.set_status_fields(status_fields);
+
+ this->_association.send_message(
+ response, request.get_requested_sop_class_uid());
+}
+
+}
diff --git a/src/odil/EchoSCP.h b/src/odil/NSetSCP.h
similarity index 60%
copy from src/odil/EchoSCP.h
copy to src/odil/NSetSCP.h
index 5fa0433..4c22784 100644
--- a/src/odil/EchoSCP.h
+++ b/src/odil/NSetSCP.h
@@ -6,38 +6,39 @@
* for details.
************************************************************************/
-#ifndef _1a61d976_ba12_4dba_af34_67f064d38506
-#define _1a61d976_ba12_4dba_af34_67f064d38506
+#ifndef _cca2fb7a_c3b6_47f4_a619_44701b074cda
+#define _cca2fb7a_c3b6_47f4_a619_44701b074cda
#include <functional>
#include "odil/Association.h"
+#include "odil/odil.h"
#include "odil/SCP.h"
#include "odil/Value.h"
-#include "odil/message/CEchoRequest.h"
#include "odil/message/Message.h"
+#include "odil/message/NSetRequest.h"
namespace odil
{
-/// @brief SCP for C-Echo services.
-class EchoSCP: public SCP
+/// @brief SCP for N-Set services.
+class ODIL_API NSetSCP: public SCP
{
public:
/**
* @brief Callback called when a request is received, shall throw an
* SCP::Exception on error.
*/
- typedef std::function<Value::Integer(message::CEchoRequest const &)> Callback;
+ typedef std::function<Value::Integer(message::NSetRequest const &)> Callback;
/// @brief Constructor.
- EchoSCP(Association & association);
+ NSetSCP(Association & association);
/// @brief Constructor.
- EchoSCP(Association & association, Callback const & callback);
+ NSetSCP(Association & association, Callback const & callback);
/// @brief Destructor.
- virtual ~EchoSCP();
+ virtual ~NSetSCP();
/// @brief Return the callback.
Callback const & get_callback() const;
@@ -45,13 +46,18 @@ public:
/// @brief Set the callback.
void set_callback(Callback const & callback);
- /// @brief Process a C-Echo request.
+ /// @brief Process a N-Set request.
virtual void operator()(message::Message const & message);
+ /// @brief Process a N-Set request.
+ virtual void operator()(message::Message && message);
+
+
private:
Callback _callback;
+ void operator()(message::NSetRequest const & message);
};
}
-#endif // _1a61d976_ba12_4dba_af34_67f064d38506
+#endif // _cca2fb7a_c3b6_47f4_a619_44701b074cda
diff --git a/src/odil/NSetSCU.cpp b/src/odil/NSetSCU.cpp
new file mode 100644
index 0000000..5f308d5
--- /dev/null
+++ b/src/odil/NSetSCU.cpp
@@ -0,0 +1,74 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#include "NSetSCU.h"
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "odil/message/NSetRequest.h"
+#include "odil/message/NSetResponse.h"
+#include "odil/DataSet.h"
+#include "odil/Exception.h"
+#include "odil/registry.h"
+#include "odil/SCU.h"
+
+namespace odil
+{
+
+NSetSCU
+::NSetSCU(Association & association)
+: SCU(association)
+{
+ // Nothing else.
+}
+
+NSetSCU
+::~NSetSCU()
+{
+ // Nothing to do.
+}
+
+void
+NSetSCU
+::set_affected_sop_class(DataSet const & dataset)
+{
+ auto const & sop_class_uid = dataset.as_string(registry::RequestedSOPClassUID, 0);
+
+ this->SCU::set_affected_sop_class(sop_class_uid);
+}
+
+void
+NSetSCU
+::set( DataSet const & dataset) const
+{
+
+ message::NSetRequest const request(
+ this->_association.next_message_id(),
+ this->_affected_sop_class,
+ dataset.as_string(registry::RequestedSOPInstanceUID, 0),
+ dataset
+ );
+
+ this->_association.send_message(request, this->_affected_sop_class);
+
+ message::NSetResponse const response = this->_association.receive_message();
+
+ if(response.get_message_id_being_responded_to() != request.get_message_id())
+ {
+ std::ostringstream message;
+ message << "DIMSE: Unexpected Response MsgId: "
+ << response.get_message_id_being_responded_to()
+ << "(expected: " << request.get_message_id() << ")";
+ throw Exception(message.str());
+ }
+}
+
+}
diff --git a/src/odil/StoreSCU.h b/src/odil/NSetSCU.h
similarity index 63%
copy from src/odil/StoreSCU.h
copy to src/odil/NSetSCU.h
index 7500fa1..be67ae0 100644
--- a/src/odil/StoreSCU.h
+++ b/src/odil/NSetSCU.h
@@ -6,38 +6,36 @@
* for details.
************************************************************************/
-#ifndef _1b2f876e_1ad2_464d_9423_28181320aed0
-#define _1b2f876e_1ad2_464d_9423_28181320aed0
+#ifndef _c80c338c_36d7_4724_9732_c7afed87902b
+#define _c80c338c_36d7_4724_9732_c7afed87902b
#include "odil/Association.h"
#include "odil/DataSet.h"
+#include "odil/odil.h"
#include "odil/SCU.h"
namespace odil
{
/// @brief SCU for C-Store services.
-class StoreSCU: public SCU
+class ODIL_API NSetSCU: public SCU
{
public:
/// @brief Constructor.
- StoreSCU(Association & association);
+ NSetSCU(Association & association);
/// @brief Destructor.
- virtual ~StoreSCU();
+ virtual ~NSetSCU();
/// @brief Set the affected SOP class based on the dataset.
void set_affected_sop_class(DataSet const & dataset);
using SCU::set_affected_sop_class;
- /// @brief Perform the C-STORE.
- void store(
- DataSet const & dataset,
- Value::String const & move_originator_ae_title = "",
- Value::Integer move_originator_message_id = -1) const;
+ /// @brief Perform the N-SET.
+ void set( DataSet const & dataset) const;
};
}
-#endif // _1b2f876e_1ad2_464d_9423_28181320aed0
+#endif // _c80c338c_36d7_4724_9732_c7afed87902b
diff --git a/src/odil/Reader.cpp b/src/odil/Reader.cpp
index 6c06033..587d905 100644
--- a/src/odil/Reader.cpp
+++ b/src/odil/Reader.cpp
@@ -12,6 +12,7 @@
#include <cstdint>
#include <functional>
#include <istream>
+#include <memory>
#include <sstream>
#include <string>
#include <utility>
@@ -141,7 +142,7 @@ Reader
if(this->keep_group_length || tag.element != 0)
{
- data_set.add(tag, element);
+ data_set.add(tag, std::move(element));
}
}
@@ -210,56 +211,43 @@ Reader
vr = vr_finder(tag, data_set, this->transfer_syntax);
}
- Value value;
+ std::shared_ptr<Value> value;
auto const vl = this->read_length(vr);
- if(vl == 0)
+ if(is_int(vr))
{
- value = Value();
+ value = std::make_shared<Value>(Value::Integers());
}
- else if(vr == VR::IS || vr == VR::SL || vr == VR::SS ||
- vr == VR::UL || vr == VR::US)
+ else if(is_real(vr))
{
- value = Value(Value::Integers());
+ value = std::make_shared<Value>(Value::Reals());
}
- else if(vr == VR::DS || vr == VR::FD || vr == VR::FL)
+ else if(is_string(vr))
{
- value = Value(Value::Reals());
- }
- else if(vr == VR::AE || vr == VR::AS || vr == VR::AT || vr == VR::CS ||
- vr == VR::DA || vr == VR::DS || vr == VR::DT || vr == VR::LO ||
- vr == VR::LT || vr == VR::PN || vr == VR::SH || vr == VR::ST ||
- vr == VR::TM || vr == VR::UC || vr == VR::UI || vr == VR::UR ||
- vr == VR::UT)
- {
- value = Value(Value::Strings());
+ value = std::make_shared<Value>(Value::Strings());
}
else if(vr == VR::SQ)
{
- value = Value(Value::DataSets());
+ value = std::make_shared<Value>(Value::DataSets());
}
else if(is_binary(vr))
{
- value = Value(Value::Binary());
+ value = std::make_shared<Value>(Value::Binary());
}
else
{
throw Exception("Cannot create value for VR " + as_string(vr));
}
- if(!value.empty())
+ if(vl > 0)
{
Visitor visitor(
this->stream, vr, vl, this->transfer_syntax, this->byte_ordering,
this->explicit_vr, this->keep_group_length);
- apply_visitor(visitor, value);
- if(vr == VR::SQ && value.as_data_sets().empty())
- {
- value = Value();
- }
+ apply_visitor(visitor, *value);
}
- return Element(value, vr);
+ return Element(*value, vr);
}
std::pair<DataSet, DataSet>
@@ -285,7 +273,7 @@ Reader
// Read meta information
Reader meta_information_reader(
stream, registry::ExplicitVRLittleEndian, keep_group_length);
- auto const meta_information = meta_information_reader.read_data_set(
+ auto meta_information = meta_information_reader.read_data_set(
[](Tag const & tag) { return (tag.group != 0x0002); });
if(!meta_information.has(registry::TransferSyntaxUID))
@@ -304,9 +292,9 @@ Reader
Reader data_set_reader(
stream, meta_information.as_string(registry::TransferSyntaxUID)[0],
keep_group_length);
- auto const data_set = data_set_reader.read_data_set(halt_condition);
+ auto data_set = data_set_reader.read_data_set(halt_condition);
- return std::pair<DataSet, DataSet>(meta_information, data_set);
+ return std::make_pair(std::move(meta_information), std::move(data_set));
}
Reader::Visitor
diff --git a/src/odil/Reader.h b/src/odil/Reader.h
index e4193ce..f36f00f 100644
--- a/src/odil/Reader.h
+++ b/src/odil/Reader.h
@@ -17,6 +17,7 @@
#include "odil/DataSet.h"
#include "odil/Element.h"
#include "odil/endian.h"
+#include "odil/odil.h"
#include "odil/Tag.h"
#include "odil/Value.h"
#include "odil/VR.h"
@@ -25,7 +26,7 @@ namespace odil
{
/// @brief Read DICOM objects from a stream.
-class Reader
+class ODIL_API Reader
{
public:
/// @brief Input stream.
diff --git a/src/odil/SCP.cpp b/src/odil/SCP.cpp
index 854c0b6..422d55f 100644
--- a/src/odil/SCP.cpp
+++ b/src/odil/SCP.cpp
@@ -54,8 +54,8 @@ void
SCP
::receive_and_process()
{
- auto const message = this->_association.receive_message();
- (*this)(message);
+ auto message = this->_association.receive_message();
+ (*this)(std::move(message));
}
}
diff --git a/src/odil/SCP.h b/src/odil/SCP.h
index 4f55077..2a2dc1a 100644
--- a/src/odil/SCP.h
+++ b/src/odil/SCP.h
@@ -14,13 +14,14 @@
#include "odil/Exception.h"
#include "odil/message/Message.h"
#include "odil/message/Request.h"
+#include "odil/odil.h"
#include "odil/Value.h"
namespace odil
{
/// @brief Base class for all Service Class Providers.
-class SCP
+class ODIL_API SCP
{
public:
/**
@@ -28,7 +29,7 @@ public:
*
* initialize, done, next and get shall throw an SCP::Exception on error.
*/
- class DataSetGenerator
+ class ODIL_API DataSetGenerator
{
public:
/// @brief Destructor.
@@ -76,6 +77,9 @@ public:
/// @brief Process a message.
virtual void operator()(message::Message const & message) =0;
+
+ /// @brief Process a message.
+ virtual void operator()(message::Message && message) =0;
protected:
/// @brief Association with peer.
Association & _association;
diff --git a/src/odil/SCPDispatcher.cpp b/src/odil/SCPDispatcher.cpp
index 6ddcbdc..a0828bc 100644
--- a/src/odil/SCPDispatcher.cpp
+++ b/src/odil/SCPDispatcher.cpp
@@ -6,22 +6,22 @@
* for details.
************************************************************************/
-#include "odil/SCPDispatcher.h"
-
-#include <map>
-#include <memory>
-
#include "odil/Association.h"
#include "odil/Exception.h"
#include "odil/SCP.h"
+#include "odil/SCPDispatcher.h"
#include "odil/Value.h"
+#include <map>
+#include <memory>
+#include <sstream>
+
namespace odil
{
SCPDispatcher
-::SCPDispatcher(Association & association)
-: _association(association)
+::SCPDispatcher(Association& association)
+ : _association(association)
{
// Nothing else.
}
@@ -40,7 +40,7 @@ SCPDispatcher
return (it != this->_providers.end());
}
-std::shared_ptr<SCP> const &
+std::shared_ptr<SCP> const&
SCPDispatcher
::get_scp(Value::Integer command) const
{
@@ -54,7 +54,7 @@ SCPDispatcher
void
SCPDispatcher
-::set_scp(Value::Integer command, std::shared_ptr<SCP> const & scp)
+::set_scp(Value::Integer command, std::shared_ptr<SCP> const& scp)
{
this->_providers[command] = scp;
}
@@ -68,10 +68,15 @@ SCPDispatcher
auto const it = this->_providers.find(message.get_command_field());
if(it == this->_providers.end())
{
- throw Exception("No such provider");
+ std::ostringstream error_message;
+ error_message
+ << "No provider for: "
+ << std::hex << std::setw(4) << std::setfill('0')
+ << message.get_command_field();
+ throw Exception(error_message.str());
}
- auto & scp = *(it->second);
+ auto& scp = *(it->second);
scp(message);
}
diff --git a/src/odil/SCPDispatcher.h b/src/odil/SCPDispatcher.h
index 511b19f..f638dc7 100644
--- a/src/odil/SCPDispatcher.h
+++ b/src/odil/SCPDispatcher.h
@@ -13,6 +13,7 @@
#include <memory>
#include "odil/Association.h"
+#include "odil/odil.h"
#include "odil/SCP.h"
#include "odil/Value.h"
@@ -20,7 +21,7 @@ namespace odil
{
/// @brief Dispatch an incoming message to one of the registered SCPs.
-class SCPDispatcher
+class ODIL_API SCPDispatcher
{
public:
/// @brief Create a dispatcher with network and association.
@@ -40,11 +41,13 @@ public:
/// @brief Receive and dispatch an incoming message.
void dispatch();
+
private:
typedef std::shared_ptr<SCP> SCPPointer;
Association & _association;
- std::map<Value::Integer, std::shared_ptr<SCP>> _providers;
+ std::map<Value::Integer, std::shared_ptr<SCP> > _providers;
+
};
}
diff --git a/src/odil/SCU.h b/src/odil/SCU.h
index 0f380bd..7c46903 100644
--- a/src/odil/SCU.h
+++ b/src/odil/SCU.h
@@ -12,12 +12,13 @@
#include <string>
#include "odil/Association.h"
+#include "odil/odil.h"
namespace odil
{
/// @brief Base class for all Service Class Users.
-class SCU
+class ODIL_API SCU
{
public:
/// @brief Create a default Service Class User.
diff --git a/src/odil/StoreSCP.cpp b/src/odil/StoreSCP.cpp
index ae1a3a9..3224aa2 100644
--- a/src/odil/StoreSCP.cpp
+++ b/src/odil/StoreSCP.cpp
@@ -60,14 +60,28 @@ void
StoreSCP
::operator()(message::Message const & message)
{
- message::CStoreRequest const request(message);
+ message::CStoreRequest request(message);
+ this->operator()(request);
+}
+void
+StoreSCP
+::operator()(message::Message && message)
+{
+ message::CStoreRequest request(std::move(message));
+ this->operator()(request);
+}
+
+void
+StoreSCP
+::operator()(message::CStoreRequest & request)
+{
Value::Integer status=message::CStoreResponse::Success;
DataSet status_fields;
try
{
- status = this->_callback(request);
+ status = this->_callback(std::move(request));
}
catch(SCP::Exception const & e)
{
diff --git a/src/odil/StoreSCP.h b/src/odil/StoreSCP.h
index 55ac977..c1e0703 100644
--- a/src/odil/StoreSCP.h
+++ b/src/odil/StoreSCP.h
@@ -12,6 +12,7 @@
#include <functional>
#include "odil/Association.h"
+#include "odil/odil.h"
#include "odil/SCP.h"
#include "odil/Value.h"
#include "odil/message/CStoreRequest.h"
@@ -21,14 +22,14 @@ namespace odil
{
/// @brief SCP for C-Store services.
-class StoreSCP: public SCP
+class ODIL_API StoreSCP: public SCP
{
public:
/**
* @brief Callback called when a request is received, shall throw an
* SCP::Exception on error.
*/
- typedef std::function<Value::Integer(message::CStoreRequest const &)> Callback;
+ typedef std::function<Value::Integer(message::CStoreRequest &&)> Callback;
/// @brief Constructor.
StoreSCP(Association & association);
@@ -48,8 +49,12 @@ public:
/// @brief Process a C-Store request.
virtual void operator()(message::Message const & message);
+ /// @brief Process a C-Store request.
+ virtual void operator()(message::Message && message);
+
private:
Callback _callback;
+ void operator()(message::CStoreRequest & request);
};
}
diff --git a/src/odil/StoreSCU.cpp b/src/odil/StoreSCU.cpp
index f4c7ae7..876499d 100644
--- a/src/odil/StoreSCU.cpp
+++ b/src/odil/StoreSCU.cpp
@@ -17,6 +17,7 @@
#include "odil/message/CStoreResponse.h"
#include "odil/DataSet.h"
#include "odil/Exception.h"
+#include "odil/logging.h"
#include "odil/registry.h"
#include "odil/SCU.h"
@@ -66,8 +67,8 @@ void
StoreSCU
::store(
DataSet const & dataset,
- Value::String const & move_originator_ae_title,
- Value::Integer move_originator_message_id) const
+ Value::String const & move_originator_ae_title ,
+ Value::Integer move_originator_message_id ) const
{
message::CStoreRequest const request(
this->_association.next_message_id(),
@@ -76,7 +77,30 @@ StoreSCU
message::Message::Priority::MEDIUM,
dataset, move_originator_ae_title,
move_originator_message_id);
+ this->_store(request);
+}
+void
+StoreSCU
+::store(
+ DataSet && dataset,
+ Value::String const & move_originator_ae_title ,
+ Value::Integer move_originator_message_id ) const
+{
+ message::CStoreRequest const request(
+ this->_association.next_message_id(),
+ this->_affected_sop_class,
+ dataset.as_string(registry::SOPInstanceUID, 0),
+ message::Message::Priority::MEDIUM,
+ std::move(dataset), move_originator_ae_title,
+ move_originator_message_id);
+ this->_store(request);
+}
+
+void
+StoreSCU
+::_store(message::CStoreRequest const & request) const
+{
this->_association.send_message(request, this->_affected_sop_class);
message::CStoreResponse const response = this->_association.receive_message();
@@ -108,6 +132,15 @@ StoreSCU
<< " (expected: " << request.get_affected_sop_instance_uid() << ")";
throw Exception(message.str());
}
+
+ if(message::Response::is_warning(response.get_status()))
+ {
+ ODIL_LOG(WARN) << "C-STORE response status: " << response.get_status();
+ }
+ else if(message::Response::is_failure(response.get_status()))
+ {
+ ODIL_LOG(ERROR) << "C-STORE response status: " << response.get_status();
+ }
}
}
diff --git a/src/odil/StoreSCU.h b/src/odil/StoreSCU.h
index 7500fa1..80213c8 100644
--- a/src/odil/StoreSCU.h
+++ b/src/odil/StoreSCU.h
@@ -11,13 +11,15 @@
#include "odil/Association.h"
#include "odil/DataSet.h"
+#include "odil/message/CStoreRequest.h"
+#include "odil/odil.h"
#include "odil/SCU.h"
namespace odil
{
/// @brief SCU for C-Store services.
-class StoreSCU: public SCU
+class ODIL_API StoreSCU: public SCU
{
public:
/// @brief Constructor.
@@ -36,6 +38,14 @@ public:
DataSet const & dataset,
Value::String const & move_originator_ae_title = "",
Value::Integer move_originator_message_id = -1) const;
+
+ /// @brief Perform the C-STORE.
+ void store(
+ DataSet && dataset,
+ Value::String const & move_originator_ae_title = "",
+ Value::Integer move_originator_message_id = -1) const;
+private:
+ void _store(message::CStoreRequest const & request) const;
};
}
diff --git a/src/odil/Tag.h b/src/odil/Tag.h
index a3947b3..9a59d45 100644
--- a/src/odil/Tag.h
+++ b/src/odil/Tag.h
@@ -13,13 +13,15 @@
#include <ostream>
#include <string>
+#include "odil/odil.h"
+
namespace odil
{
/**
* @brief A DICOM element tag.
*/
-class Tag
+class ODIL_API Tag
{
public:
/// @brief Create a tag based on its group and element as two 16-bits words.
@@ -48,6 +50,16 @@ public:
*/
Tag(char const * string);
+ /** @addtogroup default_operations Default class operations
+ * @{
+ */
+ ~Tag() =default;
+ Tag(Tag const &) =default;
+ Tag(Tag &&) =default;
+ Tag & operator=(Tag const &) =default;
+ Tag & operator=(Tag &&) =default;
+ /// @}
+
/// @brief Group of the tag.
uint16_t group;
@@ -91,7 +103,7 @@ private:
};
/// @brief Stream inserter
-std::ostream & operator<<(std::ostream & stream, Tag const & tag);
+ODIL_API std::ostream & operator<<(std::ostream & stream, Tag const & tag);
}
diff --git a/src/odil/UIDsDictionary.h b/src/odil/UIDsDictionary.h
index f2523a9..b014923 100644
--- a/src/odil/UIDsDictionary.h
+++ b/src/odil/UIDsDictionary.h
@@ -12,13 +12,15 @@
#include <map>
#include <string>
+#include "odil/odil.h"
+
namespace odil
{
/**
* @brief Entry in a dictionary of DICOM UIDs.
*/
-struct UIDsDictionaryEntry
+struct ODIL_API UIDsDictionaryEntry
{
/// @brief Full name.
std::string name;
diff --git a/src/odil/VR.h b/src/odil/VR.h
index 4dda97e..e0cd3bb 100644
--- a/src/odil/VR.h
+++ b/src/odil/VR.h
@@ -11,6 +11,8 @@
#include <string>
+#include "odil/odil.h"
+
namespace odil
{
@@ -26,33 +28,33 @@ enum class VR
};
/// @brief Convert a VR to its string representation.
-std::string as_string(VR vr);
+ODIL_API std::string as_string(VR vr);
/**
* @brief Convert a string to its VR.
*
* If the string does not represent a VR, a odil::Exception is raised.
*/
-VR as_vr(std::string const & vr);
+ODIL_API VR as_vr(std::string const & vr);
/**
* @brief Guess a VR from a tag.
*
* If the VR cannot be guessed, a odil::Exception is raised.
*/
-VR as_vr(Tag const & tag);
+ODIL_API VR as_vr(Tag const & tag);
/// @brief Test whether a VR contains integers.
-bool is_int(VR vr);
+ODIL_API bool is_int(VR vr);
/// @brief Test whether a VR contains rel numbers.
-bool is_real(VR vr);
+ODIL_API bool is_real(VR vr);
/// @brief Test whether a VR contains text.
-bool is_string(VR vr);
+ODIL_API bool is_string(VR vr);
/// @brief Test whether a VR contains binary data.
-bool is_binary(VR vr);
+ODIL_API bool is_binary(VR vr);
}
diff --git a/src/odil/VRFinder.h b/src/odil/VRFinder.h
index c279609..9585633 100644
--- a/src/odil/VRFinder.h
+++ b/src/odil/VRFinder.h
@@ -14,6 +14,7 @@
#include <vector>
#include "odil/DataSet.h"
+#include "odil/odil.h"
#include "odil/Tag.h"
#include "odil/VR.h"
@@ -21,7 +22,7 @@ namespace odil
{
/// @brief Find the VR of elements in an implicit VR data set.
-class VRFinder
+class ODIL_API VRFinder
{
public:
/**
diff --git a/src/odil/Value.cpp b/src/odil/Value.cpp
index af2f77b..44cebc5 100644
--- a/src/odil/Value.cpp
+++ b/src/odil/Value.cpp
@@ -10,91 +10,113 @@
#include <cstdint>
#include <initializer_list>
+#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include "odil/DataSet.h"
#include "odil/Exception.h"
-namespace odil
+namespace
{
-Value
-::Value()
-: _type(Type::Empty)
+struct IsEmptyValue
{
- // Nothing else.
-}
+ typedef bool result_type;
-Value
-::Value(Integers const & integers)
-: _type(Type::Integers), _integers(integers)
-{
- // Nothing else.
-}
+ template <typename T>
+ result_type operator()(T const & container) const
+ {
+ return container.empty();
+ }
+};
-Value
-::Value(Reals const & reals)
-: _type(Type::Reals), _reals(reals)
+struct ValueSizeGetter
{
- // Nothing else.
-}
+ typedef std::size_t result_type;
-Value
-::Value(Strings const & strings)
-: _type(Type::Strings), _strings(strings)
-{
- // Nothing else.
-}
+ template <typename T>
+ result_type operator()(T const & container) const
+ {
+ return container.size();
+ }
+};
-Value
-::Value(DataSets const & datasets)
-: _type(Type::DataSets), _data_sets(datasets)
+struct ClearValue
{
- // Nothing else.
+ typedef void result_type;
+
+ template <typename T>
+ result_type operator()(T & container) const
+ {
+ return container.clear();
+ }
+};
}
-Value
-::Value(Binary const & binary)
-: _type(Type::Binary), _binary(binary)
+namespace odil
{
- // Nothing else.
-}
+
+#define ODIL_VALUE_CONSTRUCTORS(type, holder) \
+ Value\
+ ::Value(type const & value)\
+ : _type(Type::type), holder(value) \
+ {} \
+ \
+ Value\
+ ::Value(type && value)\
+ : _type(Type::type), holder(std::move(value)) \
+ {} \
+ \
+ Value\
+ ::Value(std::initializer_list<type::value_type> const & value)\
+ : _type(Type::type), holder(value) \
+ {}
+ /*
+ * No need for for a rvalue reference version of std::initializer_list:
+ * copying a std::initializer_list does not copy the underlying objects.
+ */
+
+ ODIL_VALUE_CONSTRUCTORS(Integers, _integers);
+ ODIL_VALUE_CONSTRUCTORS(Reals, _reals);
+ ODIL_VALUE_CONSTRUCTORS(Strings, _strings);
+ ODIL_VALUE_CONSTRUCTORS(Binary, _binary);
+
+#undef ODIL_VALUE_CONSTRUCTORS
Value
-::Value(std::initializer_list<int> const & list)
-: _type(Type::Integers)
+::Value(DataSets const & value)
+: _type(Type::DataSets), _data_sets(std::make_shared<DataSets>(value))
{
- this->_integers.resize(list.size());
- std::copy(list.begin(), list.end(), this->_integers.begin());
}
Value
-::Value(std::initializer_list<Integer> const & list)
-: _type(Type::Integers), _integers(list)
+::Value(DataSets && value)
+: _type(Type::DataSets), _data_sets(std::make_shared<DataSets>(std::move(value)))
{
- // Nothing else
}
Value
-::Value(std::initializer_list<Real> const & list)
-: _type(Type::Reals), _reals(list)
+::Value(std::initializer_list<DataSets::value_type> const & value)
+: _type(Type::DataSets), _data_sets(std::make_shared<DataSets>(value))
{
- // Nothing else
}
Value
-::Value(std::initializer_list<String> const & list)
-: _type(Type::Strings), _strings(list)
+::Value(std::initializer_list<int> const & value)
+: _type(Type::Integers)
{
- // Nothing else
+ this->_integers.resize(value.size());
+ std::copy(value.begin(), value.end(), this->_integers.begin());
}
Value
-::Value(std::initializer_list<DataSet> const & list)
-: _type(Type::DataSets), _data_sets(list)
+::Value(std::initializer_list<std::initializer_list<uint8_t>> const & value)
+: _type(Type::Binary)
{
- // Nothing else
+ this->_binary.resize(value.size());
+ std::copy(value.begin(), value.end(), this->_binary.begin());
}
Value::Type
@@ -108,7 +130,14 @@ bool
Value
::empty() const
{
- return (this->_type == Type::Empty);
+ return apply_visitor(IsEmptyValue(), *this);
+}
+
+std::size_t
+Value
+::size() const
+{
+ return apply_visitor(ValueSizeGetter(), *this);
}
#define DECLARE_CONST_ACCESSOR(type, name) \
@@ -144,8 +173,27 @@ DECLARE_NON_CONST_ACCESSOR(Reals, reals)
DECLARE_CONST_ACCESSOR(Strings, strings)
DECLARE_NON_CONST_ACCESSOR(Strings, strings)
-DECLARE_CONST_ACCESSOR(DataSets, data_sets)
-DECLARE_NON_CONST_ACCESSOR(DataSets, data_sets)
+Value::DataSets const &
+Value
+::as_data_sets() const
+{
+ if(this->get_type() != Type::DataSets)
+ {
+ throw Exception("Type mismatch");
+ }
+ return *this->_data_sets;
+}
+
+Value::DataSets &
+Value
+::as_data_sets()
+{
+ if(this->get_type() != Type::DataSets)
+ {
+ throw Exception("Type mismatch");
+ }
+ return *this->_data_sets;
+}
DECLARE_CONST_ACCESSOR(Binary, binary)
DECLARE_NON_CONST_ACCESSOR(Binary, binary)
@@ -161,10 +209,6 @@ Value
{
return false;
}
- else if(this->_type == Value::Type::Empty)
- {
- return true;
- }
else if(this->_type == Value::Type::Integers)
{
return this->_integers == other._integers;
@@ -179,7 +223,7 @@ Value
}
else if(this->_type == Value::Type::DataSets)
{
- return this->_data_sets == other._data_sets;
+ return *(this->_data_sets) == *(other._data_sets);
}
else if(this->_type == Value::Type::Binary)
{
@@ -198,6 +242,12 @@ Value
return !(*this == other);
}
-
+void
+Value
+::clear()
+{
+ apply_visitor(ClearValue(), *this);
+}
}
+
diff --git a/src/odil/Value.h b/src/odil/Value.h
index 29b9828..323ce07 100644
--- a/src/odil/Value.h
+++ b/src/odil/Value.h
@@ -11,9 +11,12 @@
#include <cstdint>
#include <initializer_list>
+#include <memory>
#include <string>
#include <vector>
+#include "odil/odil.h"
+
namespace odil
{
@@ -22,13 +25,12 @@ class DataSet;
/**
* @brief A value held in a DICOM element.
*/
-class Value
+class ODIL_API Value
{
public:
/// @brief Possible types stored in the value.
enum class Type
{
- Empty,
Integers,
Reals,
Strings,
@@ -60,38 +62,35 @@ public:
/// @brief Binary data container.
typedef std::vector<std::vector<uint8_t>> Binary;
- /// @brief Build an empty value.
- Value();
-
- /// @brief Build a value from integers.
- Value(Integers const & integers);
-
- /// @brief Build a value from reals.
- Value(Reals const & reals);
-
- /// @brief Build a value from strings.
- Value(Strings const & strings);
-
- /// @brief Build a value from data sets.
- Value(DataSets const & datasets);
-
- /// @brief Build a value from binary data.
- Value(Binary const & binary);
-
- /// @brief Build a value from integers.
- Value(std::initializer_list<int> const & list);
+#define ODIL_VALUE_CONSTRUCTORS(type) \
+ Value(type const & value); \
+ Value(type && value); \
+ Value(std::initializer_list<type::value_type> const & value);
+ /*
+ * No need for for a rvalue reference version of std::initializer_list:
+ * copying a std::initializer_list does not copy the underlying objects.
+ */
- /// @brief Build a value from integers.
- Value(std::initializer_list<Integer> const & list);
+ ODIL_VALUE_CONSTRUCTORS(Integers);
+ ODIL_VALUE_CONSTRUCTORS(Reals);
+ ODIL_VALUE_CONSTRUCTORS(Strings);
+ ODIL_VALUE_CONSTRUCTORS(DataSets);
+ ODIL_VALUE_CONSTRUCTORS(Binary);
+#undef ODIL_VALUE_CONSTRUCTORS
- /// @brief Build a value from reals.
- Value(std::initializer_list<Real> const & list);
+ Value(std::initializer_list<int> const & value);
- /// @brief Build a value from strings.
- Value(std::initializer_list<String> const & list);
+ Value(std::initializer_list<std::initializer_list<uint8_t>> const & value);
- /// @brief Build a value from data sets.
- Value(std::initializer_list<DataSet> const & list);
+ /** @addtogroup default_operations Default class operations
+ * @{
+ */
+ ~Value() =default;
+ Value(Value const &) =default;
+ Value(Value &&) =default;
+ Value & operator=(Value const &) =default;
+ Value & operator=(Value &&) =default;
+ /// @}
/// @brief Return the type store in the value.
Type get_type() const;
@@ -99,6 +98,9 @@ public:
/// @brief Test whether the value is empty.
bool empty() const;
+ /// @brief Return the number of items.
+ std::size_t size() const;
+
/**
* @brief Return the integers contained in the value.
*
@@ -175,11 +177,16 @@ public:
/// @brief Difference test.
bool operator!=(Value const & other) const;
+ /// @brief Clear the value (value.empty() will be true).
+ void clear();
+
private:
Integers _integers;
Reals _reals;
Strings _strings;
- DataSets _data_sets;
+ // NOTE: can't use std::vector<DataSet> with forward-declaration of DataSet
+ // cf. C++11, 17.6.4.8, last bullet of clause 2
+ std::shared_ptr<DataSets> _data_sets;
Binary _binary;
Type _type;
diff --git a/src/odil/Value.txx b/src/odil/Value.txx
index 765676f..6a8826d 100644
--- a/src/odil/Value.txx
+++ b/src/odil/Value.txx
@@ -19,11 +19,7 @@ template<typename TVisitor>
typename TVisitor::result_type
apply_visitor(TVisitor const & visitor, Value const & value)
{
- if(value.get_type() == Value::Type::Empty)
- {
- throw Exception("Empty value");
- }
- else if(value.get_type() == Value::Type::Integers)
+ if(value.get_type() == Value::Type::Integers)
{
return visitor(value.as_integers());
}
@@ -53,11 +49,7 @@ template<typename TVisitor>
typename TVisitor::result_type
apply_visitor(TVisitor const & visitor, Value & value)
{
- if(value.get_type() == Value::Type::Empty)
- {
- throw Exception("Empty value");
- }
- else if(value.get_type() == Value::Type::Integers)
+ if(value.get_type() == Value::Type::Integers)
{
return visitor(value.as_integers());
}
diff --git a/src/odil/Writer.h b/src/odil/Writer.h
index b7eb63f..166f1f6 100644
--- a/src/odil/Writer.h
+++ b/src/odil/Writer.h
@@ -15,6 +15,7 @@
#include "odil/DataSet.h"
#include "odil/Element.h"
#include "odil/endian.h"
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/Tag.h"
#include "odil/Value.h"
@@ -24,7 +25,7 @@ namespace odil
{
/// @brief Write DICOM objects to a stream.
-class Writer
+class ODIL_API Writer
{
public:
/// @brief Encodings of sequence items.
diff --git a/src/odil/base64.h b/src/odil/base64.h
index 3619886..c2b5e6e 100644
--- a/src/odil/base64.h
+++ b/src/odil/base64.h
@@ -11,6 +11,8 @@
#include <string>
+#include "odil/odil.h"
+
namespace odil
{
@@ -18,10 +20,10 @@ namespace base64
{
/// @brief Dictionary of symbols for Base64.
-extern std::string const symbols;
+extern ODIL_API std::string const symbols;
/// @brief Mapping of ASCII characters to values of Base64 symbols.
-extern std::string const reversed_symbols;
+extern ODIL_API std::string const reversed_symbols;
/// @brief Encode a sequence of 8 bits data to Base64.
template<typename TInputIterator, typename TOutputIterator>
diff --git a/src/odil/dcmtk/ElementAccessor.h b/src/odil/dcmtk/ElementAccessor.h
index cbaaf7f..24a4224 100644
--- a/src/odil/dcmtk/ElementAccessor.h
+++ b/src/odil/dcmtk/ElementAccessor.h
@@ -17,6 +17,7 @@
#include "odil/dcmtk/ElementTraits.h"
#include "odil/dcmtk/Exception.h"
+#include "odil/odil.h"
namespace odil
{
@@ -36,14 +37,14 @@ struct ElementAccessor
ValueType(DcmElement const &, unsigned long const)> GetterType;
/// @brief Return the value in the element.
- static GetterType const element_get;
+ static ODIL_API GetterType const element_get;
/// @brief Setter type.
typedef std::function<
void(DcmElement &, ValueType const &, unsigned long const)> SetterType;
/// @brief Set the value in the element.
- static SetterType const element_set;
+ static ODIL_API SetterType const element_set;
/// @brief Test whether the data set contains a given tag.
static bool has(DcmDataset const & dataset, DcmTagKey const & tag);
diff --git a/src/odil/dcmtk/Exception.h b/src/odil/dcmtk/Exception.h
index 38a6b30..3a1668b 100644
--- a/src/odil/dcmtk/Exception.h
+++ b/src/odil/dcmtk/Exception.h
@@ -13,6 +13,7 @@
#include <dcmtk/ofstd/ofcond.h>
#include "odil/Exception.h"
+#include "odil/odil.h"
namespace odil
{
@@ -20,7 +21,7 @@ namespace odil
namespace dcmtk
{
-class Exception: public ::odil::Exception
+class ODIL_API Exception: public ::odil::Exception
{
public:
/**
diff --git a/src/odil/dcmtk/conversion.cpp b/src/odil/dcmtk/conversion.cpp
index d4ce23c..55a856a 100644
--- a/src/odil/dcmtk/conversion.cpp
+++ b/src/odil/dcmtk/conversion.cpp
@@ -8,6 +8,8 @@
#include "odil/dcmtk/conversion.h"
+#include <memory>
+
#include <dcmtk/config/osconfig.h>
#include <dcmtk/dcmdata/dctk.h>
@@ -341,7 +343,7 @@ void convert<std::vector<uint8_t>, Value::Binary>(
Element convert(DcmElement * source)
{
- Element destination;
+ std::shared_ptr<Element> destination;
DcmEVR const source_vr = source->getTag().getVR().getValidEVR();
VR const destination_vr = convert(source_vr);
@@ -352,13 +354,13 @@ Element convert(DcmElement * source)
source_vr == EVR_ST || source_vr == EVR_TM || source_vr == EVR_UI ||
source_vr == EVR_UT)
{
- destination = Element(Value::Strings(), destination_vr);
- convert<std::string, Value::Strings>(source, destination, &Element::as_string);
+ destination = std::make_shared<Element>(Value::Strings(), destination_vr);
+ convert<std::string, Value::Strings>(source, *destination, &Element::as_string);
}
else if(source_vr == EVR_AT)
{
- destination = Element(Value::Strings(), destination_vr);
- destination.as_string().reserve(source->getVM());
+ destination = std::make_shared<Element>(Value::Strings(), destination_vr);
+ destination->as_string().reserve(source->getVM());
for(unsigned int i=0; i<source->getVM(); ++i)
{
DcmTagKey source_tag;
@@ -368,34 +370,34 @@ Element convert(DcmElement * source)
throw Exception(condition);
}
Tag const destination_tag = convert(source_tag);
- destination.as_string().push_back(std::string(destination_tag));
+ destination->as_string().push_back(std::string(destination_tag));
}
}
else if(source_vr == EVR_DS || source_vr == EVR_FD)
{
- destination = Element(Value::Reals(), destination_vr);
- convert<Float64, Value::Reals>(source, destination, &Element::as_real);
+ destination = std::make_shared<Element>(Value::Reals(), destination_vr);
+ convert<Float64, Value::Reals>(source, *destination, &Element::as_real);
}
else if(source_vr == EVR_FL)
{
- destination = Element(Value::Reals(), destination_vr);
- convert<Float32, Value::Reals>(source, destination, &Element::as_real);
+ destination = std::make_shared<Element>(Value::Reals(), destination_vr);
+ convert<Float32, Value::Reals>(source, *destination, &Element::as_real);
}
else if(source_vr == EVR_IS || source_vr == EVR_SL)
{
- destination = Element(Value::Integers(), destination_vr);
- convert<Sint32, Value::Integers>(source, destination, &Element::as_int);
+ destination = std::make_shared<Element>(Value::Integers(), destination_vr);
+ convert<Sint32, Value::Integers>(source, *destination, &Element::as_int);
}
else if(source_vr == EVR_SQ)
{
- destination = Element(Value::DataSets(), destination_vr);
+ destination = std::make_shared<Element>(Value::DataSets(), destination_vr);
DcmSequenceOfItems * sequence = dynamic_cast<DcmSequenceOfItems*>(source);
if(sequence == NULL)
{
throw Exception("Element is not a DcmSequenceOfItems");
}
- Value::DataSets & destination_value = destination.as_data_set();
+ Value::DataSets & destination_value = destination->as_data_set();
destination_value.reserve(sequence->card());
for(unsigned int i=0; i<sequence->card(); ++i)
@@ -407,31 +409,31 @@ Element convert(DcmElement * source)
}
else if(source_vr == EVR_SS)
{
- destination = Element(Value::Integers(), destination_vr);
- convert<Sint16, Value::Integers>(source, destination, &Element::as_int);
+ destination = std::make_shared<Element>(Value::Integers(), destination_vr);
+ convert<Sint16, Value::Integers>(source, *destination, &Element::as_int);
}
else if(source_vr == EVR_UL)
{
- destination = Element(Value::Integers(), destination_vr);
- convert<Uint32, Value::Integers>(source, destination, &Element::as_int);
+ destination = std::make_shared<Element>(Value::Integers(), destination_vr);
+ convert<Uint32, Value::Integers>(source, *destination, &Element::as_int);
}
else if(source_vr == EVR_OB || source_vr == EVR_OF || source_vr == EVR_OW ||
source_vr == EVR_UN)
{
- destination = Element(Value::Binary(), destination_vr);
- convert<std::vector<uint8_t>, Value::Binary>(source, destination, &Element::as_binary);
+ destination = std::make_shared<Element>(Value::Binary(), destination_vr);
+ convert<std::vector<uint8_t>, Value::Binary>(source, *destination, &Element::as_binary);
}
else if(source_vr == EVR_US)
{
- destination = Element(Value::Integers(), destination_vr);
- convert<Uint16, Value::Integers>(source, destination, &Element::as_int);
+ destination = std::make_shared<Element>(Value::Integers(), destination_vr);
+ convert<Uint16, Value::Integers>(source, *destination, &Element::as_int);
}
else
{
throw Exception("Unknown VR: "+std::string(DcmVR(source_vr).getVRName()));
}
- return destination;
+ return *destination;
}
void convert(Element const & source, DcmOtherByteOtherWord * destination)
diff --git a/src/odil/dcmtk/conversion.h b/src/odil/dcmtk/conversion.h
index fddc6fc..3717180 100644
--- a/src/odil/dcmtk/conversion.h
+++ b/src/odil/dcmtk/conversion.h
@@ -14,6 +14,7 @@
#include "odil/DataSet.h"
#include "odil/Element.h"
+#include "odil/odil.h"
#include "odil/Tag.h"
#include "odil/VR.h"
@@ -24,19 +25,19 @@ namespace dcmtk
{
/// @brief Convert a odil::VR to a DcmVR.
-DcmEVR convert(VR vr);
+ODIL_API DcmEVR convert(VR vr);
/// @brief Convert a DcmVR to a odil::VR.
-VR convert(DcmEVR evr);
+ODIL_API VR convert(DcmEVR evr);
/// @brief Convert a odil::Tag to a DcmTagKey.
-DcmTagKey convert(Tag const & tag);
+ODIL_API DcmTagKey convert(Tag const & tag);
/// @brief Convert a DcmTagKey to a odil::Tag.
-Tag convert(DcmTagKey const & tag);
+ODIL_API Tag convert(DcmTagKey const & tag);
/// @brief Convert a odil::Element to a DcmElement.
-DcmElement * convert(Tag const & tag, Element const & source);
+ODIL_API DcmElement * convert(Tag const & tag, Element const & source);
/// @brief Low-level element converter.
template<typename TSourceType, typename TDestinationType>
@@ -45,7 +46,7 @@ void convert(
TSourceType const & (Element::*getter)() const);
/// @brief Convert a DcmElement to a odil::Element.
-Element convert(DcmElement * source);
+ODIL_API Element convert(DcmElement * source);
/// @brief Low-level element converter.
template<typename TSourceType>
@@ -54,10 +55,11 @@ void convert(
TSourceType const & (Element::*getter)() const);
/// @brief Low-level element converter.
+ODIL_API
void convert(Element const & source, DcmOtherByteOtherWord * destination);
/// @brief Low-level element converter.
-void convert(Element const & source, DcmOtherFloat * destination);
+ODIL_API void convert(Element const & source, DcmOtherFloat * destination);
/// @brief Low-level element converter.
template<typename TSourceType, typename TDestinationType>
@@ -66,10 +68,10 @@ void convert(
TDestinationType & (Element::*getter)());
/// @brief Convert a odil::DataSet to a DcmDataset or a DcmItem.
-DcmItem * convert(DataSet const & source, bool as_data_set=true);
+ODIL_API DcmItem * convert(DataSet const & source, bool as_data_set=true);
/// @brief Convert a DcmDataset to a odil::DataSet.
-DataSet convert(DcmItem * source);
+ODIL_API DataSet convert(DcmItem * source);
}
diff --git a/src/odil/dul/EventData.h b/src/odil/dul/EventData.h
index 9402309..bae2ab2 100644
--- a/src/odil/dul/EventData.h
+++ b/src/odil/dul/EventData.h
@@ -14,6 +14,7 @@
#include "odil/AssociationAcceptor.h"
#include "odil/AssociationParameters.h"
#include "odil/dul/Transport.h"
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -23,7 +24,7 @@ namespace dul
{
/// @brief Data related to events of the DUL state machine.
-class EventData
+class ODIL_API EventData
{
public:
Transport::Socket::endpoint_type peer_endpoint;
diff --git a/src/odil/dul/StateMachine.h b/src/odil/dul/StateMachine.h
index a0c9703..f45688a 100644
--- a/src/odil/dul/StateMachine.h
+++ b/src/odil/dul/StateMachine.h
@@ -19,6 +19,7 @@
#include "odil/AssociationAcceptor.h"
#include "odil/dul/EventData.h"
#include "odil/dul/Transport.h"
+#include "odil/odil.h"
namespace odil
{
@@ -27,7 +28,7 @@ namespace dul
{
/// @brief State machine for the DICOM upper layer.
-class StateMachine
+class ODIL_API StateMachine
{
public:
diff --git a/src/odil/dul/Transport.h b/src/odil/dul/Transport.h
index 8b9d046..93a6bab 100644
--- a/src/odil/dul/Transport.h
+++ b/src/odil/dul/Transport.h
@@ -15,6 +15,8 @@
#include <boost/asio.hpp>
#include <boost/date_time.hpp>
+#include "odil/odil.h"
+
namespace odil
{
@@ -28,7 +30,7 @@ namespace dul
* value: if the timeout expires before the operation is completed, an exception
* will be raised.
*/
-struct Transport
+struct ODIL_API Transport
{
/// @brief Socket type.
typedef boost::asio::ip::tcp::socket Socket;
diff --git a/src/odil/json_converter.cpp b/src/odil/json_converter.cpp
index c9a970f..2a3f0c9 100644
--- a/src/odil/json_converter.cpp
+++ b/src/odil/json_converter.cpp
@@ -239,12 +239,10 @@ DataSet as_dataset(Json::Value const & json)
Json::Value const & json_element = *it;
VR const vr = as_vr(json_element["vr"].asString());
- Element element;
+ Element element(vr);
if(odil::is_string(vr) && vr != odil::VR::PN)
{
- element = Element(Value::Strings(), vr);
-
auto const & json_value = json_element["Value"];
for(auto const & json_item: json_value)
{
@@ -253,7 +251,6 @@ DataSet as_dataset(Json::Value const & json)
}
else if(vr == VR::PN)
{
- element = Element(Value::Strings(), vr);
auto const & json_value = json_element["Value"];
for(auto const & json_item: json_value)
{
@@ -278,8 +275,6 @@ DataSet as_dataset(Json::Value const & json)
}
else if(is_real(vr))
{
- element = Element(Value::Reals(), vr);
-
auto const & json_value = json_element["Value"];
for(auto const & json_item: json_value)
{
@@ -288,8 +283,6 @@ DataSet as_dataset(Json::Value const & json)
}
else if(is_int(vr))
{
- element = Element(Value::Integers(), vr);
-
auto const & json_value = json_element["Value"];
for(auto const & json_item: json_value)
{
@@ -298,7 +291,6 @@ DataSet as_dataset(Json::Value const & json)
}
else if(vr == VR::SQ)
{
- element = Element(Value::DataSets(), vr);
auto const & json_value = json_element["Value"];
for(auto const & json_item: json_value)
{
@@ -308,8 +300,6 @@ DataSet as_dataset(Json::Value const & json)
}
else if(is_binary(vr))
{
- element = Element(Value::Binary(), vr);
-
// cf. ToJSONVisitor::operator()(VR, Value::Binary): InlineBinary is
// single-valued
auto const & encoded = json_element["InlineBinary"].asString();
diff --git a/src/odil/json_converter.h b/src/odil/json_converter.h
index f4bcab7..529df68 100644
--- a/src/odil/json_converter.h
+++ b/src/odil/json_converter.h
@@ -12,18 +12,19 @@
#include <json/json.h>
#include "odil/DataSet.h"
+#include "odil/odil.h"
#include "odil/Value.h"
namespace odil
{
/// @brief Convert a data set to its JSON representation.
-Json::Value as_json(
+ODIL_API Json::Value as_json(
DataSet const & data_set,
odil::Value::Strings const & specific_character_set=odil::Value::Strings());
/// @brief Create a data set from its JSON representation.
-DataSet as_dataset(Json::Value const & json);
+ODIL_API DataSet as_dataset(Json::Value const & json);
}
diff --git a/src/odil/message/CEchoRequest.h b/src/odil/message/CEchoRequest.h
index d8a2f3c..494b2a5 100644
--- a/src/odil/message/CEchoRequest.h
+++ b/src/odil/message/CEchoRequest.h
@@ -10,6 +10,7 @@
#define _aec786b8_0074_4cb2_b9a1_4bf26bbd20fc
#include "odil/message/Request.h"
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/Value.h"
@@ -20,7 +21,7 @@ namespace message
{
/// @brief C-ECHO-RQ message.
-class CEchoRequest: public Request
+class ODIL_API CEchoRequest: public Request
{
public:
/**
diff --git a/src/odil/message/CEchoResponse.h b/src/odil/message/CEchoResponse.h
index 45b13d6..abb4108 100644
--- a/src/odil/message/CEchoResponse.h
+++ b/src/odil/message/CEchoResponse.h
@@ -9,6 +9,7 @@
#ifndef _266252d9_e801_479e_a805_004b101c5250
#define _266252d9_e801_479e_a805_004b101c5250
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/message/Response.h"
#include "odil/Value.h"
@@ -20,7 +21,7 @@ namespace message
{
/// @brief C-ECHO-RSP message.
-class CEchoResponse: public Response
+class ODIL_API CEchoResponse: public Response
{
public:
/**
diff --git a/src/odil/message/CFindRequest.cpp b/src/odil/message/CFindRequest.cpp
index 032a74d..10c1df0 100644
--- a/src/odil/message/CFindRequest.cpp
+++ b/src/odil/message/CFindRequest.cpp
@@ -27,6 +27,48 @@ CFindRequest
Value::Integer priority, DataSet const & dataset)
: Request(message_id)
{
+ this->_create(affected_sop_class_uid, priority, dataset);
+ this->set_data_set(dataset);
+}
+
+CFindRequest
+::CFindRequest(
+ Value::Integer message_id, Value::String const & affected_sop_class_uid,
+ Value::Integer priority, DataSet && dataset)
+: Request(message_id)
+{
+ this->_create(affected_sop_class_uid, priority, dataset);
+ this->set_data_set(std::move(dataset));
+}
+
+CFindRequest
+::CFindRequest(Message const & message)
+: Request(message)
+{
+ this->_parse(message);
+ this->set_data_set(message.get_data_set());
+}
+
+CFindRequest
+::CFindRequest(Message && message)
+: Request(message)
+{
+ this->_parse(message);
+ this->set_data_set(std::move(message.get_data_set()));
+}
+
+CFindRequest
+::~CFindRequest()
+{
+ // Nothing to do.
+}
+
+void
+CFindRequest
+::_create(
+ Value::String const & affected_sop_class_uid, Value::Integer priority,
+ DataSet const & dataset)
+{
this->set_command_field(Command::C_FIND_RQ);
this->set_affected_sop_class_uid(affected_sop_class_uid);
this->set_priority(priority);
@@ -34,12 +76,11 @@ CFindRequest
{
throw Exception("Data set is required");
}
- this->set_data_set(dataset);
}
+void
CFindRequest
-::CFindRequest(Message const & message)
-: Request(message)
+::_parse(Message const & message)
{
if(message.get_command_field() != Command::C_FIND_RQ)
{
@@ -56,13 +97,6 @@ CFindRequest
{
throw Exception("Data set is required");
}
- this->set_data_set(message.get_data_set());
-}
-
-CFindRequest
-::~CFindRequest()
-{
- // Nothing to do.
}
}
diff --git a/src/odil/message/CFindRequest.h b/src/odil/message/CFindRequest.h
index f3a23cc..e3f571a 100644
--- a/src/odil/message/CFindRequest.h
+++ b/src/odil/message/CFindRequest.h
@@ -9,6 +9,7 @@
#ifndef _74cfa9e7_da35_4130_a941_e17cb6932f60
#define _74cfa9e7_da35_4130_a941_e17cb6932f60
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/message/Request.h"
#include "odil/Value.h"
@@ -20,7 +21,7 @@ namespace message
{
/// @brief C-FIND-RQ message.
-class CFindRequest: public Request
+class ODIL_API CFindRequest: public Request
{
public:
/**
@@ -32,18 +33,39 @@ public:
Value::Integer priority, DataSet const & dataset);
/**
+ * @brief Create an find request with given Message ID,
+ * affected SOP class UID, priority, and data set.
+ */
+ CFindRequest(
+ Value::Integer message_id, Value::String const & affected_sop_class_uid,
+ Value::Integer priority, DataSet && dataset);
+
+ /**
* @brief Create a C-FIND-RQ from a generic Message.
*
* Raise an exception if the Message does not contain a C-FIND-RQ.
*/
CFindRequest(Message const & message);
+ /**
+ * @brief Create a C-FIND-RQ from a generic Message.
+ *
+ * Raise an exception if the Message does not contain a C-FIND-RQ.
+ */
+ CFindRequest(Message && message);
+
/// @brief Destructor.
virtual ~CFindRequest();
ODIL_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
affected_sop_class_uid, registry::AffectedSOPClassUID)
ODIL_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(priority, registry::Priority)
+
+private:
+ void _create(
+ Value::String const & affected_sop_class_uid, Value::Integer priority,
+ DataSet const & dataset);
+ void _parse(Message const & message);
};
}
diff --git a/src/odil/message/CFindResponse.cpp b/src/odil/message/CFindResponse.cpp
index c118dbe..39547fd 100644
--- a/src/odil/message/CFindResponse.cpp
+++ b/src/odil/message/CFindResponse.cpp
@@ -39,24 +39,34 @@ CFindResponse
}
CFindResponse
+::CFindResponse(
+ Value::Integer message_id_being_responded_to, Value::Integer status,
+ DataSet && dataset)
+: Response(message_id_being_responded_to, status)
+{
+ this->set_command_field(Command::C_FIND_RSP);
+ this->set_data_set(std::move(dataset));
+}
+
+CFindResponse
::CFindResponse(Message const & message)
: Response(message)
{
- if(message.get_command_field() != Command::C_FIND_RSP)
+ this->_parse(message);
+ if(message.has_data_set())
{
- throw Exception("Message is not a C-FIND-RSP");
+ this->set_data_set(message.get_data_set());
}
- this->set_command_field(message.get_command_field());
-
- ODIL_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
- message.get_command_set(), message_id, registry::MessageID, as_int)
- ODIL_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
- message.get_command_set(), affected_sop_class_uid,
- registry::AffectedSOPClassUID, as_string)
+}
+CFindResponse
+::CFindResponse(Message && message)
+: Response(message)
+{
+ this->_parse(message);
if(message.has_data_set())
{
- this->set_data_set(message.get_data_set());
+ this->set_data_set(std::move(message.get_data_set()));
}
}
@@ -66,6 +76,23 @@ CFindResponse
// Nothing to do.
}
+void
+CFindResponse
+::_parse(Message const & message)
+{
+ if(message.get_command_field() != Command::C_FIND_RSP)
+ {
+ throw Exception("Message is not a C-FIND-RSP");
+ }
+ this->set_command_field(message.get_command_field());
+
+ ODIL_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+ message.get_command_set(), message_id, registry::MessageID, as_int)
+ ODIL_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+ message.get_command_set(), affected_sop_class_uid,
+ registry::AffectedSOPClassUID, as_string)
+}
+
}
}
diff --git a/src/odil/message/CFindResponse.h b/src/odil/message/CFindResponse.h
index a628fb0..611cae7 100644
--- a/src/odil/message/CFindResponse.h
+++ b/src/odil/message/CFindResponse.h
@@ -10,6 +10,7 @@
#define _5fd36547_9498_4cf3_87cc_737af51e93a9
#include "odil/DataSet.h"
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/message/Response.h"
#include "odil/Value.h"
@@ -21,7 +22,7 @@ namespace message
{
/// @brief C-FIND-RSP message.
-class CFindResponse: public Response
+class ODIL_API CFindResponse: public Response
{
public:
/// @brief C-FIND status codes, PS 3.4, C.4.1.1.4
@@ -50,18 +51,36 @@ public:
DataSet const & dataset);
/**
+ * @brief Create an find response with given Message ID, status,
+ * and data set.
+ */
+ CFindResponse(
+ Value::Integer message_id_being_responded_to, Value::Integer status,
+ DataSet && dataset);
+
+ /**
* @brief Create a C-FIND-RSP from a generic Message.
*
* Raise an exception if the Message does not contain a C-FIND-RSP.
*/
CFindResponse(Message const & message);
+ /**
+ * @brief Create a C-FIND-RSP from a generic Message.
+ *
+ * Raise an exception if the Message does not contain a C-FIND-RSP.
+ */
+ CFindResponse(Message && message);
+
/// @brief Destructor.
virtual ~CFindResponse();
ODIL_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(message_id, registry::MessageID)
ODIL_MESSAGE_OPTIONAL_FIELD_STRING_MACRO(
affected_sop_class_uid, registry::AffectedSOPClassUID)
+
+private:
+ void _parse(Message const & message);
};
}
diff --git a/src/odil/message/CGetRequest.cpp b/src/odil/message/CGetRequest.cpp
index 6283fa3..af339f3 100644
--- a/src/odil/message/CGetRequest.cpp
+++ b/src/odil/message/CGetRequest.cpp
@@ -28,6 +28,48 @@ CGetRequest
Value::Integer priority, DataSet const & dataset)
: Request(message_id)
{
+ this->_create(affected_sop_class_uid, priority, dataset);
+ this->set_data_set(dataset);
+}
+
+CGetRequest
+::CGetRequest(
+ Value::Integer message_id, Value::String const & affected_sop_class_uid,
+ Value::Integer priority, DataSet && dataset)
+: Request(message_id)
+{
+ this->_create(affected_sop_class_uid, priority, dataset);
+ this->set_data_set(std::move(dataset));
+}
+
+CGetRequest
+::CGetRequest(Message const & message)
+: Request(message)
+{
+ this->_parse(message);
+ this->set_data_set(message.get_data_set());
+}
+
+CGetRequest
+::CGetRequest(Message && message)
+: Request(message)
+{
+ this->_parse(message);
+ this->set_data_set(std::move(message.get_data_set()));
+}
+
+CGetRequest
+::~CGetRequest()
+{
+ // Nothing to do.
+}
+
+void
+CGetRequest
+::_create(
+ Value::String const & affected_sop_class_uid, Value::Integer priority,
+ DataSet const & dataset)
+{
this->set_command_field(Command::C_GET_RQ);
this->set_affected_sop_class_uid(affected_sop_class_uid);
this->set_priority(priority);
@@ -35,12 +77,11 @@ CGetRequest
{
throw Exception("Data set is required");
}
- this->set_data_set(dataset);
}
+void
CGetRequest
-::CGetRequest(Message const & message)
-: Request(message)
+::_parse(Message const & message)
{
if(message.get_command_field() != Command::C_GET_RQ)
{
@@ -57,13 +98,6 @@ CGetRequest
{
throw Exception("Data set is required");
}
- this->set_data_set(message.get_data_set());
-}
-
-CGetRequest
-::~CGetRequest()
-{
- // Nothing to do.
}
}
diff --git a/src/odil/message/CGetRequest.h b/src/odil/message/CGetRequest.h
index 8152f5e..c2943c9 100644
--- a/src/odil/message/CGetRequest.h
+++ b/src/odil/message/CGetRequest.h
@@ -10,6 +10,7 @@
#define _6a22f126_7cc6_47ab_81c2_5f66b2714345
#include "odil/DataSet.h"
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/message/Request.h"
#include "odil/Value.h"
@@ -21,7 +22,7 @@ namespace message
{
/// @brief C-GET-RQ message.
-class CGetRequest: public Request
+class ODIL_API CGetRequest: public Request
{
public:
/**
@@ -33,18 +34,39 @@ public:
Value::Integer priority, DataSet const & dataset);
/**
+ * @brief Create an get request with given Message ID,
+ * affected SOP class UID, priority, and data set.
+ */
+ CGetRequest(
+ Value::Integer message_id, Value::String const & affected_sop_class_uid,
+ Value::Integer priority, DataSet && dataset);
+
+ /**
* @brief Create a C-GET-RQ from a generic Message.
*
* Raise an exception if the Message does not contain a C-GET-RQ.
*/
CGetRequest(Message const & message);
+ /**
+ * @brief Create a C-GET-RQ from a generic Message.
+ *
+ * Raise an exception if the Message does not contain a C-GET-RQ.
+ */
+ CGetRequest(Message && message);
+
/// @brief Destructor.
virtual ~CGetRequest();
ODIL_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
affected_sop_class_uid, registry::AffectedSOPClassUID)
ODIL_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(priority, registry::Priority)
+
+private:
+ void _create(
+ Value::String const & affected_sop_class_uid, Value::Integer priority,
+ DataSet const & dataset);
+ void _parse(Message const & message);
};
}
diff --git a/src/odil/message/CGetResponse.cpp b/src/odil/message/CGetResponse.cpp
index c624da0..9c3a9b8 100644
--- a/src/odil/message/CGetResponse.cpp
+++ b/src/odil/message/CGetResponse.cpp
@@ -39,15 +39,53 @@ CGetResponse
}
CGetResponse
+::CGetResponse(
+ Value::Integer message_id_being_responded_to, Value::Integer status,
+ DataSet && dataset)
+: Response(message_id_being_responded_to, status)
+{
+ this->set_command_field(Command::C_GET_RSP);
+ this->set_data_set(std::move(dataset));
+}
+
+CGetResponse
::CGetResponse(Message const & message)
: Response(message)
{
+ this->_parse(message);
+ if(message.has_data_set())
+ {
+ this->set_data_set(message.get_data_set());
+ }
+}
+
+CGetResponse
+::CGetResponse(Message && message)
+: Response(message)
+{
+ this->_parse(message);
+ if(message.has_data_set())
+ {
+ this->set_data_set(std::move(message.get_data_set()));
+ }
+}
+
+CGetResponse
+::~CGetResponse()
+{
+ // Nothing to do.
+}
+
+void
+CGetResponse
+::_parse(Message const & message)
+{
if(message.get_command_field() != Command::C_GET_RSP)
{
throw Exception("Message is not a C-GET-RSP");
}
this->set_command_field(message.get_command_field());
-
+
ODIL_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
message.get_command_set(), message_id, registry::MessageID, as_int)
ODIL_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
@@ -66,17 +104,6 @@ CGetResponse
ODIL_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
message.get_command_set(), number_of_warning_sub_operations,
registry::NumberOfWarningSuboperations, as_int)
-
- if(message.has_data_set())
- {
- this->set_data_set(message.get_data_set());
- }
-}
-
-CGetResponse
-::~CGetResponse()
-{
- // Nothing to do.
}
}
diff --git a/src/odil/message/CGetResponse.h b/src/odil/message/CGetResponse.h
index cc01120..797db38 100644
--- a/src/odil/message/CGetResponse.h
+++ b/src/odil/message/CGetResponse.h
@@ -10,6 +10,7 @@
#define _7b9819f1_d7a2_4898_a850_3ed6a61f08c6
#include "odil/DataSet.h"
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/message/Response.h"
#include "odil/Value.h"
@@ -21,7 +22,7 @@ namespace message
{
/// @brief C-GET-RSP message.
-class CGetResponse: public Response
+class ODIL_API CGetResponse: public Response
{
public:
/// @brief C-GET status codes, PS 3.4, C.4.3.1.4
@@ -51,12 +52,27 @@ public:
DataSet const & dataset);
/**
+ * @brief Create an get response with given Message ID, status,
+ * and data set.
+ */
+ CGetResponse(
+ Value::Integer message_id_being_responded_to, Value::Integer status,
+ DataSet && dataset);
+
+ /**
* @brief Create a C-GET-RSP from a generic Message.
*
* Raise an exception if the Message does not contain a C-GET-RSP.
*/
CGetResponse(Message const & message);
+ /**
+ * @brief Create a C-GET-RSP from a generic Message.
+ *
+ * Raise an exception if the Message does not contain a C-GET-RSP.
+ */
+ CGetResponse(Message && message);
+
/// @brief Destructor.
virtual ~CGetResponse();
@@ -72,6 +88,9 @@ public:
number_of_failed_sub_operations, registry::NumberOfFailedSuboperations)
ODIL_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
number_of_warning_sub_operations, registry::NumberOfWarningSuboperations)
+
+private:
+ void _parse(Message const & message);
};
}
diff --git a/src/odil/message/CMoveRequest.cpp b/src/odil/message/CMoveRequest.cpp
index 15e81ab..fa00292 100644
--- a/src/odil/message/CMoveRequest.cpp
+++ b/src/odil/message/CMoveRequest.cpp
@@ -27,6 +27,50 @@ CMoveRequest
DataSet const & dataset)
: Request(message_id)
{
+ this->_create(affected_sop_class_uid, priority, move_destination, dataset);
+ this->set_data_set(dataset);
+}
+
+CMoveRequest
+::CMoveRequest(
+ Value::Integer message_id, Value::String const & affected_sop_class_uid,
+ Value::Integer priority, Value::String const & move_destination,
+ DataSet && dataset)
+: Request(message_id)
+{
+ this->_create(affected_sop_class_uid, priority, move_destination, dataset);
+ this->set_data_set(std::move(dataset));
+}
+
+CMoveRequest
+::CMoveRequest(Message const & message)
+: Request(message)
+{
+ this->_parse(message);
+ this->set_data_set(message.get_data_set());
+}
+
+CMoveRequest
+::CMoveRequest(Message && message)
+: Request(message)
+{
+ this->_parse(message);
+ this->set_data_set(std::move(message.get_data_set()));
+}
+
+CMoveRequest
+::~CMoveRequest()
+{
+ // Nothing to do.
+}
+
+void
+CMoveRequest
+::_create(
+ Value::String const & affected_sop_class_uid,
+ Value::Integer priority, Value::String const & move_destination,
+ DataSet const & dataset)
+{
this->set_command_field(Command::C_MOVE_RQ);
this->set_affected_sop_class_uid(affected_sop_class_uid);
this->set_priority(priority);
@@ -35,12 +79,11 @@ CMoveRequest
{
throw Exception("Data set is required");
}
- this->set_data_set(dataset);
}
+void
CMoveRequest
-::CMoveRequest(Message const & message)
-: Request(message)
+::_parse(Message const & message)
{
if(message.get_command_field() != Command::C_MOVE_RQ)
{
@@ -60,13 +103,6 @@ CMoveRequest
{
throw Exception("Data set is required");
}
- this->set_data_set(message.get_data_set());
-}
-
-CMoveRequest
-::~CMoveRequest()
-{
- // Nothing to do.
}
}
diff --git a/src/odil/message/CMoveRequest.h b/src/odil/message/CMoveRequest.h
index 4977e34..fc3437a 100644
--- a/src/odil/message/CMoveRequest.h
+++ b/src/odil/message/CMoveRequest.h
@@ -10,6 +10,7 @@
#define _f6e243d2_6113_4fe3_8d04_3f034fc796bf
#include "odil/DataSet.h"
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/message/Request.h"
#include "odil/Value.h"
@@ -21,7 +22,7 @@ namespace message
{
/// @brief C-MOVE-RQ message.
-class CMoveRequest: public Request
+class ODIL_API CMoveRequest: public Request
{
public:
/**
@@ -34,12 +35,28 @@ public:
DataSet const & dataset);
/**
+ * @brief Create an move request with given Message ID,
+ * affected SOP class UID, priority, move destination, and data set.
+ */
+ CMoveRequest(
+ Value::Integer message_id, Value::String const & affected_sop_class_uid,
+ Value::Integer priority, Value::String const & move_destination,
+ DataSet && dataset);
+
+ /**
* @brief Create a C-MOVE-RQ from a generic Message.
*
* Raise an exception if the Message does not contain a C-MOVE-RQ.
*/
CMoveRequest(Message const & message);
+ /**
+ * @brief Create a C-MOVE-RQ from a generic Message.
+ *
+ * Raise an exception if the Message does not contain a C-MOVE-RQ.
+ */
+ CMoveRequest(Message && message);
+
/// @brief Destructor.
virtual ~CMoveRequest();
@@ -48,6 +65,13 @@ public:
ODIL_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(priority, registry::Priority)
ODIL_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
move_destination, registry::MoveDestination)
+
+private:
+ void _create(
+ Value::String const & affected_sop_class_uid,
+ Value::Integer priority, Value::String const & move_destination,
+ DataSet const & dataset);
+ void _parse(Message const & message);
};
}
diff --git a/src/odil/message/CMoveResponse.cpp b/src/odil/message/CMoveResponse.cpp
index 126fae8..54c8e5b 100644
--- a/src/odil/message/CMoveResponse.cpp
+++ b/src/odil/message/CMoveResponse.cpp
@@ -39,15 +39,53 @@ CMoveResponse
}
CMoveResponse
+::CMoveResponse(
+ Value::Integer message_id_being_responded_to, Value::Integer status,
+ DataSet && dataset)
+: Response(message_id_being_responded_to, status)
+{
+ this->set_command_field(Command::C_MOVE_RSP);
+ this->set_data_set(std::move(dataset));
+}
+
+CMoveResponse
::CMoveResponse(Message const & message)
: Response(message)
{
+ this->_parse(message);
+ if(message.has_data_set())
+ {
+ this->set_data_set(message.get_data_set());
+ }
+}
+
+CMoveResponse
+::CMoveResponse(Message && message)
+: Response(message)
+{
+ this->_parse(message);
+ if(message.has_data_set())
+ {
+ this->set_data_set(std::move(message.get_data_set()));
+ }
+}
+
+CMoveResponse
+::~CMoveResponse()
+{
+ // Nothing to do.
+}
+
+void
+CMoveResponse
+::_parse(Message const & message)
+{
if(message.get_command_field() != Command::C_MOVE_RSP)
{
throw Exception("Message is not a C-MOVE-RSP");
}
this->set_command_field(message.get_command_field());
-
+
ODIL_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
message.get_command_set(), message_id, registry::MessageID, as_int)
ODIL_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
@@ -66,17 +104,6 @@ CMoveResponse
ODIL_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
message.get_command_set(), number_of_warning_sub_operations,
registry::NumberOfWarningSuboperations, as_int)
-
- if(message.has_data_set())
- {
- this->set_data_set(message.get_data_set());
- }
-}
-
-CMoveResponse
-::~CMoveResponse()
-{
- // Nothing to do.
}
}
diff --git a/src/odil/message/CMoveResponse.h b/src/odil/message/CMoveResponse.h
index abded08..de9de2c 100644
--- a/src/odil/message/CMoveResponse.h
+++ b/src/odil/message/CMoveResponse.h
@@ -10,6 +10,7 @@
#define _b245f6f2_50c3_4c7c_80e1_f03d9c831301
#include "odil/DataSet.h"
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/message/Response.h"
#include "odil/Value.h"
@@ -21,7 +22,7 @@ namespace message
{
/// @brief C-MOVE-RSP message.
-class CMoveResponse: public Response
+class ODIL_API CMoveResponse: public Response
{
public:
/// @brief C-MOVE status codes, PS 3.4, C.4.2.1.5
@@ -52,12 +53,27 @@ public:
DataSet const & dataset);
/**
+ * @brief Create an move response with given Message ID, status,
+ * and data set.
+ */
+ CMoveResponse(
+ Value::Integer message_id_being_responded_to, Value::Integer status,
+ DataSet && dataset);
+
+ /**
* @brief Create a C-MOVE-RSP from a generic Message.
*
* Raise an exception if the Message does not contain a C-MOVE-RSP.
*/
CMoveResponse(Message const & message);
+ /**
+ * @brief Create a C-MOVE-RSP from a generic Message.
+ *
+ * Raise an exception if the Message does not contain a C-MOVE-RSP.
+ */
+ CMoveResponse(Message && message);
+
/// @brief Destructor.
virtual ~CMoveResponse();
@@ -73,6 +89,9 @@ public:
number_of_failed_sub_operations, registry::NumberOfFailedSuboperations)
ODIL_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
number_of_warning_sub_operations, registry::NumberOfWarningSuboperations)
+
+private:
+ void _parse(Message const & message);
};
}
diff --git a/src/odil/message/CStoreRequest.cpp b/src/odil/message/CStoreRequest.cpp
index 5cd1f31..a4773c3 100644
--- a/src/odil/message/CStoreRequest.cpp
+++ b/src/odil/message/CStoreRequest.cpp
@@ -28,6 +28,58 @@ CStoreRequest
Value::Integer move_originator_message_id)
: Request(message_id)
{
+ this->_create(
+ affected_sop_class_uid, affected_sop_instance_uid, priority,
+ dataset, move_originator_ae_title, move_originator_message_id);
+ this->set_data_set(dataset);
+}
+
+CStoreRequest
+::CStoreRequest(
+ Value::Integer message_id, Value::String const & affected_sop_class_uid,
+ Value::String const & affected_sop_instance_uid,
+ Value::Integer priority, DataSet && dataset,
+ Value::String const & move_originator_ae_title,
+ Value::Integer move_originator_message_id)
+: Request(message_id)
+{
+ this->_create(
+ affected_sop_class_uid, affected_sop_instance_uid, priority,
+ dataset, move_originator_ae_title, move_originator_message_id);
+ this->set_data_set(std::move(dataset));
+}
+
+CStoreRequest
+::CStoreRequest(Message const & message)
+: Request(message)
+{
+ this->_parse(message);
+ this->set_data_set(message.get_data_set());
+}
+
+CStoreRequest
+::CStoreRequest(Message && message)
+: Request(message)
+{
+ this->_parse(message);
+ this->set_data_set(std::move(message.get_data_set()));
+}
+
+CStoreRequest
+::~CStoreRequest()
+{
+ // Nothing to do.
+}
+
+void
+CStoreRequest
+::_create(
+ Value::String const & affected_sop_class_uid,
+ Value::String const & affected_sop_instance_uid,
+ Value::Integer priority, DataSet const & dataset,
+ Value::String const & move_originator_ae_title,
+ Value::Integer move_originator_message_id)
+{
this->set_command_field(Command::C_STORE_RQ);
this->set_affected_sop_class_uid(affected_sop_class_uid);
this->set_affected_sop_instance_uid(affected_sop_instance_uid);
@@ -42,12 +94,11 @@ CStoreRequest
{
throw Exception("Data set is required");
}
- this->set_data_set(dataset);
}
+void
CStoreRequest
-::CStoreRequest(Message const & message)
-: Request(message)
+::_parse(Message const & message)
{
if(message.get_command_field() != Command::C_STORE_RQ)
{
@@ -72,13 +123,6 @@ CStoreRequest
{
throw Exception("Data set is required");
}
- this->set_data_set(message.get_data_set());
-}
-
-CStoreRequest
-::~CStoreRequest()
-{
- // Nothing to do.
}
}
diff --git a/src/odil/message/CStoreRequest.h b/src/odil/message/CStoreRequest.h
index 0c08e26..f2d2559 100644
--- a/src/odil/message/CStoreRequest.h
+++ b/src/odil/message/CStoreRequest.h
@@ -12,6 +12,7 @@
#include <string>
#include "odil/DataSet.h"
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/message/Request.h"
#include "odil/Value.h"
@@ -23,7 +24,7 @@ namespace message
{
/// @brief C-STORE-RQ message.
-class CStoreRequest: public Request
+class ODIL_API CStoreRequest: public Request
{
public:
/**
@@ -38,12 +39,30 @@ public:
Value::Integer move_originator_message_id = -1);
/**
+ * @brief Create an store request with given Message ID,
+ * affected SOP class UID, priority, and data set.
+ */
+ CStoreRequest(
+ Value::Integer message_id, Value::String const & affected_sop_class_uid,
+ Value::String const & affected_sop_instance_uid,
+ Value::Integer priority, DataSet && dataset,
+ Value::String const & move_originator_ae_title = "",
+ Value::Integer move_originator_message_id = -1);
+
+ /**
* @brief Create a C-STORE-RQ from a generic Message.
*
* Raise an exception if the Message does not contain a C-STORE-RQ.
*/
CStoreRequest(Message const & message);
+ /**
+ * @brief Create a C-STORE-RQ from a generic Message.
+ *
+ * Raise an exception if the Message does not contain a C-STORE-RQ.
+ */
+ CStoreRequest(Message && message);
+
/// @brief Destructor.
virtual ~CStoreRequest();
@@ -52,10 +71,20 @@ public:
ODIL_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
affected_sop_instance_uid, registry::AffectedSOPInstanceUID)
ODIL_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(priority, registry::Priority)
+
ODIL_MESSAGE_OPTIONAL_FIELD_STRING_MACRO(
move_originator_ae_title, registry::MoveOriginatorApplicationEntityTitle)
ODIL_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
move_originator_message_id, registry::MoveOriginatorMessageID)
+
+private:
+ void _create(
+ Value::String const & affected_sop_class_uid,
+ Value::String const & affected_sop_instance_uid,
+ Value::Integer priority, DataSet const & dataset,
+ Value::String const & move_originator_ae_title,
+ Value::Integer move_originator_message_id);
+ void _parse(Message const & message);
};
}
diff --git a/src/odil/message/CStoreResponse.h b/src/odil/message/CStoreResponse.h
index 7ed82d1..a6b23cd 100644
--- a/src/odil/message/CStoreResponse.h
+++ b/src/odil/message/CStoreResponse.h
@@ -9,6 +9,7 @@
#ifndef _7e193624_081c_47dd_a011_986e96916ea9
#define _7e193624_081c_47dd_a011_986e96916ea9
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/message/Response.h"
#include "odil/Value.h"
@@ -20,7 +21,7 @@ namespace message
{
/// @brief C-STORE-RSP message.
-class CStoreResponse: public Response
+class ODIL_API CStoreResponse: public Response
{
public:
/// @brief C-STORE status codes, PS 3.4, B.2.3
diff --git a/src/odil/message/Cancellation.h b/src/odil/message/Cancellation.h
index 8290486..3efb611 100644
--- a/src/odil/message/Cancellation.h
+++ b/src/odil/message/Cancellation.h
@@ -10,6 +10,7 @@
#define _97fc1bfc_4cff_40f2_a1ed_4550c71a0bda
#include "odil/message/Message.h"
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/Value.h"
@@ -20,7 +21,7 @@ namespace message
{
/// @brief Base class for cancellation messages.
-class Cancellation: public Message
+class ODIL_API Cancellation: public Message
{
public:
/// @brief Create a response with given message id being responded to.
diff --git a/src/odil/message/Message.cpp b/src/odil/message/Message.cpp
index ff0836a..2eed751 100644
--- a/src/odil/message/Message.cpp
+++ b/src/odil/message/Message.cpp
@@ -37,6 +37,17 @@ Message
}
Message
+::Message(DataSet && command_set)
+: _command_set(std::move(command_set))
+{
+ if(!this->_command_set.has(registry::CommandDataSetType))
+ {
+ this->_command_set.add(registry::CommandDataSetType, VR::US);
+ }
+ this->_command_set.as_int(registry::CommandDataSetType) = { DataSetType::ABSENT };
+}
+
+Message
::Message(DataSet const & command_set, DataSet const & data_set)
: _command_set(command_set)
{
@@ -48,6 +59,17 @@ Message
}
Message
+::Message(DataSet && command_set, DataSet && data_set)
+: _command_set(std::move(command_set))
+{
+ if(!this->_command_set.has(registry::CommandDataSetType))
+ {
+ this->_command_set.add(registry::CommandDataSetType, VR::US);
+ }
+ this->set_data_set(std::move(data_set));
+}
+
+Message
::~Message()
{
// Nothing to do.
@@ -78,6 +100,17 @@ Message
return this->_data_set;
}
+DataSet &
+Message
+::get_data_set()
+{
+ if(!this->has_data_set())
+ {
+ throw Exception("No data set in message");
+ }
+ return this->_data_set;
+}
+
void
Message
::set_data_set(DataSet const & data_set)
@@ -88,6 +121,14 @@ Message
void
Message
+::set_data_set(DataSet && data_set)
+{
+ this->_data_set = std::move(data_set);
+ this->_command_set.as_int(registry::CommandDataSetType) = { DataSetType::PRESENT };
+}
+
+void
+Message
::delete_data_set()
{
this->_command_set.as_int(registry::CommandDataSetType) = { DataSetType::ABSENT };
diff --git a/src/odil/message/Message.h b/src/odil/message/Message.h
index 5a74391..f4c9e75 100644
--- a/src/odil/message/Message.h
+++ b/src/odil/message/Message.h
@@ -10,6 +10,7 @@
#define _dcfa5213_ad7e_4194_8b4b_e630aa0df2e8
#include "odil/DataSet.h"
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/Value.h"
@@ -72,7 +73,7 @@ namespace message
/**
* @brief Base class for all DIMSE messages.
*/
-class Message
+class ODIL_API Message
{
public:
struct Command
@@ -142,8 +143,14 @@ public:
Message(DataSet const & command_set);
/// @brief Create a message from existing data.
+ Message(DataSet && command_set);
+
+ /// @brief Create a message from existing data.
Message(DataSet const & command_set, DataSet const & data_set);
+ /// @brief Create a message from existing data.
+ Message(DataSet && command_set, DataSet && data_set);
+
/// @brief Destructor;
virtual ~Message();
@@ -158,10 +165,19 @@ public:
* data set is present.
*/
DataSet const & get_data_set() const;
+
+ /**
+ * @brief Return the data set of the message, raise an exception if no
+ * data set is present.
+ */
+ DataSet & get_data_set();
/// @brief Set the data set of the message.
void set_data_set(DataSet const & data_set);
+ /// @brief Set the data set of the message.
+ void set_data_set(DataSet && data_set);
+
/// @brief Delete the data set in this message.
void delete_data_set();
diff --git a/src/odil/message/NCreateRequest.cpp b/src/odil/message/NCreateRequest.cpp
new file mode 100644
index 0000000..5e9f79b
--- /dev/null
+++ b/src/odil/message/NCreateRequest.cpp
@@ -0,0 +1,51 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#include "NCreateRequest.h"
+
+#include "odil/message/Request.h"
+#include "odil/registry.h"
+#include "odil/Value.h"
+
+namespace odil
+{
+
+namespace message
+{
+
+NCreateRequest
+::NCreateRequest(Value::Integer message_id, const Value::String &affected_sop_class_uid)
+: Request(message_id)
+{
+ this->set_command_field(Command::N_CREATE_RQ);
+ this->set_affected_sop_class_uid( affected_sop_class_uid ) ;
+}
+
+NCreateRequest
+::NCreateRequest(Message const & message)
+: Request(message)
+{
+ if(message.get_command_field() != Command::N_CREATE_RQ)
+ {
+ throw Exception("Message is not a N-CREATE-RQ");
+ }
+ this->set_command_field(message.get_command_field());
+
+ this->set_affected_sop_class_uid(
+ message.get_command_set().as_string( registry::AffectedSOPClassUID, 0));
+}
+
+NCreateRequest
+::~NCreateRequest()
+{
+ // Nothing to do.
+}
+
+}
+
+}
diff --git a/src/odil/message/NCreateRequest.h b/src/odil/message/NCreateRequest.h
new file mode 100644
index 0000000..b2f85ac
--- /dev/null
+++ b/src/odil/message/NCreateRequest.h
@@ -0,0 +1,63 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#ifndef _9a741b7f_0254_4eac_9bbd_04b719c1f86a
+#define _9a741b7f_0254_4eac_9bbd_04b719c1f86a
+
+#include "odil/message/Request.h"
+#include "odil/odil.h"
+#include "odil/registry.h"
+#include "odil/Value.h"
+
+namespace odil
+{
+
+namespace message
+{
+
+/// @brief N-Create-RQ message.
+class ODIL_API NCreateRequest: public Request
+{
+public:
+ /**
+ * @brief Create an NCreate request with given Message ID and
+ * affected SOP class UID.
+ */
+ NCreateRequest(
+ Value::Integer message_id,
+ Value::String const & affected_sop_class_uid);
+
+ /**
+ * @brief Create a N-Create-RQ from a generic Message.
+ *
+ * Raise an exception if the Message does not contain a N-Create-RQ.
+ */
+ NCreateRequest(Message const & message);
+
+ /// @brief Destructor.
+ virtual ~NCreateRequest();
+
+ ODIL_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(
+ message_id, registry::MessageID)
+
+ ODIL_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
+ affected_sop_class_uid, registry::AffectedSOPClassUID)
+
+ ODIL_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
+ affected_sop_instance_uid, registry::AffectedSOPInstanceUID)
+
+ ODIL_MESSAGE_OPTIONAL_FIELD_STRING_MACRO(
+ attribute_list, registry::AttributeIdentifierList)
+
+};
+
+}
+
+}
+
+#endif // _9a741b7f_0254_4eac_9bbd_04b719c1f86a
diff --git a/src/odil/message/NCreateResponse.cpp b/src/odil/message/NCreateResponse.cpp
new file mode 100644
index 0000000..4516794
--- /dev/null
+++ b/src/odil/message/NCreateResponse.cpp
@@ -0,0 +1,53 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#include "NCreateResponse.h"
+
+#include "odil/Exception.h"
+#include "odil/registry.h"
+#include "odil/message/Response.h"
+#include "odil/Value.h"
+
+namespace odil
+{
+
+namespace message
+{
+
+NCreateResponse
+::NCreateResponse(const Value::Integer &message_id_being_responded_to, const Value::Integer &status,
+ Value::String const & affected_sop_class_uid)
+: Response(message_id_being_responded_to, status)
+{
+ this->set_command_field(Command::N_CREATE_RSP);
+ this->set_affected_sop_class_uid(affected_sop_class_uid);
+}
+
+NCreateResponse
+::NCreateResponse(Message const & message)
+: Response(message)
+{
+ if(message.get_command_field() != Command::N_CREATE_RSP)
+ {
+ throw Exception("Message is not a N-CREATE-RSP");
+ }
+ this->set_command_field(message.get_command_field());
+
+ this->set_affected_sop_class_uid(
+ message.get_command_set().as_string(registry::AffectedSOPClassUID, 0));
+}
+
+NCreateResponse
+::~NCreateResponse()
+{
+ // Nothing to do.
+}
+
+}
+
+}
diff --git a/src/odil/message/NCreateResponse.h b/src/odil/message/NCreateResponse.h
new file mode 100644
index 0000000..f789960
--- /dev/null
+++ b/src/odil/message/NCreateResponse.h
@@ -0,0 +1,61 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#ifndef _4f465ff9_8cd7_47cb_afc5_51461124bb01
+#define _4f465ff9_8cd7_47cb_afc5_51461124bb01
+
+#include "odil/odil.h"
+#include "odil/registry.h"
+#include "odil/message/Response.h"
+#include "odil/Value.h"
+
+namespace odil
+{
+
+namespace message
+{
+
+/// @brief N-Create-RSP message.
+class ODIL_API NCreateResponse: public Response
+{
+public:
+ /**
+ * @brief Create an NCreate response with given Message ID and
+ * affected SOP class UID.
+ */
+ NCreateResponse(
+ Value::Integer const & message_id_being_responded_to
+ , Value::Integer const & status
+ , Value::String const & affected_sop_class_uid);
+
+ /**
+ * @brief Create a N-Create-RSP from a generic Message.
+ *
+ * Raise an exception if the Message does not contain a N-Create-RSP.
+ */
+ NCreateResponse(Message const & message);
+
+ /// @brief Destructor.
+ virtual ~NCreateResponse();
+
+ ODIL_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(
+ message_id_being_responded_to, registry::MessageIDBeingRespondedTo)
+
+ ODIL_MESSAGE_OPTIONAL_FIELD_STRING_MACRO(
+ affected_sop_class_uid, registry::AffectedSOPClassUID)
+
+
+
+
+};
+
+}
+
+}
+
+#endif // _4f465ff9_8cd7_47cb_afc5_51461124bb01
diff --git a/src/odil/message/NSetRequest.cpp b/src/odil/message/NSetRequest.cpp
new file mode 100644
index 0000000..87aaba9
--- /dev/null
+++ b/src/odil/message/NSetRequest.cpp
@@ -0,0 +1,93 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#include "NSetRequest.h"
+
+#include <string>
+
+#include "odil/Exception.h"
+#include "odil/VR.h"
+
+namespace odil
+{
+
+namespace message
+{
+
+NSetRequest
+::NSetRequest(
+ Value::Integer message_id,
+ Value::String const & requested_sop_class_uid,
+ Value::String const & requested_sop_instance_uid,
+ DataSet const & dataset)
+: Request(message_id)
+{
+ this->set_command_field( ::odil::message::Message::Command::N_SET_RQ);
+ this->set_requested_sop_class_uid(requested_sop_class_uid);
+ this->set_requested_sop_instance_uid(requested_sop_instance_uid);
+
+ if(dataset.empty() )
+ {
+ throw Exception("Data set is required");
+ }
+ this->set_data_set(dataset);
+}
+
+/*
+NSetRequest
+::NSetRequest(Value::Integer message_id,
+ Value::String const & requested_sop_class_uid,
+ Value::String const & requested_sop_instance_uid,
+ DataSet const & dataset
+ )
+ : Request(message_id)
+{
+ this->set_command_field( ::odil::message::Message::Command::N_SET_RQ);
+ this->set_requested_sop_class_uid(requested_sop_class_uid);
+ this->set_requested_sop_instance_uid(requested_sop_instance_uid);
+
+ if( dataset.empty() )
+ {
+ throw Exception("Data set is required");
+ }
+ this->set_data_set(dataset);
+}
+*/
+
+NSetRequest
+::NSetRequest(Message const & message)
+: Request(message)
+{
+ if(message.get_command_field() != Command::N_SET_RQ)
+ {
+ throw Exception("Message is not a N-SET-RQ");
+ }
+
+ this->set_command_field(message.get_command_field());
+
+ this->set_requested_sop_class_uid(
+ message.get_command_set().as_string(registry::RequestedSOPClassUID, 0));
+ this->set_requested_sop_instance_uid(
+ message.get_command_set().as_string(registry::RequestedSOPInstanceUID, 0));
+
+ if(!message.has_data_set() || message.get_data_set().empty() )
+ {
+ throw Exception("Data set is required");
+ }
+ this->set_data_set(message.get_data_set());
+}
+
+NSetRequest
+::~NSetRequest()
+{
+ // Nothing to do.
+}
+
+}
+
+}
diff --git a/src/odil/message/NSetRequest.h b/src/odil/message/NSetRequest.h
new file mode 100644
index 0000000..72a78e2
--- /dev/null
+++ b/src/odil/message/NSetRequest.h
@@ -0,0 +1,59 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#ifndef _8125ab8d_bf37_4116_8ca8_93151ba022a8
+#define _8125ab8d_bf37_4116_8ca8_93151ba022a8
+
+#include "odil/message/Request.h"
+#include "odil/odil.h"
+#include "odil/registry.h"
+#include "odil/Value.h"
+
+namespace odil
+{
+
+namespace message
+{
+
+/// @brief N-Set-RQ message.
+class ODIL_API NSetRequest: public Request
+{
+public:
+ /**
+ * @brief Create a N-Set-RQ from a generic Message.
+ *
+ * Raise an exception if the Message does not contain a N-Set-RQ.
+ */
+ NSetRequest(Message const & message);
+
+ /**
+ * @brief Create an NSet request with given Message ID and
+ * requested SOP class UID and SOP Instance UID.
+ */
+ NSetRequest(
+ Value::Integer message_id,
+ Value::String const & requested_sop_class_uid,
+ Value::String const & requested_sop_instance_uid,
+ DataSet const & dataset //will be used to describe list of modifications to do.
+ );
+
+ /// @brief Destructor.
+ virtual ~NSetRequest();
+
+ ODIL_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
+ requested_sop_class_uid, registry::RequestedSOPClassUID)
+ ODIL_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
+ requested_sop_instance_uid, registry::RequestedSOPInstanceUID)
+
+};
+
+}
+
+}
+
+#endif // _8125ab8d_bf37_4116_8ca8_93151ba022a8
diff --git a/src/odil/message/NSetResponse.cpp b/src/odil/message/NSetResponse.cpp
new file mode 100644
index 0000000..d55d45f
--- /dev/null
+++ b/src/odil/message/NSetResponse.cpp
@@ -0,0 +1,61 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#include "NSetResponse.h"
+
+#include "odil/Exception.h"
+#include "odil/registry.h"
+#include "odil/message/Response.h"
+#include "odil/Value.h"
+
+namespace odil
+{
+
+namespace message
+{
+
+NSetResponse
+::NSetResponse(const Value::Integer &message_id_being_responded_to
+ , const Value::Integer & status
+ , Value::String const & requested_sop_class_uid
+ , Value::String const & requested_sop_instance_uid)
+: Response(message_id_being_responded_to, status)
+{
+ this->set_command_field(Command::N_SET_RSP);
+ this->set_affected_sop_class_uid(requested_sop_class_uid);
+ this->set_affected_sop_instance_uid(requested_sop_instance_uid );
+
+}
+
+NSetResponse
+::NSetResponse(Message const & message)
+: Response(message )
+{
+ if(message.get_command_field() != Command::N_SET_RSP)
+ {
+ throw Exception("Message is not a N-SET-RSP");
+ }
+
+ this->set_command_field(message.get_command_field());
+
+ this->set_affected_sop_class_uid(
+ message.get_command_set().as_string(registry::RequestedSOPClassUID, 0));
+
+ this->set_affected_sop_instance_uid(
+ message.get_command_set().as_string(registry::RequestedSOPInstanceUID, 0));
+}
+
+NSetResponse
+::~NSetResponse()
+{
+ // Nothing to do.
+}
+
+}
+
+}
diff --git a/src/odil/message/NSetResponse.h b/src/odil/message/NSetResponse.h
new file mode 100644
index 0000000..71a452f
--- /dev/null
+++ b/src/odil/message/NSetResponse.h
@@ -0,0 +1,58 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#ifndef _5d350855_531e_405a_a221_af3b0e720fd1
+#define _5d350855_531e_405a_a221_af3b0e720fd1
+
+#include "odil/registry.h"
+#include "odil/message/Response.h"
+#include "odil/odil.h"
+#include "odil/Value.h"
+
+namespace odil
+{
+
+namespace message
+{
+
+/// @brief N-Set-RSP message.
+class ODIL_API NSetResponse: public Response
+{
+public:
+ /**
+ * @brief Create an NSet response with given Message ID and
+ * affected SOP class UID.
+ */
+ NSetResponse(
+ Value::Integer const & message_id_being_responded_to,
+ Value::Integer const & status,
+ Value::String const & requested_sop_class_uid ,
+ Value::String const & requested_sop_instance_uid
+ );
+
+ /**
+ * @brief Create a N-Set-RSP from a generic Message.
+ *
+ * Raise an exception if the Message does not contain a N-Set-RSP.
+ */
+ NSetResponse(Message const & message);
+
+ /// @brief Destructor.
+ virtual ~NSetResponse();
+
+ ODIL_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO( status, registry::Status )
+
+ ODIL_MESSAGE_OPTIONAL_FIELD_STRING_MACRO(affected_sop_class_uid, registry::AffectedSOPClassUID)
+
+};
+
+}
+
+}
+
+#endif // _5d350855_531e_405a_a221_af3b0e720fd1
diff --git a/src/odil/message/Request.h b/src/odil/message/Request.h
index 63aba04..29344a1 100644
--- a/src/odil/message/Request.h
+++ b/src/odil/message/Request.h
@@ -10,6 +10,7 @@
#define _8d06a300_6aee_4d1f_bf10_ecdf4916ae9f
#include "odil/message/Message.h"
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/Value.h"
@@ -20,7 +21,7 @@ namespace message
{
/// @brief Base class for all DIMSE request messages.
-class Request: public Message
+class ODIL_API Request: public Message
{
public:
/// @brief Create a request with given Message ID.
diff --git a/src/odil/message/Response.h b/src/odil/message/Response.h
index fe1dd80..eb8c672 100644
--- a/src/odil/message/Response.h
+++ b/src/odil/message/Response.h
@@ -10,6 +10,7 @@
#define _0dd2e31e_212a_494a_a8d3_93b235336658
#include "odil/message/Message.h"
+#include "odil/odil.h"
#include "odil/registry.h"
#include "odil/Value.h"
@@ -20,7 +21,7 @@ namespace message
{
/// @brief Base class for all DIMSE response messages.
-class Response: public Message
+class ODIL_API Response: public Message
{
public:
/// @brief General status codes, from PS3.7, C
diff --git a/src/odil/odil.h b/src/odil/odil.h
index dcecb68..e2ddabb 100644
--- a/src/odil/odil.h
+++ b/src/odil/odil.h
@@ -3,6 +3,11 @@
#ifdef WIN32
# define EXPORT_DYNAMIC_LIBRARY __declspec(dllexport)
# define IMPORT_DYNAMIC_LIBRARY __declspec(dllimport)
+// disable warning: 'identifier': class 'type' needs to have dll-interface to be
+// used by clients of class 'type2'
+// disable warning: non - DLL-interface classkey 'identifier' used as base for
+// DLL-interface classkey 'identifier'
+#pragma warning( disable : 4251 4275 )
#else // WIN32
# define EXPORT_DYNAMIC_LIBRARY
# define IMPORT_DYNAMIC_LIBRARY
@@ -12,4 +17,4 @@
# define ODIL_API EXPORT_DYNAMIC_LIBRARY
#else // BUILDING_ODIL
# define ODIL_API IMPORT_DYNAMIC_LIBRARY
-#endif // BUILDING_ODIL
\ No newline at end of file
+#endif // BUILDING_ODIL
diff --git a/src/odil/pdu/AAbort.h b/src/odil/pdu/AAbort.h
index 7da2f07..3013e5f 100644
--- a/src/odil/pdu/AAbort.h
+++ b/src/odil/pdu/AAbort.h
@@ -11,6 +11,7 @@
#include <istream>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -20,7 +21,7 @@ namespace pdu
{
/// @brief A-ABORT PDU, cf. PS 3.8, 9.3.8.
-class AAbort: public Object
+class ODIL_API AAbort: public Object
{
public:
/// @brief Constructor.
diff --git a/src/odil/pdu/AAssociate.h b/src/odil/pdu/AAssociate.h
index ed18e27..d45463d 100644
--- a/src/odil/pdu/AAssociate.h
+++ b/src/odil/pdu/AAssociate.h
@@ -13,6 +13,7 @@
#include <istream>
#include <string>
+#include "odil/odil.h"
#include "odil/pdu/ApplicationContext.h"
#include "odil/pdu/Object.h"
#include "odil/pdu/UserInformation.h"
@@ -24,7 +25,7 @@ namespace pdu
{
/// @brief A-ASSOCIATE-RQ and A-ASSOCIATE-AC PDU, cf. PS 3.8, 9.3.2 and 9.3.3.
-class AAssociate: public Object
+class ODIL_API AAssociate: public Object
{
public:
/// @brief Constructor.
diff --git a/src/odil/pdu/AAssociateAC.h b/src/odil/pdu/AAssociateAC.h
index 3982bdd..979ea90 100644
--- a/src/odil/pdu/AAssociateAC.h
+++ b/src/odil/pdu/AAssociateAC.h
@@ -11,6 +11,7 @@
#include <vector>
+#include "odil/odil.h"
#include "odil/pdu/AAssociate.h"
#include "odil/pdu/PresentationContextAC.h"
@@ -21,7 +22,7 @@ namespace pdu
{
/// @brief A-ASSOCIATE-AC PDU, cf. PS 3.8, 9.3.3.
-class AAssociateAC: public AAssociate
+class ODIL_API AAssociateAC: public AAssociate
{
public:
/// @brief Constructor.
diff --git a/src/odil/pdu/AAssociateRJ.h b/src/odil/pdu/AAssociateRJ.h
index 2886113..6455cdc 100644
--- a/src/odil/pdu/AAssociateRJ.h
+++ b/src/odil/pdu/AAssociateRJ.h
@@ -9,6 +9,7 @@
#ifndef _3980566c_9185_40a2_8e7d_6286c2cd1959
#define _3980566c_9185_40a2_8e7d_6286c2cd1959
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -18,7 +19,7 @@ namespace pdu
{
/// @brief A-ASSOCIATE-RJ PDU, cf. PS 3.8, 9.3.4.
-class AAssociateRJ: public Object
+class ODIL_API AAssociateRJ: public Object
{
public:
/// @brief Constructor.
diff --git a/src/odil/pdu/AAssociateRQ.h b/src/odil/pdu/AAssociateRQ.h
index 98b8809..a9c0068 100644
--- a/src/odil/pdu/AAssociateRQ.h
+++ b/src/odil/pdu/AAssociateRQ.h
@@ -11,6 +11,7 @@
#include <vector>
+#include "odil/odil.h"
#include "odil/pdu/AAssociate.h"
#include "odil/pdu/PresentationContextRQ.h"
@@ -21,7 +22,7 @@ namespace pdu
{
/// @brief A-ASSOCIATE-RQ, cf. PS 3.8, 9.3.2
-class AAssociateRQ: public AAssociate
+class ODIL_API AAssociateRQ: public AAssociate
{
public:
/// @brief Constructor.
diff --git a/src/odil/pdu/AReleaseRP.h b/src/odil/pdu/AReleaseRP.h
index d9f0cc2..1d0628e 100644
--- a/src/odil/pdu/AReleaseRP.h
+++ b/src/odil/pdu/AReleaseRP.h
@@ -11,6 +11,7 @@
#include <istream>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -20,7 +21,7 @@ namespace pdu
{
/// @brief A-RELEASE-RP PDU, cf. PS 3.8, 9.3.7.
-class AReleaseRP: public Object
+class ODIL_API AReleaseRP: public Object
{
public:
/// @brief Constructor.
diff --git a/src/odil/pdu/AReleaseRQ.h b/src/odil/pdu/AReleaseRQ.h
index 87c2fcf..71e28fe 100644
--- a/src/odil/pdu/AReleaseRQ.h
+++ b/src/odil/pdu/AReleaseRQ.h
@@ -11,6 +11,7 @@
#include <istream>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -20,7 +21,7 @@ namespace pdu
{
/// @brief A-RELEASE-RQ PDU, cf. PS 3.8, 9.3.6.
-class AReleaseRQ: public Object
+class ODIL_API AReleaseRQ: public Object
{
public:
/// @brief Constructor.
diff --git a/src/odil/pdu/ApplicationContext.h b/src/odil/pdu/ApplicationContext.h
index 7d7260a..6a36202 100644
--- a/src/odil/pdu/ApplicationContext.h
+++ b/src/odil/pdu/ApplicationContext.h
@@ -12,6 +12,7 @@
#include <istream>
#include <string>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -23,7 +24,7 @@ namespace pdu
/**
* @brief Application Context item, (PS 3.8, 9.3.2.1).
*/
-class ApplicationContext: public Object
+class ODIL_API ApplicationContext: public Object
{
public:
/// @brief Create an Application Context.
diff --git a/src/odil/pdu/AsynchronousOperationsWindow.h b/src/odil/pdu/AsynchronousOperationsWindow.h
index 608246b..abae2ab 100644
--- a/src/odil/pdu/AsynchronousOperationsWindow.h
+++ b/src/odil/pdu/AsynchronousOperationsWindow.h
@@ -12,6 +12,7 @@
#include <cstdint>
#include <istream>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -21,7 +22,7 @@ namespace pdu
{
/// @brief Asynchronous Operations Window Sub-Item (PS 3.7, D.3.3.3.1 and D.3.3.3.2).
-class AsynchronousOperationsWindow: public Object
+class ODIL_API AsynchronousOperationsWindow: public Object
{
public:
/// @brief Item type.
diff --git a/src/odil/pdu/ImplementationClassUID.h b/src/odil/pdu/ImplementationClassUID.h
index 3a3a41f..aaf2cb0 100644
--- a/src/odil/pdu/ImplementationClassUID.h
+++ b/src/odil/pdu/ImplementationClassUID.h
@@ -13,6 +13,7 @@
#include <istream>
#include <string>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -22,7 +23,7 @@ namespace pdu
{
/// @brief Implementation Class UID Sub-Item (PS 3.7, D.3.3.2.1 and D.3.3.2.2).
-class ImplementationClassUID: public Object
+class ODIL_API ImplementationClassUID: public Object
{
public:
/// @brief Item type.
diff --git a/src/odil/pdu/ImplementationVersionName.h b/src/odil/pdu/ImplementationVersionName.h
index 1218709..827a682 100644
--- a/src/odil/pdu/ImplementationVersionName.h
+++ b/src/odil/pdu/ImplementationVersionName.h
@@ -13,6 +13,7 @@
#include <istream>
#include <string>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -22,7 +23,7 @@ namespace pdu
{
/// @brief Implementation Version Name Sub-Item (PS 3.7, D.3.3.2.3 and D.3.3.2.4).
-class ImplementationVersionName: public Object
+class ODIL_API ImplementationVersionName: public Object
{
public:
/// @brief Item type.
diff --git a/src/odil/pdu/Item.h b/src/odil/pdu/Item.h
index 37cb44f..b6444ec 100644
--- a/src/odil/pdu/Item.h
+++ b/src/odil/pdu/Item.h
@@ -16,6 +16,8 @@
#include <utility>
#include <vector>
+#include "odil/odil.h"
+
namespace odil
{
@@ -23,11 +25,11 @@ namespace pdu
{
/// @brief A sequence of fields forming a full PDU or a part of it.
-class Item
+class ODIL_API Item
{
public:
/// @brief Generic field.
- class Field
+ class ODIL_API Field
{
public:
/// @brief Possible types stored in the field.
@@ -256,6 +258,7 @@ private:
// No operator>> since we need explicit names and types.
+ODIL_API
std::ostream &
operator<<(std::ostream & stream, Item const & item);
diff --git a/src/odil/pdu/MaximumLength.h b/src/odil/pdu/MaximumLength.h
index cc01877..a1d6899 100644
--- a/src/odil/pdu/MaximumLength.h
+++ b/src/odil/pdu/MaximumLength.h
@@ -12,6 +12,7 @@
#include <cstdint>
#include <istream>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -21,7 +22,7 @@ namespace pdu
{
/// @brief Maximum Length Sub-Item Structure (PS 3.8, D.1).
-class MaximumLength: public Object
+class ODIL_API MaximumLength: public Object
{
public:
/// @brief Item type.
diff --git a/src/odil/pdu/Object.h b/src/odil/pdu/Object.h
index db1bfcd..0584465 100644
--- a/src/odil/pdu/Object.h
+++ b/src/odil/pdu/Object.h
@@ -10,6 +10,8 @@
#define _da2270e3_d393_415a_9c5c_6253152ed9da
#include <ostream>
+
+#include "odil/odil.h"
#include "odil/pdu/Item.h"
namespace odil
@@ -22,7 +24,7 @@ namespace pdu
* @brief Base class for all PDU-related high-level objects (PDU, items and
* sub-items).
*/
-class Object
+class ODIL_API Object
{
public:
/// @brief Destructor, makes the type polymorphic.
@@ -45,6 +47,7 @@ protected:
};
/// @brief Dump the PDU-object in its binary form.
+ODIL_API
std::ostream &
operator<<(std::ostream & stream, Object const & object);
diff --git a/src/odil/pdu/PDataTF.h b/src/odil/pdu/PDataTF.h
index cc3abbf..2bc0201 100644
--- a/src/odil/pdu/PDataTF.h
+++ b/src/odil/pdu/PDataTF.h
@@ -13,6 +13,7 @@
#include <istream>
#include <vector>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -22,10 +23,10 @@ namespace pdu
{
/// @brief P-DATA-TF PDU, cf. PS 3.8, 9.3.5.
-class PDataTF: public Object
+class ODIL_API PDataTF: public Object
{
public:
- class PresentationDataValueItem: public Object
+ class ODIL_API PresentationDataValueItem: public Object
{
public:
PresentationDataValueItem(
diff --git a/src/odil/pdu/PresentationContext.h b/src/odil/pdu/PresentationContext.h
index 2cf07c8..1174641 100644
--- a/src/odil/pdu/PresentationContext.h
+++ b/src/odil/pdu/PresentationContext.h
@@ -14,6 +14,7 @@
#include <string>
#include <vector>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -26,7 +27,7 @@ namespace pdu
* @brief Presentation Context item, either for a A-ASSOCIATE-RQ PDU (PS 3.8,
* 9.3.2.2) or for a A-ASSOCIATE-AC PDU (PS 3.8, 9.3.3.2).
*/
-class PresentationContext: public Object
+class ODIL_API PresentationContext: public Object
{
public:
/// @brief Constructor
diff --git a/src/odil/pdu/PresentationContextAC.h b/src/odil/pdu/PresentationContextAC.h
index e04108e..75c156e 100644
--- a/src/odil/pdu/PresentationContextAC.h
+++ b/src/odil/pdu/PresentationContextAC.h
@@ -13,6 +13,7 @@
#include <istream>
#include <string>
+#include "odil/odil.h"
#include "odil/pdu/PresentationContext.h"
namespace odil
@@ -22,7 +23,7 @@ namespace pdu
{
/// @brief Presentation Context item for a A-ASSOCIATE-AC PDU (PS 3.8, 9.3.3.2).
-class PresentationContextAC: public PresentationContext
+class ODIL_API PresentationContextAC: public PresentationContext
{
public:
/// @brief Constructor.
diff --git a/src/odil/pdu/PresentationContextRQ.h b/src/odil/pdu/PresentationContextRQ.h
index 4582601..87377a8 100644
--- a/src/odil/pdu/PresentationContextRQ.h
+++ b/src/odil/pdu/PresentationContextRQ.h
@@ -14,6 +14,7 @@
#include <string>
#include <vector>
+#include "odil/odil.h"
#include "odil/pdu/PresentationContext.h"
namespace odil
@@ -23,7 +24,7 @@ namespace pdu
{
/// @brief Presentation Context item for a A-ASSOCIATE-RQ PDU (PS 3.8, 9.3.2.2).
-class PresentationContextRQ: public PresentationContext
+class ODIL_API PresentationContextRQ: public PresentationContext
{
public:
/// @brief Constructor.
diff --git a/src/odil/pdu/RoleSelection.h b/src/odil/pdu/RoleSelection.h
index edcaaee..e828e71 100644
--- a/src/odil/pdu/RoleSelection.h
+++ b/src/odil/pdu/RoleSelection.h
@@ -13,6 +13,7 @@
#include <istream>
#include <string>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -22,7 +23,7 @@ namespace pdu
{
/// @brief SCU/SCP Role Selection Sub-Item (PS 3.7, D.3.3.4.1 and D.3.3.4.2).
-class RoleSelection: public Object
+class ODIL_API RoleSelection: public Object
{
public:
/// @brief Item type.
diff --git a/src/odil/pdu/SOPClassCommonExtendedNegotiation.h b/src/odil/pdu/SOPClassCommonExtendedNegotiation.h
index 36ef78d..a0188e2 100644
--- a/src/odil/pdu/SOPClassCommonExtendedNegotiation.h
+++ b/src/odil/pdu/SOPClassCommonExtendedNegotiation.h
@@ -13,6 +13,7 @@
#include <string>
#include <vector>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -22,7 +23,7 @@ namespace pdu
{
/// @brief SOP Class Common Extended Negotiation sub-item (PS 3.7, D.3.3.6).
-class SOPClassCommonExtendedNegotiation: public Object
+class ODIL_API SOPClassCommonExtendedNegotiation: public Object
{
public:
/// @brief Item type.
diff --git a/src/odil/pdu/SOPClassExtendedNegotiation.h b/src/odil/pdu/SOPClassExtendedNegotiation.h
index 91acf0f..638ed79 100644
--- a/src/odil/pdu/SOPClassExtendedNegotiation.h
+++ b/src/odil/pdu/SOPClassExtendedNegotiation.h
@@ -14,6 +14,7 @@
#include <string>
#include <vector>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -23,7 +24,7 @@ namespace pdu
{
/// @brief SOP Class Extended Negotiation sub-item (PS 3.7, D.3.3.5).
-class SOPClassExtendedNegotiation: public Object
+class ODIL_API SOPClassExtendedNegotiation: public Object
{
public:
/// @brief Item type.
diff --git a/src/odil/pdu/UserIdentityAC.h b/src/odil/pdu/UserIdentityAC.h
index c646ed6..32d6b86 100644
--- a/src/odil/pdu/UserIdentityAC.h
+++ b/src/odil/pdu/UserIdentityAC.h
@@ -12,6 +12,7 @@
#include <istream>
#include <string>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -21,7 +22,7 @@ namespace pdu
{
/// @brief User Identity Sub-Item Structure (A-ASSOCIATE-AC) (PS 3.7, D.3.3.7.2).
-class UserIdentityAC: public Object
+class ODIL_API UserIdentityAC: public Object
{
public:
/// @brief Item type.
diff --git a/src/odil/pdu/UserIdentityRQ.h b/src/odil/pdu/UserIdentityRQ.h
index 3289cfe..3d6d104 100644
--- a/src/odil/pdu/UserIdentityRQ.h
+++ b/src/odil/pdu/UserIdentityRQ.h
@@ -13,6 +13,7 @@
#include <istream>
#include <string>
+#include "odil/odil.h"
#include "odil/pdu/Object.h"
namespace odil
@@ -22,7 +23,7 @@ namespace pdu
{
/// @brief User Identity Sub-Item Structure (A-ASSOCIATE-RQ) (PS 3.7, D.3.3.7.1).
-class UserIdentityRQ: public Object
+class ODIL_API UserIdentityRQ: public Object
{
public:
/// @brief Item type.
diff --git a/src/odil/pdu/UserInformation.h b/src/odil/pdu/UserInformation.h
index 3f7c6fb..7ba4caa 100644
--- a/src/odil/pdu/UserInformation.h
+++ b/src/odil/pdu/UserInformation.h
@@ -13,6 +13,7 @@
#include <istream>
#include <vector>
+#include "odil/odil.h"
#include "odil/pdu/MaximumLength.h"
#include "odil/pdu/Object.h"
#include "odil/pdu/UserIdentityAC.h"
@@ -25,7 +26,7 @@ namespace pdu
{
/// @brief User Information Item Structure (PS 3.8, 9.3.2.3 and 9.3.3.3).
-class UserInformation: public Object
+class ODIL_API UserInformation: public Object
{
public:
/// @brief Create a User Information item with no sub-items.
diff --git a/src/odil/registry.cpp b/src/odil/registry.cpp
index d15a09d..186615b 100644
--- a/src/odil/registry.cpp
+++ b/src/odil/registry.cpp
@@ -618,6 +618,14 @@ ElementsDictionary create_public_dictionary()
"Strain Additional Information", "StrainAdditionalInformation", "UT", "1" },
{ Tag(0x0010, 0x0219),
"Strain Code Sequence", "StrainCodeSequence", "SQ", "1" },
+ { Tag(0x0010, 0x0221),
+ "Genetic Modifications Sequence", "GeneticModificationsSequence", "SQ", "1" },
+ { Tag(0x0010, 0x0222),
+ "Genetic Modifications Description", "GeneticModificationsDescription", "UC", "1" },
+ { Tag(0x0010, 0x0223),
+ "Genetic Modifications Nomenclature", "GeneticModificationsNomenclature", "LO", "1" },
+ { Tag(0x0010, 0x0229),
+ "Genetic Modifications Code Sequence", "GeneticModificationsCodeSequence", "SQ", "1" },
{ Tag(0x0010, 0x1000),
"Other Patient IDs", "OtherPatientIDs", "LO", "1-n" },
{ Tag(0x0010, 0x1001),
@@ -3726,6 +3734,12 @@ ElementsDictionary create_public_dictionary()
"Segmented Blue Palette Color Lookup Table Data", "SegmentedBluePaletteColorLookupTableData", "OW", "1" },
{ Tag(0x0028, 0x1224),
"Segmented Alpha Palette Color Lookup Table Data", "SegmentedAlphaPaletteColorLookupTableData", "OW", "1" },
+ { Tag(0x0028, 0x1230),
+ "Stored Value Color Range Sequence", "StoredValueColorRangeSequence", "SQ", "1" },
+ { Tag(0x0028, 0x1231),
+ "Minimum Stored Value Mapped", "MinimumStoredValueMapped", "FD", "1" },
+ { Tag(0x0028, 0x1232),
+ "Maximum Stored Value Mapped", "MaximumStoredValueMapped", "FD", "1" },
{ Tag(0x0028, 0x1300),
"Breast Implant Present", "BreastImplantPresent", "CS", "1" },
{ Tag(0x0028, 0x1350),
@@ -5324,6 +5338,8 @@ ElementsDictionary create_public_dictionary()
"Segment Label", "SegmentLabel", "LO", "1" },
{ Tag(0x0062, 0x0006),
"Segment Description", "SegmentDescription", "ST", "1" },
+ { Tag(0x0062, 0x0007),
+ "Segmentation Algorithm Identification Sequence", "SegmentationAlgorithmIdentificationSequence", "SQ", "1" },
{ Tag(0x0062, 0x0008),
"Segment Algorithm Type", "SegmentAlgorithmType", "CS", "1" },
{ Tag(0x0062, 0x0009),
@@ -5537,7 +5553,7 @@ ElementsDictionary create_public_dictionary()
{ Tag(0x0068, 0x62e0),
"View Orientation Code Sequence", "ViewOrientationCodeSequence", "SQ", "1" },
{ Tag(0x0068, 0x62f0),
- "View Orientation Modifier", "ViewOrientationModifier", "FD", "9" },
+ "View Orientation Modifier Code Sequence", "ViewOrientationModifierCodeSequence", "SQ", "1" },
{ Tag(0x0068, 0x62f2),
"HPGL Document Scaling", "HPGLDocumentScaling", "FD", "1" },
{ Tag(0x0068, 0x6300),
@@ -6359,7 +6375,7 @@ ElementsDictionary create_public_dictionary()
{ Tag(0x0076, 0x0032),
"Component Types Sequence", "ComponentTypesSequence", "SQ", "1" },
{ Tag(0x0076, 0x0034),
- "Component Type Code Sequence", "ComponentTypeCodeSequence", "CS", "1" },
+ "Component Type Code Sequence", "ComponentTypeCodeSequence", "SQ", "1" },
{ Tag(0x0076, 0x0036),
"Exclusive Component Type", "ExclusiveComponentType", "CS", "1" },
{ Tag(0x0076, 0x0038),
@@ -7095,6 +7111,8 @@ ElementsDictionary create_public_dictionary()
"Parameter Pointer", "ParameterPointer", "AT", "1" },
{ Tag(0x3008, 0x0066),
"Override Reason", "OverrideReason", "ST", "1" },
+ { Tag(0x3008, 0x0067),
+ "Parameter Value Number", "ParameterValueNumber", "US", "1" },
{ Tag(0x3008, 0x0068),
"Corrected Parameter Sequence", "CorrectedParameterSequence", "SQ", "1" },
{ Tag(0x3008, 0x006a),
@@ -7885,6 +7903,8 @@ ElementsDictionary create_public_dictionary()
"Range Modulator Gating Stop Water Equivalent Thickness", "RangeModulatorGatingStopWaterEquivalentThickness", "FL", "1" },
{ Tag(0x300a, 0x038a),
"Isocenter to Range Modulator Distance", "IsocenterToRangeModulatorDistance", "FL", "1" },
+ { Tag(0x300a, 0x038f),
+ "Scan Spot Time Offset", "ScanSpotTimeOffset", "FL", "1-n" },
{ Tag(0x300a, 0x0390),
"Scan Spot Tune ID", "ScanSpotTuneID", "SH", "1" },
{ Tag(0x300a, 0x0391),
@@ -8869,7 +8889,11 @@ std::map<std::string, odil::Tag> create_public_tags()
"Strain Stock Sequence", "StrainStockSequence", "SQ", "1" }, { Tag(0x0010, 0x0217),
"Strain Source", "StrainSource", "LO", "1" }, { Tag(0x0010, 0x0218),
"Strain Additional Information", "StrainAdditionalInformation", "UT", "1" }, { Tag(0x0010, 0x0219),
- "Strain Code Sequence", "StrainCodeSequence", "SQ", "1" }, { Tag(0x0010, 0x1000),
+ "Strain Code Sequence", "StrainCodeSequence", "SQ", "1" }, { Tag(0x0010, 0x0221),
+ "Genetic Modifications Sequence", "GeneticModificationsSequence", "SQ", "1" }, { Tag(0x0010, 0x0222),
+ "Genetic Modifications Description", "GeneticModificationsDescription", "UC", "1" }, { Tag(0x0010, 0x0223),
+ "Genetic Modifications Nomenclature", "GeneticModificationsNomenclature", "LO", "1" }, { Tag(0x0010, 0x0229),
+ "Genetic Modifications Code Sequence", "GeneticModificationsCodeSequence", "SQ", "1" }, { Tag(0x0010, 0x1000),
"Other Patient IDs", "OtherPatientIDs", "LO", "1-n" }, { Tag(0x0010, 0x1001),
"Other Patient Names", "OtherPatientNames", "PN", "1-n" }, { Tag(0x0010, 0x1002),
"Other Patient IDs Sequence", "OtherPatientIDsSequence", "SQ", "1" }, { Tag(0x0010, 0x1005),
@@ -10408,7 +10432,10 @@ std::map<std::string, odil::Tag> create_public_tags()
"Segmented Red Palette Color Lookup Table Data", "SegmentedRedPaletteColorLookupTableData", "OW", "1" }, { Tag(0x0028, 0x1222),
"Segmented Green Palette Color Lookup Table Data", "SegmentedGreenPaletteColorLookupTableData", "OW", "1" }, { Tag(0x0028, 0x1223),
"Segmented Blue Palette Color Lookup Table Data", "SegmentedBluePaletteColorLookupTableData", "OW", "1" }, { Tag(0x0028, 0x1224),
- "Segmented Alpha Palette Color Lookup Table Data", "SegmentedAlphaPaletteColorLookupTableData", "OW", "1" }, { Tag(0x0028, 0x1300),
+ "Segmented Alpha Palette Color Lookup Table Data", "SegmentedAlphaPaletteColorLookupTableData", "OW", "1" }, { Tag(0x0028, 0x1230),
+ "Stored Value Color Range Sequence", "StoredValueColorRangeSequence", "SQ", "1" }, { Tag(0x0028, 0x1231),
+ "Minimum Stored Value Mapped", "MinimumStoredValueMapped", "FD", "1" }, { Tag(0x0028, 0x1232),
+ "Maximum Stored Value Mapped", "MaximumStoredValueMapped", "FD", "1" }, { Tag(0x0028, 0x1300),
"Breast Implant Present", "BreastImplantPresent", "CS", "1" }, { Tag(0x0028, 0x1350),
"Partial View", "PartialView", "CS", "1" }, { Tag(0x0028, 0x1351),
"Partial View Description", "PartialViewDescription", "ST", "1" }, { Tag(0x0028, 0x1352),
@@ -11207,7 +11234,8 @@ std::map<std::string, odil::Tag> create_public_tags()
"Segmented Property Category Code Sequence", "SegmentedPropertyCategoryCodeSequence", "SQ", "1" }, { Tag(0x0062, 0x0004),
"Segment Number", "SegmentNumber", "US", "1" }, { Tag(0x0062, 0x0005),
"Segment Label", "SegmentLabel", "LO", "1" }, { Tag(0x0062, 0x0006),
- "Segment Description", "SegmentDescription", "ST", "1" }, { Tag(0x0062, 0x0008),
+ "Segment Description", "SegmentDescription", "ST", "1" }, { Tag(0x0062, 0x0007),
+ "Segmentation Algorithm Identification Sequence", "SegmentationAlgorithmIdentificationSequence", "SQ", "1" }, { Tag(0x0062, 0x0008),
"Segment Algorithm Type", "SegmentAlgorithmType", "CS", "1" }, { Tag(0x0062, 0x0009),
"Segment Algorithm Name", "SegmentAlgorithmName", "LO", "1" }, { Tag(0x0062, 0x000a),
"Segment Identification Sequence", "SegmentIdentificationSequence", "SQ", "1" }, { Tag(0x0062, 0x000b),
@@ -11314,7 +11342,7 @@ std::map<std::string, odil::Tag> create_public_tags()
"HPGL Document ID", "HPGLDocumentID", "US", "1" }, { Tag(0x0068, 0x62d5),
"HPGL Document Label", "HPGLDocumentLabel", "LO", "1" }, { Tag(0x0068, 0x62e0),
"View Orientation Code Sequence", "ViewOrientationCodeSequence", "SQ", "1" }, { Tag(0x0068, 0x62f0),
- "View Orientation Modifier", "ViewOrientationModifier", "FD", "9" }, { Tag(0x0068, 0x62f2),
+ "View Orientation Modifier Code Sequence", "ViewOrientationModifierCodeSequence", "SQ", "1" }, { Tag(0x0068, 0x62f2),
"HPGL Document Scaling", "HPGLDocumentScaling", "FD", "1" }, { Tag(0x0068, 0x6300),
"HPGL Document", "HPGLDocument", "OB", "1" }, { Tag(0x0068, 0x6310),
"HPGL Contour Pen Number", "HPGLContourPenNumber", "US", "1" }, { Tag(0x0068, 0x6320),
@@ -11725,7 +11753,7 @@ std::map<std::string, odil::Tag> create_public_tags()
"Procedure Type Code Sequence", "ProcedureTypeCodeSequence", "SQ", "1" }, { Tag(0x0076, 0x0030),
"Surgical Technique", "SurgicalTechnique", "LO", "1" }, { Tag(0x0076, 0x0032),
"Component Types Sequence", "ComponentTypesSequence", "SQ", "1" }, { Tag(0x0076, 0x0034),
- "Component Type Code Sequence", "ComponentTypeCodeSequence", "CS", "1" }, { Tag(0x0076, 0x0036),
+ "Component Type Code Sequence", "ComponentTypeCodeSequence", "SQ", "1" }, { Tag(0x0076, 0x0036),
"Exclusive Component Type", "ExclusiveComponentType", "CS", "1" }, { Tag(0x0076, 0x0038),
"Mandatory Component Type", "MandatoryComponentType", "CS", "1" }, { Tag(0x0076, 0x0040),
"Component Sequence", "ComponentSequence", "SQ", "1" }, { Tag(0x0076, 0x0055),
@@ -12082,7 +12110,8 @@ std::map<std::string, odil::Tag> create_public_tags()
"Parameter Item Index", "ParameterItemIndex", "IS", "1" }, { Tag(0x3008, 0x0064),
"Measured Dose Reference Number", "MeasuredDoseReferenceNumber", "IS", "1" }, { Tag(0x3008, 0x0065),
"Parameter Pointer", "ParameterPointer", "AT", "1" }, { Tag(0x3008, 0x0066),
- "Override Reason", "OverrideReason", "ST", "1" }, { Tag(0x3008, 0x0068),
+ "Override Reason", "OverrideReason", "ST", "1" }, { Tag(0x3008, 0x0067),
+ "Parameter Value Number", "ParameterValueNumber", "US", "1" }, { Tag(0x3008, 0x0068),
"Corrected Parameter Sequence", "CorrectedParameterSequence", "SQ", "1" }, { Tag(0x3008, 0x006a),
"Correction Value", "CorrectionValue", "FL", "1" }, { Tag(0x3008, 0x0070),
"Calculated Dose Reference Sequence", "CalculatedDoseReferenceSequence", "SQ", "1" }, { Tag(0x3008, 0x0072),
@@ -12477,7 +12506,8 @@ std::map<std::string, odil::Tag> create_public_tags()
"Range Modulator Gating Stop Value", "RangeModulatorGatingStopValue", "FL", "1" }, { Tag(0x300a, 0x0386),
"Range Modulator Gating Start Water Equivalent Thickness", "RangeModulatorGatingStartWaterEquivalentThickness", "FL", "1" }, { Tag(0x300a, 0x0388),
"Range Modulator Gating Stop Water Equivalent Thickness", "RangeModulatorGatingStopWaterEquivalentThickness", "FL", "1" }, { Tag(0x300a, 0x038a),
- "Isocenter to Range Modulator Distance", "IsocenterToRangeModulatorDistance", "FL", "1" }, { Tag(0x300a, 0x0390),
+ "Isocenter to Range Modulator Distance", "IsocenterToRangeModulatorDistance", "FL", "1" }, { Tag(0x300a, 0x038f),
+ "Scan Spot Time Offset", "ScanSpotTimeOffset", "FL", "1-n" }, { Tag(0x300a, 0x0390),
"Scan Spot Tune ID", "ScanSpotTuneID", "SH", "1" }, { Tag(0x300a, 0x0391),
"Scan Spot Prescribed Indices", "ScanSpotPrescribedIndices", "IS", "1-n" }, { Tag(0x300a, 0x0392),
"Number of Scan Spot Positions", "NumberOfScanSpotPositions", "IS", "1" }, { Tag(0x300a, 0x0393),
@@ -12763,13 +12793,15 @@ UIDsDictionary create_uids_dictionary()
{ "1.2.840.10008.1.2.4.93", "JPEG 2000 Part 2 Multi-component Image Compression", "JPEG2000Part2MulticomponentImageCompression", "Transfer Syntax" },
{ "1.2.840.10008.1.2.4.94", "JPIP Referenced", "JPIPReferenced", "Transfer Syntax" },
{ "1.2.840.10008.1.2.4.95", "JPIP Referenced Deflate", "JPIPReferencedDeflate", "Transfer Syntax" },
- { "1.2.840.10008.1.2.4.100", "MPEG2 Main Profile @ Main Level", "MPEG2MainProfileMainLevel", "Transfer Syntax" },
- { "1.2.840.10008.1.2.4.101", "MPEG2 Main Profile @ High Level", "MPEG2MainProfileHighLevel", "Transfer Syntax" },
+ { "1.2.840.10008.1.2.4.100", "MPEG2 Main Profile / Main Level", "MPEG2MainProfileMainLevel", "Transfer Syntax" },
+ { "1.2.840.10008.1.2.4.101", "MPEG2 Main Profile / High Level", "MPEG2MainProfileHighLevel", "Transfer Syntax" },
{ "1.2.840.10008.1.2.4.102", "MPEG-4 AVC/H.264 High Profile / Level 4.1", "MPEG4AVCH264HighProfileLevel41", "Transfer Syntax" },
{ "1.2.840.10008.1.2.4.103", "MPEG-4 AVC/H.264 BD-compatible High Profile / Level 4.1", "MPEG4AVCH264BDcompatibleHighProfileLevel41", "Transfer Syntax" },
{ "1.2.840.10008.1.2.4.104", "MPEG-4 AVC/H.264 High Profile / Level 4.2 For 2D Video", "MPEG4AVCH264HighProfileLevel42For2DVideo", "Transfer Syntax" },
{ "1.2.840.10008.1.2.4.105", "MPEG-4 AVC/H.264 High Profile / Level 4.2 For 3D Video", "MPEG4AVCH264HighProfileLevel42For3DVideo", "Transfer Syntax" },
{ "1.2.840.10008.1.2.4.106", "MPEG-4 AVC/H.264 Stereo High Profile / Level 4.2", "MPEG4AVCH264StereoHighProfileLevel42", "Transfer Syntax" },
+ { "1.2.840.10008.1.2.4.107", "HEVC/H.265 Main Profile / Level 5.1", "HEVCH265MainProfileLevel51", "Transfer Syntax" },
+ { "1.2.840.10008.1.2.4.108", "HEVC/H.265 Main 10 Profile / Level 5.1", "HEVCH265Main10ProfileLevel51", "Transfer Syntax" },
{ "1.2.840.10008.1.2.5", "RLE Lossless", "RLELossless", "Transfer Syntax" },
{ "1.2.840.10008.1.2.6.1", "RFC 2557 MIME encapsulation", "RFC2557MIMEencapsulation", "Transfer Syntax" },
{ "1.2.840.10008.1.2.6.2", "XML Encoding", "XMLEncoding", "Transfer Syntax" },
@@ -12798,6 +12830,10 @@ UIDsDictionary create_uids_dictionary()
{ "1.2.840.10008.1.5.2", "PET Color Palette SOP Instance", "PETColorPaletteSOPInstance", "Well-known SOP Instance" },
{ "1.2.840.10008.1.5.3", "Hot Metal Blue Color Palette SOP Instance", "HotMetalBlueColorPaletteSOPInstance", "Well-known SOP Instance" },
{ "1.2.840.10008.1.5.4", "PET 20 Step Color Palette SOP Instance", "PET20StepColorPaletteSOPInstance", "Well-known SOP Instance" },
+ { "1.2.840.10008.1.5.5", "Spring Color Palette SOP Instance", "SpringColorPaletteSOPInstance", "Well-known SOP Instance" },
+ { "1.2.840.10008.1.5.6", "Summer Color Palette SOP Instance", "SummerColorPaletteSOPInstance", "Well-known SOP Instance" },
+ { "1.2.840.10008.1.5.7", "Fall Color Palette SOP Instance", "FallColorPaletteSOPInstance", "Well-known SOP Instance" },
+ { "1.2.840.10008.1.5.8", "Winter Color Palette SOP Instance", "WinterColorPaletteSOPInstance", "Well-known SOP Instance" },
{ "1.2.840.10008.1.9", "Basic Study Content Notification SOP Class (Retired)", "BasicStudyContentNotificationSOPClass_Retired", "SOP Class" },
{ "1.2.840.10008.1.20", "Papyrus 3 Implicit VR Little Endian (Retired)", "Papyrus3ImplicitVRLittleEndian_Retired", "Transfer Syntax" },
{ "1.2.840.10008.1.20.1", "Storage Commitment Push Model SOP Class", "StorageCommitmentPushModelSOPClass", "SOP Class" },
@@ -12975,6 +13011,7 @@ UIDsDictionary create_uids_dictionary()
{ "1.2.840.10008.5.1.4.1.1.88.69", "Colon CAD SR Storage", "ColonCADSRStorage", "SOP Class" },
{ "1.2.840.10008.5.1.4.1.1.88.70", "Implantation Plan SR Storage", "ImplantationPlanSRStorage", "SOP Class" },
{ "1.2.840.10008.5.1.4.1.1.88.71", "Acquisition Context SR Storage", "AcquisitionContextSRStorage", "SOP Class" },
+ { "1.2.840.10008.5.1.4.1.1.88.72", "Simplified Adult Echo SR Storage", "SimplifiedAdultEchoSRStorage", "SOP Class" },
{ "1.2.840.10008.5.1.4.1.1.90.1", "Content Assessment Results Storage", "ContentAssessmentResultsStorage", "SOP Class" },
{ "1.2.840.10008.5.1.4.1.1.104.1", "Encapsulated PDF Storage", "EncapsulatedPDFStorage", "SOP Class" },
{ "1.2.840.10008.5.1.4.1.1.104.2", "Encapsulated CDA Storage", "EncapsulatedCDAStorage", "SOP Class" },
diff --git a/src/odil/registry.h b/src/odil/registry.h
index ff10bf3..6bae532 100644
--- a/src/odil/registry.h
+++ b/src/odil/registry.h
@@ -313,6 +313,10 @@ Tag const StrainStockSequence(0x0010, 0x0216);
Tag const StrainSource(0x0010, 0x0217);
Tag const StrainAdditionalInformation(0x0010, 0x0218);
Tag const StrainCodeSequence(0x0010, 0x0219);
+Tag const GeneticModificationsSequence(0x0010, 0x0221);
+Tag const GeneticModificationsDescription(0x0010, 0x0222);
+Tag const GeneticModificationsNomenclature(0x0010, 0x0223);
+Tag const GeneticModificationsCodeSequence(0x0010, 0x0229);
Tag const OtherPatientIDs(0x0010, 0x1000);
Tag const OtherPatientNames(0x0010, 0x1001);
Tag const OtherPatientIDsSequence(0x0010, 0x1002);
@@ -1862,6 +1866,9 @@ Tag const SegmentedRedPaletteColorLookupTableData(0x0028, 0x1221);
Tag const SegmentedGreenPaletteColorLookupTableData(0x0028, 0x1222);
Tag const SegmentedBluePaletteColorLookupTableData(0x0028, 0x1223);
Tag const SegmentedAlphaPaletteColorLookupTableData(0x0028, 0x1224);
+Tag const StoredValueColorRangeSequence(0x0028, 0x1230);
+Tag const MinimumStoredValueMapped(0x0028, 0x1231);
+Tag const MaximumStoredValueMapped(0x0028, 0x1232);
Tag const BreastImplantPresent(0x0028, 0x1300);
Tag const PartialView(0x0028, 0x1350);
Tag const PartialViewDescription(0x0028, 0x1351);
@@ -2661,6 +2668,7 @@ Tag const SegmentedPropertyCategoryCodeSequence(0x0062, 0x0003);
Tag const SegmentNumber(0x0062, 0x0004);
Tag const SegmentLabel(0x0062, 0x0005);
Tag const SegmentDescription(0x0062, 0x0006);
+Tag const SegmentationAlgorithmIdentificationSequence(0x0062, 0x0007);
Tag const SegmentAlgorithmType(0x0062, 0x0008);
Tag const SegmentAlgorithmName(0x0062, 0x0009);
Tag const SegmentIdentificationSequence(0x0062, 0x000a);
@@ -2767,7 +2775,7 @@ Tag const HPGLDocumentSequence(0x0068, 0x62c0);
Tag const HPGLDocumentID(0x0068, 0x62d0);
Tag const HPGLDocumentLabel(0x0068, 0x62d5);
Tag const ViewOrientationCodeSequence(0x0068, 0x62e0);
-Tag const ViewOrientationModifier(0x0068, 0x62f0);
+Tag const ViewOrientationModifierCodeSequence(0x0068, 0x62f0);
Tag const HPGLDocumentScaling(0x0068, 0x62f2);
Tag const HPGLDocument(0x0068, 0x6300);
Tag const HPGLContourPenNumber(0x0068, 0x6310);
@@ -3543,6 +3551,7 @@ Tag const ParameterItemIndex(0x3008, 0x0063);
Tag const MeasuredDoseReferenceNumber(0x3008, 0x0064);
Tag const ParameterPointer(0x3008, 0x0065);
Tag const OverrideReason(0x3008, 0x0066);
+Tag const ParameterValueNumber(0x3008, 0x0067);
Tag const CorrectedParameterSequence(0x3008, 0x0068);
Tag const CorrectionValue(0x3008, 0x006a);
Tag const CalculatedDoseReferenceSequence(0x3008, 0x0070);
@@ -3938,6 +3947,7 @@ Tag const RangeModulatorGatingStopValue(0x300a, 0x0384);
Tag const RangeModulatorGatingStartWaterEquivalentThickness(0x300a, 0x0386);
Tag const RangeModulatorGatingStopWaterEquivalentThickness(0x300a, 0x0388);
Tag const IsocenterToRangeModulatorDistance(0x300a, 0x038a);
+Tag const ScanSpotTimeOffset(0x300a, 0x038f);
Tag const ScanSpotTuneID(0x300a, 0x0390);
Tag const ScanSpotPrescribedIndices(0x300a, 0x0391);
Tag const NumberOfScanSpotPositions(0x300a, 0x0392);
@@ -4277,6 +4287,8 @@ std::string const MPEG4AVCH264BDcompatibleHighProfileLevel41("1.2.840.10008.1.2.
std::string const MPEG4AVCH264HighProfileLevel42For2DVideo("1.2.840.10008.1.2.4.104");
std::string const MPEG4AVCH264HighProfileLevel42For3DVideo("1.2.840.10008.1.2.4.105");
std::string const MPEG4AVCH264StereoHighProfileLevel42("1.2.840.10008.1.2.4.106");
+std::string const HEVCH265MainProfileLevel51("1.2.840.10008.1.2.4.107");
+std::string const HEVCH265Main10ProfileLevel51("1.2.840.10008.1.2.4.108");
std::string const RLELossless("1.2.840.10008.1.2.5");
std::string const RFC2557MIMEencapsulation("1.2.840.10008.1.2.6.1");
std::string const XMLEncoding("1.2.840.10008.1.2.6.2");
@@ -4305,6 +4317,10 @@ std::string const HotIronColorPaletteSOPInstance("1.2.840.10008.1.5.1");
std::string const PETColorPaletteSOPInstance("1.2.840.10008.1.5.2");
std::string const HotMetalBlueColorPaletteSOPInstance("1.2.840.10008.1.5.3");
std::string const PET20StepColorPaletteSOPInstance("1.2.840.10008.1.5.4");
+std::string const SpringColorPaletteSOPInstance("1.2.840.10008.1.5.5");
+std::string const SummerColorPaletteSOPInstance("1.2.840.10008.1.5.6");
+std::string const FallColorPaletteSOPInstance("1.2.840.10008.1.5.7");
+std::string const WinterColorPaletteSOPInstance("1.2.840.10008.1.5.8");
std::string const BasicStudyContentNotificationSOPClass_Retired("1.2.840.10008.1.9");
std::string const Papyrus3ImplicitVRLittleEndian_Retired("1.2.840.10008.1.20");
std::string const StorageCommitmentPushModelSOPClass("1.2.840.10008.1.20.1");
@@ -4482,6 +4498,7 @@ std::string const RadiopharmaceuticalRadiationDoseSRStorage("1.2.840.10008.5.1.4
std::string const ColonCADSRStorage("1.2.840.10008.5.1.4.1.1.88.69");
std::string const ImplantationPlanSRStorage("1.2.840.10008.5.1.4.1.1.88.70");
std::string const AcquisitionContextSRStorage("1.2.840.10008.5.1.4.1.1.88.71");
+std::string const SimplifiedAdultEchoSRStorage("1.2.840.10008.5.1.4.1.1.88.72");
std::string const ContentAssessmentResultsStorage("1.2.840.10008.5.1.4.1.1.90.1");
std::string const EncapsulatedPDFStorage("1.2.840.10008.5.1.4.1.1.104.1");
std::string const EncapsulatedCDAStorage("1.2.840.10008.5.1.4.1.1.104.2");
diff --git a/src/odil/uid.h b/src/odil/uid.h
index e60d25c..79a019d 100644
--- a/src/odil/uid.h
+++ b/src/odil/uid.h
@@ -26,7 +26,7 @@ extern ODIL_API std::string implementation_class_uid;
extern ODIL_API std::string implementation_version_name;
/// @brief Generate a UID under the UID prefix.
-std::string generate_uid();
+std::string ODIL_API generate_uid();
}
diff --git a/src/odil/unicode.h b/src/odil/unicode.h
index 03a6f94..3d62dcd 100644
--- a/src/odil/unicode.h
+++ b/src/odil/unicode.h
@@ -10,18 +10,20 @@
#define _4a178325_e3d6_4f6f_9a18_ba6a983ee396
#include <string>
+
+#include "odil/odil.h"
#include "odil/Value.h"
namespace odil
{
/// @brief Convert a string to its UTF-8 representation
-std::string as_utf8(
+ODIL_API std::string as_utf8(
std::string const & input, Value::Strings const & specific_character_set,
bool is_pn=false);
/// @brief Convert an UTF-8 string to a specific representation
-std::string as_specific_character_set(
+ODIL_API std::string as_specific_character_set(
std::string const & input, Value::Strings const & specific_character_set,
bool is_pn=false);
diff --git a/src/odil/write_ds.h b/src/odil/write_ds.h
index 87b5cac..fed335c 100644
--- a/src/odil/write_ds.h
+++ b/src/odil/write_ds.h
@@ -14,11 +14,13 @@
#include <cstdlib>
#include <cstring>
+#include "odil/odil.h"
+
namespace odil
{
/// @brief Write a double as a DS to the buffer.
-void write_ds(double f, char * buffer, int size=16);
+ODIL_API void write_ds(double f, char * buffer, int size=16);
}
diff --git a/src/odil/xml_converter.cpp b/src/odil/xml_converter.cpp
index 94a7944..846e68b 100644
--- a/src/odil/xml_converter.cpp
+++ b/src/odil/xml_converter.cpp
@@ -388,15 +388,10 @@ DataSet as_dataset(boost::property_tree::ptree const & xml)
Tag const tag(it->second.get<std::string>("<xmlattr>.tag"));
VR const vr = as_vr(it->second.get<std::string>("<xmlattr>.vr"));
- Element element;
+ Element element(vr);
- if(vr == VR::AE || vr == VR::AS || vr == VR::AT || vr == VR::CS ||
- vr == VR::DA || vr == VR::DT || vr == VR::LO || vr == VR::LT ||
- vr == VR::SH || vr == VR::ST || vr == VR::TM || vr == VR::UI ||
- vr == VR::UT)
+ if(odil::is_string(vr) && vr != odil::VR::PN)
{
- element = Element(Value::Strings(), vr);
-
auto values = parse_value<Value::Strings::value_type>(it->second,
vr);
@@ -407,8 +402,6 @@ DataSet as_dataset(boost::property_tree::ptree const & xml)
}
else if(vr == VR::PN)
{
- element = Element(Value::Strings(), vr);
-
std::map<int, Value::Strings::value_type> values;
for(auto it_value = it->second.begin();
it_value != it->second.end(); ++it_value)
@@ -479,10 +472,8 @@ DataSet as_dataset(boost::property_tree::ptree const & xml)
element.as_string().push_back(it->second);
}
}
- else if(vr == VR::DS || vr == VR::FD || vr == VR::FL)
+ else if(is_real(vr))
{
- element = Element(Value::Reals(), vr);
-
auto values = parse_value<Value::Reals::value_type>(it->second, vr);
for (auto it = values.begin(); it != values.end(); ++it)
@@ -490,11 +481,8 @@ DataSet as_dataset(boost::property_tree::ptree const & xml)
element.as_real().push_back(it->second);
}
}
- else if(vr == VR::IS || vr == VR::SL || vr == VR::SS ||
- vr == VR::UL || vr == VR::US)
+ else if(is_int(vr))
{
- element = Element(Value::Integers(), vr);
-
auto values = parse_value<Value::Integers::value_type>(it->second,
vr);
@@ -505,8 +493,6 @@ DataSet as_dataset(boost::property_tree::ptree const & xml)
}
else if(vr == VR::SQ)
{
- element = Element(Value::DataSets(), vr);
-
std::map<int, Value::DataSets::value_type> values;
for(auto it_value = it->second.begin();
it_value != it->second.end(); ++it_value)
@@ -547,8 +533,6 @@ DataSet as_dataset(boost::property_tree::ptree const & xml)
}
else if(is_binary(vr))
{
- element = Element(Value::Binary(), vr);
-
bool find_inline_binary = false; // only one Tag InlineBinary
for(auto it_value = it->second.begin();
it_value != it->second.end(); ++it_value)
diff --git a/src/odil/xml_converter.h b/src/odil/xml_converter.h
index 5b01ef2..4be72bb 100644
--- a/src/odil/xml_converter.h
+++ b/src/odil/xml_converter.h
@@ -12,15 +12,16 @@
#include <boost/property_tree/ptree.hpp>
#include "odil/DataSet.h"
+#include "odil/odil.h"
namespace odil
{
/// @brief Convert a data set to its XML representation.
-boost::property_tree::ptree as_xml(DataSet const & data_set);
+ODIL_API boost::property_tree::ptree as_xml(DataSet const & data_set);
/// @brief Create a data set from its XML representation.
-DataSet as_dataset(boost::property_tree::ptree const & xml);
+ODIL_API DataSet as_dataset(boost::property_tree::ptree const & xml);
} // namespace odil
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 2afa0eb..3962239 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -23,12 +23,15 @@ endif()
include_directories(
${CMAKE_SOURCE_DIR}/src ${Boost_INCLUDE_DIRS} ${DCMTK_INCLUDE_DIRS}
${JsonCpp_INCLUDE_DIRS})
+
add_definitions(
${DCMTK_DEFINITIONS}
- -D BOOST_ASIO_DYN_LINK
-D ODIL_MAJOR_VERSION=${odil_MAJOR_VERSION}
- -DBOOST_TEST_DYN_LINK
)
+if(BUILD_SHARED_LIBS)
+ add_definitions(-D BOOST_ALL_DYN_LINK)
+endif()
+
link_directories(${Boost_LIBRARY_DIRS} ${DCMTK_LIBRARY_DIRS})
diff --git a/tests/code/BasicDirectoryCreator.cpp b/tests/code/BasicDirectoryCreator.cpp
index ec75cf0..8a511b6 100644
--- a/tests/code/BasicDirectoryCreator.cpp
+++ b/tests/code/BasicDirectoryCreator.cpp
@@ -49,9 +49,6 @@ BOOST_AUTO_TEST_CASE(Constructor)
BOOST_AUTO_TEST_CASE(BasicDirectory)
{
- std::stringstream stream1;
- stream1 << "{";
-
{
odil::DataSet data_set;
data_set.add("PatientID", {"DJ123"});
@@ -68,7 +65,8 @@ BOOST_AUTO_TEST_CASE(BasicDirectory)
data_set.add("SOPInstanceUID", {"1.2.3.4.1.1"});
data_set.add("SOPClassUID", {odil::registry::RawDataStorage});
- std::ofstream stream("a.dcm");
+ std::ofstream stream(
+ "a.dcm", std::ofstream::out | std::ofstream::binary);
odil::Writer::write_file(data_set, stream);
}
@@ -88,7 +86,8 @@ BOOST_AUTO_TEST_CASE(BasicDirectory)
data_set.add("SOPInstanceUID", {"1.2.3.4.1.2"});
data_set.add("SOPClassUID", {odil::registry::RawDataStorage});
- std::ofstream stream("b.dcm");
+ std::ofstream stream(
+ "b.dcm", std::ofstream::out | std::ofstream::binary);
odil::Writer::write_file(data_set, stream);
}
@@ -99,8 +98,11 @@ BOOST_AUTO_TEST_CASE(BasicDirectory)
".", {"a.dcm", "b.dcm"}, extra_records);
creator();
- boost::filesystem::ifstream stream(boost::filesystem::path(".")/"DICOMDIR");
+ boost::filesystem::ifstream stream(
+ boost::filesystem::path(".")/"DICOMDIR",
+ boost::filesystem::ifstream::in | boost::filesystem::ifstream::binary);
auto const dicomdir_and_header = odil::Reader::read_file(stream);
+ stream.close();
BOOST_REQUIRE(
dicomdir_and_header.first.as_string("MediaStorageSOPClassUID") ==
@@ -156,4 +158,5 @@ BOOST_AUTO_TEST_CASE(BasicDirectory)
boost::filesystem::remove("a.dcm");
boost::filesystem::remove("b.dcm");
+ boost::filesystem::remove("DICOMDIR");
}
diff --git a/tests/code/DataSet.cpp b/tests/code/DataSet.cpp
index 891071d..0f790b0 100644
--- a/tests/code/DataSet.cpp
+++ b/tests/code/DataSet.cpp
@@ -94,266 +94,248 @@ BOOST_AUTO_TEST_CASE(AddInvalidTag)
BOOST_CHECK_THROW(dataset.add(tag), odil::Exception);
}
-BOOST_AUTO_TEST_CASE(AddIntEmpty)
-{
- odil::Tag const tag("Rows");
-
- odil::DataSet dataset;
- dataset.add(tag);
-
- BOOST_CHECK(dataset.is_int(tag));
- BOOST_CHECK(dataset.empty(tag));
- BOOST_CHECK_EQUAL(dataset.size(tag), 0);
-
- std::vector<int64_t> const & value = dataset.as_int(tag);
- BOOST_CHECK(value.empty());
-}
+template<typename TContainer>
+void test_element_value(
+ odil::DataSet const & data_set, odil::Tag const & tag,
+ TContainer const & contents,
+ bool (odil::DataSet::*type_check)(odil::Tag const &) const,
+ TContainer const & (odil::DataSet::*getter)(odil::Tag const &) const,
+ typename TContainer::value_type const & (odil::DataSet::*getter_pos)(odil::Tag const &, unsigned int) const)
+{
+ BOOST_CHECK(data_set.has(tag));
+ BOOST_CHECK_EQUAL(data_set.empty(tag), contents.empty());
+ BOOST_CHECK_EQUAL(data_set.size(tag), contents.size());
+ BOOST_CHECK((data_set.*type_check)(tag));
+ BOOST_CHECK((data_set.*getter)(tag) == contents);
+
+ for(int i=0; i<contents.size(); ++i)
+ {
+ BOOST_CHECK((data_set.*getter_pos)(tag, i) == contents[i]);
+ }
+ BOOST_CHECK_THROW((data_set.*getter_pos)(tag, contents.size()), odil::Exception);
+
+ if(!data_set.is_int(tag))
+ {
+ BOOST_CHECK_THROW(data_set.as_int(tag), odil::Exception);
+ }
+ if(!data_set.is_real(tag))
+ {
+ BOOST_CHECK_THROW(data_set.as_real(tag), odil::Exception);
+ }
+ if(!data_set.is_string(tag))
+ {
+ BOOST_CHECK_THROW(data_set.as_string(tag), odil::Exception);
+ }
+ if(!data_set.is_data_set(tag))
+ {
+ BOOST_CHECK_THROW(data_set.as_data_set(tag), odil::Exception);
+ }
+ if(!data_set.is_binary(tag))
+ {
+ BOOST_CHECK_THROW(data_set.as_binary(tag), odil::Exception);
+ }
+}
+
+template<typename TContainer>
+void test_implicit_container(
+ odil::Tag const & tag,
+ bool (odil::DataSet::*type_check)(odil::Tag const &) const,
+ TContainer const & (odil::DataSet::*getter)(odil::Tag const &) const,
+ typename TContainer::value_type const & (odil::DataSet::*getter_pos)(odil::Tag const &, unsigned int) const)
+{
+ odil::DataSet data_set;
+ data_set.add(tag);
+ test_element_value(data_set, tag, TContainer(), type_check, getter, getter_pos);
+}
+
+template<typename TContainer>
+void test_implicit_container(
+ odil::Tag const & tag, odil::VR const & vr,
+ bool (odil::DataSet::*type_check)(odil::Tag const &) const,
+ TContainer const & (odil::DataSet::*getter)(odil::Tag const &) const,
+ typename TContainer::value_type const & (odil::DataSet::*getter_pos)(odil::Tag const &, unsigned int) const)
+{
+ odil::DataSet data_set;
+ data_set.add(tag, vr);
+ test_element_value(data_set, tag, TContainer(), type_check, getter, getter_pos);
+}
+
+template<typename TContainer>
+void test_container(
+ odil::Tag const & tag, TContainer const & contents,
+ bool (odil::DataSet::*type_check)(odil::Tag const &) const,
+ TContainer const & (odil::DataSet::*getter)(odil::Tag const &) const,
+ typename TContainer::value_type const & (odil::DataSet::*getter_pos)(odil::Tag const &, unsigned int) const)
+{
+ odil::DataSet data_set;
+ data_set.add(tag, contents);
+ test_element_value(data_set, tag, contents, type_check, getter, getter_pos);
+
+ auto contents_copy(contents);
+ odil::DataSet other_data_set;
+ other_data_set.add(tag, std::move(contents_copy));
+ BOOST_CHECK(contents_copy.empty());
+}
+
+template<typename TContainer>
+void test_container(
+ odil::Tag const & tag, TContainer const & contents, odil::VR const & vr,
+ bool (odil::DataSet::*type_check)(odil::Tag const &) const,
+ TContainer const & (odil::DataSet::*getter)(odil::Tag const &) const,
+ typename TContainer::value_type const & (odil::DataSet::*getter_pos)(odil::Tag const &, unsigned int) const)
+{
+ odil::DataSet data_set;
+ data_set.add(tag, contents, vr);
+ test_element_value(data_set, tag, contents, type_check, getter, getter_pos);
+
+ auto contents_copy(contents);
+ odil::DataSet other_data_set;
+ other_data_set.add(tag, std::move(contents_copy));
+ BOOST_CHECK(contents_copy.empty());
+}
+
+template<typename TContainer>
+void test_initializer_list(
+ odil::Tag const & tag,
+ std::initializer_list<typename TContainer::value_type> const & contents,
+ bool (odil::DataSet::*type_check)(odil::Tag const &) const,
+ TContainer const & (odil::DataSet::*getter)(odil::Tag const &) const,
+ typename TContainer::value_type const & (odil::DataSet::*getter_pos)(odil::Tag const &, unsigned int) const)
+{
+ odil::DataSet data_set;
+ data_set.add(tag, contents);
+ test_element_value(data_set, tag, TContainer(contents), type_check, getter, getter_pos);
+}
-BOOST_AUTO_TEST_CASE(AddDoubleEmpty)
+template<typename TContainer>
+void test_initializer_list(
+ odil::Tag const & tag,
+ std::initializer_list<typename TContainer::value_type> const & contents,
+ odil::VR const & vr,
+ bool (odil::DataSet::*type_check)(odil::Tag const &) const,
+ TContainer const & (odil::DataSet::*getter)(odil::Tag const &) const,
+ typename TContainer::value_type const & (odil::DataSet::*getter_pos)(odil::Tag const &, unsigned int) const)
{
- odil::Tag const tag("SpacingBetweenSlices");
-
- odil::DataSet dataset;
- dataset.add(tag);
-
- BOOST_CHECK(dataset.is_real(tag));
- BOOST_CHECK(dataset.empty(tag));
- BOOST_CHECK_EQUAL(dataset.size(tag), 0);
-
- std::vector<double> const & value = dataset.as_real(tag);
- BOOST_CHECK(value.empty());
+ odil::DataSet data_set;
+ data_set.add(tag, contents, vr);
+ test_element_value(data_set, tag, TContainer(contents), type_check, getter, getter_pos);
}
-BOOST_AUTO_TEST_CASE(AddStringEmpty)
+template<typename TContainer>
+void test_modify(
+ odil::Tag const & tag, TContainer const & contents,
+ TContainer const & (odil::DataSet::*getter)(odil::Tag const &) const,
+ TContainer & (odil::DataSet::*setter)(odil::Tag const &))
{
- odil::Tag const tag("PatientID");
-
- odil::DataSet dataset;
- dataset.add(tag);
-
- BOOST_CHECK(dataset.is_string(tag));
- BOOST_CHECK(dataset.empty(tag));
- BOOST_CHECK_EQUAL(dataset.size(tag), 0);
-
- std::vector<std::string> const & value = dataset.as_string(tag);
- BOOST_CHECK(value.empty());
+ odil::DataSet data_set;
+ data_set.add(tag, {contents[0]});
+ (data_set.*setter)(tag).push_back(contents[1]);
+ BOOST_CHECK((data_set.*getter)(tag) == contents);
}
-BOOST_AUTO_TEST_CASE(AddDataSetEmpty)
+template<typename TContainer>
+void test_clear(
+ odil::Tag const & tag, TContainer const & contents,
+ bool (odil::DataSet::*type_check)(odil::Tag const &) const)
{
- odil::Tag const tag("ReferencedStudySequence");
-
- odil::DataSet dataset;
- dataset.add(tag);
-
- BOOST_CHECK(dataset.is_data_set(tag));
- BOOST_CHECK(dataset.empty(tag));
- BOOST_CHECK_EQUAL(dataset.size(tag), 0);
-
- odil::Value::DataSets const & value = dataset.as_data_set(tag);
- BOOST_CHECK(value.empty());
+ odil::DataSet data_set;
+ data_set.add(tag, contents);
+ data_set.clear(tag);
+ BOOST_CHECK((data_set.*type_check)(tag));
+ BOOST_CHECK(data_set.empty(tag));
}
-BOOST_AUTO_TEST_CASE(AddBinaryEmpty)
+template<typename TContainer>
+void test_element(
+ odil::Tag const & tag,
+ std::initializer_list<typename TContainer::value_type> const & contents,
+ odil::VR const & vr,
+ bool (odil::DataSet::*type_check)(odil::Tag const &) const,
+ TContainer const & (odil::DataSet::*getter)(odil::Tag const &) const,
+ typename TContainer::value_type const & (odil::DataSet::*getter_pos)(odil::Tag const &, unsigned int) const,
+ TContainer & (odil::DataSet::*setter)(odil::Tag const &))
{
- odil::Tag const tag("BadPixelImage");
+ test_implicit_container(tag, type_check, getter, getter_pos);
+ test_implicit_container(tag, vr, type_check, getter, getter_pos);
- odil::DataSet dataset;
- dataset.add(tag);
+ TContainer const container(contents);
- BOOST_CHECK(dataset.is_binary(tag));
- BOOST_CHECK(dataset.empty(tag));
- BOOST_CHECK_EQUAL(dataset.size(tag), 0);
+ test_container(tag, container, type_check, getter, getter_pos);
+ test_container(tag, container, vr, type_check, getter, getter_pos);
- auto const & value = dataset.as_binary(tag);
- BOOST_CHECK(value.empty());
-}
+ test_initializer_list(tag, contents, type_check, getter, getter_pos);
+ test_initializer_list(tag, contents, vr, type_check, getter, getter_pos);
-BOOST_AUTO_TEST_CASE(AddInt)
-{
- odil::Tag const tag("Rows");
+ test_modify(tag, container, getter, setter);
- odil::DataSet dataset;
- dataset.add(tag, odil::Value::Integers({123}));
-
- BOOST_CHECK(dataset.is_int(tag));
- BOOST_REQUIRE_EQUAL(dataset.size(tag), 1);
- BOOST_REQUIRE(dataset.as_int(tag) == odil::Value::Integers({123}));
+ test_clear(tag, container, type_check);
}
-BOOST_AUTO_TEST_CASE(AddDouble)
+BOOST_AUTO_TEST_CASE(Int)
{
- odil::Tag const tag("SpacingBetweenSlices");
-
- odil::DataSet dataset;
- dataset.add(tag, odil::Value::Reals({123.456}));
+ odil::DataSet data_set;
+ data_set.add(odil::registry::Rows, {1234, 5678});
+ data_set.is_int(odil::registry::Rows);
- BOOST_CHECK(dataset.is_real(tag));
- BOOST_REQUIRE_EQUAL(dataset.size(tag), 1);
- BOOST_REQUIRE(dataset.as_real(tag) == odil::Value::Reals({123.456}));
+ test_element<odil::Value::Integers>(
+ odil::registry::Rows, {1234, 5678}, odil::VR::US,
+ &odil::DataSet::is_int,
+ &odil::DataSet::as_int, &odil::DataSet::as_int, &odil::DataSet::as_int);
}
-BOOST_AUTO_TEST_CASE(AddString)
+BOOST_AUTO_TEST_CASE(Real)
{
- odil::Tag const tag("PatientID");
-
- odil::DataSet dataset;
- dataset.add(tag, odil::Value::Strings({"DJ123"}));
-
- BOOST_CHECK(dataset.is_string(tag));
- BOOST_REQUIRE_EQUAL(dataset.size(tag), 1);
- BOOST_REQUIRE(dataset.as_string(tag) == odil::Value::Strings({"DJ123"}));
-}
-
-BOOST_AUTO_TEST_CASE(AddDataSet)
-{
- odil::Tag const tag("ReferencedStudySequence");
- odil::DataSet item;
- item.add(odil::registry::StudyInstanceUID, {"1.2.3"});
-
- odil::DataSet dataset;
- dataset.add(tag, odil::Value::DataSets({item}));
+ odil::DataSet data_set;
+ data_set.add(odil::registry::SpacingBetweenSlices, {12.34, 56.78});
+ data_set.is_int(odil::registry::SpacingBetweenSlices);
- BOOST_CHECK(dataset.is_data_set(tag));
- BOOST_REQUIRE_EQUAL(dataset.size(tag), 1);
- BOOST_REQUIRE(dataset.as_data_set(tag, 0) == item);
+ test_element<odil::Value::Reals>(
+ odil::registry::SpacingBetweenSlices, {12.34, 56.78}, odil::VR::FL,
+ &odil::DataSet::is_real,
+ &odil::DataSet::as_real, &odil::DataSet::as_real, &odil::DataSet::as_real);
}
-BOOST_AUTO_TEST_CASE(AddIntInitializer1)
+BOOST_AUTO_TEST_CASE(String)
{
- odil::Tag const tag("Rows");
+ odil::DataSet data_set;
+ data_set.add(odil::registry::PatientID, {"foo", "bar"});
+ data_set.is_int(odil::registry::PatientID);
- odil::DataSet dataset;
- dataset.add(tag, {123});
-
- BOOST_CHECK(dataset.is_int(tag));
- BOOST_REQUIRE_EQUAL(dataset.size(tag), 1);
- BOOST_REQUIRE(dataset.as_int(tag) == odil::Value::Integers({123}));
+ test_element<odil::Value::Strings>(
+ odil::registry::PatientID, {"foo", "bar"}, odil::VR::LT,
+ &odil::DataSet::is_string,
+ &odil::DataSet::as_string, &odil::DataSet::as_string, &odil::DataSet::as_string);
}
-BOOST_AUTO_TEST_CASE(AddIntInitializer2)
+BOOST_AUTO_TEST_CASE(DataSets)
{
- odil::Tag const tag("Rows");
+ odil::DataSet data_set_1;
+ data_set_1.add("PatientID", {"DJ1234"});
- odil::DataSet dataset;
- dataset.add(tag, {odil::Value::Integer(123)});
+ odil::DataSet data_set_2;
+ data_set_2.add("EchoTime", {100});
- BOOST_CHECK(dataset.is_int(tag));
- BOOST_REQUIRE_EQUAL(dataset.size(tag), 1);
- BOOST_REQUIRE(dataset.as_int(tag) == odil::Value::Integers({123}));
-}
-
-
-BOOST_AUTO_TEST_CASE(AddDoubleInitializer)
-{
- odil::Tag const tag("SpacingBetweenSlices");
+ odil::DataSet data_set;
+ data_set.add(
+ odil::registry::ReferencedStudySequence, {data_set_1, data_set_2});
+ data_set.is_int(odil::registry::ReferencedStudySequence);
- odil::DataSet dataset;
- dataset.add(tag, {123.456});
-
- BOOST_CHECK(dataset.is_real(tag));
- BOOST_REQUIRE_EQUAL(dataset.size(tag), 1);
- BOOST_REQUIRE(dataset.as_real(tag) == odil::Value::Reals({123.456}));
+ test_element<odil::Value::DataSets>(
+ odil::registry::ReferencedStudySequence, {data_set_1, data_set_2}, odil::VR::SQ,
+ &odil::DataSet::is_data_set,
+ &odil::DataSet::as_data_set, &odil::DataSet::as_data_set, &odil::DataSet::as_data_set);
}
-BOOST_AUTO_TEST_CASE(AddStringInitializer)
+BOOST_AUTO_TEST_CASE(Binary)
{
- odil::Tag const tag("PatientID");
+ odil::DataSet data_set;
+ data_set.add(odil::registry::BadPixelImage, {{0x1, 0x2}, {0x3}});
+ data_set.is_int(odil::registry::BadPixelImage);
- odil::DataSet dataset;
- dataset.add(tag, {"DJ123"});
-
- BOOST_CHECK(dataset.is_string(tag));
- BOOST_REQUIRE_EQUAL(dataset.size(tag), 1);
- BOOST_REQUIRE(dataset.as_string(tag) == odil::Value::Strings({"DJ123"}));
-}
-
-BOOST_AUTO_TEST_CASE(AddDataSetInitializer)
-{
- odil::Tag const tag("ReferencedStudySequence");
- odil::DataSet item;
- item.add(odil::registry::StudyInstanceUID, {"1.2.3"});
-
- odil::DataSet dataset;
- dataset.add(tag, {item});
-
- BOOST_CHECK(dataset.is_data_set(tag));
- BOOST_REQUIRE_EQUAL(dataset.size(tag), 1);
- BOOST_REQUIRE(dataset.as_data_set(tag, 0) == item);
-}
-
-BOOST_AUTO_TEST_CASE(AddBinary)
-{
- odil::Tag const tag("BadPixelImage");
-
- odil::DataSet dataset;
- dataset.add(tag, odil::Value::Binary({{0x01, 0x02}}));
-
- BOOST_CHECK(dataset.is_binary(tag));
- BOOST_REQUIRE(
- dataset.as_binary(tag) == odil::Value::Binary({{ 0x01, 0x02 }}));
-}
-
-BOOST_AUTO_TEST_CASE(ModifyInt)
-{
- odil::Tag const tag("Rows");
-
- odil::DataSet dataset;
- dataset.add(tag);
- dataset.as_int(tag).push_back(256);
-
- BOOST_CHECK(!dataset.empty(tag));
- BOOST_CHECK_EQUAL(dataset.size(tag), 1);
- BOOST_CHECK_EQUAL(dataset.as_int(tag, 0), 256);
-}
-
-BOOST_AUTO_TEST_CASE(ModifyDouble)
-{
- odil::Tag const tag("SpacingBetweenSlices");
-
- odil::DataSet dataset;
- dataset.add(tag);
- dataset.as_real(tag).push_back(3.14);
-
- BOOST_CHECK(!dataset.empty(tag));
- BOOST_CHECK_EQUAL(dataset.size(tag), 1);
- BOOST_CHECK_EQUAL(dataset.as_real(tag, 0), 3.14);
-}
-
-BOOST_AUTO_TEST_CASE(ModifyString)
-{
- odil::Tag const tag("PatientID");
-
- odil::DataSet dataset;
- dataset.add(tag);
- dataset.as_string(tag).push_back("FooBar");
-
- BOOST_CHECK(!dataset.empty(tag));
- BOOST_CHECK_EQUAL(dataset.size(tag), 1);
- BOOST_CHECK_EQUAL(dataset.as_string(tag, 0), "FooBar");
-}
-
-BOOST_AUTO_TEST_CASE(ModifyDataSet)
-{
- odil::Tag const tag("ReferencedStudySequence");
-
- odil::DataSet dataset;
- dataset.add(tag);
-
- odil::DataSet item;
- item.add("PatientID", {"DJ1234"});
- dataset.as_data_set(tag).push_back(item);
-
- BOOST_CHECK(!dataset.empty(tag));
- BOOST_CHECK_EQUAL(dataset.size(tag), 1);
-
- odil::Value::DataSets const & value = dataset.as_data_set(tag);
- BOOST_CHECK_EQUAL(value.size(), 1);
- BOOST_CHECK_EQUAL(value.size(), 1);
- BOOST_CHECK_EQUAL(value[0].size(), 1);
- BOOST_CHECK(value[0].has("PatientID"));
- BOOST_CHECK(
- value[0].as_string("PatientID") == odil::Value::Strings({"DJ1234"}));
+ test_element<odil::Value::Binary>(
+ odil::registry::BadPixelImage, {{0x1, 0x2}, {0x3}}, odil::VR::OB,
+ &odil::DataSet::is_binary,
+ &odil::DataSet::as_binary, &odil::DataSet::as_binary, &odil::DataSet::as_binary);
}
BOOST_AUTO_TEST_CASE(ElementAccessor)
@@ -375,7 +357,7 @@ BOOST_AUTO_TEST_CASE(GetVRMissing)
BOOST_CHECK_THROW(dataset.get_vr(tag), odil::Exception);
}
-BOOST_AUTO_TEST_CASE(TestEmptyMissing)
+BOOST_AUTO_TEST_CASE(EmptyMissing)
{
odil::Tag const tag("PatientID");
odil::DataSet dataset;
@@ -389,6 +371,13 @@ BOOST_AUTO_TEST_CASE(SizeMissing)
BOOST_CHECK_THROW(dataset.size(tag), odil::Exception);
}
+BOOST_AUTO_TEST_CASE(ClearMissing)
+{
+ odil::Tag const tag("PatientID");
+ odil::DataSet dataset;
+ BOOST_CHECK_THROW(dataset.clear(tag), odil::Exception);
+}
+
BOOST_AUTO_TEST_CASE(Remove)
{
odil::Tag const tag("PatientID");
@@ -441,3 +430,13 @@ BOOST_AUTO_TEST_CASE(Difference)
BOOST_CHECK(! (dataset1 != dataset2));
BOOST_CHECK(dataset1 != dataset3);
}
+
+BOOST_AUTO_TEST_CASE(Clear)
+{
+ odil::DataSet data_set;
+ data_set.add("PatientID", {"DJ1234"});
+ data_set.clear("PatientID");
+ BOOST_CHECK(data_set.empty("PatientID"));
+ BOOST_CHECK_THROW(data_set.clear("PatietName"), odil::Exception);
+}
+
diff --git a/tests/code/Element.cpp b/tests/code/Element.cpp
index be392f7..a1bcdc2 100644
--- a/tests/code/Element.cpp
+++ b/tests/code/Element.cpp
@@ -1,172 +1,293 @@
#define BOOST_TEST_MODULE Element
#include <boost/test/unit_test.hpp>
+#include <string>
+#include <utility>
+
#include "odil/DataSet.h"
#include "odil/Element.h"
#include "odil/Exception.h"
-BOOST_AUTO_TEST_CASE(Empty)
+template<typename TContainer>
+void test_value(
+ odil::Element const & element,
+ odil::VR const & vr, TContainer const & contents,
+ bool (odil::Element::*type_check)() const,
+ TContainer const & (odil::Element::*getter)() const)
{
- odil::Element element;
- BOOST_CHECK(element.empty());
- BOOST_CHECK_EQUAL(element.size(), 0);
+ BOOST_CHECK((element.*type_check)());
+ BOOST_CHECK_EQUAL(element.empty(), contents.empty());
+ BOOST_CHECK_EQUAL(element.size(), contents.size());
+ BOOST_CHECK((element.*getter)() == contents);
+ BOOST_CHECK(element.vr == vr);
+
+ if(!element.is_int())
+ {
+ BOOST_CHECK_THROW(element.as_int(), odil::Exception);
+ }
+ if(!element.is_real())
+ {
+ BOOST_CHECK_THROW(element.as_real(), odil::Exception);
+ }
+ if(!element.is_string())
+ {
+ BOOST_CHECK_THROW(element.as_string(), odil::Exception);
+ }
+ if(!element.is_data_set())
+ {
+ BOOST_CHECK_THROW(element.as_data_set(), odil::Exception);
+ }
+ if(!element.is_binary())
+ {
+ BOOST_CHECK_THROW(element.as_binary(), odil::Exception);
+ }
}
-BOOST_AUTO_TEST_CASE(Int)
+template<typename TContainer>
+void test_implicit_container(
+ odil::VR const & vr,
+ bool (odil::Element::*type_check)() const,
+ TContainer const & (odil::Element::*getter)() const)
{
- odil::Element const element((odil::Value::Integers()));
- BOOST_CHECK(element.is_int());
-
- std::vector<int64_t> const & value = element.as_int();
- BOOST_CHECK(value.empty());
+ odil::Element const element(vr);
+ test_value(element, vr, TContainer(), type_check, getter);
}
-BOOST_AUTO_TEST_CASE(ModifyInt)
+template<typename TContainer>
+void test_container(
+ TContainer const & contents, odil::VR const & vr,
+ bool (odil::Element::*type_check)() const,
+ TContainer const & (odil::Element::*getter)() const)
{
- odil::Element element({0});
- element.as_int().push_back(1);
-
- BOOST_CHECK(!element.empty());
- BOOST_CHECK_EQUAL(element.size(), 2);
+ odil::Element const element(contents, vr);
+ test_value(element, vr, contents, type_check, getter);
- std::vector<int64_t> const & value = element.as_int();
- BOOST_CHECK(value == odil::Value::Integers({0, 1}));
+ auto contents_copy(contents);
+ odil::Element const other_element(std::move(contents_copy));
+ BOOST_CHECK(contents_copy.empty());
}
-BOOST_AUTO_TEST_CASE(ModifyInt2)
+template<typename TContainer>
+void test_initializer_list(
+ std::initializer_list<typename TContainer::value_type> const & contents,
+ bool (odil::Element::*type_check)() const,
+ TContainer const & (odil::Element::*getter)() const)
{
- odil::Element element({odil::Value::Integer(0)});
- element.as_int().push_back(1);
-
- BOOST_CHECK(!element.empty());
- BOOST_CHECK_EQUAL(element.size(), 2);
-
- std::vector<int64_t> const & value = element.as_int();
- BOOST_CHECK(value == odil::Value::Integers({0, 1}));
+ odil::Element const element(contents);
+ test_value(element, element.vr, TContainer(contents), type_check, getter);
}
-BOOST_AUTO_TEST_CASE(IntWrong)
+template<typename TContainer>
+void test_modify(
+ TContainer const & contents,
+ TContainer const & (odil::Element::*getter)() const,
+ TContainer & (odil::Element::*setter)())
{
- odil::Element element((odil::Value::Integers()));
- BOOST_CHECK_THROW(element.as_real(), odil::Exception);
- BOOST_CHECK_THROW(element.as_string(), odil::Exception);
+ odil::Element value(TContainer{{contents[0]}});
+ (value.*setter)().push_back(contents[1]);
+ BOOST_CHECK((value.*getter)() == contents);
}
-BOOST_AUTO_TEST_CASE(Double)
+template<typename TContainer>
+void test_clear(
+ TContainer const & contents,
+ bool (odil::Element::*type_check)() const)
{
- odil::Element const element((odil::Value::Reals()));
- BOOST_CHECK(element.is_real());
-
- std::vector<double> const & value = element.as_real();
- BOOST_CHECK(value.empty());
+ odil::Element element(contents);
+ element.clear();
+ BOOST_CHECK((element.*type_check)());
+ BOOST_CHECK(element.empty());
}
-BOOST_AUTO_TEST_CASE(ModifyDouble)
+template<typename TContainer>
+void test_equality(
+ TContainer const & contents_1, TContainer const & contents_2,
+ odil::VR const & vr_1, odil::VR const & vr_2)
{
- odil::Element element({0.});
- element.as_real().push_back(1.5);
-
- BOOST_CHECK(!element.empty());
- BOOST_CHECK_EQUAL(element.size(), 2);
-
- std::vector<double> const & value = element.as_real();
- BOOST_CHECK(value == odil::Value::Reals({0., 1.5}));
+ odil::Element const value_1(contents_1, vr_1);
+ odil::Element const value_2(contents_1, vr_1);
+ odil::Element const value_3(contents_1, vr_2);
+ odil::Element const value_4(contents_2, vr_1);
+
+ BOOST_CHECK(value_1 == value_2);
+ BOOST_CHECK( ! (value_1 == value_3));
+ BOOST_CHECK( ! (value_1 == value_4));
+
+ BOOST_CHECK(! (value_1 != value_2));
+ BOOST_CHECK(value_1 != value_3);
+ BOOST_CHECK(value_1 != value_4);
}
-BOOST_AUTO_TEST_CASE(DoubleWrong)
+struct Visitor
+{
+ typedef std::pair<std::string, std::string> result_type;
+
+ result_type operator()(odil::VR const & vr) const
+ {
+ return std::make_pair(odil::as_string(vr), std::string());
+ }
+
+ template<typename T>
+ result_type operator()(odil::VR const & vr, T const & container) const
+ {
+ return std::make_pair(odil::as_string(vr), typeid(container).name());
+ }
+};
+
+template<typename TContainer>
+void test_visitor(
+ TContainer const & contents, odil::VR const & vr)
{
- odil::Element element((odil::Value::Reals()));
- BOOST_CHECK_THROW(element.as_int(), odil::Exception);
- BOOST_CHECK_THROW(element.as_string(), odil::Exception);
- BOOST_CHECK_THROW(element.as_data_set(), odil::Exception);
+ odil::Element const element(contents, vr);
+ BOOST_REQUIRE(
+ odil::apply_visitor(Visitor(), element)
+ == std::make_pair(
+ odil::as_string(vr),
+ contents.empty()?std::string():typeid(TContainer).name()));
}
-BOOST_AUTO_TEST_CASE(String)
+
+template<typename TContainer>
+void test(
+ std::initializer_list<typename TContainer::value_type> const & contents,
+ std::initializer_list<typename TContainer::value_type> const & other_contents,
+ odil::VR const & vr, odil::VR const & other_vr,
+ bool (odil::Element::*type_check)() const,
+ TContainer const & (odil::Element::*getter)() const,
+ TContainer & (odil::Element::*setter)())
{
- odil::Element const element((odil::Value::Strings()));
- BOOST_CHECK(element.is_string());
+ TContainer const container(contents);
+ TContainer const other_container(other_contents);
- std::vector<std::string> const & value = element.as_string();
- BOOST_CHECK(value.empty());
-}
+ test_container(TContainer(), vr, type_check, getter);
+ test_container(container, vr, type_check, getter);
+ test_initializer_list(contents, type_check, getter);
+
+ test_modify(container, getter, setter);
-BOOST_AUTO_TEST_CASE(ModifyString)
-{
- odil::Element element({""});
- element.as_string().push_back("foo");
+ test_clear(container, type_check);
- BOOST_CHECK(!element.empty());
- BOOST_CHECK_EQUAL(element.size(), 2);
+ test_equality(container, other_container, vr, other_vr);
- std::vector<std::string> const & value = element.as_string();
- BOOST_CHECK(value == odil::Value::Strings({"", "foo"}));
+ test_visitor(TContainer(), vr);
+ test_visitor(container, vr);
}
-BOOST_AUTO_TEST_CASE(StringWrong)
+BOOST_AUTO_TEST_CASE(ImplicitType)
{
- odil::Element element((odil::Value::Strings()));
- BOOST_CHECK_THROW(element.as_int(), odil::Exception);
- BOOST_CHECK_THROW(element.as_real(), odil::Exception);
- BOOST_CHECK_THROW(element.as_data_set(), odil::Exception);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::AE, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::AS, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::AT, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::CS, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::DA, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Reals>(
+ odil::VR::DS, &odil::Element::is_real, &odil::Element::as_real);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::DT, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Reals>(
+ odil::VR::FL, &odil::Element::is_real, &odil::Element::as_real);
+ test_implicit_container<odil::Value::Reals>(
+ odil::VR::FD, &odil::Element::is_real, &odil::Element::as_real);
+ test_implicit_container<odil::Value::Integers>(
+ odil::VR::IS, &odil::Element::is_int, &odil::Element::as_int);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::LO, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::LT, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Binary>(
+ odil::VR::OB, &odil::Element::is_binary, &odil::Element::as_binary);
+ test_implicit_container<odil::Value::Binary>(
+ odil::VR::OD, &odil::Element::is_binary, &odil::Element::as_binary);
+ test_implicit_container<odil::Value::Binary>(
+ odil::VR::OF, &odil::Element::is_binary, &odil::Element::as_binary);
+ test_implicit_container<odil::Value::Binary>(
+ odil::VR::OL, &odil::Element::is_binary, &odil::Element::as_binary);
+ test_implicit_container<odil::Value::Binary>(
+ odil::VR::OW, &odil::Element::is_binary, &odil::Element::as_binary);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::PN, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::SH, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Integers>(
+ odil::VR::SL, &odil::Element::is_int, &odil::Element::as_int);
+ test_implicit_container<odil::Value::DataSets>(
+ odil::VR::SQ, &odil::Element::is_data_set, &odil::Element::as_data_set);
+ test_implicit_container<odil::Value::Integers>(
+ odil::VR::SS, &odil::Element::is_int, &odil::Element::as_int);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::ST, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::TM, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::UC, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::UI, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Integers>(
+ odil::VR::UL, &odil::Element::is_int, &odil::Element::as_int);
+ test_implicit_container<odil::Value::Binary>(
+ odil::VR::UN, &odil::Element::is_binary, &odil::Element::as_binary);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::UR, &odil::Element::is_string, &odil::Element::as_string);
+ test_implicit_container<odil::Value::Integers>(
+ odil::VR::US, &odil::Element::is_int, &odil::Element::as_int);
+ test_implicit_container<odil::Value::Strings>(
+ odil::VR::UT, &odil::Element::is_string, &odil::Element::as_string);
}
-BOOST_AUTO_TEST_CASE(DataSet)
+BOOST_AUTO_TEST_CASE(Int)
{
- odil::Element const element((odil::Value::DataSets()));
- BOOST_CHECK(element.is_data_set());
-
- odil::Value::DataSets const & value = element.as_data_set();
- BOOST_CHECK(value.empty());
+ BOOST_CHECK(odil::Element({1234, 5678}).is_int());
+ test<odil::Value::Integers>(
+ {1234, 5678}, {9012, 3456}, odil::VR::US, odil::VR::UL,
+ &odil::Element::is_int,
+ &odil::Element::as_int, &odil::Element::as_int);
}
-BOOST_AUTO_TEST_CASE(ModifyDataSet)
+BOOST_AUTO_TEST_CASE(Real)
{
- odil::Element element((odil::Value::DataSets()));
-
- odil::DataSet data_set;
- data_set.add("PatientID");
- data_set.as_string("PatientID").push_back("DJ1234");
- element.as_data_set().push_back(data_set);
-
- BOOST_CHECK(!element.empty());
- BOOST_CHECK_EQUAL(element.size(), 1);
-
- odil::Value::DataSets const & value = element.as_data_set();
- BOOST_CHECK_EQUAL(value.size(), 1);
- BOOST_CHECK_EQUAL(value[0].size(), 1);
- BOOST_CHECK(value[0].has("PatientID"));
- BOOST_CHECK(
- value[0].as_string("PatientID") == odil::Value::Strings({"DJ1234"}));
+ BOOST_CHECK(odil::Element({12.34, 56.78}).is_real());
+ test<odil::Value::Reals>(
+ {12.34, 56.78}, {1., 2.}, odil::VR::FD, odil::VR::DS,
+ &odil::Element::is_real,
+ &odil::Element::as_real, &odil::Element::as_real);
}
-BOOST_AUTO_TEST_CASE(DataSetWrong)
+BOOST_AUTO_TEST_CASE(String)
{
- odil::Element element((odil::Value::DataSets()));
- BOOST_CHECK_THROW(element.as_int(), odil::Exception);
- BOOST_CHECK_THROW(element.as_real(), odil::Exception);
- BOOST_CHECK_THROW(element.as_string(), odil::Exception);
+ BOOST_CHECK(odil::Element({"foo", "bar"}).is_string());
+ test<odil::Value::Strings>(
+ {"foo", "bar"}, {"plip", "plop"}, odil::VR::CS, odil::VR::UT,
+ &odil::Element::is_string,
+ &odil::Element::as_string, &odil::Element::as_string);
}
-BOOST_AUTO_TEST_CASE(Equality)
+BOOST_AUTO_TEST_CASE(DataSets)
{
- odil::Element const element1({12,34}, odil::VR::US);
- odil::Element const element2({12,34}, odil::VR::US);
- odil::Element const element3({12.,34.}, odil::VR::FL);
- odil::Element const element4({12,34}, odil::VR::UL);
-
- BOOST_CHECK(element1 == element2);
- BOOST_CHECK(! (element1 == element3));
- BOOST_CHECK(! (element1 == element4));
+ odil::DataSet data_set_1;
+ data_set_1.add("PatientID", {"DJ1234"});
+
+ odil::DataSet data_set_2;
+ data_set_2.add("EchoTime", {100});
+
+ BOOST_CHECK(odil::Element({data_set_1, data_set_2}).is_data_set());
+ test<odil::Value::DataSets>(
+ {data_set_1, data_set_2}, {data_set_2, data_set_1},
+ odil::VR::SQ, odil::VR::UN,
+ &odil::Element::is_data_set,
+ &odil::Element::as_data_set, &odil::Element::as_data_set);
}
-BOOST_AUTO_TEST_CASE(Difference)
+BOOST_AUTO_TEST_CASE(Binary)
{
- odil::Element const element1({12,34}, odil::VR::US);
- odil::Element const element2({12,34}, odil::VR::US);
- odil::Element const element3({12.,34.}, odil::VR::FL);
- odil::Element const element4({12,34}, odil::VR::UL);
-
- BOOST_CHECK(! (element1 != element2));
- BOOST_CHECK(element1 != element3);
- BOOST_CHECK(element1 != element4);
+ BOOST_CHECK(odil::Element({{0x1, 0x2}, {0x3}}).is_binary());
+ test<odil::Value::Binary>(
+ {{0x1, 0x2}, {0x3}}, {{0x4}, {0x5, 0x6}},
+ odil::VR::OB, odil::VR::OW,
+ &odil::Element::is_binary,
+ &odil::Element::as_binary, &odil::Element::as_binary);
}
diff --git a/tests/code/FindSCP.cpp b/tests/code/FindSCP.cpp
index fdc4f6a..a0af937 100644
--- a/tests/code/FindSCP.cpp
+++ b/tests/code/FindSCP.cpp
@@ -43,12 +43,12 @@ public:
odil::DataSet data_set_1;
data_set_1.add(odil::registry::PatientName, {"Hello^World"});
data_set_1.add(odil::registry::PatientID, {"1234"});
- this->_responses.push_back(data_set_1);
+ this->_responses.push_back(std::move(data_set_1));
odil::DataSet data_set_2;
data_set_2.add(odil::registry::PatientName, {"Doe^John"});
data_set_2.add(odil::registry::PatientID, {"5678"});
- this->_responses.push_back(data_set_2);
+ this->_responses.push_back(std::move(data_set_2));
this->_response_iterator = this->_responses.begin();
}
@@ -60,7 +60,7 @@ public:
virtual odil::DataSet get() const
{
- return *this->_response_iterator;
+ return *std::make_move_iterator(this->_response_iterator);
}
virtual void next()
@@ -70,8 +70,8 @@ public:
private:
- std::vector<odil::DataSet> _responses;
- std::vector<odil::DataSet>::const_iterator _response_iterator;
+ mutable std::vector<odil::DataSet> _responses;
+ std::vector<odil::DataSet>::iterator _response_iterator;
};
void run_server(Status * status)
@@ -88,8 +88,8 @@ void run_server(Status * status)
find_scp.set_generator(generator);
// Get echo message
- auto const message = association.receive_message();
- find_scp(message);
+ auto message = association.receive_message();
+ find_scp(std::move(message));
// Should throw with peer closing connection
association.receive_message();
}
@@ -134,8 +134,8 @@ void run_client(Status * status)
}
std::ifstream stream(it->path().string());
- auto const data_set = odil::Reader::read_file(stream).second;
- status->responses.push_back(data_set);
+ auto data_set = odil::Reader::read_file(stream).second;
+ status->responses.push_back(std::move(data_set));
boost::filesystem::remove(it->path());
}
diff --git a/tests/code/FindSCU.cpp b/tests/code/FindSCU.cpp
index 33d4fa7..82607a4 100644
--- a/tests/code/FindSCU.cpp
+++ b/tests/code/FindSCU.cpp
@@ -43,6 +43,21 @@ BOOST_FIXTURE_TEST_CASE(Find, Fixture)
scu.set_affected_sop_class(odil::registry::PatientRootQueryRetrieveInformationModelFIND);
auto const results = scu.find(this->query);
+ BOOST_REQUIRE(!this->query.empty());
+
+ BOOST_REQUIRE_EQUAL(results.size(), 1);
+ BOOST_CHECK(
+ results[0].as_string("PatientID") ==
+ odil::Value::Strings({"DJ001"}));
+}
+
+BOOST_FIXTURE_TEST_CASE(FindMove, Fixture)
+{
+ odil::FindSCU scu(this->association);
+
+ scu.set_affected_sop_class(odil::registry::PatientRootQueryRetrieveInformationModelFIND);
+ auto const results = scu.find(std::move(this->query));
+ BOOST_REQUIRE(this->query.empty());
BOOST_REQUIRE_EQUAL(results.size(), 1);
BOOST_CHECK(
@@ -56,6 +71,18 @@ BOOST_FIXTURE_TEST_CASE(FindCallback, Fixture)
scu.set_affected_sop_class(odil::registry::PatientRootQueryRetrieveInformationModelFIND);
scu.find(this->query, Fixture::callback);
+ BOOST_REQUIRE(!this->query.empty());
+
+ BOOST_CHECK(Fixture::called);
+}
+
+BOOST_FIXTURE_TEST_CASE(FindCallbackMove, Fixture)
+{
+ odil::FindSCU scu(this->association);
+
+ scu.set_affected_sop_class(odil::registry::PatientRootQueryRetrieveInformationModelFIND);
+ scu.find(std::move(this->query), Fixture::callback);
+ BOOST_REQUIRE(this->query.empty());
BOOST_CHECK(Fixture::called);
}
diff --git a/tests/code/GetSCP.cpp b/tests/code/GetSCP.cpp
index 1c0a9e3..e0468dd 100644
--- a/tests/code/GetSCP.cpp
+++ b/tests/code/GetSCP.cpp
@@ -49,7 +49,7 @@ public:
{"1.2.826.0.1.3680043.9.5560.3127449359877365688774406533090568532"});
data_set_1.add("PatientName", {"Hello^World"});
data_set_1.add("PatientID", {"1234"});
- this->_responses.push_back(data_set_1);
+ this->_responses.push_back(std::move(data_set_1));
odil::DataSet data_set_2;
data_set_2.add("SOPClassUID", {odil::registry::RawDataStorage});
@@ -58,7 +58,7 @@ public:
{"1.2.826.0.1.3680043.9.5560.3221615743193123463515381981101110692"});
data_set_2.add("PatientName", {"Doe^John"});
data_set_2.add("PatientID", {"5678"});
- this->_responses.push_back(data_set_2);
+ this->_responses.push_back(std::move(data_set_2));
this->_response_iterator = this->_responses.begin();
}
@@ -70,7 +70,7 @@ public:
virtual odil::DataSet get() const
{
- return *this->_response_iterator;
+ return *std::make_move_iterator(this->_response_iterator);
}
virtual void next()
@@ -84,8 +84,8 @@ public:
}
private:
- std::vector<odil::DataSet> _responses;
- std::vector<odil::DataSet>::const_iterator _response_iterator;
+ mutable std::vector<odil::DataSet> _responses;
+ std::vector<odil::DataSet>::iterator _response_iterator;
};
void run_server(Status * status)
@@ -101,9 +101,9 @@ void run_server(Status * status)
auto const generator = std::make_shared<Generator>();
get_scp.set_generator(generator);
- // Get echo message
- auto const message = association.receive_message();
- get_scp(message);
+ // Get C-GET message
+ auto message = association.receive_message();
+ get_scp(std::move(message));
// Should throw with peer closing connection
association.receive_message();
}
@@ -149,8 +149,8 @@ void run_client(Status * status)
}
std::ifstream stream(it->path().string());
- auto const data_set = odil::Reader::read_file(stream).second;
- status->responses.push_back(data_set);
+ auto data_set = odil::Reader::read_file(stream).second;
+ status->responses.push_back(std::move(data_set));
boost::filesystem::remove(it->path());
}
diff --git a/tests/code/GetSCU.cpp b/tests/code/GetSCU.cpp
index 97f47fd..403e4ff 100644
--- a/tests/code/GetSCU.cpp
+++ b/tests/code/GetSCU.cpp
@@ -63,6 +63,21 @@ BOOST_FIXTURE_TEST_CASE(Get, Fixture)
{"2.25.95090344942250266709587559073467305647"}));
}
+BOOST_FIXTURE_TEST_CASE(GetMove, Fixture)
+{
+ odil::GetSCU scu(this->association);
+
+ scu.set_affected_sop_class(
+ odil::registry::PatientRootQueryRetrieveInformationModelGET);
+ auto const results = scu.get(std::move(this->query));
+
+ BOOST_REQUIRE_EQUAL(results.size(), 1);
+ BOOST_CHECK(
+ results[0].as_string("SOPInstanceUID") ==
+ odil::Value::Strings(
+ {"2.25.95090344942250266709587559073467305647"}));
+}
+
BOOST_FIXTURE_TEST_CASE(GetBothCallbacks, Fixture)
{
odil::GetSCU scu(this->association);
@@ -75,6 +90,19 @@ BOOST_FIXTURE_TEST_CASE(GetBothCallbacks, Fixture)
BOOST_CHECK(Fixture::get_callback_called);
}
+BOOST_FIXTURE_TEST_CASE(GetBothCallbacksMove, Fixture)
+{
+ odil::GetSCU scu(this->association);
+
+ scu.set_affected_sop_class(
+ odil::registry::PatientRootQueryRetrieveInformationModelGET);
+ scu.get(
+ std::move(this->query), Fixture::store_callback, Fixture::get_callback);
+
+ BOOST_CHECK(Fixture::store_callback_called);
+ BOOST_CHECK(Fixture::get_callback_called);
+}
+
BOOST_FIXTURE_TEST_CASE(GetOnlyStoreCallback, Fixture)
{
odil::GetSCU scu(this->association);
@@ -86,3 +114,15 @@ BOOST_FIXTURE_TEST_CASE(GetOnlyStoreCallback, Fixture)
BOOST_CHECK(Fixture::store_callback_called);
BOOST_CHECK(!Fixture::get_callback_called);
}
+
+BOOST_FIXTURE_TEST_CASE(GetOnlyStoreCallbackMove, Fixture)
+{
+ odil::GetSCU scu(this->association);
+
+ scu.set_affected_sop_class(
+ odil::registry::PatientRootQueryRetrieveInformationModelGET);
+ scu.get(std::move(this->query), Fixture::store_callback);
+
+ BOOST_CHECK(Fixture::store_callback_called);
+ BOOST_CHECK(!Fixture::get_callback_called);
+}
diff --git a/tests/code/MoveSCP.cpp b/tests/code/MoveSCP.cpp
index e6f261d..2fc6c5f 100644
--- a/tests/code/MoveSCP.cpp
+++ b/tests/code/MoveSCP.cpp
@@ -51,7 +51,7 @@ public:
{"1.2.826.0.1.3680043.9.5560.3127449359877365688774406533090568532"});
data_set_1.add("PatientName", {"Hello^World"});
data_set_1.add("PatientID", {"1234"});
- this->_responses.push_back(data_set_1);
+ this->_responses.push_back(std::move(data_set_1));
odil::DataSet data_set_2;
data_set_2.add("SOPClassUID", {odil::registry::RawDataStorage});
@@ -60,7 +60,7 @@ public:
{"1.2.826.0.1.3680043.9.5560.3221615743193123463515381981101110692"});
data_set_2.add("PatientName", {"Doe^John"});
data_set_2.add("PatientID", {"5678"});
- this->_responses.push_back(data_set_2);
+ this->_responses.push_back(std::move(data_set_2));
this->_response_iterator = this->_responses.begin();
}
@@ -72,7 +72,7 @@ public:
virtual odil::DataSet get() const
{
- return *this->_response_iterator;
+ return *std::make_move_iterator(this->_response_iterator);
}
virtual void next()
@@ -120,8 +120,8 @@ public:
}
private:
- std::vector<odil::DataSet> _responses;
- std::vector<odil::DataSet>::const_iterator _response_iterator;
+ mutable std::vector<odil::DataSet> _responses;
+ std::vector<odil::DataSet>::iterator _response_iterator;
odil::Association & _association;
};
@@ -139,8 +139,8 @@ void run_server(Status * status)
move_scp.set_generator(generator);
// Get move message
- auto const message = association.receive_message();
- move_scp(message);
+ auto message = association.receive_message();
+ move_scp(std::move(message));
// Should throw with peer closing connection
association.receive_message();
}
@@ -185,8 +185,8 @@ void run_client(Status * status)
}
std::ifstream stream(it->path().string());
- auto const data_set = odil::Reader::read_file(stream).second;
- status->responses.push_back(data_set);
+ auto data_set = odil::Reader::read_file(stream).second;
+ status->responses.push_back(std::move(data_set));
boost::filesystem::remove(it->path());
}
diff --git a/tests/code/MoveSCU.cpp b/tests/code/MoveSCU.cpp
index 59c8fec..bb9d3bc 100644
--- a/tests/code/MoveSCU.cpp
+++ b/tests/code/MoveSCU.cpp
@@ -84,6 +84,22 @@ BOOST_FIXTURE_TEST_CASE(Move, Fixture)
odil::Value::Strings{"2.25.95090344942250266709587559073467305647"});
}
+BOOST_FIXTURE_TEST_CASE(MoveMove, Fixture)
+{
+ odil::MoveSCU scu(this->association);
+ scu.set_move_destination("LOCAL");
+ scu.set_incoming_port(11113);
+
+ scu.set_affected_sop_class(
+ odil::registry::PatientRootQueryRetrieveInformationModelMOVE);
+ auto const results = scu.move(std::move(this->query));
+
+ BOOST_REQUIRE_EQUAL(results.size(), 1);
+ BOOST_CHECK(
+ results[0].as_string("SOPInstanceUID") ==
+ odil::Value::Strings{"2.25.95090344942250266709587559073467305647"});
+}
+
BOOST_FIXTURE_TEST_CASE(MoveBothCallback, Fixture)
{
odil::MoveSCU scu(this->association);
@@ -98,6 +114,22 @@ BOOST_FIXTURE_TEST_CASE(MoveBothCallback, Fixture)
BOOST_CHECK(Fixture::move_callback_called);
}
+BOOST_FIXTURE_TEST_CASE(MoveBothCallbackMove, Fixture)
+{
+ odil::MoveSCU scu(this->association);
+ scu.set_move_destination("LOCAL");
+ scu.set_incoming_port(11113);
+
+ scu.set_affected_sop_class(
+ odil::registry::PatientRootQueryRetrieveInformationModelMOVE);
+ scu.move(
+ std::move(this->query), Fixture::store_callback,
+ Fixture::move_callback);
+
+ BOOST_CHECK(Fixture::store_callback_called);
+ BOOST_CHECK(Fixture::move_callback_called);
+}
+
BOOST_FIXTURE_TEST_CASE(MoveOnlyStoreCallback, Fixture)
{
odil::MoveSCU scu(this->association);
@@ -112,3 +144,19 @@ BOOST_FIXTURE_TEST_CASE(MoveOnlyStoreCallback, Fixture)
BOOST_CHECK(Fixture::store_callback_called);
BOOST_CHECK(!Fixture::move_callback_called);
}
+
+BOOST_FIXTURE_TEST_CASE(MoveOnlyStoreCallbackMove, Fixture)
+{
+ odil::MoveSCU scu(this->association);
+ scu.set_move_destination("LOCAL");
+ scu.set_incoming_port(11113);
+
+ scu.set_affected_sop_class(
+ odil::registry::PatientRootQueryRetrieveInformationModelMOVE);
+ scu.move(
+ std::move(this->query), Fixture::store_callback,
+ odil::MoveSCU::MoveCallback());
+
+ BOOST_CHECK(Fixture::store_callback_called);
+ BOOST_CHECK(!Fixture::move_callback_called);
+}
diff --git a/tests/code/NCreateSCP.cpp b/tests/code/NCreateSCP.cpp
new file mode 100644
index 0000000..5fcda09
--- /dev/null
+++ b/tests/code/NCreateSCP.cpp
@@ -0,0 +1,91 @@
+#define BOOST_TEST_MODULE NCreateSCP
+#include <boost/test/unit_test.hpp>
+
+#include <chrono>
+#include <cstdlib>
+#include <thread>
+
+#include <boost/asio.hpp>
+
+#include "odil/Association.h"
+#include "odil/NCreateSCP.h"
+#include "odil/Exception.h"
+#include "odil/message/NCreateRequest.h"
+#include "odil/message/Response.h"
+
+struct Status
+{
+ int client;
+ std::string server;
+ bool called;
+};
+
+void run_server(Status * status)
+{
+ odil::Association association;
+ association.set_tcp_timeout(boost::posix_time::seconds(1));
+
+ try
+ {
+ association.receive_association(boost::asio::ip::tcp::v4(), 11113);
+
+ odil::NCreateSCP NCreate_scp(association,
+ [status](odil::message::NCreateRequest const &)
+ {
+ status->called = true;
+ return odil::message::Response::Success;
+ });
+
+ // Get NCreate message
+ auto const message = association.receive_message();
+ NCreate_scp(message);
+ // Should throw with peer closing connection
+ association.receive_message();
+ }
+ catch(odil::AssociationAborted const &)
+ {
+ status->server = "abort";
+ }
+ catch(odil::AssociationReleased const &)
+ {
+ status->server = "release";
+ }
+ catch(odil::Exception const &)
+ {
+ status->server = "Other Odil exception";
+ }
+ catch(...)
+ {
+ status->server = "Other exception";
+ }
+}
+
+// void run_client(Status * status, bool use_abort)
+// {
+// std::string command = "NCreatescu -ll error";
+// if(use_abort)
+// {
+// command += " --abort";
+// }
+// command += " 127.0.0.1 11113";
+// status->client = system(command.c_str());
+// }
+
+BOOST_AUTO_TEST_CASE(Callback)
+{
+ odil::Association association;
+ odil::NCreateSCP scp(association);
+
+ bool called = false;
+ auto const callback =
+ [&called](odil::message::NCreateRequest const &)
+ {
+ called = true;
+ return odil::message::Response::Success;
+ };
+
+ scp.set_callback(callback);
+ scp.get_callback()(odil::message::NCreateRequest(1, ""));
+ BOOST_REQUIRE_EQUAL(called, true);
+}
+
diff --git a/tests/code/Reader.cpp b/tests/code/Reader.cpp
index 78395bd..96004f9 100644
--- a/tests/code/Reader.cpp
+++ b/tests/code/Reader.cpp
@@ -84,7 +84,7 @@ void do_test(odil::Tag const & tag, odil::VR vr, std::initializer_list<T> const
{
// Empty element
{
- odil::Element element(odil::Value(), vr);
+ odil::Element element(std::initializer_list<T>(), vr);
odil::DataSet data_set;
data_set.add(tag, element);
do_test(data_set);
diff --git a/tests/code/SCPDispatcher.cpp b/tests/code/SCPDispatcher.cpp
index 3280232..2a92f68 100644
--- a/tests/code/SCPDispatcher.cpp
+++ b/tests/code/SCPDispatcher.cpp
@@ -127,6 +127,6 @@ BOOST_AUTO_TEST_CASE(DispatchWithoutEcho)
client.join();
BOOST_REQUIRE_EQUAL(status.client, 0);
- BOOST_REQUIRE_EQUAL(status.server, "No such provider");
+ BOOST_REQUIRE_EQUAL(status.server, "No provider for: 0030");
BOOST_REQUIRE_EQUAL(status.called, false);
}
diff --git a/tests/code/StoreSCU.cpp b/tests/code/StoreSCU.cpp
index f4f6c86..dc75521 100644
--- a/tests/code/StoreSCU.cpp
+++ b/tests/code/StoreSCU.cpp
@@ -64,3 +64,11 @@ BOOST_FIXTURE_TEST_CASE(Store, Fixture)
scu.set_affected_sop_class(this->dataset);
scu.store(this->dataset);
}
+
+BOOST_FIXTURE_TEST_CASE(StoreMove, Fixture)
+{
+ odil::StoreSCU scu(this->association);
+
+ scu.set_affected_sop_class(this->dataset);
+ scu.store(std::move(this->dataset));
+}
diff --git a/tests/code/Value.cpp b/tests/code/Value.cpp
index 3365305..f41f8a8 100644
--- a/tests/code/Value.cpp
+++ b/tests/code/Value.cpp
@@ -2,232 +2,101 @@
#include <boost/test/unit_test.hpp>
#include "odil/DataSet.h"
-#include "odil/Element.h"
#include "odil/Exception.h"
+#include "odil/Value.h"
-BOOST_AUTO_TEST_CASE(Empty)
+template<typename TContainer>
+void test_contents(
+ odil::Value const & value,
+ TContainer const & contents, odil::Value::Type type,
+ TContainer const & (odil::Value::*getter)() const)
{
- odil::Value const value;
+ BOOST_CHECK(value.get_type() == type);
+ BOOST_CHECK_EQUAL(value.empty(), contents.empty());
+ BOOST_CHECK_EQUAL(value.size(), contents.size());
+ BOOST_CHECK((value.*getter)() == contents);
- BOOST_CHECK(value.get_type() == odil::Value::Type::Empty);
- BOOST_CHECK_THROW(value.as_integers(), odil::Exception);
- BOOST_CHECK_THROW(value.as_reals(), odil::Exception);
- BOOST_CHECK_THROW(value.as_strings(), odil::Exception);
- BOOST_CHECK_THROW(value.as_data_sets(), odil::Exception);
-}
-
-BOOST_AUTO_TEST_CASE(Integers)
-{
- odil::Value const value({1234});
-
- BOOST_CHECK(value.get_type() == odil::Value::Type::Integers);
- BOOST_CHECK(value.as_integers() == odil::Value::Integers({1234}));
-
- BOOST_CHECK_THROW(value.as_reals(), odil::Exception);
- BOOST_CHECK_THROW(value.as_strings(), odil::Exception);
- BOOST_CHECK_THROW(value.as_data_sets(), odil::Exception);
-}
-
-BOOST_AUTO_TEST_CASE(ModifyIntegers)
-{
- odil::Value value({1234});
- value.as_integers().push_back(5678);
- BOOST_CHECK(value.as_integers() == odil::Value::Integers({1234, 5678}));
-}
-
-BOOST_AUTO_TEST_CASE(Reals)
-{
- odil::Value const value({12.34});
-
- BOOST_CHECK(value.get_type() == odil::Value::Type::Reals);
- BOOST_CHECK(value.as_reals() == odil::Value::Reals({12.34}));
-
- BOOST_CHECK_THROW(value.as_integers(), odil::Exception);
- BOOST_CHECK_THROW(value.as_strings(), odil::Exception);
- BOOST_CHECK_THROW(value.as_data_sets(), odil::Exception);
-}
-
-BOOST_AUTO_TEST_CASE(ModifyReals)
-{
- odil::Value value({12.34});
- value.as_reals().push_back(56.78);
- BOOST_CHECK(value.as_reals() == odil::Value::Reals({12.34, 56.78}));
-}
-
-BOOST_AUTO_TEST_CASE(Strings)
-{
- odil::Value const value({"foo"});
-
- BOOST_CHECK(value.get_type() == odil::Value::Type::Strings);
- BOOST_CHECK(value.as_strings() == odil::Value::Strings({"foo"}));
-
- BOOST_CHECK_THROW(value.as_integers(), odil::Exception);
- BOOST_CHECK_THROW(value.as_reals(), odil::Exception);
- BOOST_CHECK_THROW(value.as_data_sets(), odil::Exception);
-}
-
-BOOST_AUTO_TEST_CASE(ModifyStrings)
-{
- odil::Value value({"foo"});
- value.as_strings().push_back("bar");
- BOOST_CHECK(value.as_strings() == odil::Value::Strings({"foo", "bar"}));
-}
-
-BOOST_AUTO_TEST_CASE(DataSets)
-{
- odil::DataSet data_set;
- data_set.add("PatientID", {"DJ1234"});
- odil::Value const value({data_set});
-
- BOOST_CHECK(value.get_type() == odil::Value::Type::DataSets);
- BOOST_CHECK_EQUAL(value.as_data_sets().size(), 1);
- BOOST_CHECK(value.as_data_sets()[0].has("PatientID"));
- BOOST_CHECK(
- value.as_data_sets()[0].as_string("PatientID") ==
- odil::Value::Strings({"DJ1234"}));
-
- BOOST_CHECK_THROW(value.as_integers(), odil::Exception);
- BOOST_CHECK_THROW(value.as_strings(), odil::Exception);
- BOOST_CHECK_THROW(value.as_reals(), odil::Exception);
-}
-
-BOOST_AUTO_TEST_CASE(ModifyDataSets)
-{
- odil::DataSet data_set;
- data_set.add("PatientID");
- data_set.as_string("PatientID").push_back("DJ1234");
- odil::Value value({data_set});
-
- value.as_data_sets()[0].as_string("PatientID")[0] = "XXX";
-
- BOOST_CHECK(value.get_type() == odil::Value::Type::DataSets);
- BOOST_CHECK_EQUAL(value.as_data_sets().size(), 1);
- BOOST_CHECK(value.as_data_sets()[0].has("PatientID"));
- BOOST_CHECK(
- value.as_data_sets()[0].as_string("PatientID") ==
- odil::Value::Strings({"XXX"}));
-}
-
-BOOST_AUTO_TEST_CASE(EqualityEmpty)
-{
- odil::Value const value1;
- odil::Value const value2;
- odil::Value const value3((odil::Value::Integers()));
- BOOST_CHECK(value1 == value2);
- BOOST_CHECK( ! (value1 == value3));
-}
-
-BOOST_AUTO_TEST_CASE(EqualityIntegers)
-{
- odil::Value const value1({1,2});
- odil::Value const value2({1,2});
- odil::Value const value3({3,4});
- odil::Value const value4({3,4});
- BOOST_CHECK(value1 == value2);
- BOOST_CHECK( ! (value1 == value3));
- BOOST_CHECK( ! (value1 == value4));
-}
-
-BOOST_AUTO_TEST_CASE(EqualityReals)
-{
- odil::Value const value1({1,2});
- odil::Value const value2({1,2});
- odil::Value const value3({3,4});
- odil::Value const value4({3,4});
- BOOST_CHECK(value1 == value2);
- BOOST_CHECK( ! (value1 == value3));
- BOOST_CHECK( ! (value1 == value4));
-}
-
-BOOST_AUTO_TEST_CASE(EqualityStrings)
-{
- odil::Value const value1({"1","2"});
- odil::Value const value2({"1","2"});
- odil::Value const value3({"3","4"});
- odil::Value const value4({3,4});
- BOOST_CHECK(value1 == value2);
- BOOST_CHECK( ! (value1 == value3));
- BOOST_CHECK( ! (value1 == value4));
+ if(type != odil::Value::Type::Integers)
+ {
+ BOOST_CHECK_THROW(value.as_integers(), odil::Exception);
+ }
+ if(type != odil::Value::Type::Reals)
+ {
+ BOOST_CHECK_THROW(value.as_reals(), odil::Exception);
+ }
+ if(type != odil::Value::Type::Strings)
+ {
+ BOOST_CHECK_THROW(value.as_strings(), odil::Exception);
+ }
+ if(type != odil::Value::Type::DataSets)
+ {
+ BOOST_CHECK_THROW(value.as_data_sets(), odil::Exception);
+ }
+ if(type != odil::Value::Type::Binary)
+ {
+ BOOST_CHECK_THROW(value.as_binary(), odil::Exception);
+ }
}
-BOOST_AUTO_TEST_CASE(EqualityDataSets)
+template<typename TContainer>
+void test_container(
+ TContainer const & contents, odil::Value::Type type,
+ TContainer const & (odil::Value::*getter)() const)
{
- odil::DataSet dataset1;
- dataset1.add("PatientID", {"DJ1234"});
- dataset1.add("PixelSpacing", {1.5, 2.5});
-
- odil::DataSet dataset2;
- dataset1.add("PatientName", {"Doe^John"});
- dataset1.add("PatientAge", {"042Y"});
+ odil::Value const value(contents);
+ test_contents(value, contents, type, getter);
- odil::Value const value1({dataset1});
- odil::Value const value2({dataset1});
- odil::Value const value3({dataset2});
- odil::Value const value4({3,4});
- BOOST_CHECK(value1 == value2);
- BOOST_CHECK( ! (value1 == value3));
- BOOST_CHECK( ! (value1 == value4));
-}
-
-BOOST_AUTO_TEST_CASE(DifferenceEmpty)
-{
- odil::Value const value1;
- odil::Value const value2;
- odil::Value const value3((odil::Value::Integers()));
- BOOST_CHECK(! (value1 != value2));
- BOOST_CHECK(value1 != value3);
+ auto contents_copy(contents);
+ odil::Value const other_value(std::move(contents_copy));
+ BOOST_CHECK(contents_copy.empty());
}
-BOOST_AUTO_TEST_CASE(DifferenceIntegers)
+template<typename TContainer>
+void test_initializer_list(
+ std::initializer_list<typename TContainer::value_type> const & contents,
+ odil::Value::Type type,
+ TContainer const & (odil::Value::*getter)() const)
{
- odil::Value const value1({1,2});
- odil::Value const value2({1,2});
- odil::Value const value3({3,4});
- odil::Value const value4({3,4});
- BOOST_CHECK(! (value1 != value2));
- BOOST_CHECK(value1 != value3);
- BOOST_CHECK(value1 != value4);
+ odil::Value const value(contents);
+ test_contents(value, TContainer(contents), type, getter);
}
-BOOST_AUTO_TEST_CASE(DifferenceReals)
+template<typename TContainer>
+void test_modify(
+ TContainer const & contents,
+ TContainer const & (odil::Value::*getter)() const,
+ TContainer & (odil::Value::*setter)())
{
- odil::Value const value1({1.,2.});
- odil::Value const value2({1.,2.});
- odil::Value const value3({3.,4.});
- odil::Value const value4({3,4});
- BOOST_CHECK(! (value1 != value2));
- BOOST_CHECK(value1 != value3);
- BOOST_CHECK(value1 != value4);
+ odil::Value value(TContainer{{contents[0]}});
+ (value.*setter)().push_back(contents[1]);
+ BOOST_CHECK((value.*getter)() == contents);
}
-BOOST_AUTO_TEST_CASE(DifferenceStrings)
+template<typename TContainer>
+void test_clear(TContainer const & contents, odil::Value::Type type)
{
- odil::Value const value1({"1","2"});
- odil::Value const value2({"1","2"});
- odil::Value const value3({"3","4"});
- odil::Value const value4({3,4});
- BOOST_CHECK(! (value1 != value2));
- BOOST_CHECK(value1 != value3);
- BOOST_CHECK(value1 != value4);
+ odil::Value value(contents);
+ value.clear();
+ BOOST_CHECK(value.get_type() == type);
+ BOOST_CHECK(value.empty());
}
-BOOST_AUTO_TEST_CASE(DifferenceDataSets)
+template<typename TContainer>
+void test_equality(
+ TContainer const & contents_1, TContainer const & contents_2)
{
- odil::DataSet dataset1;
- dataset1.add("PatientID", {"DJ1234"});
- dataset1.add("PixelSpacing", {1.5, 2.5});
+ odil::Value const value_1(contents_1);
+ odil::Value const value_2(contents_1);
+ odil::Value const value_3(contents_2);
+ odil::Value const value_4(contents_2);
- odil::DataSet dataset2;
- dataset1.add("PatientName", {"Doe^John"});
- dataset1.add("PatientAge", {"042Y"});
+ BOOST_CHECK(value_1 == value_2);
+ BOOST_CHECK( ! (value_1 == value_3));
+ BOOST_CHECK( ! (value_1 == value_4));
- odil::Value const value1({dataset1});
- odil::Value const value2({dataset1});
- odil::Value const value3({dataset2});
- odil::Value const value4({3,4});
- BOOST_CHECK(! (value1 != value2));
- BOOST_CHECK(value1 != value3);
- BOOST_CHECK(value1 != value4);
+ BOOST_CHECK(! (value_1 != value_2));
+ BOOST_CHECK(value_1 != value_3);
+ BOOST_CHECK(value_1 != value_4);
}
struct Visitor
@@ -241,50 +110,94 @@ struct Visitor
}
};
-BOOST_AUTO_TEST_CASE(VisitorEmpty)
+template<typename TContainer>
+void test_visitor(
+ TContainer const & contents)
{
- odil::Value const value;
- BOOST_CHECK_THROW(
+ odil::Value const value(contents);
+ BOOST_REQUIRE_EQUAL(
odil::apply_visitor(Visitor(), value),
- odil::Exception);
+ typeid(TContainer).name());
}
-BOOST_AUTO_TEST_CASE(VisitorIntegers)
+template<typename TContainer>
+void test(
+ std::initializer_list<typename TContainer::value_type> const & contents,
+ std::initializer_list<typename TContainer::value_type> const & other_contents,
+ odil::Value::Type type,
+ TContainer const & (odil::Value::*getter)() const,
+ TContainer & (odil::Value::*setter)())
{
- odil::Value const value({1234});
- BOOST_REQUIRE_EQUAL(
- odil::apply_visitor(Visitor(), value),
- typeid(odil::Value::Integers).name());
+ TContainer const container(contents);
+ TContainer const other_container(other_contents);
+
+ test_container(TContainer(), type, getter);
+ test_container(container, type, getter);
+ test_initializer_list(contents, type, getter);
+
+ test_modify(container, getter, setter);
+
+ test_clear(container, type);
+
+ test_equality(container, other_container);
+
+ test_visitor(container);
+}
+
+BOOST_AUTO_TEST_CASE(Integers)
+{
+ BOOST_CHECK(
+ odil::Value({1234, 5678}).get_type() == odil::Value::Type::Integers);
+ test<odil::Value::Integers>(
+ {1234, 5678}, {9012, 3456},
+ odil::Value::Type::Integers,
+ &odil::Value::as_integers, &odil::Value::as_integers);
}
-BOOST_AUTO_TEST_CASE(VisitorReals)
+BOOST_AUTO_TEST_CASE(Reals)
{
- odil::Value const value({12.34});
- BOOST_REQUIRE_EQUAL(
- odil::apply_visitor(Visitor(), value),
- typeid(odil::Value::Reals).name());
+ BOOST_CHECK(
+ odil::Value({12.34, 56.78}).get_type() == odil::Value::Type::Reals);
+ test<odil::Value::Reals>(
+ {12.34, 56.78}, {1., 2.},
+ odil::Value::Type::Reals,
+ &odil::Value::as_reals, &odil::Value::as_reals);
}
-BOOST_AUTO_TEST_CASE(VisitorStrings)
+BOOST_AUTO_TEST_CASE(Strings)
{
- odil::Value const value({"foo"});
- BOOST_REQUIRE_EQUAL(
- odil::apply_visitor(Visitor(), value),
- typeid(odil::Value::Strings).name());
+ BOOST_CHECK(
+ odil::Value({"foo", "bar"}).get_type() == odil::Value::Type::Strings);
+ test<odil::Value::Strings>(
+ {"foo", "bar"}, {"plip", "plop"},
+ odil::Value::Type::Strings,
+ &odil::Value::as_strings, &odil::Value::as_strings);
}
-BOOST_AUTO_TEST_CASE(VisitorDataSets)
+BOOST_AUTO_TEST_CASE(DataSets)
{
- odil::Value const value({odil::DataSet()});
- BOOST_REQUIRE_EQUAL(
- odil::apply_visitor(Visitor(), value),
- typeid(odil::Value::DataSets).name());
+ odil::DataSet data_set_1;
+ data_set_1.add("PatientID", {"DJ1234"});
+
+ odil::DataSet data_set_2;
+ data_set_2.add("EchoTime", {100});
+
+ BOOST_CHECK(
+ odil::Value({data_set_1, data_set_2}).get_type()
+ == odil::Value::Type::DataSets);
+ test<odil::Value::DataSets>(
+ {data_set_1, data_set_2}, {data_set_2, data_set_1},
+ odil::Value::Type::DataSets,
+ &odil::Value::as_data_sets, &odil::Value::as_data_sets);
}
-BOOST_AUTO_TEST_CASE(VisitorBinary)
+BOOST_AUTO_TEST_CASE(Binary)
{
- odil::Value const value((odil::Value::Binary()));
- BOOST_REQUIRE_EQUAL(
- odil::apply_visitor(Visitor(), value),
- typeid(odil::Value::Binary).name());
+ BOOST_CHECK(
+ odil::Value({{0x1, 0x2}, {0x3}}).get_type()
+ == odil::Value::Type::Binary);
+ test<odil::Value::Binary>(
+ {{0x1, 0x2}, {0x3}}, {{0x4}, {0x5, 0x6}},
+ odil::Value::Type::Binary,
+ &odil::Value::as_binary, &odil::Value::as_binary);
}
diff --git a/tests/run b/tests/run
index e426ca4..ed3ea71 100755
--- a/tests/run
+++ b/tests/run
@@ -14,9 +14,15 @@ def main():
description="Run all tests (C++ and Python). "
"This program must be run from the build directory.")
parser.add_argument("tests", nargs="*", help="Python only")
- parser.add_argument("--no-network", action="store_true")
+ parser.add_argument(
+ "--no-network", action="store_true",
+ help="Don't run network-related tests")
+ parser.add_argument(
+ "--verbose", "-v", action="store_true", help="Increase tests verbosity")
parser.add_argument("--test-regex", "-R", help="C++ only")
parser.add_argument("--exclude-regex", "-E", help="C++ only")
+ parser.add_argument(
+ "--nose", default="nosetests", help="nosetests executable")
parser.add_argument("--exclude", "-e", help="Python only")
arguments = parser.parse_args()
@@ -67,12 +73,16 @@ def main():
source_directory = match.group(1)
break
- cpp_code = subprocess.call(
- ["ctest", "--no-compress-output", "-T", "Test"]+cpp_args,
- env=environment)
- python_code = subprocess.call(
- ["nosetests-2.7", os.path.join(source_directory, "tests", "wrappers")]+python_args,
- env=environment)
+ ctest = ["ctest", "--no-compress-output", "-T", "Test"]
+ if arguments.verbose:
+ ctest.append("-V")
+ cpp_code = subprocess.call(ctest+cpp_args, env=environment)
+
+ nose = [
+ arguments.nose, os.path.join(source_directory, "tests", "wrappers")]
+ if arguments.verbose:
+ nose.append("-v")
+ python_code = subprocess.call(nose+python_args, env=environment)
tearDown(directory, process)
diff --git a/tests/tools/CMakeLists.txt b/tests/tools/CMakeLists.txt
index 35b445e..e3ec9c1 100644
--- a/tests/tools/CMakeLists.txt
+++ b/tests/tools/CMakeLists.txt
@@ -7,6 +7,8 @@ link_directories(${DCMTK_LIBRARY_DIRS})
file(GLOB headers *.h)
file(GLOB files "*.cc")
-add_executable(dcmtk_getscu ${files} ${headers})
-target_link_libraries(dcmtk_getscu ${DCMTK_LIBRARIES})
-set_target_properties(dcmtk_getscu PROPERTIES OUTPUT_NAME getscu)
+if(USE_BUILTIN_DCMTK_GETSCU)
+ add_executable(dcmtk_getscu ${files} ${headers})
+ target_link_libraries(dcmtk_getscu ${DCMTK_LIBRARIES})
+ set_target_properties(dcmtk_getscu PROPERTIES OUTPUT_NAME getscu)
+endif()
diff --git a/tests/wrappers/test_association_parameters.py b/tests/wrappers/test_association_parameters.py
index 721f77b..455ea4b 100644
--- a/tests/wrappers/test_association_parameters.py
+++ b/tests/wrappers/test_association_parameters.py
@@ -12,7 +12,7 @@ class TestAssociationParameters(unittest.TestCase):
user_identity = parameters.get_user_identity()
self.assertEqual(
user_identity.type,
- odil.AssociationParameters.UserIdentity.Type.None)
+ getattr(odil.AssociationParameters.UserIdentity.Type, "None"))
self.assertEqual(parameters.get_maximum_length(), 16384)
@@ -85,7 +85,7 @@ class TestAssociationParameters(unittest.TestCase):
user_identity = parameters.get_user_identity()
self.assertEqual(
user_identity.type,
- odil.AssociationParameters.UserIdentity.Type.None)
+ getattr(odil.AssociationParameters.UserIdentity.Type, "None"))
def test_maximum_length(self):
parameters = odil.AssociationParameters()
diff --git a/tests/wrappers/test_data_set.py b/tests/wrappers/test_data_set.py
index 8e4a20e..12fba09 100644
--- a/tests/wrappers/test_data_set.py
+++ b/tests/wrappers/test_data_set.py
@@ -36,154 +36,118 @@ class TestDataSet(unittest.TestCase):
self.assertTrue(data_set.empty(tag))
self.assertEqual(data_set.size(tag), 0)
- def test_int_element(self):
- tag = odil.registry.SelectorUSValue
- value = [1, 2, 3]
+ def _test_sequences(self, odil_contents, python_contents):
+ if python_contents and isinstance(python_contents[0], bytearray):
+ self.assertSequenceEqual(
+ [bytearray([x for x in item]) for item in odil_contents],
+ python_contents)
+ else:
+ self.assertSequenceEqual(list(odil_contents), list(python_contents))
+
+ def _test_element_value(
+ self, data_set, tag, contents, type_check, accessor):
+ self.assertTrue(data_set.has(tag))
+ self.assertEqual(data_set.empty(tag), len(contents)==0)
+ self.assertEqual(data_set.size(tag), len(contents))
+ self.assertTrue(type_check(data_set, tag))
+ self._test_sequences(accessor(data_set, tag), contents)
+
+ if not data_set.is_int(tag):
+ with self.assertRaises(odil.Exception):
+ data_set.as_int(tag)
+ if not data_set.is_real(tag):
+ with self.assertRaises(odil.Exception):
+ data_set.as_real(tag)
+ if not data_set.is_string(tag):
+ with self.assertRaises(odil.Exception):
+ data_set.as_string(tag)
+ if not data_set.is_data_set(tag):
+ with self.assertRaises(odil.Exception):
+ data_set.as_data_set(tag)
+ if not data_set.is_binary(tag):
+ with self.assertRaises(odil.Exception):
+ data_set.as_binary(tag)
+
+ def _test_implicit_container(
+ self, tag, empty_content, type_check, accessor):
data_set = odil.DataSet()
- data_set.add(tag, value)
-
- self.assertFalse(data_set.empty())
- self.assertEqual(data_set.size(), 1)
- self.assertEqual(len(data_set), 1)
-
- self.assertEqual(data_set.get_vr(tag), odil.VR.US)
- self.assertFalse(data_set.empty(tag))
- self.assertEqual(data_set.size(tag), 3)
- self.assertTrue(data_set.is_int(tag))
- self.assertSequenceEqual(data_set.as_int(tag), value)
-
- value = [4, 5]
- data_set.set(tag, value)
-
- self.assertFalse(data_set.empty())
- self.assertEqual(data_set.size(), 1)
- self.assertEqual(len(data_set), 1)
-
- self.assertEqual(data_set.get_vr(tag), odil.VR.US)
- self.assertFalse(data_set.empty(tag))
- self.assertEqual(data_set.size(tag), len(value))
- self.assertTrue(data_set.is_int(tag))
- self.assertSequenceEqual(data_set.as_int(tag), value)
+ data_set.add(tag)
+ self._test_element_value(
+ data_set, tag, empty_content, type_check, accessor)
- def test_real_element(self):
- tag = odil.registry.SelectorFLValue
- value = [1.1, 2, 3.3]
+ def _test_container_no_vr(self, tag, contents, type_check, accessor):
data_set = odil.DataSet()
- data_set.add(tag, value)
-
- self.assertFalse(data_set.empty())
- self.assertEqual(data_set.size(), 1)
- self.assertEqual(len(data_set), 1)
-
- self.assertEqual(data_set.get_vr(tag), odil.VR.FL)
- self.assertFalse(data_set.empty(tag))
- self.assertEqual(data_set.size(tag), 3)
- self.assertTrue(data_set.is_real(tag))
- self.assertSequenceEqual(data_set.as_real(tag), value)
-
- value = [4.4, 5]
- data_set.set(tag, value)
-
- self.assertFalse(data_set.empty())
- self.assertEqual(data_set.size(), 1)
- self.assertEqual(len(data_set), 1)
-
- self.assertEqual(data_set.get_vr(tag), odil.VR.FL)
- self.assertFalse(data_set.empty(tag))
- self.assertEqual(data_set.size(tag), len(value))
- self.assertTrue(data_set.is_real(tag))
- self.assertSequenceEqual(data_set.as_real(tag), value)
+ data_set.add(tag, contents)
+ self._test_element_value(data_set, tag, contents, type_check, accessor)
- def test_string_element(self):
- tag = odil.registry.SelectorCSValue
- value = ["foo", "bar"]
+ def _test_container_vr(self, tag, contents, vr, type_check, accessor):
data_set = odil.DataSet()
- data_set.add(tag, value)
-
- self.assertFalse(data_set.empty())
- self.assertEqual(data_set.size(), 1)
- self.assertEqual(len(data_set), 1)
-
- self.assertEqual(data_set.get_vr(tag), odil.VR.CS)
- self.assertFalse(data_set.empty(tag))
- self.assertEqual(data_set.size(tag), 2)
- self.assertTrue(data_set.is_string(tag))
- self.assertSequenceEqual(data_set.as_string(tag), value)
-
- value = ["baz"]
- data_set.set(tag, value)
-
- self.assertFalse(data_set.empty())
- self.assertEqual(data_set.size(), 1)
- self.assertEqual(len(data_set), 1)
-
- self.assertEqual(data_set.get_vr(tag), odil.VR.CS)
- self.assertFalse(data_set.empty(tag))
- self.assertEqual(data_set.size(tag), len(value))
- self.assertTrue(data_set.is_string(tag))
- self.assertSequenceEqual(data_set.as_string(tag), value)
+ data_set.add(tag, contents, vr)
+ self._test_element_value(data_set, tag, contents, type_check, accessor)
- def test_data_set_element(self):
- tag = odil.registry.SelectorCodeSequenceValue
- value = [odil.DataSet(), odil.DataSet()]
+ def _test_modify(self, tag, contents, accessor):
data_set = odil.DataSet()
- data_set.add(tag, value)
-
- self.assertFalse(data_set.empty())
- self.assertEqual(data_set.size(), 1)
- self.assertEqual(len(data_set), 1)
-
- self.assertEqual(data_set.get_vr(tag), odil.VR.SQ)
- self.assertFalse(data_set.empty(tag))
- self.assertEqual(data_set.size(tag), 2)
- self.assertTrue(data_set.is_data_set(tag))
- self.assertSequenceEqual(data_set.as_data_set(tag), value)
-
- value = [odil.DataSet()]
- data_set.set(tag, value)
-
- self.assertFalse(data_set.empty())
- self.assertEqual(data_set.size(), 1)
- self.assertEqual(len(data_set), 1)
-
- self.assertEqual(data_set.get_vr(tag), odil.VR.SQ)
- self.assertFalse(data_set.empty(tag))
- self.assertEqual(data_set.size(tag), len(value))
- self.assertTrue(data_set.is_data_set(tag))
- self.assertSequenceEqual(data_set.as_data_set(tag), value)
-
- def test_binary_element(self):
- tag = odil.registry.RedPaletteColorLookupTableData
- value = [bytearray("\x01\x02\x03")]
+ data_set.add(tag, [contents[0]])
+ if isinstance(contents[0], bytearray):
+ accessor(data_set, tag).append(
+ odil.Value.BinaryItem("".join(chr(x) for x in contents[1])))
+ else:
+ accessor(data_set, tag).append(contents[1])
+ self._test_sequences(accessor(data_set, tag), contents)
+
+ def _test_clear(self, tag, contents, type_check):
data_set = odil.DataSet()
- data_set.add(tag, value)
-
- self.assertFalse(data_set.empty())
- self.assertEqual(data_set.size(), 1)
- self.assertEqual(len(data_set), 1)
-
- self.assertEqual(data_set.get_vr(tag), odil.VR.OW)
- self.assertFalse(data_set.empty(tag))
- self.assertEqual(data_set.size(tag), 1)
- self.assertTrue(data_set.is_binary(tag))
- self.assertSequenceEqual(
- [bytearray([x for x in item]) for item in data_set.as_binary(tag)],
- value)
-
- value = [bytearray("\x04\x05")]
- data_set.set(tag, value)
-
- self.assertFalse(data_set.empty())
- self.assertEqual(data_set.size(), 1)
- self.assertEqual(len(data_set), 1)
+ data_set.add(tag, contents)
+ data_set.clear(tag)
+ self.assertTrue(type_check(data_set, tag))
+ self.assertTrue(data_set.empty(tag))
- self.assertEqual(data_set.get_vr(tag), odil.VR.OW)
- self.assertFalse(data_set.empty(tag))
- self.assertEqual(data_set.size(tag), len(value))
- self.assertTrue(data_set.is_binary(tag))
- self.assertSequenceEqual(
- [bytearray([x for x in item]) for item in data_set.as_binary(tag)],
- value)
+ def _test_element(
+ self, tag, empty_content, contents, vr, type_check, accessor):
+ self._test_implicit_container(
+ tag, empty_content, type_check, accessor)
+
+ self._test_container_no_vr(tag, contents, type_check, accessor)
+ self._test_container_vr(tag, contents, vr, type_check, accessor)
+
+ self._test_modify(tag, contents, accessor)
+
+ self._test_clear(tag, contents, type_check)
+
+ def test_int(self):
+ self._test_element(
+ odil.registry.Rows, odil.Value.Integers(), [1234, 5678], odil.VR.US,
+ odil.DataSet.is_int, odil.DataSet.as_int)
+
+ def test_real(self):
+ self._test_element(
+ odil.registry.SpacingBetweenSlices, odil.Value.Reals(),
+ [12.34, 56.78], odil.VR.FL,
+ odil.DataSet.is_real, odil.DataSet.as_real)
+
+ def test_string(self):
+ self._test_element(
+ odil.registry.PatientID, odil.Value.Strings(), ["foo", "bar"],
+ odil.VR.LT,
+ odil.DataSet.is_string, odil.DataSet.as_string)
+
+ def test_data_set(self):
+ data_set_1 = odil.DataSet()
+ data_set_1.add("PatientID", ["DJ1234"])
+
+ data_set_2 = odil.DataSet()
+ data_set_2.add("EchoTime", [100])
+
+ self._test_element(
+ odil.registry.ReferencedStudySequence, odil.Value.DataSets(),
+ [data_set_1, data_set_2], odil.VR.SQ,
+ odil.DataSet.is_data_set, odil.DataSet.as_data_set)
+
+ def test_binary(self):
+ self._test_element(
+ odil.registry.BadPixelImage, odil.Value.Binary(),
+ [bytearray([0x01, 0x02]), bytearray([0x03])], odil.VR.OB,
+ odil.DataSet.is_binary, odil.DataSet.as_binary)
def test_getitem(self):
data_set = odil.DataSet()
@@ -230,3 +194,4 @@ class TestDataSet(unittest.TestCase):
if __name__ == "__main__":
unittest.main()
+
diff --git a/tests/wrappers/test_element.py b/tests/wrappers/test_element.py
index 01cac2c..34764e4 100644
--- a/tests/wrappers/test_element.py
+++ b/tests/wrappers/test_element.py
@@ -1,56 +1,156 @@
+import re
import unittest
import odil
class TestElement(unittest.TestCase):
- def test_empty_constructor(self):
- element = odil.Element()
+ def _test_sequences(self, odil_contents, python_contents):
+ if python_contents and isinstance(python_contents[0], bytearray):
+ self.assertSequenceEqual(
+ [bytearray([x for x in item]) for item in odil_contents],
+ python_contents)
+ else:
+ self.assertSequenceEqual(list(odil_contents), list(python_contents))
+
+ def _test_value(self, element, vr, contents, type_check, accessor):
+ self.assertTrue(type_check(element))
+ self.assertEqual(element.empty(), len(contents)==0)
+ self.assertEqual(element.size(), len(contents))
+ self.assertEqual(len(element), len(contents))
+ self._test_sequences(accessor(element), contents)
+ self.assertEqual(element.vr, vr)
+
+ if not element.is_int():
+ with self.assertRaises(odil.Exception):
+ element.as_int()
+ if not element.is_real():
+ with self.assertRaises(odil.Exception):
+ element.as_real()
+ if not element.is_string():
+ with self.assertRaises(odil.Exception):
+ element.as_string()
+ if not element.is_data_set():
+ with self.assertRaises(odil.Exception):
+ element.as_data_set()
+ if not element.is_binary():
+ with self.assertRaises(odil.Exception):
+ element.as_binary()
+
+ def _test_implicit_container(self, empty_content, vr, type_check, accessor):
+ element = odil.Element(vr)
+ self._test_value(element, vr, empty_content, type_check, accessor)
+
+ def _test_container(self, contents, vr, type_check, accessor):
+ element = odil.Element(contents, vr)
+ self._test_value(element, vr, contents, type_check, accessor)
+
+ def _test_modify(self, contents, vr, accessor):
+ value = odil.Element([contents[0]], vr)
+ if isinstance(contents[0], bytearray):
+ accessor(value).append(odil.Value.BinaryItem("".join(chr(x) for x in contents[1])))
+ else:
+ accessor(value).append(contents[1])
+
+ self._test_sequences(accessor(value), contents)
+
+ def _test_clear(self, contents, vr, type_check):
+ element = odil.Element(contents, vr)
+ element.clear()
+ self.assertTrue(type_check(element))
self.assertTrue(element.empty())
- self.assertEqual(element.size(), 0)
- self.assertEqual(len(element), 0)
- self.assertEqual(element.vr, odil.VR.INVALID)
-
- def test_integers_constructor(self):
- items = [1, 2, 3]
- element = odil.Element(items, odil.VR.US)
- self.assertSequenceEqual(element.as_int(), items)
- self.assertEqual(element.vr, odil.VR.US)
- self.assertEqual(element.size(), 3)
- self.assertEqual(len(element), 3)
-
- def test_reals_constructor(self):
- items = [1.1, 2, 3.3]
- element = odil.Element(items, odil.VR.FL)
- self.assertSequenceEqual(element.as_real(), items)
- self.assertEqual(element.vr, odil.VR.FL)
- self.assertEqual(element.size(), 3)
- self.assertEqual(len(element), 3)
-
- def test_strings_constructor(self):
- items = ["foo", "bar"]
- element = odil.Element(items, odil.VR.CS)
- self.assertSequenceEqual(element.as_string(), items)
- self.assertEqual(element.vr, odil.VR.CS)
- self.assertEqual(element.size(), 2)
- self.assertEqual(len(element), 2)
-
- def test_data_sets_constructor(self):
- items = [odil.DataSet(), odil.DataSet()]
- element = odil.Element(items, odil.VR.SQ)
- self.assertSequenceEqual(element.as_data_set(), items)
- self.assertEqual(element.vr, odil.VR.SQ)
- self.assertEqual(element.size(), 2)
- self.assertEqual(len(element), 2)
-
- def test_binary_constructor(self):
- items = [bytearray("\x01\x02\x03")]
- element = odil.Element(items, odil.VR.OB)
- self.assertSequenceEqual(
- [bytearray([x for x in item]) for item in element.as_binary()],
- items)
- self.assertEqual(element.vr, odil.VR.OB)
- self.assertEqual(element.size(), 1)
- self.assertEqual(len(element), 1)
+
+ def _test_equality(self, contents_1, contents_2, vr_1, vr_2):
+ element_1 = odil.Element(contents_1, vr_1)
+ element_2 = odil.Element(contents_1, vr_1)
+ element_3 = odil.Element(contents_1, vr_2)
+ element_4 = odil.Element(contents_2, vr_1)
+
+ self.assertTrue(element_1 == element_2)
+ self.assertFalse(element_1 == element_3)
+ self.assertFalse(element_1 == element_4)
+
+ self.assertFalse(element_1 != element_2)
+ self.assertTrue(element_1 != element_3)
+ self.assertTrue(element_1 != element_4)
+
+ def _test(
+ self,
+ empty_content, contents, other_contents, vr, other_vr,
+ type_check, accessor):
+ self._test_implicit_container(empty_content, vr, type_check, accessor)
+ self._test_container(contents, vr, type_check, accessor)
+
+ self._test_modify(contents, vr, accessor)
+
+ self._test_clear(contents, vr, type_check)
+
+ self._test_equality(contents, other_contents, vr, other_vr)
+
+ def test_implicit_type(self):
+ for vr in dir(odil.VR):
+ if re.match(r"^[A-Z]{2}$", vr) is None:
+ continue
+
+ vr = getattr(odil.VR, vr)
+ if odil.is_int(vr):
+ self._test_implicit_container(
+ odil.Value.Integers(), vr,
+ odil.Element.is_int, odil.Element.as_int)
+ elif odil.is_real(vr):
+ self._test_implicit_container(
+ odil.Value.Reals(), vr,
+ odil.Element.is_real, odil.Element.as_real)
+ elif odil.is_string(vr):
+ self._test_implicit_container(
+ odil.Value.Strings(), vr,
+ odil.Element.is_string, odil.Element.as_string)
+ elif vr == odil.VR.SQ:
+ self._test_implicit_container(
+ odil.Value.DataSets(), vr,
+ odil.Element.is_data_set, odil.Element.as_data_set)
+ elif odil.is_binary(vr):
+ self._test_implicit_container(
+ odil.Value.Binary(), vr,
+ odil.Element.is_binary, odil.Element.as_binary)
+
+ def test_integers(self):
+ self._test(
+ odil.Value.Integers(), [1234, 5678], [9012, 3456],
+ odil.VR.US, odil.VR.UL,
+ odil.Element.is_int, odil.Element.as_int)
+
+ def test_reals(self):
+ self._test(
+ odil.Value.Reals(), [12.34, 56.78], [1., 2.],
+ odil.VR.FD, odil.VR.DS,
+ odil.Element.is_real, odil.Element.as_real)
+
+ def test_strings(self):
+ self._test(
+ odil.Value.Strings(), ["foo", "bar"], ["plip", "plop"],
+ odil.VR.CS, odil.VR.UT,
+ odil.Element.is_string, odil.Element.as_string)
+
+ def test_data_sets(self):
+ data_set_1 = odil.DataSet()
+ data_set_1.add("PatientID", ["DJ1234"])
+
+ data_set_2 = odil.DataSet()
+ data_set_2.add("EchoTime", [100])
+
+ self._test(
+ odil.Value.DataSets(),
+ [data_set_1, data_set_2], [data_set_2, data_set_1],
+ odil.VR.SQ, odil.VR.UN,
+ odil.Element.is_data_set, odil.Element.as_data_set)
+
+ def test_binary(self):
+ self._test(
+ odil.Value.Binary(),
+ [bytearray([0x01, 0x02]), bytearray([0x03])],
+ [bytearray([0x04]), bytearray([0x05, 0x06])],
+ odil.VR.OB, odil.VR.OW,
+ odil.Element.is_binary, odil.Element.as_binary)
if __name__ == "__main__":
unittest.main()
diff --git a/tests/wrappers/test_tag.py b/tests/wrappers/test_tag.py
index cf21990..4f580e8 100644
--- a/tests/wrappers/test_tag.py
+++ b/tests/wrappers/test_tag.py
@@ -83,5 +83,16 @@ class TestTag(unittest.TestCase):
tag = odil.Tag(0x1234, 0x5678)
self.assertEqual(str(tag), "12345678")
+ def test_hash(self):
+ tag = odil.Tag(
+ odil.registry.PatientName.group, odil.registry.PatientName.element)
+ d = {tag: True}
+
+ self.assertTrue(tag in d)
+ self.assertTrue(odil.registry.PatientName in d)
+
+ other = odil.Tag(
+ odil.registry.PatientID.group, odil.registry.PatientID.element)
+
if __name__ == "__main__":
unittest.main()
diff --git a/tests/wrappers/test_value.py b/tests/wrappers/test_value.py
index b461690..207f3a6 100644
--- a/tests/wrappers/test_value.py
+++ b/tests/wrappers/test_value.py
@@ -1,44 +1,126 @@
+#encoding: utf-8
import unittest
import odil
class TestValue(unittest.TestCase):
- def test_empty_constructor(self):
- value = odil.Value()
- self.assertEqual(value.type, odil.Value.Type.Empty)
- self.assertTrue(value.empty)
+ def _test_sequences(self, odil_contents, python_contents):
+ if python_contents and isinstance(python_contents[0], bytearray):
+ self.assertSequenceEqual(
+ [bytearray([x for x in item]) for item in odil_contents],
+ python_contents)
+ else:
+ self.assertSequenceEqual(list(odil_contents), list(python_contents))
- def test_integers_constructor(self):
- items = [1, 2, 3]
- value = odil.Value(items)
- self.assertEqual(value.type, odil.Value.Type.Integers)
- self.assertSequenceEqual(value.as_integers(), items)
-
- def test_reals_constructor(self):
- items = [1.1, 2., 3.3]
- value = odil.Value(items)
- self.assertEqual(value.type, odil.Value.Type.Reals)
- self.assertSequenceEqual(value.as_reals(), items)
-
- def test_strings_constructor(self):
- items = ["foo", "bar"]
- value = odil.Value(items)
- self.assertEqual(value.type, odil.Value.Type.Strings)
- self.assertSequenceEqual(value.as_strings(), items)
-
- def test_data_sets_constructor(self):
- items = [odil.DataSet(), odil.DataSet()]
- value = odil.Value(items)
- self.assertEqual(value.type, odil.Value.Type.DataSets)
- self.assertSequenceEqual(value.as_data_sets(), items)
+ def _test_contents(self, value, contents, type_, accessor):
+ self.assertEqual(value.type, type_)
+ self.assertEqual(value.empty(), len(contents) == 0)
+ self.assertEqual(value.size(), len(contents))
+ self.assertEqual(len(value), len(contents))
+ self._test_sequences(accessor(value), contents)
+
+ if type_ != odil.Value.Type.Integers:
+ with self.assertRaises(odil.Exception):
+ value.as_integers()
+ if type_ != odil.Value.Type.Reals:
+ with self.assertRaises(odil.Exception):
+ value.as_reals()
+ if type_ != odil.Value.Type.Strings:
+ with self.assertRaises(odil.Exception):
+ value.as_strings()
+ if type_ != odil.Value.Type.DataSets:
+ with self.assertRaises(odil.Exception):
+ value.as_data_sets()
+ if type_ != odil.Value.Type.Binary:
+ with self.assertRaises(odil.Exception):
+ value.as_binary()
+
+ def _test_container(self, contents, type_, accessor):
+ value = odil.Value(contents)
+ self._test_contents(value, contents, type_, accessor)
+
+ def _test_modify(self, contents, accessor):
+ value = odil.Value([contents[0]])
+ if isinstance(contents[0], bytearray):
+ accessor(value).append(odil.Value.BinaryItem("".join(chr(x) for x in contents[1])))
+ else:
+ accessor(value).append(contents[1])
+
+ self._test_sequences(accessor(value), contents)
+
+ def _test_clear(self, contents, type_):
+ value = odil.Value(contents)
+ value.clear()
+ self.assertEqual(value.type, type_)
+ self.assertTrue(value.empty())
+
+ def _test_equality(self, contents_1, contents_2):
+ value_1 = odil.Value(contents_1)
+ value_2 = odil.Value(contents_1)
+ value_3 = odil.Value(contents_2)
+ value_4 = odil.Value(contents_2)
+
+ self.assertTrue(value_1 == value_2)
+ self.assertFalse(value_1 == value_3)
+ self.assertFalse(value_1 == value_4)
+
+ self.assertFalse(value_1 != value_2)
+ self.assertTrue(value_1 != value_3)
+ self.assertTrue(value_1 != value_4)
+
+ def _test(self, empty_content, contents, other_contents, type_, accessor):
+ self._test_container(empty_content, type_, accessor)
+ self._test_container(contents, type_, accessor)
+
+ self._test_modify(contents, accessor)
+
+ self._test_clear(contents, type_)
+
+ self._test_equality(contents, other_contents)
+
+ def test_integers(self):
+ self._test(
+ odil.Value.Integers(), [1234, 5678], [9012, 3456],
+ odil.Value.Type.Integers, odil.Value.as_integers)
+
+ def test_reals(self):
+ self._test(
+ odil.Value.Reals(), [12.34, 56.78], [1., 2.],
+ odil.Value.Type.Reals, odil.Value.as_reals)
+
+ def test_strings(self):
+ self._test(
+ odil.Value.Strings(), ["foo", "bar"], ["plip", "plop"],
+ odil.Value.Type.Strings, odil.Value.as_strings)
+
+ # FIXME: strings in DICOM are byte-string, with some VR requiring
+ # conversion based on Specific Character Set. In Boost.Python, some
+ # explicit conversion are used (unicode <-> std::string in Python 3).
+
+ def test_data_sets(self):
+ data_set_1 = odil.DataSet()
+ data_set_1.add("PatientID", ["DJ1234"])
- def test_binary_constructor(self):
- items = [bytearray("\x01\x02\x03")]
- value = odil.Value(items)
- self.assertEqual(value.type, odil.Value.Type.Binary)
- self.assertSequenceEqual(
- [bytearray([x for x in item]) for item in value.as_binary()],
- items)
+ data_set_2 = odil.DataSet()
+ data_set_2.add("EchoTime", [100])
+
+ self._test(
+ odil.Value.DataSets(),
+ [data_set_1, data_set_2], [data_set_2, data_set_1],
+ odil.Value.Type.DataSets, odil.Value.as_data_sets)
+
+ def test_binary(self):
+ self._test(
+ odil.Value.Binary(),
+ [bytearray([0x01, 0x02]), bytearray([0x03])],
+ [bytearray([0x04]), bytearray([0x05, 0x06])],
+ odil.Value.Type.Binary, odil.Value.as_binary)
+
+ def test_unknown_constructor(self):
+ class Foo(object): pass
+ items = [Foo()]
+ with self.assertRaises(odil.Exception):
+ odil.Value(items)
class TestValueIntegers(unittest.TestCase):
def test_empty_constructor(self):
diff --git a/tests/wrappers/test_vr.py b/tests/wrappers/test_vr.py
index ef1660f..3254690 100644
--- a/tests/wrappers/test_vr.py
+++ b/tests/wrappers/test_vr.py
@@ -3,6 +3,26 @@ import unittest
import odil
class TestVR(unittest.TestCase):
+ def test_string_constructor(self):
+ data_set = odil.DataSet()
+ data_set.add(odil.registry.PatientName, ["Doe^John"], "UT")
+ self.assertEqual(data_set.get_vr(odil.registry.PatientName), odil.VR.UT)
+
+ def test_unicode_constructor(self):
+ data_set = odil.DataSet()
+ data_set.add(odil.registry.PatientName, ["Doe^John"], u"UT")
+ self.assertEqual(data_set.get_vr(odil.registry.PatientName), odil.VR.UT)
+
+ def test_invalid_string_constructor(self):
+ data_set = odil.DataSet()
+ with self.assertRaises(Exception):
+ data_set.add(odil.registry.PatientName, ["Doe^John"], "XX")
+
+ def test_invalid_unicode_constructor(self):
+ data_set = odil.DataSet()
+ with self.assertRaises(Exception):
+ data_set.add(odil.registry.PatientName, ["Doe^John"], u"XX")
+
def test_string(self):
vr = odil.VR.AE
self.assertEqual(str(vr), "AE")
diff --git a/wrappers/Assocation.cpp b/wrappers/Assocation.cpp
index 50872b0..4c424ba 100644
--- a/wrappers/Assocation.cpp
+++ b/wrappers/Assocation.cpp
@@ -6,44 +6,48 @@
* for details.
************************************************************************/
-#include <boost/asio.hpp>
-#include <boost/python.hpp>
+#include "exception_factory.h"
#include "odil/Association.h"
-#include "exception_factory.h"
+#include <boost/asio.hpp>
+#include <boost/python.hpp>
namespace
{
-PyObject * wrapped_AssociationReleased;
-PyObject * wrapped_AssociationAborted;
+PyObject* wrapped_AssociationReleased;
+PyObject* wrapped_AssociationAborted;
void receive_association(
- odil::Association & association, std::string protocol, unsigned short port)
+ odil::Association& association, std::string protocol, unsigned short port)
{
if(protocol == "v4")
{
association.receive_association(boost::asio::ip::tcp::v4(), port);
}
+ else if (protocol == "v6")
+ {
+ association.receive_association(boost::asio::ip::tcp::v6(), port);
+ }
}
-void released_translator(odil::AssociationReleased const & e)
+void released_translator(odil::AssociationReleased const& e)
{
PyErr_SetString(wrapped_AssociationReleased, e.what());
}
-void aborted_translator(odil::AssociationAborted const & e)
+void aborted_translator(odil::AssociationAborted const& e)
{
PyErr_SetString(wrapped_AssociationAborted, e.what());
}
-float get_tcp_timeout(odil::Association const & association)
+float get_tcp_timeout(odil::Association const& association)
{
return association.get_tcp_timeout().total_microseconds()/1000000.;
}
-void set_tcp_timeout(odil::Association & association, float seconds)
+void set_tcp_timeout(odil::Association& association, float seconds)
{
association.set_tcp_timeout(
boost::posix_time::microseconds(seconds*1000000.));
@@ -55,62 +59,64 @@ void wrap_Association()
{
using namespace boost::python;
using namespace odil;
-
+
object wrapped_exception = scope().attr("Exception");
-
+
wrapped_AssociationReleased = exception_factory(
"AssociationReleased", wrapped_exception.ptr());
register_exception_translator<AssociationReleased>(released_translator);
-
+
wrapped_AssociationAborted = exception_factory(
"AssociationAborted", wrapped_exception.ptr());
register_exception_translator<AssociationAborted>(aborted_translator);
-
+
scope association_scope = class_<Association>("Association", init<>())
- .def("get_peer_host", &Association::get_peer_host,
- return_value_policy<copy_const_reference>())
- .def("set_peer_host", &Association::set_peer_host)
- .def("get_peer_port", &Association::get_peer_port)
- .def("set_peer_port", &Association::set_peer_port)
- .def(
- "get_parameters",
- &Association::get_parameters,
- return_value_policy<reference_existing_object>()
+ .def("get_peer_host", &Association::get_peer_host,
+ return_value_policy<copy_const_reference>())
+ .def("set_peer_host", &Association::set_peer_host)
+ .def("get_peer_port", &Association::get_peer_port)
+ .def("set_peer_port", &Association::set_peer_port)
+ .def(
+ "get_parameters",
+ &Association::get_parameters,
+ return_value_policy<reference_existing_object>()
)
- .def(
- "set_parameters",
- &Association::set_parameters,
- return_value_policy<reference_existing_object>()
+ .def(
+ "set_parameters",
+ &Association::set_parameters,
+ return_value_policy<reference_existing_object>()
)
- .def(
- "update_parameters",
- &Association::update_parameters,
- return_value_policy<reference_existing_object>()
+ .def(
+ "update_parameters",
+ &Association::update_parameters,
+ return_value_policy<reference_existing_object>()
)
- .def(
- "get_negotiated_parameters",
- &Association::get_negotiated_parameters,
- return_value_policy<reference_existing_object>()
+ .def(
+ "get_negotiated_parameters",
+ &Association::get_negotiated_parameters,
+ return_value_policy<reference_existing_object>()
)
- .def("get_tcp_timeout", &get_tcp_timeout)
- .def("set_tcp_timeout", &set_tcp_timeout)
- // Message timeout
- .def("is_associated", &Association::is_associated)
- .def("associate", &Association::associate)
- // Receive association
- .def("receive_association", &receive_association)
- //.def("reject", &Association::reject)
- .def("release", &Association::release)
- .def("abort", &Association::abort)
- // Receive message
- .def("receive_message", &Association::receive_message)
- // Send message
- .def("next_message_id", &Association::next_message_id)
+ .def("get_tcp_timeout", &get_tcp_timeout)
+ .def("set_tcp_timeout", &set_tcp_timeout)
+ // Message timeout
+ .def("is_associated", &Association::is_associated)
+ .def("associate", &Association::associate)
+ // Receive association
+ .def("receive_association", &receive_association)
+ //.def("reject", &Association::reject)
+ .def("release", &Association::release)
+ .def("abort", &Association::abort)
+ // Receive message
+ .def("receive_message", &Association::receive_message)
+ // Send message
+ .def("next_message_id", &Association::next_message_id)
+ // Send message
+ .def("send_message", &Association::send_message)
;
enum_<Association::Result>("Result")
- .value("Accepted", Association::Accepted)
- .value("RejectedPermanent", Association::RejectedPermanent)
- .value("RejectedTransient", Association::RejectedTransient)
+ .value("Accepted", Association::Accepted)
+ .value("RejectedPermanent", Association::RejectedPermanent)
+ .value("RejectedTransient", Association::RejectedTransient)
;
}
diff --git a/wrappers/AssocationParameters.cpp b/wrappers/AssocationParameters.cpp
index e799795..47dc2f0 100644
--- a/wrappers/AssocationParameters.cpp
+++ b/wrappers/AssocationParameters.cpp
@@ -209,7 +209,8 @@ void wrap_AssociationParameters()
{
scope user_identity_scope =
- class_<AssociationParameters::UserIdentity>("UserIdentity")
+ class_<AssociationParameters::UserIdentity>(
+ "UserIdentity", init<>())
.def_readwrite(
"type",
&AssociationParameters::UserIdentity::type
diff --git a/wrappers/CEchoResponse.cpp b/wrappers/CEchoResponse.cpp
new file mode 100644
index 0000000..107ac6f
--- /dev/null
+++ b/wrappers/CEchoResponse.cpp
@@ -0,0 +1,30 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#include <boost/python.hpp>
+
+#include "odil/message/CEchoResponse.h"
+
+void wrap_CEchoResponse()
+{
+ using namespace boost::python;
+ using namespace odil;
+ using namespace odil::message;
+
+ class_<CEchoResponse, bases<Response>>(
+ "CEchoResponse", init<Value::Integer,Value::Integer, Value::String const &>())
+ .def(init<Message const &>())
+ .def(
+ "get_affected_sop_class_uid",
+ &CEchoResponse::get_affected_sop_class_uid,
+ return_value_policy<copy_const_reference>())
+ .def(
+ "set_affected_sop_class_uid",
+ &CEchoResponse::set_affected_sop_class_uid)
+ ;
+}
diff --git a/wrappers/CMakeLists.txt b/wrappers/CMakeLists.txt
index d5ab3b8..3d4d7aa 100644
--- a/wrappers/CMakeLists.txt
+++ b/wrappers/CMakeLists.txt
@@ -1,13 +1,25 @@
find_package(Boost REQUIRED COMPONENTS python)
find_package(JsonCpp REQUIRED)
+find_package(PythonInterp 2.7 REQUIRED)
find_package(PythonLibs 2.7 REQUIRED)
+if(NOT "${PYTHONLIBS_VERSION_STRING}" STREQUAL "${PYTHON_VERSION_STRING}")
+ message(
+ WARNING
+ "Python version mismatch: libraries are \"${PYTHONLIBS_VERSION_STRING}\", interpreter is \"${PYTHON_VERSION_STRING}\"")
+endif()
+
+if(BUILD_SHARED_LIBS)
+ add_definitions(-D BOOST_ALL_DYN_LINK)
+endif()
+
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../src ${Boost_INCLUDE_DIRS}
${JsonCpp_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
file(GLOB_RECURSE files "*.cpp")
+list(SORT files)
python_add_module(pyodil SHARED ${files})
set_target_properties(
pyodil PROPERTIES OUTPUT_NAME odil FOLDER "Wrappers")
@@ -17,3 +29,11 @@ endif()
target_link_libraries(
pyodil ${Boost_LIBRARIES} ${JsonCpp_LIBRARIES} libodil ${PYTHON_LIBRARIES})
+
+execute_process(
+ COMMAND ${PYTHON_EXECUTABLE}
+ -c "from distutils import sysconfig; print( sysconfig.get_python_lib( plat_specific=True, prefix='${CMAKE_INSTALL_PREFIX}' ) )"
+ OUTPUT_VARIABLE PYTHON_SITE_PACKAGES
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+install(TARGETS pyodil DESTINATION ${PYTHON_SITE_PACKAGES})
diff --git a/wrappers/CStoreResponse.cpp b/wrappers/CStoreResponse.cpp
new file mode 100644
index 0000000..fbd923b
--- /dev/null
+++ b/wrappers/CStoreResponse.cpp
@@ -0,0 +1,54 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#include <boost/python.hpp>
+
+#include "odil/message/CStoreResponse.h"
+
+void wrap_CStoreResponse()
+{
+ using namespace boost::python;
+ using namespace odil;
+ using namespace odil::message;
+
+ class_<CStoreResponse, bases<Response>>(
+ "CStoreResponse",
+ init< Value::Integer, Value::Integer>())
+ .def(init<Message>())
+ .def(
+ "has_message_id",
+ &CStoreResponse::has_message_id)
+ .def(
+ "get_message_id",
+ &CStoreResponse::get_message_id,
+ return_value_policy<copy_const_reference>())
+ .def(
+ "set_message_id",
+ &CStoreResponse::set_message_id)
+ .def(
+ "has_affected_sop_class_uid",
+ &CStoreResponse::has_affected_sop_class_uid)
+ .def(
+ "get_affected_sop_class_uid",
+ &CStoreResponse::get_affected_sop_class_uid,
+ return_value_policy<copy_const_reference>())
+ .def(
+ "set_affected_sop_class_uid",
+ &CStoreResponse::set_affected_sop_class_uid)
+ .def(
+ "has_affected_sop_instance_uid",
+ &CStoreResponse::has_affected_sop_instance_uid)
+ .def(
+ "get_affected_sop_instance_uid",
+ &CStoreResponse::get_affected_sop_instance_uid,
+ return_value_policy<copy_const_reference>())
+ .def(
+ "set_affected_sop_instance_uid",
+ &CStoreResponse::set_affected_sop_instance_uid)
+ ;
+}
diff --git a/wrappers/DataSet.cpp b/wrappers/DataSet.cpp
index e9cd25e..f15fb8b 100644
--- a/wrappers/DataSet.cpp
+++ b/wrappers/DataSet.cpp
@@ -247,5 +247,7 @@ void wrap_DataSet()
.def(
"__len__",
static_cast<std::size_t (DataSet::*)() const>(&DataSet::size))
+ .def("clear", &DataSet::clear)
;
}
+
diff --git a/wrappers/EchoSCP.cpp b/wrappers/EchoSCP.cpp
index e6ee791..edb6025 100644
--- a/wrappers/EchoSCP.cpp
+++ b/wrappers/EchoSCP.cpp
@@ -6,22 +6,28 @@
* for details.
************************************************************************/
-#include <boost/python.hpp>
-
#include "odil/EchoSCP.h"
+#include <boost/python.hpp>
+
namespace
{
-void
-set_callback(odil::EchoSCP & scp, boost::python::object const & f)
+void
+set_callback(odil::EchoSCP& scp, boost::python::object const& f)
{
scp.set_callback(
- [f](odil::message::CEchoRequest const & message)
- {
+ [f](odil::message::CEchoRequest const& message)
+ {
return boost::python::call<odil::Value::Integer>(f.ptr(), message);
}
- );
+ );
+}
+
+std::shared_ptr<odil::EchoSCP>
+New_EchoSCP( odil::Association& a )
+{
+ return std::shared_ptr<odil::EchoSCP>( new odil::EchoSCP(a) );
}
}
@@ -31,8 +37,16 @@ void wrap_EchoSCP()
using namespace boost::python;
using namespace odil;
- class_<EchoSCP>("EchoSCP", init<Association &>())
+ class_<EchoSCP>("EchoSCP", init<Association&>())
.def("set_callback", &set_callback)
- .def("__call__", &EchoSCP::operator())
+ .def(
+ "__call__",
+ static_cast<
+ void (EchoSCP::*)(message::Message const &)
+ >(&EchoSCP::operator())
+ )
;
+
+
+ def("New_EchoSCP", &New_EchoSCP);
}
diff --git a/wrappers/Element.cpp b/wrappers/Element.cpp
index bcf24ec..7c251d3 100644
--- a/wrappers/Element.cpp
+++ b/wrappers/Element.cpp
@@ -18,11 +18,9 @@ namespace
{
boost::shared_ptr<odil::Element>
-constructor(
- boost::python::object const & value_python, odil::VR vr=odil::VR::INVALID)
+constructor(boost::python::object const & value, odil::VR vr)
{
- auto value_cpp = value_constructor(value_python);
-
+ auto value_cpp = value_constructor(value);
odil::Element * element = new odil::Element(*value_cpp, vr);
// Old versions of Boost.Python (Debian 7, Ubuntu 12.04) do not like
@@ -43,9 +41,10 @@ void wrap_Element()
typedef Value::DataSets & (Element::*AsDataSets)();
typedef Value::Binary & (Element::*AsBinary)();
- class_<Element>("Element", init<>())
+ class_<Element>("Element", no_init)
.def_readwrite("vr", &Element::vr)
- .def("__init__", make_constructor(constructor))
+ .def(init<VR>())
+ .def("__init__", make_constructor(&constructor))
.def("empty", &Element::empty)
.def("size", &Element::size)
.def(
@@ -74,5 +73,6 @@ void wrap_Element()
.def(self == self)
.def(self != self)
.def("__len__", &Element::size)
+ .def("clear", &Element::clear)
;
}
diff --git a/wrappers/FindSCP.cpp b/wrappers/FindSCP.cpp
index 6a5809c..60ce40a 100644
--- a/wrappers/FindSCP.cpp
+++ b/wrappers/FindSCP.cpp
@@ -38,7 +38,12 @@ void wrap_FindSCP()
scope find_scp_scope = class_<FindSCP>("FindSCP", init<Association &>())
.def("set_generator", &set_generator)
- .def("__call__", &FindSCP::operator())
+ .def(
+ "__call__",
+ static_cast<
+ void (FindSCP::*)(message::Message const &)
+ >(&FindSCP::operator())
+ )
;
class_<
diff --git a/wrappers/GetSCP.cpp b/wrappers/GetSCP.cpp
index 26a8cb2..f983e22 100644
--- a/wrappers/GetSCP.cpp
+++ b/wrappers/GetSCP.cpp
@@ -55,7 +55,12 @@ void wrap_GetSCP()
scope get_scp_scope = class_<GetSCP>("GetSCP", init<Association &>())
.def("set_generator", &set_generator)
- .def("__call__", &odil::GetSCP::operator())
+ .def(
+ "__call__",
+ static_cast<
+ void (GetSCP::*)(message::Message const &)
+ >(&GetSCP::operator())
+ )
;
class_<DataSetGeneratorWrapperGet, boost::noncopyable>(
diff --git a/wrappers/Message.cpp b/wrappers/Message.cpp
index 655069f..fd370e5 100644
--- a/wrappers/Message.cpp
+++ b/wrappers/Message.cpp
@@ -6,11 +6,11 @@
* for details.
************************************************************************/
-#include <boost/python.hpp>
-
#include "odil/DataSet.h"
#include "odil/message/Message.h"
+#include <boost/python.hpp>
+
void wrap_Message()
{
using namespace boost::python;
@@ -18,18 +18,53 @@ void wrap_Message()
using namespace odil::message;
class_<Message>("Message", init<>())
- .def(init<DataSet const &>())
- .def(init<DataSet const &, DataSet const &>())
- .def(
- "get_command_set", &Message::get_command_set,
- return_value_policy<copy_const_reference>())
- .def("has_data_set", &Message::has_data_set)
- .def(
- "get_data_set", &Message::get_data_set,
- return_value_policy<copy_const_reference>())
- .def(
- "get_command_field", &Message::get_command_field,
- return_value_policy<copy_const_reference>())
- .def("set_command_field", &Message::set_command_field)
+ .def(init<DataSet const&>())
+ .def(init<DataSet const&, DataSet const&>())
+ .def(
+ "get_command_set", &Message::get_command_set,
+ return_value_policy<copy_const_reference>())
+ .def("has_data_set", &Message::has_data_set)
+ .def(
+ "get_data_set",
+ static_cast<DataSet const & (Message::*)() const>(&Message::get_data_set),
+ return_value_policy<copy_const_reference>())
+ .def(
+ "get_command_field", &Message::get_command_field,
+ return_value_policy<copy_const_reference>())
+ .def("set_command_field", &Message::set_command_field)
;
}
+
+void wrap_CommandTypeEnum()
+{
+ using namespace boost::python;
+ using namespace odil;
+ using namespace odil::message;
+
+ enum_< Message::Command::Type>("message_command_type")
+ .value("C_STORE_RQ", Message::Command::Type::C_STORE_RQ )
+ .value("C_STORE_RSP", Message::Command::Type::C_STORE_RSP )
+ .value("C_FIND_RQ", Message::Command::Type::C_FIND_RQ )
+ .value("C_FIND_RSP", Message::Command::Type::C_FIND_RSP )
+ .value("C_CANCEL_RQ", Message::Command::Type::C_CANCEL_RQ )
+ .value("C_GET_RQ", Message::Command::Type::C_GET_RQ )
+ .value("C_GET_RSP", Message::Command::Type::C_GET_RSP )
+ .value("C_MOVE_RQ", Message::Command::Type::C_MOVE_RQ )
+ .value("C_MOVE_RSP", Message::Command::Type::C_MOVE_RSP )
+ .value("C_ECHO_RQ", Message::Command::Type::C_ECHO_RQ )
+ .value("C_ECHO_RSP", Message::Command::Type::C_ECHO_RSP )
+ .value("N_EVENT_REPORT_RQ", Message::Command::Type::N_EVENT_REPORT_RQ )
+ .value("N_EVENT_REPORT_RSP", Message::Command::Type::N_EVENT_REPORT_RSP)
+ .value("N_GET_RQ", Message::Command::Type::N_GET_RQ )
+ .value("N_GET_RSP", Message::Command::Type::N_GET_RSP )
+ .value("N_SET_RQ", Message::Command::Type::N_SET_RQ )
+ .value("N_SET_RSP", Message::Command::Type::N_SET_RSP )
+ .value("N_ACTION_RQ", Message::Command::Type::N_ACTION_RQ )
+ .value("N_ACTION_RSP", Message::Command::Type::N_ACTION_RSP )
+ .value("N_CREATE_RQ", Message::Command::Type::N_CREATE_RQ )
+ .value("N_CREATE_RSP", Message::Command::Type::N_CREATE_RSP )
+ .value("N_DELETE_RQ", Message::Command::Type::N_DELETE_RQ )
+ .value("N_DELETE_RSP", Message::Command::Type::N_DELETE_RSP )
+ ;
+}
+
diff --git a/wrappers/MoveSCP.cpp b/wrappers/MoveSCP.cpp
index e51bbab..24fc523 100644
--- a/wrappers/MoveSCP.cpp
+++ b/wrappers/MoveSCP.cpp
@@ -62,7 +62,12 @@ void wrap_MoveSCP()
scope move_scp_scope = class_<MoveSCP>("MoveSCP", init<Association &>())
.def("set_generator", &set_generator)
- .def("__call__", &odil::MoveSCP::operator())
+ .def(
+ "__call__",
+ static_cast<
+ void (MoveSCP::*)(message::Message const &)
+ >(&MoveSCP::operator())
+ )
;
class_<DataSetGeneratorWrapperMove, boost::noncopyable>(
diff --git a/wrappers/EchoSCP.cpp b/wrappers/NCreateSCP.cpp
similarity index 62%
copy from wrappers/EchoSCP.cpp
copy to wrappers/NCreateSCP.cpp
index e6ee791..52ad76c 100644
--- a/wrappers/EchoSCP.cpp
+++ b/wrappers/NCreateSCP.cpp
@@ -8,16 +8,16 @@
#include <boost/python.hpp>
-#include "odil/EchoSCP.h"
+#include "odil/NCreateSCP.h"
namespace
{
void
-set_callback(odil::EchoSCP & scp, boost::python::object const & f)
+set_callback(odil::NCreateSCP & scp, boost::python::object const & f)
{
scp.set_callback(
- [f](odil::message::CEchoRequest const & message)
+ [f](odil::message::NCreateRequest const & message)
{
return boost::python::call<odil::Value::Integer>(f.ptr(), message);
}
@@ -26,13 +26,18 @@ set_callback(odil::EchoSCP & scp, boost::python::object const & f)
}
-void wrap_EchoSCP()
+void wrap_NCreateSCP()
{
using namespace boost::python;
using namespace odil;
- class_<EchoSCP>("EchoSCP", init<Association &>())
+ class_<NCreateSCP>("NCreateSCP", init<Association &>())
.def("set_callback", &set_callback)
- .def("__call__", &EchoSCP::operator())
+ .def(
+ "__call__",
+ static_cast<
+ void (NCreateSCP::*)(message::Message const &)
+ >(&NCreateSCP::operator())
+ )
;
}
diff --git a/wrappers/NSetRequest.cpp b/wrappers/NSetRequest.cpp
new file mode 100644
index 0000000..4f7f05b
--- /dev/null
+++ b/wrappers/NSetRequest.cpp
@@ -0,0 +1,50 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#include <boost/python.hpp>
+
+#include "odil/message/NSetRequest.h"
+
+void wrap_NSetRequest()
+{
+ using namespace boost::python;
+ using namespace odil;
+ using namespace odil::message;
+
+ class_<NSetRequest, bases<Request>>(
+ "NSetRequest",
+ init<
+ Value::Integer, Value::String const &, Value::String const &,
+ DataSet const &
+ >())
+ .def(init<Message>())
+ .def(
+ "get_requested_sop_class_uid",
+ &NSetRequest::get_requested_sop_class_uid,
+ return_value_policy<copy_const_reference>())
+ .def(
+ "set_requested_sop_class_uid",
+ &NSetRequest::set_requested_sop_class_uid)
+ .def(
+ "get_requested_sop_instance_uid",
+ &NSetRequest::get_requested_sop_instance_uid,
+ return_value_policy<copy_const_reference>())
+ .def(
+ "set_requested_sop_instance_uid",
+ &NSetRequest::set_requested_sop_instance_uid)
+ .def("has_command_field",
+ &NSetRequest::set_command_field)
+ .def(
+ "get_command_field",
+ &NSetRequest::get_command_field,
+ return_value_policy<copy_const_reference>())
+ .def(
+ "set_command_field",
+ &NSetRequest::set_command_field)
+ ;
+}
diff --git a/wrappers/EchoSCP.cpp b/wrappers/NSetSCP.cpp
similarity index 59%
copy from wrappers/EchoSCP.cpp
copy to wrappers/NSetSCP.cpp
index e6ee791..afcdfff 100644
--- a/wrappers/EchoSCP.cpp
+++ b/wrappers/NSetSCP.cpp
@@ -6,33 +6,38 @@
* for details.
************************************************************************/
-#include <boost/python.hpp>
+#include "odil/NSetSCP.h"
-#include "odil/EchoSCP.h"
+#include <boost/python.hpp>
namespace
{
-void
-set_callback(odil::EchoSCP & scp, boost::python::object const & f)
+void
+set_callback( odil::NSetSCP& scp, boost::python::object const& f)
{
scp.set_callback(
- [f](odil::message::CEchoRequest const & message)
- {
+ [f](odil::message::NSetRequest const& message)
+ {
return boost::python::call<odil::Value::Integer>(f.ptr(), message);
}
- );
+ );
}
-
}
-void wrap_EchoSCP()
+void wrap_NSetSCP()
{
using namespace boost::python;
using namespace odil;
- class_<EchoSCP>("EchoSCP", init<Association &>())
+ class_<NSetSCP >("NSetSCP", init<Association&>() )
+ .def (init<Association&, NSetSCP::Callback&>())
.def("set_callback", &set_callback)
- .def("__call__", &EchoSCP::operator())
+ .def(
+ "__call__",
+ static_cast<
+ void (NSetSCP::*)(message::Message const &)
+ >(&NSetSCP::operator())
+ )
;
}
diff --git a/wrappers/StoreSCU.cpp b/wrappers/NSetSCU.cpp
similarity index 63%
copy from wrappers/StoreSCU.cpp
copy to wrappers/NSetSCU.cpp
index 1481201..9d8678f 100644
--- a/wrappers/StoreSCU.cpp
+++ b/wrappers/NSetSCU.cpp
@@ -8,29 +8,27 @@
#include <boost/python.hpp>
-#include "odil/StoreSCU.h"
+#include "odil/NSetSCU.h"
-BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(storeMethod, odil::StoreSCU::store, 1, 3)
-void wrap_StoreSCU()
+void wrap_NSetSCU()
{
using namespace boost::python;
using namespace odil;
- class_<StoreSCU>("StoreSCU", init<Association &>())
+ class_<NSetSCU>("NSetSCU", init<Association &>())
.def(
"get_affected_sop_class",
- &StoreSCU::get_affected_sop_class,
+ &NSetSCU::get_affected_sop_class,
return_value_policy<copy_const_reference>()
)
.def(
"set_affected_sop_class",
- static_cast<void(StoreSCU::*)(DataSet const &)>(&StoreSCU::set_affected_sop_class)
+ static_cast<void(NSetSCU::*)(DataSet const &)>(&NSetSCU::set_affected_sop_class)
)
.def(
- "store",
- &StoreSCU::store,
- storeMethod()
+ "set",
+ &NSetSCU::set
)
;
}
diff --git a/wrappers/Response.cpp b/wrappers/Response.cpp
index 492c57e..7099c03 100644
--- a/wrappers/Response.cpp
+++ b/wrappers/Response.cpp
@@ -41,3 +41,37 @@ void wrap_Response()
static_cast<bool (Response::*)() const>(&Response::is_failure))
;
}
+
+void wrap_ResponseStatus()
+{
+ using namespace boost::python;
+ using namespace odil;
+ using namespace odil::message;
+
+ enum_< Response::Status >("response_status")
+ .value("Success", Response::Status::Success )
+ .value("Cancel", Response::Status::Cancel )
+ .value("Pending", Response::Status::Pending )
+ .value("AttributeListError", Response::Status::AttributeListError )
+ .value("AttributeValueOutOfRange", Response::Status::AttributeValueOutOfRange )
+ .value("SOPClassNotSupported", Response::Status::SOPClassNotSupported )
+ .value("ClassInstanceConflict", Response::Status::ClassInstanceConflict )
+ .value("DuplicateSOPInstance", Response::Status::DuplicateSOPInstance )
+ .value("DuplicateInvocation", Response::Status::DuplicateInvocation )
+ .value("InvalidArgumentValue", Response::Status::InvalidArgumentValue )
+ .value("InvalidAttributeValue", Response::Status::InvalidAttributeValue )
+ .value("InvalidObjectInstance", Response::Status::InvalidObjectInstance )
+ .value("MissingAttribute", Response::Status::MissingAttribute )
+ .value("MissingAttributeValue", Response::Status::MissingAttributeValue )
+ .value("MistypedArgument", Response::Status::MistypedArgument )
+ .value("NoSuchArgument", Response::Status::NoSuchArgument )
+ .value("NoSuchAttribute", Response::Status::NoSuchAttribute )
+ .value("NoSuchEventType", Response::Status::NoSuchEventType )
+ .value("NoSuchSOPInstance", Response::Status::NoSuchSOPInstance )
+ .value("NoSuchSOPClass", Response::Status::NoSuchSOPClass )
+ .value("ProcessingFailure", Response::Status::ProcessingFailure )
+ .value("ResourceLimitation", Response::Status::ResourceLimitation )
+ .value("UnrecognizedOperation", Response::Status::UnrecognizedOperation )
+ .value("NoSuchActionType", Response::Status::NoSuchActionType)
+ ;
+}
diff --git a/wrappers/EchoSCP.cpp b/wrappers/SCP.cpp
similarity index 73%
copy from wrappers/EchoSCP.cpp
copy to wrappers/SCP.cpp
index e6ee791..116e50e 100644
--- a/wrappers/EchoSCP.cpp
+++ b/wrappers/SCP.cpp
@@ -8,13 +8,13 @@
#include <boost/python.hpp>
-#include "odil/EchoSCP.h"
-
+#include "odil/SCP.h"
+/*
namespace
{
void
-set_callback(odil::EchoSCP & scp, boost::python::object const & f)
+set_callback(odil::SCP & scp, boost::python::object const & f)
{
scp.set_callback(
[f](odil::message::CEchoRequest const & message)
@@ -25,14 +25,15 @@ set_callback(odil::EchoSCP & scp, boost::python::object const & f)
}
}
+*/
-void wrap_EchoSCP()
+void wrap_SCP()
{
using namespace boost::python;
using namespace odil;
- class_<EchoSCP>("EchoSCP", init<Association &>())
- .def("set_callback", &set_callback)
- .def("__call__", &EchoSCP::operator())
+ class_<SCP, bases<>, boost::shared_ptr<SCP>, boost::noncopyable>("SCP", no_init)
+ .def("receive_and_process", &SCP::receive_and_process)
;
+
}
diff --git a/wrappers/SCPDispatcher.cpp b/wrappers/SCPDispatcher.cpp
new file mode 100644
index 0000000..b4276fb
--- /dev/null
+++ b/wrappers/SCPDispatcher.cpp
@@ -0,0 +1,47 @@
+/*************************************************************************
+ * odil - Copyright (C) Universite de Strasbourg
+ * Distributed under the terms of the CeCILL-B license, as published by
+ * the CEA-CNRS-INRIA. Refer to the LICENSE file or to
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
+ * for details.
+ ************************************************************************/
+
+#include "odil/EchoSCP.h"
+#include "odil/NSetSCP.h"
+#include "odil/SCP.h"
+#include "odil/SCPDispatcher.h"
+#include "odil/StoreSCP.h"
+
+#include <boost/python.hpp>
+
+namespace
+{
+
+void dispatch_in_python( odil::SCPDispatcher& dispatcher)
+{
+ dispatcher.dispatch();
+}
+
+template<typename TSCP, odil::message::Message::Command::Type Command>
+void set_scp(odil::SCPDispatcher & dispatcher, TSCP scp)
+{
+ dispatcher.set_scp(Command, std::make_shared<TSCP>( scp ));
+}
+
+}
+
+void wrap_SCPDispatcher()
+{
+ using namespace boost::python;
+ using namespace odil;
+
+ class_<SCPDispatcher >("SCPDispatcher", init<Association&>())
+ .def("set_scp", &SCPDispatcher::set_scp )
+ .def("dispatch", &dispatch_in_python )
+ .def("set_echo_scp", &set_scp<EchoSCP, message::Message::Command::Type::C_ECHO_RQ>)
+ .def("set_store_scp", &set_scp<StoreSCP, message::Message::Command::Type::C_STORE_RQ>)
+ .def("set_nset_scp", &set_scp<NSetSCP, message::Message::Command::Type::N_SET_RQ>)
+ ;
+}
+
+
diff --git a/wrappers/StoreSCP.cpp b/wrappers/StoreSCP.cpp
index 3e6d0af..49ed7ed 100644
--- a/wrappers/StoreSCP.cpp
+++ b/wrappers/StoreSCP.cpp
@@ -6,22 +6,24 @@
* for details.
************************************************************************/
+#include "odil/StoreSCP.h"
+
#include <boost/python.hpp>
-#include "odil/StoreSCP.h"
+#include <functional>
namespace
{
-
-void
-set_callback(odil::StoreSCP & scp, boost::python::object const & f)
+using namespace std;
+void
+set_callback(odil::StoreSCP& scp, boost::python::object const& f)
{
scp.set_callback(
- [f](odil::message::CStoreRequest const & message)
- {
+ [f](odil::message::CStoreRequest const& message)
+ {
return boost::python::call<odil::Value::Integer>(f.ptr(), message);
}
- );
+ );
}
}
@@ -29,10 +31,19 @@ set_callback(odil::StoreSCP & scp, boost::python::object const & f)
void wrap_StoreSCP()
{
using namespace boost::python;
+ using namespace std;
using namespace odil;
- class_<StoreSCP>("StoreSCP", init<Association &>())
- .def("set_callback", &set_callback)
- .def("__call__", &StoreSCP::operator())
+// class_<StoreSCP, bases<SCP>>("StoreSCP", init<Association &>())
+ class_<StoreSCP>("StoreSCP", init<Association&>())
+ .def(init<Association&, StoreSCP::Callback& >())
+ .def("set_callback", &set_callback)
+ .def(
+ "__call__",
+ static_cast<
+ void (StoreSCP::*)(message::Message const &)
+ >(&StoreSCP::operator())
+ )
;
+
}
diff --git a/wrappers/StoreSCU.cpp b/wrappers/StoreSCU.cpp
index 1481201..ca7704f 100644
--- a/wrappers/StoreSCU.cpp
+++ b/wrappers/StoreSCU.cpp
@@ -10,13 +10,18 @@
#include "odil/StoreSCU.h"
-BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(storeMethod, odil::StoreSCU::store, 1, 3)
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(
+ store_overloads, odil::StoreSCU::store, 1, 3)
void wrap_StoreSCU()
{
using namespace boost::python;
using namespace odil;
+ typedef
+ void (StoreSCU::*StoreFunction)(
+ DataSet const &, Value::String const &, Value::Integer) const;
+
class_<StoreSCU>("StoreSCU", init<Association &>())
.def(
"get_affected_sop_class",
@@ -28,9 +33,8 @@ void wrap_StoreSCU()
static_cast<void(StoreSCU::*)(DataSet const &)>(&StoreSCU::set_affected_sop_class)
)
.def(
- "store",
- &StoreSCU::store,
- storeMethod()
- )
+ "store",
+ static_cast<StoreFunction>(&odil::StoreSCU::store),
+ store_overloads())
;
}
diff --git a/wrappers/Tag.cpp b/wrappers/Tag.cpp
index e201419..26bf353 100644
--- a/wrappers/Tag.cpp
+++ b/wrappers/Tag.cpp
@@ -10,6 +10,11 @@
#include "odil/Tag.h"
+uint32_t hash(odil::Tag const & tag)
+{
+ return ((tag.group<<16)+tag.element);
+}
+
void wrap_Tag()
{
using namespace boost::python;
@@ -29,6 +34,7 @@ void wrap_Tag()
.def(self <= self)
.def(self >= self)
.def("__str__", &Tag::operator std::string)
+ .def("__hash__", &hash)
;
implicitly_convertible<std::string, Tag>();
}
diff --git a/wrappers/VR.cpp b/wrappers/VR.cpp
index 1dcc4a6..ba57161 100644
--- a/wrappers/VR.cpp
+++ b/wrappers/VR.cpp
@@ -8,8 +8,72 @@
#include <boost/python.hpp>
+#include "odil/Exception.h"
#include "odil/VR.h"
+#if PY_MAJOR_VERSION >= 3
+ #define AsString(x) PyBytes_AsString(x)
+#else
+ #define IS_PY2
+ #define AsString(x) PyString_AsString(x)
+#endif
+
+odil::VR as_vr(PyObject * object)
+{
+ PyObject * utf8 = nullptr;
+ if(PyUnicode_Check(object))
+ {
+ // New reference
+ utf8 = PyUnicode_AsUTF8String(object);
+ }
+#ifdef IS_PY2
+ else if(PyString_Check(object))
+ {
+ utf8 = object;
+ // Increase reference count to match PyUnicode_AsUTF8String
+ Py_INCREF(utf8);
+ }
+#endif
+
+ if(utf8 == nullptr)
+ {
+ throw odil::Exception("Object is not string-like");
+ }
+
+ std::string const vr_name(AsString(utf8));
+ Py_DECREF(utf8);
+
+ return odil::as_vr(vr_name);
+}
+
+void * convertible(PyObject* object)
+{
+ bool result=true;
+ try
+ {
+ as_vr(object);
+ }
+ catch(...)
+ {
+ result = false;
+ }
+
+ return result?object:nullptr;
+}
+
+void construct(
+ PyObject* object,
+ boost::python::converter::rvalue_from_python_stage1_data* data)
+{
+ auto const vr = as_vr(object);
+
+ void * storage = reinterpret_cast<
+ boost::python::converter::rvalue_from_python_storage<odil::VR>*
+ >(data)->storage.bytes;
+ new (storage) odil::VR(vr);
+ data->convertible = storage;
+}
+
void wrap_VR()
{
using namespace boost::python;
@@ -48,5 +112,11 @@ void wrap_VR()
.value("UT", VR::UT)
.value("INVALID", VR::INVALID)
;
+ converter::registry::push_back(
+ &convertible, &construct, type_id<VR>());
+ def("is_int", odil::is_int);
+ def("is_real", odil::is_real);
+ def("is_string", odil::is_string);
+ def("is_binary", odil::is_binary);
}
diff --git a/wrappers/Value.cpp b/wrappers/Value.cpp
index 829b13e..e9ab1ba 100644
--- a/wrappers/Value.cpp
+++ b/wrappers/Value.cpp
@@ -62,10 +62,11 @@ void wrap_Value()
typedef Value::Binary & (Value::*AsBinary)();
// Define scope to enclose Integers, Reals, etc. in Value
- scope value_scope = class_<Value>("Value", init<>())
+ scope value_scope = class_<Value>("Value", no_init)
.def("__init__", make_constructor(value_constructor))
.add_property("type", &Value::get_type)
.def("empty", &Value::empty)
+ .def("size", &Value::size)
.def(
"as_integers", AsIntegers(&Value::as_integers),
return_value_policy<reference_existing_object>())
@@ -83,10 +84,11 @@ void wrap_Value()
return_value_policy<reference_existing_object>())
.def(self == self)
.def(self != self)
+ .def("clear", &Value::clear)
+ .def("__len__", &Value::size)
;
enum_<Value::Type>("Type")
- .value("Empty", Value::Type::Empty)
.value("Integers", Value::Type::Integers)
.value("Reals", Value::Type::Reals)
.value("Strings", Value::Type::Strings)
diff --git a/wrappers/odil.cpp b/wrappers/odil.cpp
index b2890e6..86dbdf2 100644
--- a/wrappers/odil.cpp
+++ b/wrappers/odil.cpp
@@ -1,4 +1,4 @@
-/*************************************************************************
+ /*************************************************************************
* odil - Copyright (C) Universite de Strasbourg
* Distributed under the terms of the CeCILL-B license, as published by
* the CEA-CNRS-INRIA. Refer to the LICENSE file or to
@@ -24,7 +24,12 @@ void wrap_GetSCU();
void wrap_json_converter();
void wrap_MoveSCP();
void wrap_MoveSCU();
+void wrap_NCreateSCP();
+void wrap_NSetSCP();
+void wrap_NSetSCU();
void wrap_read();
+//__attribute__((__visibility__("default")))
+void wrap_SCPDispatcher();
void wrap_StoreSCU();
void wrap_StoreSCP();
void wrap_Tag();
@@ -39,6 +44,8 @@ void wrap_xml_converter();
void wrap_registry();
void wrap_Message();
+void wrap_CommandTypeEnum();
+void wrap_ResponseStatus();
void wrap_Request();
void wrap_Response();
void wrap_CEchoRequest();
@@ -48,6 +55,8 @@ void wrap_CGetResponse();
void wrap_CMoveRequest();
void wrap_CMoveResponse();
void wrap_CStoreRequest();
+void wrap_CStoreResponse();
+void wrap_NSetRequest();
BOOST_PYTHON_MODULE(odil)
{
@@ -68,7 +77,11 @@ BOOST_PYTHON_MODULE(odil)
wrap_json_converter();
wrap_MoveSCP();
wrap_MoveSCU();
+ wrap_NCreateSCP();
+ wrap_NSetSCP();
+ wrap_NSetSCU();
wrap_read();
+ wrap_SCPDispatcher();
wrap_StoreSCP();
wrap_StoreSCU();
wrap_Tag();
@@ -83,6 +96,8 @@ BOOST_PYTHON_MODULE(odil)
wrap_registry();
wrap_Message();
+ wrap_CommandTypeEnum();
+ wrap_ResponseStatus();
wrap_Request();
wrap_Response();
wrap_CEchoRequest();
@@ -92,4 +107,6 @@ BOOST_PYTHON_MODULE(odil)
wrap_CMoveRequest();
wrap_CMoveResponse();
wrap_CStoreRequest();
+ wrap_CStoreResponse();
+ wrap_NSetRequest();
}
diff --git a/wrappers/value_constructor.cpp b/wrappers/value_constructor.cpp
index 0206074..77fcbaf 100644
--- a/wrappers/value_constructor.cpp
+++ b/wrappers/value_constructor.cpp
@@ -14,20 +14,51 @@
#include "odil/DataSet.h"
#include "odil/Value.h"
+#if PY_MAJOR_VERSION >= 3
+#define IS_PY3K
+#endif
+
boost::shared_ptr<odil::Value>
value_constructor(boost::python::object const & source)
{
odil::Value * result = nullptr;
if(boost::python::len(source) == 0)
{
- result = new odil::Value();
+ if(boost::python::extract<odil::Value::Integers>(source).check())
+ {
+ result = new odil::Value(odil::Value::Integers());
+ }
+ else if(boost::python::extract<odil::Value::Reals>(source).check())
+ {
+ result = new odil::Value(odil::Value::Reals());
+ }
+ else if(boost::python::extract<odil::Value::Strings>(source).check())
+ {
+ result = new odil::Value(odil::Value::Strings());
+ }
+ else if(boost::python::extract<odil::Value::DataSets>(source).check())
+ {
+ result = new odil::Value(odil::Value::DataSets());
+ }
+ else if(boost::python::extract<odil::Value::Binary>(source).check())
+ {
+ result = new odil::Value(odil::Value::Binary());
+ }
+ else
+ {
+ throw odil::Exception("Unknown empty type");
+ }
}
else
{
boost::python::object first = source[0];
PyObject * first_ptr = first.ptr();
+#ifdef IS_PY3K
+ if(PyLong_Check(first_ptr))
+#else
if(PyInt_Check(first_ptr))
+#endif
{
boost::python::stl_input_iterator<odil::Value::Integer>
begin(source), end;
@@ -39,7 +70,11 @@ value_constructor(boost::python::object const & source)
begin(source), end;
result = new odil::Value(odil::Value::Reals(begin, end));
}
+#ifdef IS_PY3K
+ else if(PyUnicode_Check(first_ptr))
+#else
else if(PyString_Check(first_ptr))
+#endif
{
boost::python::stl_input_iterator<odil::Value::String>
begin(source), end;
@@ -72,6 +107,10 @@ value_constructor(boost::python::object const & source)
begin(source), end;
result = new odil::Value(odil::Value::DataSets(begin, end));
}
+ else
+ {
+ throw odil::Exception("Unknown value type");
+ }
}
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/odil.git
More information about the debian-med-commit
mailing list