[med-svn] [dcmtkpp] 01/01: Imported Upstream version 0.2.1

Julien Lamy lamy-guest at moszumanska.debian.org
Thu Jul 16 12:24:31 UTC 2015


This is an automated email from the git hooks/post-receive script.

lamy-guest pushed a commit to branch master
in repository dcmtkpp.

commit f5076a144f10de74fe163338f832cab82276b5f1
Author: Julien Lamy <lamy at picardie.u-strasbg.fr>
Date:   Thu Jul 16 14:16:22 2015 +0200

    Imported Upstream version 0.2.1
---
 .travis.yml                     |   21 +
 CMakeLists.txt                  |   17 +
 Doxyfile                        | 1813 ++++++++++++++++++
 FindICU.cmake                   |    7 +
 LICENSE.txt                     |  515 ++++++
 README.md                       |    8 +
 examples/CMakeLists.txt         |   10 +
 examples/find.cpp               |   76 +
 examples/get.cpp                |   85 +
 examples/move.cpp               |   87 +
 examples/store.cpp              |   60 +
 generate_registry               |   95 +
 src/CMakeLists.txt              |   21 +
 src/dcmtkpp/Association.cpp     |  535 ++++++
 src/dcmtkpp/Association.h       |  184 ++
 src/dcmtkpp/CEchoRequest.cpp    |   47 +
 src/dcmtkpp/CEchoRequest.h      |   47 +
 src/dcmtkpp/CEchoResponse.cpp   |   49 +
 src/dcmtkpp/CEchoResponse.h     |   47 +
 src/dcmtkpp/CFindRequest.cpp    |   65 +
 src/dcmtkpp/CFindRequest.h      |   48 +
 src/dcmtkpp/CFindResponse.cpp   |   66 +
 src/dcmtkpp/CFindResponse.h     |   55 +
 src/dcmtkpp/CGetRequest.cpp     |   66 +
 src/dcmtkpp/CGetRequest.h       |   49 +
 src/dcmtkpp/CGetResponse.cpp    |   79 +
 src/dcmtkpp/CGetResponse.h      |   64 +
 src/dcmtkpp/CMoveRequest.cpp    |   69 +
 src/dcmtkpp/CMoveRequest.h      |   52 +
 src/dcmtkpp/CMoveResponse.cpp   |   79 +
 src/dcmtkpp/CMoveResponse.h     |   64 +
 src/dcmtkpp/CStoreRequest.cpp   |   75 +
 src/dcmtkpp/CStoreRequest.h     |   61 +
 src/dcmtkpp/CStoreResponse.cpp  |   59 +
 src/dcmtkpp/CStoreResponse.h    |   48 +
 src/dcmtkpp/Cancellation.cpp    |   46 +
 src/dcmtkpp/Cancellation.h      |   42 +
 src/dcmtkpp/DataSet.cpp         |  308 ++++
 src/dcmtkpp/DataSet.h           |  200 ++
 src/dcmtkpp/Element.cpp         |  236 +++
 src/dcmtkpp/Element.h           |  212 +++
 src/dcmtkpp/Element.txx         |   57 +
 src/dcmtkpp/ElementAccessor.cpp |   39 +
 src/dcmtkpp/ElementAccessor.h   |   63 +
 src/dcmtkpp/ElementAccessor.txx |  207 +++
 src/dcmtkpp/ElementTraits.cpp   |   77 +
 src/dcmtkpp/ElementTraits.h     |   47 +
 src/dcmtkpp/Exception.cpp       |   71 +
 src/dcmtkpp/Exception.h         |   66 +
 src/dcmtkpp/FindSCU.cpp         |   87 +
 src/dcmtkpp/FindSCU.h           |   42 +
 src/dcmtkpp/GetSCU.cpp          |  105 ++
 src/dcmtkpp/GetSCU.h            |   49 +
 src/dcmtkpp/Message.cpp         |   94 +
 src/dcmtkpp/Message.h           |  178 ++
 src/dcmtkpp/MoveSCU.cpp         |  162 ++
 src/dcmtkpp/MoveSCU.h           |   60 +
 src/dcmtkpp/Network.cpp         |  201 ++
 src/dcmtkpp/Network.h           |   91 +
 src/dcmtkpp/Request.cpp         |   38 +
 src/dcmtkpp/Request.h           |   43 +
 src/dcmtkpp/Response.cpp        |   43 +
 src/dcmtkpp/Response.h          |   44 +
 src/dcmtkpp/SCP.cpp             |   44 +
 src/dcmtkpp/SCP.h               |   31 +
 src/dcmtkpp/SCU.cpp             |   70 +
 src/dcmtkpp/SCU.h               |   41 +
 src/dcmtkpp/ServiceRole.cpp     |  632 +++++++
 src/dcmtkpp/ServiceRole.h       |  114 ++
 src/dcmtkpp/ServiceRole.txx     |   39 +
 src/dcmtkpp/StoreSCP.cpp        |   94 +
 src/dcmtkpp/StoreSCP.h          |   43 +
 src/dcmtkpp/StoreSCU.cpp        |  209 +++
 src/dcmtkpp/StoreSCU.h          |   36 +
 src/dcmtkpp/Tag.cpp             |  198 ++
 src/dcmtkpp/Tag.h               |   97 +
 src/dcmtkpp/VR.cpp              |  151 ++
 src/dcmtkpp/VR.h                |   59 +
 src/dcmtkpp/VRTraits.h          |   66 +
 src/dcmtkpp/Value.cpp           |  196 ++
 src/dcmtkpp/Value.h             |  193 ++
 src/dcmtkpp/Value.txx           |   54 +
 src/dcmtkpp/conversion.cpp      |  485 +++++
 src/dcmtkpp/conversion.h        |   72 +
 src/dcmtkpp/conversion.txx      |   82 +
 src/dcmtkpp/json_converter.cpp  |  280 +++
 src/dcmtkpp/json_converter.h    |   26 +
 src/dcmtkpp/registry.h          | 3867 +++++++++++++++++++++++++++++++++++++++
 src/dcmtkpp/unicode.cpp         |  332 ++++
 src/dcmtkpp/unicode.h           |   25 +
 tests/CMakeLists.txt            |   41 +
 tests/MessageFixtureBase.h      |   54 +
 tests/PeerFixtureBase.h         |   86 +
 tests/code/Association.cpp      |  251 +++
 tests/code/CEchoRequest.cpp     |   56 +
 tests/code/CEchoResponse.cpp    |   58 +
 tests/code/CFindRequest.cpp     |   83 +
 tests/code/CFindResponse.cpp    |   72 +
 tests/code/CGetRequest.cpp      |   80 +
 tests/code/CGetResponse.cpp     |   94 +
 tests/code/CMoveRequest.cpp     |   81 +
 tests/code/CMoveResponse.cpp    |   93 +
 tests/code/CStoreRequest.cpp    |   88 +
 tests/code/CStoreResponse.cpp   |   68 +
 tests/code/Cancellation.cpp     |   40 +
 tests/code/DataSet.cpp          |  273 +++
 tests/code/Element.cpp          |  160 ++
 tests/code/ElementAccessor.cpp  |  125 ++
 tests/code/Exception.cpp        |   36 +
 tests/code/FindSCU.cpp          |   65 +
 tests/code/GetSCU.cpp           |   69 +
 tests/code/Message.cpp          |   57 +
 tests/code/MoveSCU.cpp          |   82 +
 tests/code/Network.cpp          |  156 ++
 tests/code/Request.cpp          |   27 +
 tests/code/Response.cpp         |   31 +
 tests/code/SCU.cpp              |   41 +
 tests/code/ServiceRole.cpp      |   62 +
 tests/code/StoreSCU.cpp         |   79 +
 tests/code/Tag.cpp              |  187 ++
 tests/code/VR.cpp               |   31 +
 tests/code/Value.cpp            |  250 +++
 tests/code/conversion.cpp       |  424 +++++
 tests/code/json_converter.cpp   |  269 +++
 tests/code/unicode.cpp          |  258 +++
 tests/run.sh                    |   57 +
 126 files changed, 19151 insertions(+)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..b91eb36
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,21 @@
+language: cpp
+compiler:
+  - gcc
+  - clang
+before_install:
+  - sudo apt-get update -qq
+  - sudo apt-get install -y libdcmtk2-dev libwrap0-dev libjsoncpp-dev libicu-dev zlib1g-dev libboost-test-dev dcmtk
+  - sudo pip install cpp-coveralls
+before_script:
+  - export SRC_DIR=$PWD
+  - mkdir build
+  - cd build
+  - export BIN_DIR=$PWD
+  - CMAKE_CXX_FLAGS="-std=c++0x"
+  - if [ "${CC}" = "gcc" ]; then CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} --coverage"; fi
+  - cmake -D CMAKE_CXX_FLAGS:STRING="${CMAKE_CXX_FLAGS}" -D CMAKE_BUILD_TYPE:STRING=Debug ../
+script:
+  - make -j $(nproc)
+  - ../tests/run.sh
+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} | grep -vP "^File '.*'$" | grep -vP ":creating '.*'$" | grep -vP "^Lines executed:.*" | sed '/^$/d'; fi
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..844a5fc
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 2.8)
+project("dcmtkpp")
+
+option(BUILD_EXAMPLES "Build the examples directory." ON)
+
+set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}" ${CMAKE_MODULE_PATH})
+include(CTest)
+
+add_subdirectory("src")
+
+if(BUILD_EXAMPLES)
+    add_subdirectory("examples")
+endif()
+
+if(BUILD_TESTING)
+    add_subdirectory("tests")
+endif()
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..885d4f2
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,1813 @@
+# Doxyfile 1.7.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file 
+# that follow. The default is UTF-8 which is also the encoding used for all 
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
+# iconv built into libc) for the transcoding. See 
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should 
+# identify the project. Note that if you do not use Doxywizard you need 
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME           = "dcmtkpp"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description 
+# for a project that appears at the top of each page and should give viewer 
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = 
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is 
+# included in the documentation. The maximum height of the logo should not 
+# exceed 55 pixels and the maximum width should not exceed 200 pixels. 
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ./doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, 
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English 
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, 
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, 
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful if your file system 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only). 
+# A mapping has the form "name=value". For example adding 
+# "class=itcl::class" will allow you to use the command class in the 
+# itcl::class meaning.
+
+TCL_SUBST              = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Java. For instance, namespaces will be presented as packages, qualified 
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
+# sources. Doxygen will then generate output that is tailored for 
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it 
+# parses. With this tag you can assign which parser to use for a given extension. 
+# Doxygen has a built-in mapping, but you can override or extend it using this 
+# tag. The format is ext=language, where ext is a file extension, and language 
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, 
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make 
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C 
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions 
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      = 
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
+# to include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also makes the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to 
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter 
+# and setter methods for a property. Setting this option to YES (the default) 
+# will make doxygen replace the get and set methods by a property in the 
+# documentation. This will only work if the methods are indeed getting or 
+# setting a simple type. If this is not the case, or you want to show the 
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and 
+# unions are shown inside the group in which they are included (e.g. using 
+# @ingroup) instead of on a separate page (for HTML and Man pages) or 
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and 
+# unions with only public data fields will be shown inline in the documentation 
+# of the scope in which they are defined (i.e. file, namespace, or group 
+# documentation), provided this scope is documented. If set to NO (the default), 
+# structs, classes, and unions are shown on a separate page (for HTML and Man 
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
+# is documented as struct, union, or enum with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code in case the coding convention dictates that all compound 
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 
+# determine which symbols to keep in memory and which to flush to disk. 
+# When the cache is full, less often used symbols will be written to disk. 
+# For small to medium size projects (<1000 input files) the default value is 
+# probably good enough. For larger projects a too small cache size can cause 
+# doxygen to be busy swapping symbols to and from disk most of the time 
+# causing a significant performance penalty. 
+# If the system has enough physical memory increasing the cache will improve the 
+# performance by keeping more symbols in memory. Note that the value works on 
+# a logarithmic scale so increasing the size by one will roughly double the 
+# memory usage. The cache size is given by this formula: 
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+SYMBOL_CACHE_SIZE      = 0
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be 
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given 
+# their name and scope. Since this can be an expensive process and often the 
+# same symbol appear multiple times in the code, doxygen keeps a cache of 
+# pre-resolved symbols. If the cache is too small doxygen will become slower. 
+# If the cache is too large, memory is wasted. The cache size is given by this 
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be 
+# extracted and appear in the documentation as a namespace called 
+# 'anonymous_namespace{file}', where file will be replaced with the base 
+# name of the file that contains the anonymous namespace. By default 
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen 
+# will list include files with double quotes in the documentation 
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen 
+# will sort the (brief and detailed) documentation of class members so that 
+# constructors and destructors are listed first. If set to NO (the default) 
+# the constructors will appear in the respective orders defined by 
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. 
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO 
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
+# hierarchy of group names into alphabetical order. If set to NO (the default) 
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to 
+# do proper type resolution of all parameters of a function it will reject a 
+# match between the prototype and the implementation of a member function even 
+# if there is only one candidate or it is obvious which candidate to choose 
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen 
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or macro consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and macros in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. 
+# This will remove the Files entry from the Quick Index and from the 
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
+# Namespaces page.  This will remove the Namespaces entry from the Quick Index 
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from 
+# the version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed 
+# by doxygen. The layout file controls the global structure of the generated 
+# output files in an output format independent way. The create the layout file 
+# that represents doxygen's defaults, run doxygen with the -l option. 
+# You can optionally specify a file name after the option, if omitted 
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            = 
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files 
+# containing the references data. This must be a list of .bib files. The 
+# .bib extension is automatically appended if omitted. Using this command 
+# requires the bibtex tool to be installed. See also 
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style 
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this 
+# feature you need bibtex and perl available in the search path.
+
+CITE_BIB_FILES         = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = ./src/dcmtkpp
+
+# This tag can be used to specify the character encoding of the source files 
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
+# also the default input encoding. Doxygen uses libiconv (or the iconv built 
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh 
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py 
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.d \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.idl \
+                         *.odl \
+                         *.cs \
+                         *.php \
+                         *.php3 \
+                         *.inc \
+                         *.m \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.f90 \
+                         *.f \
+                         *.for \
+                         *.vhd \
+                         *.vhdl
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag. 
+# Note that relative paths are relative to the directory from which doxygen is 
+# run.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or 
+# directories that are symbolic links (a Unix file system feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the 
+# output. The symbol name can be a fully qualified name, a word, or if the 
+# wildcard * is used, a substring. Examples: ANamespace, AClass, 
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty or if 
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file 
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) 
+# and it is also possible to disable source filtering for a specific pattern 
+# using *.ext= (so without naming a filter). This option only has effect when 
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS = 
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 
+# link to the source code.  Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header. Note that when using a custom header you are responsible  
+# for the proper inclusion of any scripts and style sheets that doxygen 
+# needs, which is dependent on the configuration options used. 
+# It is advised to generate a default header using "doxygen -w html 
+# header.html footer.html stylesheet.css YourConfigFile" and then modify 
+# that header. Note that the header is subject to change so you typically 
+# have to redo this when upgrading to a newer version of doxygen or when 
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# style sheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or 
+# other source files which should be copied to the HTML output directory. Note 
+# that these files will be copied to the base HTML output directory. Use the 
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these 
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that 
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       = 
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. 
+# Doxygen will adjust the colors in the style sheet and background images 
+# according to this color. Hue is specified as an angle on a colorwheel, 
+# see http://en.wikipedia.org/wiki/Hue for more information. 
+# For instance the value 0 represents red, 60 is yellow, 120 is green, 
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 
+# the colors in the HTML output. For a value of 0 the output will use 
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 
+# the luminance component of the colors in the HTML output. Values below 
+# 100 gradually make the output lighter, whereas values above 100 make 
+# the output darker. The value divided by 100 is the actual gamma applied, 
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 
+# page will contain the date and time when the page was generated. Setting 
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files 
+# will be generated that can be used as input for Apple's Xcode 3 
+# integrated development environment, introduced with OSX 10.5 (Leopard). 
+# To create a documentation set, doxygen will generate a Makefile in the 
+# HTML output directory. Running make will produce the docset in that 
+# directory and running "make install" will install the docset in 
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
+# it at startup. 
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
+# feed. A documentation feed provides an umbrella under which multiple 
+# documentation sets from a single provider (such as a company or product suite) 
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
+# should uniquely identify the documentation set bundle. This should be a 
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify 
+# the documentation publisher. This should be a reverse domain-name style 
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file 
+# content.
+
+CHM_INDEX_ENCODING     = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and 
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated 
+# that can be used as input for Qt's qhelpgenerator to generate a 
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can 
+# be used to specify the file name of the resulting .qch file. 
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               = 
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to 
+# add. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   = 
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the 
+# custom filter to add. For more information please see 
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> 
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  = 
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this 
+# project's 
+# filter section matches. 
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> 
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  = 
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 
+# be used to specify the location of Qt's qhelpgenerator. 
+# If non-empty doxygen will try to run qhelpgenerator on the generated 
+# .qhp file.
+
+QHG_LOCATION           = 
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files  
+# will be generated, which together with the HTML files, form an Eclipse help 
+# plugin. To install this plugin and make it available under the help contents 
+# menu in Eclipse, the contents of the directory containing the HTML and XML 
+# files needs to be copied into the plugins directory of eclipse. The name of 
+# the directory within the plugins directory should be the same as 
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before 
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin 
+# the directory name containing the HTML and XML files should also have 
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) 
+# at top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it. Since the tabs have the same information as the 
+# navigation tree you can set this option to NO if you already set 
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 
+# structure should be generated to display hierarchical information. 
+# If the tag value is set to YES, a side panel will be generated 
+# containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). 
+# Windows users are probably better off using the HTML help feature. 
+# Since the tree basically has the same information as the tab index you 
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values 
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML 
+# documentation. Note that a value of 0 will completely suppress the enum 
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, 
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open 
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included 
+# as images in the HTML documentation. The default is 10. Note that 
+# when you change the font size after a successful doxygen run you need 
+# to manually remove any form_*.png images from the HTML output directory 
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images 
+# generated for formulas are transparent PNGs. Transparent PNGs are 
+# not supported properly for IE 6.0, but are supported on all modern browsers. 
+# Note that when changing this option you need to delete any form_*.png files 
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax 
+# (see http://www.mathjax.org) which uses client side Javascript for the 
+# rendering instead of using prerendered bitmaps. Use this if you do not 
+# have LaTeX installed or if you want to formulas look prettier in the HTML 
+# output. When enabled you also need to install MathJax separately and 
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you need to specify the location relative to the 
+# HTML output directory using the MATHJAX_RELPATH option. The destination 
+# directory should contain the MathJax.js script. For instance, if the mathjax 
+# directory is located at the same level as the HTML output directory, then 
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the 
+# mathjax.org site, so you can quickly see the result without installing 
+# MathJax, but it is strongly recommended to install a local copy of MathJax 
+# before deployment.
+
+MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension 
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS     = 
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box 
+# for the HTML output. The underlying search engine uses javascript 
+# and DHTML and should work on any modern browser. Note that when using 
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets 
+# (GENERATE_DOCSET) there is already a search function so this one should 
+# typically be disabled. For large projects the javascript based search engine 
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be 
+# implemented using a PHP enabled web server instead of at the web client 
+# using Javascript. Doxygen will generate the search PHP script and index 
+# file to put on the web server. The advantage of the server 
+# based approach is that it scales better to large projects and allows 
+# full text search. The disadvantages are that it is more difficult to setup 
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name. 
+# Note that when enabling USE_PDFLATEX this option is only used for 
+# generating bitmaps for formulas in the HTML output, but not in the 
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for 
+# the generated latex document. The footer should contain everything after 
+# the last chapter. If it is left blank doxygen will generate a 
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include 
+# source code with syntax highlighting in the LaTeX output. 
+# Note that which sources are shown also depends on other settings 
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the 
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See 
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition that 
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all references to function-like macros 
+# that are alone on a line, have an all uppercase name, and do not end with a 
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links. 
+# Note that each tag file must have a unique name 
+# (where the name does NOT include the path) 
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option also works with HAVE_DOT disabled, but it is recommended to 
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see 
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
+# the mscgen tool resides. If left empty the tool is assumed to be found in the 
+# default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is 
+# allowed to run in parallel. When set to 0 (the default) doxygen will 
+# base this on the number of processors available in the system. You can set it 
+# explicitly to a value larger than 0 to get control over the balance 
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will use the Helvetica font for all dot files that 
+# doxygen generates. When you want a differently looking font you can specify 
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find 
+# the font, which can be done by putting it in a standard location or by setting 
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the 
+# directory containing the font.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the Helvetica font. 
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to 
+# set the path where dot can find it.
+
+DOT_FONTPATH           = 
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
+# doxygen will generate a call dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable call graphs 
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
+# doxygen will generate a caller dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable caller 
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include 
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are svg, png, jpg, or gif. 
+# If left blank png will be used. If you choose svg you need to set 
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files 
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to 
+# enable generation of interactive SVG images that allow zooming and panning. 
+# Note that this requires a modern browser other than Internet Explorer. 
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you 
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files 
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG        = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that 
+# contain msc files that are included in the documentation (see the 
+# \mscfile command).
+
+MSCFILE_DIRS           = 
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the 
+# number of direct children of the root node in a graph is already larger than 
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, because dot on Windows does not 
+# seem to support this out of the box. Warning: Depending on the platform used, 
+# enabling this option may lead to badly anti-aliased labels on the edges of 
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/FindICU.cmake b/FindICU.cmake
new file mode 100644
index 0000000..57cf7ed
--- /dev/null
+++ b/FindICU.cmake
@@ -0,0 +1,7 @@
+find_path(ICU_INCLUDE_DIR "unicode/ucnv.h")
+# icucore is for OS X
+find_library(ICU_LIBRARIES NAMES icuuc icucore)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(ICU DEFAULT_MSG
+    ICU_INCLUDE_DIR ICU_LIBRARIES)
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..3ad4dea
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,515 @@
+
+CeCILL-B FREE SOFTWARE LICENSE AGREEMENT
+
+
+    Notice
+
+This Agreement is a Free Software license agreement that is the result
+of discussions between its authors in order to ensure compliance with
+the two main principles guiding its drafting:
+
+    * firstly, compliance with the principles governing the distribution
+      of Free Software: access to source code, broad rights granted to
+      users,
+    * secondly, the election of a governing law, French law, with which
+      it is conformant, both as regards the law of torts and
+      intellectual property law, and the protection that it offers to
+      both authors and holders of the economic rights over software.
+
+The authors of the CeCILL-B (for Ce[a] C[nrs] I[nria] L[ogiciel] L[ibre])
+license are: 
+
+Commissariat � l'Energie Atomique - CEA, a public scientific, technical
+and industrial research establishment, having its principal place of
+business at 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris, France.
+
+Centre National de la Recherche Scientifique - CNRS, a public scientific
+and technological establishment, having its principal place of business
+at 3 rue Michel-Ange, 75794 Paris cedex 16, France.
+
+Institut National de Recherche en Informatique et en Automatique -
+INRIA, a public scientific and technological establishment, having its
+principal place of business at Domaine de Voluceau, Rocquencourt, BP
+105, 78153 Le Chesnay cedex, France.
+
+
+    Preamble
+
+This Agreement is an open source software license intended to give users
+significant freedom to modify and redistribute the software licensed
+hereunder.
+
+The exercising of this freedom is conditional upon a strong obligation
+of giving credits for everybody that distributes a software
+incorporating a software ruled by the current license so as all
+contributions to be properly identified and acknowledged.
+
+In consideration of access to the source code and the rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty and the software's author, the holder of the
+economic rights, and the successive licensors only have limited liability.
+
+In this respect, the risks associated with loading, using, modifying
+and/or developing or reproducing the software by the user are brought to
+the user's attention, given its Free Software status, which may make it
+complicated to use, with the result that its use is reserved for
+developers and experienced professionals having in-depth computer
+knowledge. Users are therefore encouraged to load and test the
+suitability of the software as regards their requirements in conditions
+enabling the security of their systems and/or data to be ensured and,
+more generally, to use and operate it in the same conditions of
+security. This Agreement may be freely reproduced and published,
+provided it is not altered, and that no provisions are either added or
+removed herefrom.
+
+This Agreement may apply to any or all software for which the holder of
+the economic rights decides to submit the use thereof to its provisions.
+
+
+    Article 1 - DEFINITIONS
+
+For the purpose of this Agreement, when the following expressions
+commence with a capital letter, they shall have the following meaning:
+
+Agreement: means this license agreement, and its possible subsequent
+versions and annexes.
+
+Software: means the software in its Object Code and/or Source Code form
+and, where applicable, its documentation, "as is" when the Licensee
+accepts the Agreement.
+
+Initial Software: means the Software in its Source Code and possibly its
+Object Code form and, where applicable, its documentation, "as is" when
+it is first distributed under the terms and conditions of the Agreement.
+
+Modified Software: means the Software modified by at least one
+Contribution.
+
+Source Code: means all the Software's instructions and program lines to
+which access is required so as to modify the Software.
+
+Object Code: means the binary files originating from the compilation of
+the Source Code.
+
+Holder: means the holder(s) of the economic rights over the Initial
+Software.
+
+Licensee: means the Software user(s) having accepted the Agreement.
+
+Contributor: means a Licensee having made at least one Contribution.
+
+Licensor: means the Holder, or any other individual or legal entity, who
+distributes the Software under the Agreement.
+
+Contribution: means any or all modifications, corrections, translations,
+adaptations and/or new functions integrated into the Software by any or
+all Contributors, as well as any or all Internal Modules.
+
+Module: means a set of sources files including their documentation that
+enables supplementary functions or services in addition to those offered
+by the Software.
+
+External Module: means any or all Modules, not derived from the
+Software, so that this Module and the Software run in separate address
+spaces, with one calling the other when they are run.
+
+Internal Module: means any or all Module, connected to the Software so
+that they both execute in the same address space.
+
+Parties: mean both the Licensee and the Licensor.
+
+These expressions may be used both in singular and plural form.
+
+
+    Article 2 - PURPOSE
+
+The purpose of the Agreement is the grant by the Licensor to the
+Licensee of a non-exclusive, transferable and worldwide license for the
+Software as set forth in Article 5 hereinafter for the whole term of the
+protection granted by the rights over said Software.
+
+
+    Article 3 - ACCEPTANCE
+
+3.1 The Licensee shall be deemed as having accepted the terms and
+conditions of this Agreement upon the occurrence of the first of the
+following events:
+
+    * (i) loading the Software by any or all means, notably, by
+      downloading from a remote server, or by loading from a physical
+      medium;
+    * (ii) the first time the Licensee exercises any of the rights
+      granted hereunder.
+
+3.2 One copy of the Agreement, containing a notice relating to the
+characteristics of the Software, to the limited warranty, and to the
+fact that its use is restricted to experienced users has been provided
+to the Licensee prior to its acceptance as set forth in Article 3.1
+hereinabove, and the Licensee hereby acknowledges that it has read and
+understood it.
+
+
+    Article 4 - EFFECTIVE DATE AND TERM
+
+
+      4.1 EFFECTIVE DATE
+
+The Agreement shall become effective on the date when it is accepted by
+the Licensee as set forth in Article 3.1.
+
+
+      4.2 TERM
+
+The Agreement shall remain in force for the entire legal term of
+protection of the economic rights over the Software.
+
+
+    Article 5 - SCOPE OF RIGHTS GRANTED
+
+The Licensor hereby grants to the Licensee, who accepts, the following
+rights over the Software for any or all use, and for the term of the
+Agreement, on the basis of the terms and conditions set forth hereinafter.
+
+Besides, if the Licensor owns or comes to own one or more patents
+protecting all or part of the functions of the Software or of its
+components, the Licensor undertakes not to enforce the rights granted by
+these patents against successive Licensees using, exploiting or
+modifying the Software. If these patents are transferred, the Licensor
+undertakes to have the transferees subscribe to the obligations set
+forth in this paragraph.
+
+
+      5.1 RIGHT OF USE
+
+The Licensee is authorized to use the Software, without any limitation
+as to its fields of application, with it being hereinafter specified
+that this comprises:
+
+   1. permanent or temporary reproduction of all or part of the Software
+      by any or all means and in any or all form.
+
+   2. loading, displaying, running, or storing the Software on any or
+      all medium.
+
+   3. entitlement to observe, study or test its operation so as to
+      determine the ideas and principles behind any or all constituent
+      elements of said Software. This shall apply when the Licensee
+      carries out any or all loading, displaying, running, transmission
+      or storage operation as regards the Software, that it is entitled
+      to carry out hereunder.
+
+
+      5.2 ENTITLEMENT TO MAKE CONTRIBUTIONS
+
+The right to make Contributions includes the right to translate, adapt,
+arrange, or make any or all modifications to the Software, and the right
+to reproduce the resulting software.
+
+The Licensee is authorized to make any or all Contributions to the
+Software provided that it includes an explicit notice that it is the
+author of said Contribution and indicates the date of the creation thereof.
+
+
+      5.3 RIGHT OF DISTRIBUTION
+
+In particular, the right of distribution includes the right to publish,
+transmit and communicate the Software to the general public on any or
+all medium, and by any or all means, and the right to market, either in
+consideration of a fee, or free of charge, one or more copies of the
+Software by any means.
+
+The Licensee is further authorized to distribute copies of the modified
+or unmodified Software to third parties according to the terms and
+conditions set forth hereinafter.
+
+
+        5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION
+
+The Licensee is authorized to distribute true copies of the Software in
+Source Code or Object Code form, provided that said distribution
+complies with all the provisions of the Agreement and is accompanied by:
+
+   1. a copy of the Agreement,
+
+   2. a notice relating to the limitation of both the Licensor's
+      warranty and liability as set forth in Articles 8 and 9,
+
+and that, in the event that only the Object Code of the Software is
+redistributed, the Licensee allows effective access to the full Source
+Code of the Software at a minimum during the entire period of its
+distribution of the Software, it being understood that the additional
+cost of acquiring the Source Code shall not exceed the cost of
+transferring the data.
+
+
+        5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE
+
+If the Licensee makes any Contribution to the Software, the resulting
+Modified Software may be distributed under a license agreement other
+than this Agreement subject to compliance with the provisions of Article
+5.3.4.
+
+
+        5.3.3 DISTRIBUTION OF EXTERNAL MODULES
+
+When the Licensee has developed an External Module, the terms and
+conditions of this Agreement do not apply to said External Module, that
+may be distributed under a separate license agreement.
+
+
+        5.3.4 CREDITS
+
+Any Licensee who may distribute a Modified Software hereby expressly
+agrees to:
+
+   1. indicate in the related documentation that it is based on the
+      Software licensed hereunder, and reproduce the intellectual
+      property notice for the Software,
+
+   2. ensure that written indications of the Software intended use,
+      intellectual property notice and license hereunder are included in
+      easily accessible format from the Modified Software interface,
+
+   3. mention, on a freely accessible website describing the Modified
+      Software, at least throughout the distribution term thereof, that
+      it is based on the Software licensed hereunder, and reproduce the
+      Software intellectual property notice,
+
+   4. where it is distributed to a third party that may distribute a
+      Modified Software without having to make its source code
+      available, make its best efforts to ensure that said third party
+      agrees to comply with the obligations set forth in this Article .
+
+If the Software, whether or not modified, is distributed with an
+External Module designed for use in connection with the Software, the
+Licensee shall submit said External Module to the foregoing obligations.
+
+
+        5.3.5 COMPATIBILITY WITH THE CeCILL AND CeCILL-C LICENSES
+
+Where a Modified Software contains a Contribution subject to the CeCILL
+license, the provisions set forth in Article 5.3.4 shall be optional.
+
+A Modified Software may be distributed under the CeCILL-C license. In
+such a case the provisions set forth in Article 5.3.4 shall be optional.
+
+
+    Article 6 - INTELLECTUAL PROPERTY
+
+
+      6.1 OVER THE INITIAL SOFTWARE
+
+The Holder owns the economic rights over the Initial Software. Any or
+all use of the Initial Software is subject to compliance with the terms
+and conditions under which the Holder has elected to distribute its work
+and no one shall be entitled to modify the terms and conditions for the
+distribution of said Initial Software.
+
+The Holder undertakes that the Initial Software will remain ruled at
+least by this Agreement, for the duration set forth in Article 4.2.
+
+
+      6.2 OVER THE CONTRIBUTIONS
+
+The Licensee who develops a Contribution is the owner of the
+intellectual property rights over this Contribution as defined by
+applicable law.
+
+
+      6.3 OVER THE EXTERNAL MODULES
+
+The Licensee who develops an External Module is the owner of the
+intellectual property rights over this External Module as defined by
+applicable law and is free to choose the type of agreement that shall
+govern its distribution.
+
+
+      6.4 JOINT PROVISIONS
+
+The Licensee expressly undertakes:
+
+   1. not to remove, or modify, in any manner, the intellectual property
+      notices attached to the Software;
+
+   2. to reproduce said notices, in an identical manner, in the copies
+      of the Software modified or not.
+
+The Licensee undertakes not to directly or indirectly infringe the
+intellectual property rights of the Holder and/or Contributors on the
+Software and to take, where applicable, vis-�-vis its staff, any and all
+measures required to ensure respect of said intellectual property rights
+of the Holder and/or Contributors.
+
+
+    Article 7 - RELATED SERVICES
+
+7.1 Under no circumstances shall the Agreement oblige the Licensor to
+provide technical assistance or maintenance services for the Software.
+
+However, the Licensor is entitled to offer this type of services. The
+terms and conditions of such technical assistance, and/or such
+maintenance, shall be set forth in a separate instrument. Only the
+Licensor offering said maintenance and/or technical assistance services
+shall incur liability therefor.
+
+7.2 Similarly, any Licensor is entitled to offer to its licensees, under
+its sole responsibility, a warranty, that shall only be binding upon
+itself, for the redistribution of the Software and/or the Modified
+Software, under terms and conditions that it is free to decide. Said
+warranty, and the financial terms and conditions of its application,
+shall be subject of a separate instrument executed between the Licensor
+and the Licensee.
+
+
+    Article 8 - LIABILITY
+
+8.1 Subject to the provisions of Article 8.2, the Licensee shall be
+entitled to claim compensation for any direct loss it may have suffered
+from the Software as a result of a fault on the part of the relevant
+Licensor, subject to providing evidence thereof.
+
+8.2 The Licensor's liability is limited to the commitments made under
+this Agreement and shall not be incurred as a result of in particular:
+(i) loss due the Licensee's total or partial failure to fulfill its
+obligations, (ii) direct or consequential loss that is suffered by the
+Licensee due to the use or performance of the Software, and (iii) more
+generally, any consequential loss. In particular the Parties expressly
+agree that any or all pecuniary or business loss (i.e. loss of data,
+loss of profits, operating loss, loss of customers or orders,
+opportunity cost, any disturbance to business activities) or any or all
+legal proceedings instituted against the Licensee by a third party,
+shall constitute consequential loss and shall not provide entitlement to
+any or all compensation from the Licensor.
+
+
+    Article 9 - WARRANTY
+
+9.1 The Licensee acknowledges that the scientific and technical
+state-of-the-art when the Software was distributed did not enable all
+possible uses to be tested and verified, nor for the presence of
+possible defects to be detected. In this respect, the Licensee's
+attention has been drawn to the risks associated with loading, using,
+modifying and/or developing and reproducing the Software which are
+reserved for experienced users.
+
+The Licensee shall be responsible for verifying, by any or all means,
+the suitability of the product for its requirements, its good working
+order, and for ensuring that it shall not cause damage to either persons
+or properties.
+
+9.2 The Licensor hereby represents, in good faith, that it is entitled
+to grant all the rights over the Software (including in particular the
+rights set forth in Article 5).
+
+9.3 The Licensee acknowledges that the Software is supplied "as is" by
+the Licensor without any other express or tacit warranty, other than
+that provided for in Article 9.2 and, in particular, without any warranty 
+as to its commercial value, its secured, safe, innovative or relevant 
+nature.
+
+Specifically, the Licensor does not warrant that the Software is free
+from any error, that it will operate without interruption, that it will
+be compatible with the Licensee's own equipment and software
+configuration, nor that it will meet the Licensee's requirements.
+
+9.4 The Licensor does not either expressly or tacitly warrant that the
+Software does not infringe any third party intellectual property right
+relating to a patent, software or any other property right. Therefore,
+the Licensor disclaims any and all liability towards the Licensee
+arising out of any or all proceedings for infringement that may be
+instituted in respect of the use, modification and redistribution of the
+Software. Nevertheless, should such proceedings be instituted against
+the Licensee, the Licensor shall provide it with technical and legal
+assistance for its defense. Such technical and legal assistance shall be
+decided on a case-by-case basis between the relevant Licensor and the
+Licensee pursuant to a memorandum of understanding. The Licensor
+disclaims any and all liability as regards the Licensee's use of the
+name of the Software. No warranty is given as regards the existence of
+prior rights over the name of the Software or as regards the existence
+of a trademark.
+
+
+    Article 10 - TERMINATION
+
+10.1 In the event of a breach by the Licensee of its obligations
+hereunder, the Licensor may automatically terminate this Agreement
+thirty (30) days after notice has been sent to the Licensee and has
+remained ineffective.
+
+10.2 A Licensee whose Agreement is terminated shall no longer be
+authorized to use, modify or distribute the Software. However, any
+licenses that it may have granted prior to termination of the Agreement
+shall remain valid subject to their having been granted in compliance
+with the terms and conditions hereof.
+
+
+    Article 11 - MISCELLANEOUS
+
+
+      11.1 EXCUSABLE EVENTS
+
+Neither Party shall be liable for any or all delay, or failure to
+perform the Agreement, that may be attributable to an event of force
+majeure, an act of God or an outside cause, such as defective
+functioning or interruptions of the electricity or telecommunications
+networks, network paralysis following a virus attack, intervention by
+government authorities, natural disasters, water damage, earthquakes,
+fire, explosions, strikes and labor unrest, war, etc.
+
+11.2 Any failure by either Party, on one or more occasions, to invoke
+one or more of the provisions hereof, shall under no circumstances be
+interpreted as being a waiver by the interested Party of its right to
+invoke said provision(s) subsequently.
+
+11.3 The Agreement cancels and replaces any or all previous agreements,
+whether written or oral, between the Parties and having the same
+purpose, and constitutes the entirety of the agreement between said
+Parties concerning said purpose. No supplement or modification to the
+terms and conditions hereof shall be effective as between the Parties
+unless it is made in writing and signed by their duly authorized
+representatives.
+
+11.4 In the event that one or more of the provisions hereof were to
+conflict with a current or future applicable act or legislative text,
+said act or legislative text shall prevail, and the Parties shall make
+the necessary amendments so as to comply with said act or legislative
+text. All other provisions shall remain effective. Similarly, invalidity
+of a provision of the Agreement, for any reason whatsoever, shall not
+cause the Agreement as a whole to be invalid.
+
+
+      11.5 LANGUAGE
+
+The Agreement is drafted in both French and English and both versions
+are deemed authentic.
+
+
+    Article 12 - NEW VERSIONS OF THE AGREEMENT
+
+12.1 Any person is authorized to duplicate and distribute copies of this
+Agreement.
+
+12.2 So as to ensure coherence, the wording of this Agreement is
+protected and may only be modified by the authors of the License, who
+reserve the right to periodically publish updates or new versions of the
+Agreement, each with a separate number. These subsequent versions may
+address new issues encountered by Free Software.
+
+12.3 Any Software distributed under a given version of the Agreement may
+only be subsequently distributed under the same version of the Agreement
+or a subsequent version.
+
+
+    Article 13 - GOVERNING LAW AND JURISDICTION
+
+13.1 The Agreement is governed by French law. The Parties agree to
+endeavor to seek an amicable solution to any disagreements or disputes
+that may arise during the performance of the Agreement.
+
+13.2 Failing an amicable solution within two (2) months as from their
+occurrence, and unless emergency proceedings are necessary, the
+disagreements or disputes shall be referred to the Paris Courts having
+jurisdiction, by the more diligent Party.
+
+
+Version 1.0 dated 2006-09-05.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c4fb856
--- /dev/null
+++ b/README.md
@@ -0,0 +1,8 @@
+DCMTK++
+=======
+
+DCMTK++ is a set of wrappers around [DCMTK](http://dicom.offis.de/dcmtk.php.en)
+to have an easier API, notably for the networking part.
+
+[![Build Status](https://travis-ci.org/lamyj/dcmtkpp.svg?branch=master)](https://travis-ci.org/lamyj/dcmtkpp)
+[![Coverage Status](https://coveralls.io/repos/lamyj/dcmtkpp/badge.svg)](https://coveralls.io/r/lamyj/dcmtkpp)
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 0000000..0764cb3
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_definitions("-D HAVE_CONFIG_H")
+
+include_directories(${CMAKE_SOURCE_DIR}/src)
+
+set(examples find get move store)
+
+foreach(example ${examples})
+    add_executable(${example} ${example}.cpp)
+    target_link_libraries(${example} dcmtkpp dcmdata)
+endforeach()
diff --git a/examples/find.cpp b/examples/find.cpp
new file mode 100644
index 0000000..321b15c
--- /dev/null
+++ b/examples/find.cpp
@@ -0,0 +1,76 @@
+#include <iostream>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dctk.h>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/FindSCU.h"
+#include "dcmtkpp/registry.h"
+
+void print_informations(dcmtkpp::DataSet const & response)
+{
+    std::cout << response.as_string("PatientName", 0) << ": "
+              << response.as_string("StudyDescription", 0)
+              << " on " << response.as_string("StudyDate", 0) << ", "
+              << response.as_int(dcmtkpp::registry::NumberOfStudyRelatedSeries, 0) << " series\n";
+}
+
+int main()
+{
+    dcmtkpp::Network network;
+    network.initialize();
+    
+    dcmtkpp::Association association;
+    
+    association.set_own_ae_title("myself");
+    
+    association.set_peer_host_name("pacs.example.com");
+    association.set_peer_port(11112);
+    association.set_peer_ae_title("pacs");
+    
+    association.add_presentation_context(
+        UID_FINDStudyRootQueryRetrieveInformationModel,
+        { UID_LittleEndianImplicitTransferSyntax });
+    
+    association.add_presentation_context(
+        UID_VerificationSOPClass,
+        { UID_LittleEndianImplicitTransferSyntax });
+    
+    association.associate(network);
+    
+    dcmtkpp::FindSCU scu;
+    scu.set_network(&network);
+    scu.set_association(&association);
+    
+    scu.echo();
+    
+    dcmtkpp::DataSet query;
+    query.add("PatientName", { "DOE^John" });
+    query.add("QueryRetrieveLevel", { "STUDY" });
+    query.add("StudyDescription");
+    query.add(dcmtkpp::registry::NumberOfStudyRelatedSeries);
+    query.add("StudyDate");
+    
+    scu.set_affected_sop_class(UID_FINDStudyRootQueryRetrieveInformationModel);
+    
+    std::cout << "--------\n";
+    std::cout << "Callback\n";
+    std::cout << "--------\n\n";
+    
+    scu.find(query, print_informations);
+    
+    std::cout << "\n";
+        
+    std::cout << "------\n";
+    std::cout << "vector\n";
+    std::cout << "------\n\n";
+    
+    std::vector<dcmtkpp::DataSet> result = scu.find(query);
+    for(auto dataset: result)
+    {
+        print_informations(dataset);
+    }
+    
+    association.release();
+    network.drop();
+}
diff --git a/examples/get.cpp b/examples/get.cpp
new file mode 100644
index 0000000..f50690e
--- /dev/null
+++ b/examples/get.cpp
@@ -0,0 +1,85 @@
+#include <iostream>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dctk.h>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/GetSCU.h"
+#include "dcmtkpp/registry.h"
+
+void print_informations(dcmtkpp::DataSet const & response)
+{
+    std::cout
+        << response.as_string("PatientName", 0)
+        << ": "
+        << response.as_string("StudyDescription", 0)
+        << " / "
+        << response.as_string("SeriesDescription", 0)
+        << ": "
+        << response.as_string("InstanceNumber", 0)
+        << "\n";
+}
+
+int main()
+{
+    dcmtkpp::Network network;
+    network.initialize();
+    
+    dcmtkpp::Association association;
+    
+    association.set_own_ae_title("myself");
+    
+    association.set_peer_host_name("pacs.example.com");
+    association.set_peer_port(11112);
+    association.set_peer_ae_title("pacs");
+    
+    association.add_presentation_context(
+        UID_GETStudyRootQueryRetrieveInformationModel,
+        { UID_LittleEndianImplicitTransferSyntax });
+    
+    association.add_presentation_context(
+        UID_MRImageStorage,
+        { UID_LittleEndianImplicitTransferSyntax },
+        ASC_SC_ROLE_SCP);
+    
+    association.add_presentation_context(
+        UID_VerificationSOPClass,
+        { UID_LittleEndianImplicitTransferSyntax });
+    
+    association.associate(network);
+    
+    dcmtkpp::GetSCU scu;
+    scu.set_network(&network);
+    scu.set_association(&association);
+    
+    scu.echo();
+    
+    dcmtkpp::DataSet query;
+    query.add("PatientID",{ "1234" });
+    query.add("QueryRetrieveLevel", { "SERIES" });
+    query.add("StudyInstanceUID", { "1.2.3.4.5" });
+    query.add("SeriesInstanceUID", { "1.2.3.4.5.1" });
+    
+    scu.set_affected_sop_class(UID_GETStudyRootQueryRetrieveInformationModel);
+    
+    std::cout << "--------\n";
+    std::cout << "Callback\n";
+    std::cout << "--------\n\n";
+    
+    scu.get(query, print_informations);
+    
+    std::cout << "\n";
+    
+    std::cout << "------\n";
+    std::cout << "vector\n";
+    std::cout << "------\n\n";
+    
+    std::vector<dcmtkpp::DataSet> result = scu.get(query);
+    for(auto dataset: result)
+    {
+        print_informations(dataset);
+    }
+    
+    association.release();
+    network.drop();
+}
diff --git a/examples/move.cpp b/examples/move.cpp
new file mode 100644
index 0000000..fb8b12d
--- /dev/null
+++ b/examples/move.cpp
@@ -0,0 +1,87 @@
+#include <iostream>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dctk.h>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/MoveSCU.h"
+#include "dcmtkpp/registry.h"
+
+void print_informations(dcmtkpp::DataSet const & response)
+{
+    std::cout
+        << response.as_string("PatientName", 0)
+        << ": "
+        << response.as_string("StudyDescription", 0)
+        << " / "
+        << response.as_string("SeriesDescription", 0)
+        << ": "
+        << response.as_string("InstanceNumber", 0)
+        << "\n";
+}
+
+int main()
+{
+    dcmtkpp::Network network;
+    network.set_role(NET_ACCEPTORREQUESTOR);
+    network.set_port(11112);
+    network.initialize();
+    
+    dcmtkpp::Association association;
+    association.set_own_ae_title("myself");
+    
+    association.set_peer_host_name("pacs.example.com");
+    association.set_peer_port(11112);
+    association.set_peer_ae_title("pacs");
+    
+    association.add_presentation_context(
+        UID_MOVEStudyRootQueryRetrieveInformationModel,
+        { UID_LittleEndianImplicitTransferSyntax });
+    
+    association.add_presentation_context(
+        UID_MRImageStorage,
+        { UID_LittleEndianImplicitTransferSyntax },
+        ASC_SC_ROLE_SCP);
+    
+    association.add_presentation_context(
+        UID_VerificationSOPClass,
+        { UID_LittleEndianImplicitTransferSyntax });
+    
+    association.associate(network);
+    
+    dcmtkpp::MoveSCU scu;
+    scu.set_network(&network);
+    scu.set_association(&association);
+    scu.set_move_destination(association.get_own_ae_title());
+    
+    scu.echo();
+    
+    dcmtkpp::DataSet query;
+    query.add("PatientID",{ "1234" });
+    query.add("QueryRetrieveLevel", { "SERIES" });
+    query.add("StudyInstanceUID", { "1.2.3.4.5" });
+    query.add("SeriesInstanceUID", { "1.2.3.4.5.1" });
+    
+    scu.set_affected_sop_class(UID_MOVEStudyRootQueryRetrieveInformationModel);
+    
+    std::cout << "--------\n";
+    std::cout << "Callback\n";
+    std::cout << "--------\n\n";
+    
+    scu.move(query, print_informations);
+    
+    std::cout << "\n";
+    
+    std::cout << "------\n";
+    std::cout << "vector\n";
+    std::cout << "------\n\n";
+    
+    std::vector<dcmtkpp::DataSet> result = scu.move(query);
+    for(auto dataset: result)
+    {
+        print_informations(dataset);
+    }
+    
+    association.release();
+    network.drop();
+}
diff --git a/examples/store.cpp b/examples/store.cpp
new file mode 100644
index 0000000..184da07
--- /dev/null
+++ b/examples/store.cpp
@@ -0,0 +1,60 @@
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dctk.h>
+
+#include "dcmtkpp/conversion.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/StoreSCU.h"
+
+void progress_callback(void * data, unsigned long bytes_count)
+{
+    long file_size = *reinterpret_cast<long*>(data);
+    std::cout << bytes_count << "/" << file_size << std::endl;
+}
+
+int main(int argc, char** argv)
+{
+    dcmtkpp::Network network;
+    network.initialize();
+    
+    dcmtkpp::Association association;
+    
+    association.set_own_ae_title("myself");
+    
+    association.set_peer_host_name("pacs.example.com");
+    association.set_peer_port(11112);
+    association.set_peer_ae_title("pacs");
+    
+    association.add_presentation_context(UID_MRImageStorage,
+        { UID_LittleEndianImplicitTransferSyntax });
+    
+    association.add_presentation_context(UID_EnhancedMRImageStorage,
+        { UID_LittleEndianImplicitTransferSyntax });
+    
+    association.add_presentation_context(UID_VerificationSOPClass,
+        { UID_LittleEndianImplicitTransferSyntax });
+    
+    association.associate(network);
+    
+    dcmtkpp::StoreSCU scu;
+    scu.set_network(&network);
+    scu.set_association(&association);
+    
+    scu.echo();
+    
+    for(int i=1; i<argc; ++i)
+    {
+        std::cout << "Storing " << argv[i] << std::endl;
+        
+        long file_size = OFStandard::getFileSize(argv[i]);
+        DcmFileFormat file;
+        file.loadFile(argv[i]);
+
+        dcmtkpp::DataSet const data_set = dcmtkpp::convert(file.getDataset());
+        
+        scu.set_affected_sop_class(data_set);
+        scu.store(data_set, progress_callback, &file_size);
+    }
+    
+    association.release();
+    network.drop();
+}
diff --git a/generate_registry b/generate_registry
new file mode 100755
index 0000000..e0a3f16
--- /dev/null
+++ b/generate_registry
@@ -0,0 +1,95 @@
+#! /usr/bin/env python
+
+import re
+import urllib
+import sys
+import xml.etree.ElementTree
+
+def main():
+    sources = [
+        ("http://medical.nema.org/medical/dicom/current/source/docbook/part07/part07.xml", "table_E.1-1"),
+        ("http://medical.nema.org/medical/dicom/current/source/docbook/part06/part06.xml", "table_7-1"),
+        ("http://medical.nema.org/medical/dicom/current/source/docbook/part06/part06.xml", "table_8-1"),
+        ("http://medical.nema.org/medical/dicom/current/source/docbook/part06/part06.xml", "table_6-1"),
+
+    ]
+
+    header = [
+        "/*************************************************************************",
+        "* dcmtkpp - 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 _afc7b2d7_0869_4fea_9a9b_7fe6228baca9",
+        "#define _afc7b2d7_0869_4fea_9a9b_7fe6228baca9",
+        "",
+        "#include \"dcmtkpp/Tag.h\"",
+        "",
+        "namespace dcmtkpp",
+        "{",
+        "",
+        "namespace registry",
+        "{",
+    ]
+
+    declarations = []
+    for url, id_ in sources:
+        declarations.extend(generate_registry(url, id_))
+
+    footer = [
+        "}",
+        "",
+        "}",
+        "",
+        "#endif // _afc7b2d7_0869_4fea_9a9b_7fe6228baca9",
+    ]
+
+    print "\n".join(header+declarations+footer)
+
+    return 0
+
+def generate_registry(url, id_):
+    fd = urllib.urlopen(url)
+    document = xml.etree.ElementTree.parse(fd)
+    fd.close()
+
+    namespaces = {
+        "xml": "http://www.w3.org/XML/1998/namespace",
+        "docbook": "http://docbook.org/ns/docbook"
+    }
+
+    table = document.find(".//*[@xml:id=\"{}\"]".format(id_), namespaces)
+
+    entries = []
+
+    for row in table.iterfind("./docbook:tbody/docbook:tr", namespaces):
+        entry = row.findall("./docbook:td/docbook:para", namespaces)
+        tag = entry[0]
+        if tag.getchildren():
+            tag = tag.find("./docbook:emphasis", namespaces)
+        tag = tag.text
+
+        match = re.match(r"\(([0-9a-fA-F]{4}),([0-9a-fA-F]{4})\)", tag)
+        if not match:
+            continue
+
+        tag = [int(x, 16) for x in match.groups()]
+
+        keyword = entry[2]
+        if keyword.getchildren():
+            keyword = keyword.find("./docbook:emphasis", namespaces)
+        keyword = keyword.text or ""
+        keyword = keyword.replace(u"\u200b", "").decode("ascii")
+        if not keyword:
+            continue
+
+        entries.append("    Tag const {}(0x{:04x}, 0x{:04x});".format(keyword, *tag))
+
+    return entries
+
+if __name__ == "__main__":
+    sys.exit(main())
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..92306ef
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,21 @@
+find_package(ICU REQUIRED)
+
+set(DCMTK_LIBRARIES dcmnet dcmdata oflog ofstd pthread z)
+find_library(USE_WRAP wrap)
+if(USE_WRAP)
+    set(DCMTK_LIBRARIES ${DCMTK_LIBRARIES} wrap)
+endif()
+
+file(GLOB_RECURSE headers "*.h")
+file(GLOB_RECURSE templates "*.txx")
+file(GLOB_RECURSE files "*.cpp")
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${ICU_INCLUDE_DIR})
+add_definitions("-D HAVE_CONFIG_H")
+
+add_library(dcmtkpp SHARED ${files})
+install(TARGETS dcmtkpp LIBRARY DESTINATION lib)
+install(FILES ${headers} ${templates} DESTINATION include/dcmtkpp)
+
+target_link_libraries(dcmtkpp ${DCMTK_LIBRARIES} jsoncpp ${ICU_LIBRARIES})
+
+
diff --git a/src/dcmtkpp/Association.cpp b/src/dcmtkpp/Association.cpp
new file mode 100644
index 0000000..d60dec2
--- /dev/null
+++ b/src/dcmtkpp/Association.cpp
@@ -0,0 +1,535 @@
+/*************************************************************************
+ * dcmtkpp - 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 "Association.h"
+
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmnet/assoc.h>
+#include <dcmtk/dcmnet/cond.h>
+
+#include "dcmtkpp/Exception.h"
+
+namespace dcmtkpp
+{
+
+Association
+::Association()
+: _own_ae_title(""),
+  _peer_host_name(""), _peer_port(104), _peer_ae_title(""),
+  _user_identity_type(UserIdentityType::None), 
+  _user_identity_primary_field(""), _user_identity_secondary_field(""),
+  _association(NULL)
+{
+    // Nothing else
+}
+
+Association
+::Association(Association const & other)
+: _own_ae_title(other.get_own_ae_title()), 
+  _peer_host_name(other.get_peer_host_name()), _peer_port(other.get_peer_port()),
+  _peer_ae_title(other.get_peer_ae_title()),
+  _user_identity_type(other.get_user_identity_type()), 
+  _user_identity_primary_field(other.get_user_identity_primary_field()), 
+  _user_identity_secondary_field(other.get_user_identity_secondary_field()),
+  _association(NULL)
+{
+}
+
+Association
+::~Association()
+{
+    if(this->is_associated())
+    {
+        this->release();
+    }
+}
+
+Association &
+Association
+::operator=(Association const & other)
+{
+    if(this != &other)
+    {
+        this->set_own_ae_title(other.get_own_ae_title());
+        this->set_peer_host_name(other.get_peer_host_name());
+        this->set_peer_port(other.get_peer_port());
+        this->set_peer_ae_title(other.get_peer_ae_title());
+        this->set_user_identity_type(other.get_user_identity_type());
+        this->set_user_identity_primary_field(other.get_user_identity_primary_field());
+        this->set_user_identity_secondary_field(other.get_user_identity_secondary_field());
+    }
+    
+    return *this;
+}
+
+std::string const &
+Association
+::get_own_ae_title() const
+{
+    return this->_own_ae_title;
+}
+
+void
+Association
+::set_own_ae_title(std::string const & ae_title)
+{
+    if(this->is_associated())
+    {
+        throw Exception("Cannot set member while associated");
+    }
+    
+    this->_own_ae_title = ae_title;
+}
+
+std::string const &
+Association
+::get_peer_host_name() const
+{
+    return this->_peer_host_name;
+}
+
+void
+Association
+::set_peer_host_name(std::string const & host_name)
+{
+    if(this->is_associated())
+    {
+        throw Exception("Cannot set member while associated");
+    }
+    
+    this->_peer_host_name = host_name;
+}
+
+uint16_t
+Association
+::get_peer_port() const
+{
+    return this->_peer_port;
+}
+
+void
+Association
+::set_peer_port(uint16_t port)
+{
+    if(this->is_associated())
+    {
+        throw Exception("Cannot set member while associated");
+    }
+    
+    this->_peer_port = port;
+}
+
+std::string const &
+Association
+::get_peer_ae_title() const
+{
+    return this->_peer_ae_title;
+}
+
+void
+Association
+::set_peer_ae_title(std::string const & ae_title)
+{
+    if(this->is_associated())
+    {
+        throw Exception("Cannot set member while associated");
+    }
+    
+    this->_peer_ae_title = ae_title;
+}
+
+void
+Association
+::add_presentation_context(std::string const & abstract_syntax,
+    std::vector<std::string> const & transfer_syntaxes, T_ASC_SC_ROLE role)
+{
+    if(this->is_associated())
+    {
+        throw Exception("Cannot set member while associated");
+    }
+    
+    this->_presentation_contexts.push_back(
+        {abstract_syntax, transfer_syntaxes, role});
+}
+
+UserIdentityType
+Association
+::get_user_identity_type() const
+{
+    return this->_user_identity_type;
+}
+
+void
+Association
+::set_user_identity_type(UserIdentityType type)
+{
+    if(this->is_associated())
+    {
+        throw Exception("Cannot set member while associated");
+    }
+    
+    this->_user_identity_type = type;
+}
+
+std::string const &
+Association
+::get_user_identity_primary_field() const
+{
+    return this->_user_identity_primary_field;
+}
+
+void
+Association
+::set_user_identity_primary_field(std::string const & value)
+{
+    if(this->is_associated())
+    {
+        throw Exception("Cannot set member while associated");
+    }
+    
+    this->_user_identity_primary_field = value;
+}
+
+std::string const &
+Association
+::get_user_identity_secondary_field() const
+{
+    return this->_user_identity_secondary_field;
+}
+
+void
+Association
+::set_user_identity_secondary_field(std::string const & value)
+{
+    if(this->is_associated())
+    {
+        throw Exception("Cannot set member while associated");
+    }
+    
+    this->_user_identity_secondary_field = value;
+}
+
+void
+Association
+::set_user_identity_to_none()
+{
+    this->set_user_identity_type(UserIdentityType::None);
+    this->set_user_identity_primary_field("");
+    this->set_user_identity_secondary_field("");
+}
+
+void
+Association
+::set_user_identity_to_username(std::string const & username)
+{
+    this->set_user_identity_type(UserIdentityType::Username);
+    this->set_user_identity_primary_field(username);
+    this->set_user_identity_secondary_field("");
+}
+
+void
+Association
+::set_user_identity_to_username_and_password(
+    std::string const & username, std::string const & password)
+{
+    this->set_user_identity_type(UserIdentityType::UsernameAndPassword);
+    this->set_user_identity_primary_field(username);
+    this->set_user_identity_secondary_field(password);
+}
+    
+void
+Association
+::set_user_identity_to_kerberos(std::string const & ticket)
+{
+    this->set_user_identity_type(UserIdentityType::Kerberos);
+    this->set_user_identity_primary_field(ticket);
+    this->set_user_identity_secondary_field("");
+}
+
+void
+Association
+::set_user_identity_to_saml(std::string const & assertion)
+{
+    this->set_user_identity_type(UserIdentityType::SAML);
+    this->set_user_identity_primary_field(assertion);
+    this->set_user_identity_secondary_field("");
+}
+
+bool
+Association
+::is_associated() const
+{
+    return (this->_association != NULL);
+}
+
+void
+Association
+::associate(Network & network)
+{
+    if(!network.is_initialized())
+    {
+        throw Exception("Network is not initialized");
+    }
+    
+    if(this->is_associated())
+    {
+        throw Exception("Already associated");
+    }
+    
+    OFCondition condition;
+    
+    T_ASC_Parameters * params;
+    condition = ASC_createAssociationParameters(&params, ASC_MAXIMUMPDUSIZE);
+    if(condition.bad())
+    {
+        throw Exception(condition);
+    }
+    
+    condition = ASC_setAPTitles(params, 
+        this->_own_ae_title.c_str(), this->_peer_ae_title.c_str(), NULL);
+    if(condition.bad())
+    {
+        ASC_destroyAssociationParameters(&params);
+        throw Exception(condition);
+    }
+    
+    std::string localhost(128, '\0');
+    gethostname(&localhost[0], localhost.size()-1);
+    
+    std::ostringstream peer;
+    peer << this->_peer_host_name << ":" << this->_peer_port;
+    
+    condition = ASC_setPresentationAddresses(params,
+        "localhost", peer.str().c_str());
+    if(condition.bad())
+    {
+        ASC_destroyAssociationParameters(&params);
+        throw Exception(condition);
+    }
+    
+    unsigned int context_id = 1;
+    for(auto const & context: this->_presentation_contexts)
+    {
+        char const ** transfer_syntaxes = new char const *[context.transfer_syntaxes.size()];
+        for(std::size_t i = 0; i < context.transfer_syntaxes.size(); ++i)
+        {
+            transfer_syntaxes[i] = context.transfer_syntaxes[i].c_str();
+        }
+        
+        condition = ASC_addPresentationContext(params, 
+            context_id, context.abstract_syntax.c_str(),
+            transfer_syntaxes, context.transfer_syntaxes.size(), context.role);
+        if(condition.bad())
+        {
+            ASC_destroyAssociationParameters(&params);
+            throw Exception(condition);
+        }
+        
+        context_id += 2;
+    }
+    
+    if(this->_user_identity_type == UserIdentityType::None)
+    {
+        // Nothing to do.
+    }
+    else if(this->_user_identity_type == UserIdentityType::Username)
+    {
+        condition = ASC_setIdentRQUserOnly(params, 
+            this->_user_identity_primary_field.c_str());
+    }
+    else if(this->_user_identity_type == UserIdentityType::UsernameAndPassword)
+    {
+        condition = ASC_setIdentRQUserOnly(params, 
+            this->_user_identity_primary_field.c_str(),
+            this->_user_identity_secondary_field.c_str());
+    }
+    else if(this->_user_identity_type == UserIdentityType::Kerberos)
+    {
+        condition = ASC_setIdentRQKerberos(params, 
+            this->_user_identity_primary_field.c_str(),
+            this->_user_identity_primary_field.size());
+    }
+    else if(this->_user_identity_type == UserIdentityType::SAML)
+    {
+        condition = ASC_setIdentRQSaml(params, 
+            this->_user_identity_primary_field.c_str(),
+            this->_user_identity_primary_field.size());
+    }
+    else
+    {
+        ASC_destroyAssociationParameters(&params);
+        throw Exception("Unknown identity type");
+    }
+    
+    if(condition.bad())
+    {
+        ASC_destroyAssociationParameters(&params);
+        throw Exception(condition);
+    }
+    
+    condition = ASC_requestAssociation(
+        network.get_network(), params, &this->_association);
+    if(condition.bad())
+    {
+        OFString empty;
+        
+        if(condition == DUL_ASSOCIATIONREJECTED)
+        {
+            T_ASC_RejectParameters rej;
+            ASC_getRejectParameters(params, &rej);
+            
+            ASC_destroyAssociationParameters(&params);
+            throw Exception(ASC_printRejectParameters(empty, &rej).c_str());
+        } 
+        else 
+        {
+            ASC_destroyAssociationParameters(&params);
+            throw Exception(DimseCondition::dump(empty, condition).c_str());
+        }
+    }
+}
+
+void 
+Association
+::receive(Network & network, bool accept_all)
+{
+    if(!network.is_initialized())
+    {
+        throw Exception("Network is not initialized");
+    }
+    
+    if(this->is_associated())
+    {
+        throw Exception("Already associated");
+    }
+    
+    OFCondition condition;
+    
+    condition = ASC_receiveAssociation(
+        network.get_network(), &this->_association, ASC_DEFAULTMAXPDU);
+    if(condition.bad())
+    {
+        throw Exception(condition);
+    }
+    
+    T_ASC_Parameters * const params = this->_association->params;
+    DUL_ASSOCIATESERVICEPARAMETERS const dul = params->DULparams;
+    // No peer port should be defined when receiving
+    this->_peer_host_name = dul.callingPresentationAddress;
+    this->_peer_port = 0;
+    this->_peer_ae_title = dul.callingAPTitle;
+    
+    if(accept_all)
+    {
+        unsigned int const pc_count = ASC_countPresentationContexts(params);
+        for(unsigned int pc_index=0; pc_index<pc_count; ++pc_index)
+        {
+            T_ASC_PresentationContext pc;
+            memset(&pc, 0, sizeof(pc));
+            ASC_getPresentationContext(params, pc_index, &pc);
+            
+            for(unsigned int ts_index=0; ts_index<pc.transferSyntaxCount; ++ts_index)
+            {
+                std::string const abstract_syntax = pc.abstractSyntax;
+                char const * abstract_syntax_data = abstract_syntax.c_str();
+                
+                condition = ASC_acceptContextsWithTransferSyntax(
+                    this->_association->params, 
+                    pc.proposedTransferSyntaxes[ts_index],
+                    1, &abstract_syntax_data);
+                if(condition.bad())
+                {
+                    this->abort();
+                    throw Exception(condition);
+                }
+            }
+        }
+    }
+    else
+    {
+        for(auto const & context: this->_presentation_contexts)
+        {
+            for(std::size_t i = 0; i < context.transfer_syntaxes.size(); ++i)
+            {
+                char const * abstract_syntax = context.abstract_syntax.c_str();
+                char const * transfer_syntax = context.transfer_syntaxes[i].c_str();
+                condition = ASC_acceptContextsWithTransferSyntax(
+                    this->_association->params, transfer_syntax,
+                    1, &abstract_syntax);
+                if(condition.bad())
+                {
+                    this->abort();
+                    throw Exception(condition);
+                }
+            }
+        }
+    }
+    
+    condition = ASC_acknowledgeAssociation(this->_association);
+    if(condition.bad())
+    {
+        throw Exception(condition);
+    }
+}
+
+T_ASC_Association *
+Association
+::get_association()
+{
+    return this->_association;
+}
+
+void
+Association
+::release()
+{
+    if(!this->is_associated())
+    {
+        throw Exception("Not associated");
+    }
+    
+    ASC_releaseAssociation(this->_association);
+    ASC_destroyAssociation(&this->_association);
+    this->_association = NULL;
+}
+
+void
+Association
+::abort()
+{
+    if(!this->is_associated())
+    {
+        throw Exception("Not associated");
+    }
+    
+    ASC_abortAssociation(this->_association);
+    ASC_destroyAssociation(&this->_association);
+    this->_association = NULL;
+}
+
+void
+Association
+::drop()
+{
+    if(!this->is_associated())
+    {
+        throw Exception("Not associated");
+    }
+    
+    ASC_acknowledgeRelease(this->_association);
+    ASC_dropSCPAssociation(this->_association);
+    ASC_destroyAssociation(&this->_association);
+    this->_association = NULL;
+}
+
+}
diff --git a/src/dcmtkpp/Association.h b/src/dcmtkpp/Association.h
new file mode 100644
index 0000000..8b2fcb8
--- /dev/null
+++ b/src/dcmtkpp/Association.h
@@ -0,0 +1,184 @@
+/*************************************************************************
+ * dcmtkpp - 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 _a52696bc_5c6e_402d_a343_6cb085eb0138
+#define _a52696bc_5c6e_402d_a343_6cb085eb0138
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmnet/assoc.h>
+
+#include "dcmtkpp/Network.h"
+
+namespace dcmtkpp
+{
+
+/// @brief User identity types as defined by PS3.8 2013 D.3.3.7
+enum class UserIdentityType
+{
+    None = 0,
+    Username = 1,
+    UsernameAndPassword = 2,
+    Kerberos = 3,
+    SAML = 4
+};
+
+/**
+ * @brief Wrapper around the T_ASC_Association class.
+ * 
+ * No member can be set while the object is associated.
+ */
+class Association
+{
+public:
+    /// @brief Create a default, un-associated, association.
+    Association();
+    
+    /// @brief Create an un-associated association.
+    Association(Association const & other);
+    
+    /// @brief Destroy the association, release it if necessary.
+    ~Association();
+    
+    /// @brief Assing an un-associated association; it remains un-associated.
+    Association & operator=(Association const & other);
+    
+    /// @brief Return the AE title of the caller. Defaults to "".
+    std::string const & get_own_ae_title() const;
+    /// @brief Set the AE title of the caller.
+    void set_own_ae_title(std::string const & ae_title);
+    
+    /// @name Peer
+    /// @{
+    
+    /// @brief Return the host name of the peer. Defaults to "".
+    std::string const & get_peer_host_name() const;
+    /// @brief Set the host name of the peer.
+    void set_peer_host_name(std::string const & host_name);
+    
+    /// @brief Return the port of the peer. Defaults to 104.
+    uint16_t get_peer_port() const;
+    /// @brief Set the port of the peer.
+    void set_peer_port(uint16_t port);
+    
+    /// @brief Return the AE title of the peer. Defaults to "".
+    std::string const & get_peer_ae_title() const;
+    /// @brief Set the AE title of the peer.
+    void set_peer_ae_title(std::string const & ae_title);
+    
+    /// @}
+    
+    /// @name Presentation contexts
+    /// @{
+    
+    void add_presentation_context(std::string const & abstract_syntax,
+        std::vector<std::string> const & transfer_syntaxes,
+        T_ASC_SC_ROLE role=ASC_SC_ROLE_DEFAULT);
+    
+    /// @}
+    
+    /// @name User identity
+    /// @{
+        
+    /// @brief Return the user identity type. Defaults to None.
+    UserIdentityType get_user_identity_type() const;
+    /// @brief Set the user identity type.
+    void set_user_identity_type(UserIdentityType type);
+    
+    /// @brief Return the user identity primary field. Defaults to "".
+    std::string const & get_user_identity_primary_field() const;
+    /// @brief Set the user identity primary field. 
+    void set_user_identity_primary_field(std::string const & value);
+    
+    /// @brief Return the user identity secondary field. Defaults to "".
+    std::string const & get_user_identity_secondary_field() const;
+    /// @brief Set the user identity secondary field.
+    void set_user_identity_secondary_field(std::string const & value);
+    
+    /// @brief Do no authenticate user.
+    void set_user_identity_to_none();
+    
+    /// @brief Authenticate user using only a username.
+    void set_user_identity_to_username(std::string const & username);
+    
+    /// @brief Authenticate user using a username and a password.
+    void set_user_identity_to_username_and_password(
+        std::string const & username, std::string const & password);
+        
+    /// @brief Authenticate user using a Kerberos ticket.
+    void set_user_identity_to_kerberos(std::string const & ticket);
+    
+    /// @brief Authenticate user using a SAML assertion.
+    void set_user_identity_to_saml(std::string const & assertion);
+    
+    /// @}
+    
+    /// @name Association
+    /// @{
+    
+    /// @brief Test whether the object is currently associated to its peer.
+    bool is_associated() const;
+    
+    /**
+     * @brief Request an association with the peer. 
+     * @param network network to use for the data transmission.
+     * 
+     * Throws an exception if already associated.
+     */
+    void associate(Network & network);
+    
+    /** 
+     * @brief Receive an association for a peer.
+     * @param network network to use for the data transmission.
+     * @param accept_all if true, accept all presentations contexts proposed
+     *  by peer.
+     */
+    void receive(Network & network, bool accept_all=false);
+    
+    /// @brief Return the association object.
+    T_ASC_Association * get_association();
+    
+    /// @brief Gracefully release the association. Throws an exception if not associated.
+    void release();
+    /// @brief Forcefully release the association. Throws an exception if not associated.
+    void abort();
+    
+    /// @brief Drop an association that has been released by the peer.
+    void drop();
+    
+    /// @}
+
+private:
+    std::string _own_ae_title;
+    
+    std::string _peer_host_name;
+    uint16_t _peer_port;
+    std::string _peer_ae_title;
+    
+    struct PresentationContext
+    {
+        std::string abstract_syntax;
+        std::vector<std::string> transfer_syntaxes;
+        T_ASC_SC_ROLE role;
+    };
+
+    std::vector<PresentationContext> _presentation_contexts;
+    
+    UserIdentityType _user_identity_type;
+    std::string _user_identity_primary_field;
+    std::string _user_identity_secondary_field;
+    
+    T_ASC_Association * _association;
+};
+
+}
+
+#endif // _a52696bc_5c6e_402d_a343_6cb085eb0138
diff --git a/src/dcmtkpp/CEchoRequest.cpp b/src/dcmtkpp/CEchoRequest.cpp
new file mode 100644
index 0000000..858abbb
--- /dev/null
+++ b/src/dcmtkpp/CEchoRequest.cpp
@@ -0,0 +1,47 @@
+/*************************************************************************
+ * dcmtkpp - 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 "CEchoRequest.h"
+
+#include "dcmtkpp/Request.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+CEchoRequest
+::CEchoRequest(
+    Value::Integer message_id, Value::String const & affected_sop_class_uid)
+: Request(message_id)
+{
+    this->set_command_field(Command::C_ECHO_RQ);
+    this->set_affected_sop_class_uid(affected_sop_class_uid);
+}
+
+CEchoRequest
+::CEchoRequest(Message const & message)
+: Request(message)
+{
+    if(message.get_command_field() != Command::C_ECHO_RQ)
+    {
+        throw Exception("Message is not a C-ECHO-RQ");
+    }
+    this->set_command_field(message.get_command_field());
+
+    this->set_affected_sop_class_uid(
+        message.get_command_set().as_string(registry::AffectedSOPClassUID, 0));
+}
+
+CEchoRequest
+::~CEchoRequest()
+{
+    // Nothing to do.
+}
+
+}
diff --git a/src/dcmtkpp/CEchoRequest.h b/src/dcmtkpp/CEchoRequest.h
new file mode 100644
index 0000000..deb60a5
--- /dev/null
+++ b/src/dcmtkpp/CEchoRequest.h
@@ -0,0 +1,47 @@
+/*************************************************************************
+ * dcmtkpp - 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 _aec786b8_0074_4cb2_b9a1_4bf26bbd20fc
+#define _aec786b8_0074_4cb2_b9a1_4bf26bbd20fc
+
+#include "dcmtkpp/Request.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief C-ECHO-RQ message.
+class CEchoRequest: public Request
+{
+public:
+    /**
+     * @brief Create an echo request with given Message ID and
+     * affected SOP class UID.
+     */
+    CEchoRequest(
+        Value::Integer message_id,
+        Value::String const & affected_sop_class_uid);
+
+    /**
+     * @brief Create a C-ECHO-RQ from a generic Message.
+     *
+     * Raise an exception if the Message does not contain a C-ECHO-RQ.
+     */
+    CEchoRequest(Message const & message);
+
+    /// @brief Destructor.
+    virtual ~CEchoRequest();
+    
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
+        affected_sop_class_uid, registry::AffectedSOPClassUID)
+};
+
+}
+
+#endif // _aec786b8_0074_4cb2_b9a1_4bf26bbd20fc
diff --git a/src/dcmtkpp/CEchoResponse.cpp b/src/dcmtkpp/CEchoResponse.cpp
new file mode 100644
index 0000000..ec176b3
--- /dev/null
+++ b/src/dcmtkpp/CEchoResponse.cpp
@@ -0,0 +1,49 @@
+/*************************************************************************
+ * dcmtkpp - 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 "CEchoResponse.h"
+
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Response.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+CEchoResponse
+::CEchoResponse(
+    Value::Integer message_id_being_responded_to, Value::Integer status,
+    Value::String const & affected_sop_class_uid)
+: Response(message_id_being_responded_to, status)
+{
+    this->set_command_field(Command::C_ECHO_RSP);
+    this->set_affected_sop_class_uid(affected_sop_class_uid);
+}
+
+CEchoResponse
+::CEchoResponse(Message const & message)
+: Response(message)
+{
+    if(message.get_command_field() != Command::C_ECHO_RSP)
+    {
+        throw Exception("Message is not a C-ECHO-RSP");
+    }
+    this->set_command_field(message.get_command_field());
+    
+    this->set_affected_sop_class_uid(
+        message.get_command_set().as_string(registry::AffectedSOPClassUID, 0));
+}
+
+CEchoResponse
+::~CEchoResponse()
+{
+    // Nothing to do.
+}
+
+}
diff --git a/src/dcmtkpp/CEchoResponse.h b/src/dcmtkpp/CEchoResponse.h
new file mode 100644
index 0000000..51c19d9
--- /dev/null
+++ b/src/dcmtkpp/CEchoResponse.h
@@ -0,0 +1,47 @@
+/*************************************************************************
+ * dcmtkpp - 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 _266252d9_e801_479e_a805_004b101c5250
+#define _266252d9_e801_479e_a805_004b101c5250
+
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Response.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief C-ECHO-RSP message.
+class CEchoResponse: public Response
+{
+public:
+    /**
+     * @brief Create an echo response with given Message ID and
+     * affected SOP class UID.
+     */
+    CEchoResponse(
+        Value::Integer message_id_being_responded_to, Value::Integer status,
+        Value::String const & affected_sop_class_uid);
+
+    /**
+     * @brief Create a C-ECHO-RSP from a generic Message.
+     *
+     * Raise an exception if the Message does not contain a C-ECHO-RSP.
+     */
+    CEchoResponse(Message const & message);
+
+    /// @brief Destructor.
+    virtual ~CEchoResponse();
+    
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
+        affected_sop_class_uid, registry::AffectedSOPClassUID)
+};
+
+}
+
+#endif // _266252d9_e801_479e_a805_004b101c5250
diff --git a/src/dcmtkpp/CFindRequest.cpp b/src/dcmtkpp/CFindRequest.cpp
new file mode 100644
index 0000000..1c096c3
--- /dev/null
+++ b/src/dcmtkpp/CFindRequest.cpp
@@ -0,0 +1,65 @@
+/*************************************************************************
+ * dcmtkpp - 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 "CFindRequest.h"
+
+#include <string>
+
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Request.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+CFindRequest
+::CFindRequest(
+    Value::Integer message_id, Value::String const & affected_sop_class_uid,
+    Value::Integer priority, DataSet const & dataset)
+: Request(message_id)
+{
+    this->set_command_field(Command::C_FIND_RQ);
+    this->set_affected_sop_class_uid(affected_sop_class_uid);
+    this->set_priority(priority);
+    if(dataset.empty())
+    {
+        throw Exception("Data set is required");
+    }
+    this->set_data_set(dataset);
+}
+
+CFindRequest
+::CFindRequest(Message const & message)
+: Request(message)
+{
+    if(message.get_command_field() != Command::C_FIND_RQ)
+    {
+        throw Exception("Message is not a C-FIND-RQ");
+    }
+    this->set_command_field(message.get_command_field());
+
+    this->set_affected_sop_class_uid(
+        message.get_command_set().as_string(registry::AffectedSOPClassUID, 0));
+
+    this->set_priority(message.get_command_set().as_int(registry::Priority, 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());
+}
+
+CFindRequest
+::~CFindRequest()
+{
+    // Nothing to do.
+}
+
+}
diff --git a/src/dcmtkpp/CFindRequest.h b/src/dcmtkpp/CFindRequest.h
new file mode 100644
index 0000000..6b9e685
--- /dev/null
+++ b/src/dcmtkpp/CFindRequest.h
@@ -0,0 +1,48 @@
+/*************************************************************************
+ * dcmtkpp - 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 _74cfa9e7_da35_4130_a941_e17cb6932f60
+#define _74cfa9e7_da35_4130_a941_e17cb6932f60
+
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Request.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief C-FIND-RQ message.
+class CFindRequest: public Request
+{
+public:
+    /**
+     * @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 const & 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 Destructor.
+    virtual ~CFindRequest();
+    
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
+        affected_sop_class_uid, registry::AffectedSOPClassUID)
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(priority, registry::Priority)
+};
+
+}
+
+#endif // _74cfa9e7_da35_4130_a941_e17cb6932f60
diff --git a/src/dcmtkpp/CFindResponse.cpp b/src/dcmtkpp/CFindResponse.cpp
new file mode 100644
index 0000000..a70d6d8
--- /dev/null
+++ b/src/dcmtkpp/CFindResponse.cpp
@@ -0,0 +1,66 @@
+/*************************************************************************
+ * dcmtkpp - 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 "CFindResponse.h"
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Response.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+CFindResponse
+::CFindResponse(
+    Value::Integer message_id_being_responded_to, Value::Integer status)
+: Response(message_id_being_responded_to, status)
+{
+    this->set_command_field(Command::C_FIND_RSP);
+}
+
+CFindResponse
+::CFindResponse(
+    Value::Integer message_id_being_responded_to, Value::Integer status,
+    DataSet const & dataset)
+: Response(message_id_being_responded_to, status)
+{
+    this->set_command_field(Command::C_FIND_RSP);
+    this->set_data_set(dataset);
+}
+
+CFindResponse
+::CFindResponse(Message const & message)
+: Response(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());
+    
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), message_id, registry::MessageID, as_int)
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), affected_sop_class_uid,
+        registry::AffectedSOPClassUID, as_string)
+
+    if(message.has_data_set())
+    {
+        this->set_data_set(message.get_data_set());
+    }
+}
+
+CFindResponse
+::~CFindResponse()
+{
+    // Nothing to do.
+}
+
+}
diff --git a/src/dcmtkpp/CFindResponse.h b/src/dcmtkpp/CFindResponse.h
new file mode 100644
index 0000000..af44833
--- /dev/null
+++ b/src/dcmtkpp/CFindResponse.h
@@ -0,0 +1,55 @@
+/*************************************************************************
+ * dcmtkpp - 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 _5fd36547_9498_4cf3_87cc_737af51e93a9
+#define _5fd36547_9498_4cf3_87cc_737af51e93a9
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Response.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief C-FIND-RSP message.
+class CFindResponse: public Response
+{
+public:
+    /**
+     * @brief Create an find response with given Message ID, and status.
+     */
+    CFindResponse(
+        Value::Integer message_id_being_responded_to, Value::Integer status);
+
+    /**
+     * @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 const & 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 Destructor.
+    virtual ~CFindResponse();
+    
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(message_id, registry::MessageID)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_STRING_MACRO(
+        affected_sop_class_uid, registry::AffectedSOPClassUID)
+};
+
+}
+
+#endif // _5fd36547_9498_4cf3_87cc_737af51e93a9
diff --git a/src/dcmtkpp/CGetRequest.cpp b/src/dcmtkpp/CGetRequest.cpp
new file mode 100644
index 0000000..3a0d5a6
--- /dev/null
+++ b/src/dcmtkpp/CGetRequest.cpp
@@ -0,0 +1,66 @@
+/*************************************************************************
+ * dcmtkpp - 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 "CGetRequest.h"
+
+#include <string>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Request.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+CGetRequest
+::CGetRequest(
+    Value::Integer message_id, Value::String const & affected_sop_class_uid,
+    Value::Integer priority, DataSet const & dataset)
+: Request(message_id)
+{
+    this->set_command_field(Command::C_GET_RQ);
+    this->set_affected_sop_class_uid(affected_sop_class_uid);
+    this->set_priority(priority);
+    if(dataset.empty())
+    {
+        throw Exception("Data set is required");
+    }
+    this->set_data_set(dataset);
+}
+
+CGetRequest
+::CGetRequest(Message const & message)
+: Request(message)
+{
+    if(message.get_command_field() != Command::C_GET_RQ)
+    {
+        throw Exception("Message is not a C-GET-RQ");
+    }
+    this->set_command_field(message.get_command_field());
+
+    this->set_affected_sop_class_uid(
+        message.get_command_set().as_string(registry::AffectedSOPClassUID, 0));
+
+    this->set_priority(message.get_command_set().as_int(registry::Priority, 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());
+}
+
+CGetRequest
+::~CGetRequest()
+{
+    // Nothing to do.
+}
+
+}
diff --git a/src/dcmtkpp/CGetRequest.h b/src/dcmtkpp/CGetRequest.h
new file mode 100644
index 0000000..a9061b8
--- /dev/null
+++ b/src/dcmtkpp/CGetRequest.h
@@ -0,0 +1,49 @@
+/*************************************************************************
+ * dcmtkpp - 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 _6a22f126_7cc6_47ab_81c2_5f66b2714345
+#define _6a22f126_7cc6_47ab_81c2_5f66b2714345
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Request.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief C-GET-RQ message.
+class CGetRequest: public Request
+{
+public:
+    /**
+     * @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 const & 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 Destructor.
+    virtual ~CGetRequest();
+
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
+        affected_sop_class_uid, registry::AffectedSOPClassUID)
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(priority, registry::Priority)
+};
+
+}
+
+#endif // _6a22f126_7cc6_47ab_81c2_5f66b2714345
diff --git a/src/dcmtkpp/CGetResponse.cpp b/src/dcmtkpp/CGetResponse.cpp
new file mode 100644
index 0000000..3deda8f
--- /dev/null
+++ b/src/dcmtkpp/CGetResponse.cpp
@@ -0,0 +1,79 @@
+/*************************************************************************
+ * dcmtkpp - 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 "CGetResponse.h"
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Response.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+CGetResponse
+::CGetResponse(
+    Value::Integer message_id_being_responded_to, Value::Integer status)
+: Response(message_id_being_responded_to, status)
+{
+    this->set_command_field(Command::C_GET_RSP);
+}
+
+CGetResponse
+::CGetResponse(
+    Value::Integer message_id_being_responded_to, Value::Integer status,
+    DataSet const & dataset)
+: Response(message_id_being_responded_to, status)
+{
+    this->set_command_field(Command::C_GET_RSP);
+    this->set_data_set(dataset);
+}
+
+CGetResponse
+::CGetResponse(Message const & message)
+: Response(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());
+    
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), message_id, registry::MessageID, as_int)
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), affected_sop_class_uid,
+        registry::AffectedSOPClassUID, as_string)
+
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), number_of_remaining_sub_operations,
+        registry::NumberOfRemainingSuboperations, as_int)
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), number_of_completed_sub_operations,
+        registry::NumberOfCompletedSuboperations, as_int)
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), number_of_failed_sub_operations,
+        registry::NumberOfFailedSuboperations, as_int)
+    DCMTKPP_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/dcmtkpp/CGetResponse.h b/src/dcmtkpp/CGetResponse.h
new file mode 100644
index 0000000..d51cba1
--- /dev/null
+++ b/src/dcmtkpp/CGetResponse.h
@@ -0,0 +1,64 @@
+/*************************************************************************
+ * dcmtkpp - 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 _7b9819f1_d7a2_4898_a850_3ed6a61f08c6
+#define _7b9819f1_d7a2_4898_a850_3ed6a61f08c6
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Response.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief C-GET-RSP message.
+class CGetResponse: public Response
+{
+public:
+    /**
+     * @brief Create an get response with given Message ID, and status.
+     */
+    CGetResponse(
+        Value::Integer message_id_being_responded_to, Value::Integer status);
+
+    /**
+     * @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 const & 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 Destructor.
+    virtual ~CGetResponse();
+    
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(message_id, registry::MessageID)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_STRING_MACRO(
+        affected_sop_class_uid, registry::AffectedSOPClassUID)
+
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
+        number_of_remaining_sub_operations, registry::NumberOfRemainingSuboperations)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
+        number_of_completed_sub_operations, registry::NumberOfCompletedSuboperations)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
+        number_of_failed_sub_operations, registry::NumberOfFailedSuboperations)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
+        number_of_warning_sub_operations, registry::NumberOfWarningSuboperations)
+};
+
+}
+
+#endif // _7b9819f1_d7a2_4898_a850_3ed6a61f08c6
diff --git a/src/dcmtkpp/CMoveRequest.cpp b/src/dcmtkpp/CMoveRequest.cpp
new file mode 100644
index 0000000..df21f83
--- /dev/null
+++ b/src/dcmtkpp/CMoveRequest.cpp
@@ -0,0 +1,69 @@
+/*************************************************************************
+ * dcmtkpp - 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 "CMoveRequest.h"
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Request.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+CMoveRequest
+::CMoveRequest(
+    Value::Integer message_id, Value::String const & affected_sop_class_uid,
+    Value::Integer priority, Value::String const & move_destination,
+    DataSet const & dataset)
+: Request(message_id)
+{
+    this->set_command_field(Command::C_MOVE_RQ);
+    this->set_affected_sop_class_uid(affected_sop_class_uid);
+    this->set_priority(priority);
+    this->set_move_destination(move_destination);
+    if(dataset.empty())
+    {
+        throw Exception("Data set is required");
+    }
+    this->set_data_set(dataset);
+}
+
+CMoveRequest
+::CMoveRequest(Message const & message)
+: Request(message)
+{
+    if(message.get_command_field() != Command::C_MOVE_RQ)
+    {
+        throw Exception("Message is not a C-MOVE-RQ");
+    }
+    this->set_command_field(message.get_command_field());
+
+    this->set_affected_sop_class_uid(
+        message.get_command_set().as_string(registry::AffectedSOPClassUID, 0));
+
+    this->set_priority(message.get_command_set().as_int(registry::Priority, 0));
+
+    this->set_move_destination(
+        message.get_command_set().as_string(registry::MoveDestination, 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());
+}
+
+CMoveRequest
+::~CMoveRequest()
+{
+    // Nothing to do.
+}
+
+}
diff --git a/src/dcmtkpp/CMoveRequest.h b/src/dcmtkpp/CMoveRequest.h
new file mode 100644
index 0000000..099e1f1
--- /dev/null
+++ b/src/dcmtkpp/CMoveRequest.h
@@ -0,0 +1,52 @@
+/*************************************************************************
+ * dcmtkpp - 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 _f6e243d2_6113_4fe3_8d04_3f034fc796bf
+#define _f6e243d2_6113_4fe3_8d04_3f034fc796bf
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Request.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief C-MOVE-RQ message.
+class CMoveRequest: public Request
+{
+public:
+    /**
+     * @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 const & 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 Destructor.
+    virtual ~CMoveRequest();
+
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
+        affected_sop_class_uid, registry::AffectedSOPClassUID)
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(priority, registry::Priority)
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
+        move_destination, registry::MoveDestination)
+};
+
+}
+
+#endif // _f6e243d2_6113_4fe3_8d04_3f034fc796bf
diff --git a/src/dcmtkpp/CMoveResponse.cpp b/src/dcmtkpp/CMoveResponse.cpp
new file mode 100644
index 0000000..b1d70b6
--- /dev/null
+++ b/src/dcmtkpp/CMoveResponse.cpp
@@ -0,0 +1,79 @@
+/*************************************************************************
+ * dcmtkpp - 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 "CMoveResponse.h"
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Response.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+CMoveResponse
+::CMoveResponse(
+    Value::Integer message_id_being_responded_to, Value::Integer status)
+: Response(message_id_being_responded_to, status)
+{
+    this->set_command_field(Command::C_MOVE_RSP);
+}
+
+CMoveResponse
+::CMoveResponse(
+    Value::Integer message_id_being_responded_to, Value::Integer status,
+    DataSet const & dataset)
+: Response(message_id_being_responded_to, status)
+{
+    this->set_command_field(Command::C_MOVE_RSP);
+    this->set_data_set(dataset);
+}
+
+CMoveResponse
+::CMoveResponse(Message const & message)
+: Response(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());
+    
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), message_id, registry::MessageID, as_int)
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), affected_sop_class_uid,
+        registry::AffectedSOPClassUID, as_string)
+
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), number_of_remaining_sub_operations,
+        registry::NumberOfRemainingSuboperations, as_int)
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), number_of_completed_sub_operations,
+        registry::NumberOfCompletedSuboperations, as_int)
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), number_of_failed_sub_operations,
+        registry::NumberOfFailedSuboperations, as_int)
+    DCMTKPP_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/dcmtkpp/CMoveResponse.h b/src/dcmtkpp/CMoveResponse.h
new file mode 100644
index 0000000..21a5f48
--- /dev/null
+++ b/src/dcmtkpp/CMoveResponse.h
@@ -0,0 +1,64 @@
+/*************************************************************************
+ * dcmtkpp - 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 _b245f6f2_50c3_4c7c_80e1_f03d9c831301
+#define _b245f6f2_50c3_4c7c_80e1_f03d9c831301
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Response.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief C-MOVE-RSP message.
+class CMoveResponse: public Response
+{
+public:
+    /**
+     * @brief Create an move response with given Message ID, and status.
+     */
+    CMoveResponse(
+        Value::Integer message_id_being_responded_to, Value::Integer status);
+
+    /**
+     * @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 const & 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 Destructor.
+    virtual ~CMoveResponse();
+    
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(message_id, registry::MessageID)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_STRING_MACRO(
+        affected_sop_class_uid, registry::AffectedSOPClassUID)
+
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
+        number_of_remaining_sub_operations, registry::NumberOfRemainingSuboperations)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
+        number_of_completed_sub_operations, registry::NumberOfCompletedSuboperations)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
+        number_of_failed_sub_operations, registry::NumberOfFailedSuboperations)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
+        number_of_warning_sub_operations, registry::NumberOfWarningSuboperations)
+};
+
+}
+
+#endif // _b245f6f2_50c3_4c7c_80e1_f03d9c831301
diff --git a/src/dcmtkpp/CStoreRequest.cpp b/src/dcmtkpp/CStoreRequest.cpp
new file mode 100644
index 0000000..1627fc7
--- /dev/null
+++ b/src/dcmtkpp/CStoreRequest.cpp
@@ -0,0 +1,75 @@
+/*************************************************************************
+ * dcmtkpp - 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 "CStoreRequest.h"
+
+#include <string>
+
+#include "dcmtkpp/ElementAccessor.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/Request.h"
+
+namespace dcmtkpp
+{
+
+CStoreRequest
+::CStoreRequest(
+    Value::Integer message_id, Value::String const & affected_sop_class_uid,
+    Value::String const & affected_sop_instance_uid,
+    Value::Integer priority, DataSet const & dataset)
+: Request(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);
+    this->set_priority(priority);
+
+    if(dataset.empty())
+    {
+        throw Exception("Data set is required");
+    }
+    this->set_data_set(dataset);
+}
+
+CStoreRequest
+::CStoreRequest(Message const & message)
+: Request(message)
+{
+    if(message.get_command_field() != Command::C_STORE_RQ)
+    {
+        throw Exception("Message is not a C-STORE-RQ");
+    }
+    this->set_command_field(message.get_command_field());
+
+    this->set_affected_sop_class_uid(
+        message.get_command_set().as_string(registry::AffectedSOPClassUID, 0));
+    this->set_affected_sop_instance_uid(
+        message.get_command_set().as_string(registry::AffectedSOPInstanceUID, 0));
+    this->set_priority(message.get_command_set().as_int(registry::Priority, 0));
+
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), move_originator_ae_title,
+        registry::MoveOriginatorApplicationEntityTitle, as_string)
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), move_originator_message_id,
+        registry::MoveOriginatorMessageID, as_int)
+
+    if(!message.has_data_set() || message.get_data_set().empty())
+    {
+        throw Exception("Data set is required");
+    }
+    this->set_data_set(message.get_data_set());
+}
+
+CStoreRequest
+::~CStoreRequest()
+{
+    // Nothing to do.
+}
+
+}
diff --git a/src/dcmtkpp/CStoreRequest.h b/src/dcmtkpp/CStoreRequest.h
new file mode 100644
index 0000000..169e126
--- /dev/null
+++ b/src/dcmtkpp/CStoreRequest.h
@@ -0,0 +1,61 @@
+/*************************************************************************
+ * dcmtkpp - 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 _b85a19af_b74d_4c96_89a0_f30a41b790b3
+#define _b85a19af_b74d_4c96_89a0_f30a41b790b3
+
+#include <string>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/ofstd/oftypes.h>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Request.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief C-STORE-RQ message.
+class CStoreRequest: public Request
+{
+public:
+    /**
+     * @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 const & dataset);
+
+    /**
+     * @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 Destructor.
+    virtual ~CStoreRequest();
+    
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
+        affected_sop_class_uid, registry::AffectedSOPClassUID)
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_STRING_MACRO(
+        affected_sop_instance_uid, registry::AffectedSOPInstanceUID)
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(priority, registry::Priority)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_STRING_MACRO(
+        move_originator_ae_title, registry::MoveOriginatorApplicationEntityTitle)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(
+        move_originator_message_id, registry::MoveOriginatorMessageID)
+};
+
+}
+
+#endif // _b85a19af_b74d_4c96_89a0_f30a41b790b3
diff --git a/src/dcmtkpp/CStoreResponse.cpp b/src/dcmtkpp/CStoreResponse.cpp
new file mode 100644
index 0000000..1c3a4b7
--- /dev/null
+++ b/src/dcmtkpp/CStoreResponse.cpp
@@ -0,0 +1,59 @@
+/*************************************************************************
+ * dcmtkpp - 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 "CStoreResponse.h"
+
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Response.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+CStoreResponse
+::CStoreResponse(
+    Value::Integer message_id_being_responded_to, Value::Integer status)
+: Response(message_id_being_responded_to, status)
+{
+    this->set_command_field(Command::C_STORE_RSP);
+}
+
+CStoreResponse
+::CStoreResponse(Message const & message)
+: Response(message)
+{
+    if(message.get_command_field() != Command::C_STORE_RSP)
+    {
+        throw Exception("Message is not a C-STORE-RSP");
+    }
+    this->set_command_field(message.get_command_field());
+
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), message_id, registry::MessageID, as_int)
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(), affected_sop_class_uid,
+        registry::AffectedSOPClassUID, as_string)
+    DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(
+        message.get_command_set(),
+        affected_sop_instance_uid, registry::AffectedSOPInstanceUID, as_string)
+
+    if(message.has_data_set()  && !message.get_data_set().empty())
+    {
+        throw Exception("Data set must not be present");
+    }
+    this->delete_data_set();
+}
+
+CStoreResponse
+::~CStoreResponse()
+{
+    // Nothing to do.
+}
+
+}
diff --git a/src/dcmtkpp/CStoreResponse.h b/src/dcmtkpp/CStoreResponse.h
new file mode 100644
index 0000000..0565073
--- /dev/null
+++ b/src/dcmtkpp/CStoreResponse.h
@@ -0,0 +1,48 @@
+/*************************************************************************
+ * dcmtkpp - 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 _7e193624_081c_47dd_a011_986e96916ea9
+#define _7e193624_081c_47dd_a011_986e96916ea9
+
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Response.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief C-STORE-RSP message.
+class CStoreResponse: public Response
+{
+public:
+    /**
+     * @brief Create an store response with given Message ID, and status.
+     */
+    CStoreResponse(
+        Value::Integer message_id_being_responded_to, Value::Integer status);
+
+    /**
+     * @brief Create a C-STORE-RSP from a generic Message.
+     *
+     * Raise an exception if the Message does not contain a C-STORE-RSP.
+     */
+    CStoreResponse(Message const & message);
+
+    /// @brief Destructor.
+    virtual ~CStoreResponse();
+
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(message_id, registry::MessageID)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_STRING_MACRO(
+        affected_sop_class_uid, registry::AffectedSOPClassUID)
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_STRING_MACRO(
+        affected_sop_instance_uid, registry::AffectedSOPInstanceUID)
+};
+
+}
+
+#endif // _7e193624_081c_47dd_a011_986e96916ea9
diff --git a/src/dcmtkpp/Cancellation.cpp b/src/dcmtkpp/Cancellation.cpp
new file mode 100644
index 0000000..af23345
--- /dev/null
+++ b/src/dcmtkpp/Cancellation.cpp
@@ -0,0 +1,46 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/Cancellation.h"
+
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+Cancellation
+::Cancellation(Uint16 message_id_being_responded_to)
+: Message()
+{
+    this->set_command_field(Command::C_CANCEL_RQ);
+    this->set_message_id_being_responded_to(message_id_being_responded_to);
+}
+
+Cancellation
+::Cancellation(Message const & message)
+{
+    if(message.get_command_field() != Command::C_CANCEL_RQ)
+    {
+        throw Exception("Message is not a C-CANCEL-RQ");
+    }
+    this->set_command_field(message.get_command_field());
+
+    this->set_message_id_being_responded_to(
+        message.get_command_set().as_int(registry::MessageIDBeingRespondedTo, 0));
+}
+
+Cancellation
+::~Cancellation()
+{
+    // Nothing to do.
+}
+
+}
diff --git a/src/dcmtkpp/Cancellation.h b/src/dcmtkpp/Cancellation.h
new file mode 100644
index 0000000..d34d4f9
--- /dev/null
+++ b/src/dcmtkpp/Cancellation.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ * dcmtkpp - 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 _97fc1bfc_4cff_40f2_a1ed_4550c71a0bda
+#define _97fc1bfc_4cff_40f2_a1ed_4550c71a0bda
+
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief Base class for cancellation messages.
+class Cancellation: public Message
+{
+public:
+    /// @brief Create a response with given message id being responded to.
+    Cancellation(Uint16 message_id_being_responded_to);
+
+    /**
+     * @brief Create a response from the Message ID Being Responded To.
+     *
+     * Raise an exception is this element is missing.
+     */
+    Cancellation(Message const & message);
+
+    /// @brief Destructor.
+    ~Cancellation();
+
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(
+        message_id_being_responded_to, registry::MessageIDBeingRespondedTo);
+};
+
+}
+
+#endif // _97fc1bfc_4cff_40f2_a1ed_4550c71a0bda
diff --git a/src/dcmtkpp/DataSet.cpp b/src/dcmtkpp/DataSet.cpp
new file mode 100644
index 0000000..120462e
--- /dev/null
+++ b/src/dcmtkpp/DataSet.cpp
@@ -0,0 +1,308 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/DataSet.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcdicent.h>
+#include <dcmtk/dcmdata/dcdict.h>
+#include <dcmtk/dcmdata/dctagkey.h>
+
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/Tag.h"
+#include "dcmtkpp/VR.h"
+
+namespace dcmtkpp
+{
+
+DataSet
+::DataSet()
+{
+    // Nothing to do.
+}
+
+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(::dcmtkpp::is_int(vr))
+    {
+        value = Value::Integers();
+    }
+    else if(::dcmtkpp::is_real(vr))
+    {
+        value = Value::Reals();
+    }
+    else if(::dcmtkpp::is_string(vr))
+    {
+        value = Value::Strings();
+    }
+    else if(::dcmtkpp::is_binary(vr))
+    {
+        value = Value::Binary();
+    }
+    else if(vr == VR::SQ)
+    {
+        value = Value::DataSets();
+    }
+    else
+    {
+        throw Exception("Unknown VR: "+::dcmtkpp::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);
+    }
+    this->add(tag, Element(value, vr));
+}
+
+void
+DataSet
+::add(Tag const & tag, Value::Reals 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::Strings 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::DataSets 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::Binary 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<int> 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::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)
+{
+    if(vr == VR::UNKNOWN)
+    {
+        vr = as_vr(tag);
+    }
+    this->add(tag, Element(value, vr));
+}
+
+void
+DataSet
+::remove(Tag const & tag)
+{
+    if(!this->has(tag))
+    {
+        throw Exception("No such element");
+    }
+
+    this->_elements.erase(tag);
+}
+
+bool
+DataSet
+::empty() const
+{
+    return this->_elements.empty();
+}
+
+std::size_t
+DataSet
+::size() const
+{
+    return this->_elements.size();
+}
+
+Element const &
+DataSet
+::operator[](Tag const & tag) const
+{
+    ElementMap::const_iterator const it = this->_elements.find(tag);
+    if(it == this->_elements.end())
+    {
+        throw Exception("No such element");
+    }
+
+    return it->second;
+}
+
+Element &
+DataSet
+::operator[](Tag const & tag)
+{
+    ElementMap::iterator it = this->_elements.find(tag);
+    if(it == this->_elements.end())
+    {
+        throw Exception("No such element");
+    }
+
+    return it->second;
+}
+
+bool
+DataSet
+::has(Tag const & tag) const
+{
+    return (this->_elements.find(tag) != this->_elements.end());
+}
+
+VR
+DataSet
+::get_vr(Tag const & tag) const
+{
+    ElementMap::const_iterator const it = this->_elements.find(tag);
+    if(it == this->_elements.end())
+    {
+        throw Exception("No such element");
+    }
+
+    return it->second.vr;
+}
+
+bool
+DataSet
+::empty(Tag const & tag) const
+{
+    ElementMap::const_iterator const it = this->_elements.find(tag);
+    if(it == this->_elements.end())
+    {
+        throw Exception("No such element");
+    }
+
+    return it->second.empty();
+}
+
+std::size_t
+DataSet
+::size(Tag const & tag) const
+{
+    ElementMap::const_iterator const it = this->_elements.find(tag);
+    if(it == this->_elements.end())
+    {
+        throw Exception("No such element");
+    }
+
+    return it->second.size();
+}
+
+bool
+DataSet
+::operator==(DataSet const & other) const
+{
+    return (this->_elements == other._elements);
+}
+
+bool
+DataSet
+::operator!=(DataSet const & other) const
+{
+    return !(*this == other);
+}
+
+}
diff --git a/src/dcmtkpp/DataSet.h b/src/dcmtkpp/DataSet.h
new file mode 100644
index 0000000..2114f86
--- /dev/null
+++ b/src/dcmtkpp/DataSet.h
@@ -0,0 +1,200 @@
+/*************************************************************************
+ * dcmtkpp - 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 _8424446e_1153_4acc_9f57_e86faa7246e3
+#define _8424446e_1153_4acc_9f57_e86faa7246e3
+
+#include <cstddef>
+#include <cstdint>
+#include <initializer_list>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "dcmtkpp/Element.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+#define dcmtkppElementTypeMacro(name, Type) \
+bool is_##name(Tag const & tag) const \
+{ \
+    auto const it = this->_elements.find(tag); \
+    if(it == this->_elements.end()) \
+    { \
+        throw Exception("No such element"); \
+    } \
+    return it->second.is_##name(); \
+} \
+Value::Type const & as_##name(Tag const & tag) const \
+{ \
+    auto const it = this->_elements.find(tag); \
+    if(it == this->_elements.end()) \
+    { \
+        throw Exception("No such element"); \
+    } \
+    return it->second.as_##name(); \
+} \
+Value::Type::value_type const & as_##name(Tag const & tag, int position) const \
+{ \
+    auto const & data = this->as_##name(tag); \
+    if(data.size() <= position) \
+    { \
+        throw Exception("No such element"); \
+    } \
+    return data[position]; \
+} \
+Value::Type & as_##name(Tag const & tag) \
+{ \
+    auto const it = this->_elements.find(tag); \
+    if(it == this->_elements.end()) \
+    { \
+        throw Exception("No such element"); \
+    } \
+    return it->second.as_##name(); \
+}
+
+/**
+ * @brief DICOM Data set.
+ */
+class DataSet
+{
+public:
+    /// @brief Create an empty data set.
+    DataSet();
+
+    /// @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);
+
+    /// @brief Add an element to the dataset.
+    void add(
+        Tag const & tag, Value::DataSets const & value, VR vr=VR::UNKNOWN);
+
+    /// @brief Add an element to the dataset.
+    void add(
+        Tag const & tag, Value::Binary const & value, VR vr=VR::UNKNOWN);
+
+    /// @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 element to the dataset.
+    void add(
+        Tag const & tag, std::initializer_list<Value::Integer> const & value,
+        VR vr=VR::UNKNOWN);
+
+    /// @brief Add an element to the dataset.
+    void add(
+        Tag const & tag, std::initializer_list<Value::Real> const & value,
+        VR vr=VR::UNKNOWN);
+
+    /// @brief Add an element to the dataset.
+    void add(
+        Tag const & tag, std::initializer_list<Value::String> const & value,
+        VR vr=VR::UNKNOWN);
+
+    /// @brief Add an element to the dataset.
+    void add(
+        Tag const & tag, std::initializer_list<DataSet> const & value,
+        VR vr=VR::UNKNOWN);
+
+    /**
+     * @brief Remove an element from the data set.
+     *
+     * If the element is not in the data set, a dcmtkpp::Exception is raised.
+     */
+    void remove(Tag const & tag);
+
+    /// @brief Test whether the data set is empty.
+    bool empty() const;
+
+    /// @brief Return the number of elements in the data set.
+    std::size_t size() const;
+
+    /// @brief Test whether an element is in the data set.
+    bool has(Tag const & tag) const;
+
+    /**
+     * @brief Return the VR of an element in the data set.
+     *
+     * If the element is not in the data set, a dcmtkpp::Exception is raised.
+     */
+    VR get_vr(Tag const & tag) const;
+
+    /**
+     * @brief Test whether an element of the data set is empty.
+     *
+     * If the element is not in the data set, a dcmtkpp::Exception is raised.
+     */
+    bool empty(Tag const & tag) const;
+
+    /**
+     * @brief Return the number of values in an element of the data set.
+     *
+     * If the element is not in the data set, a dcmtkpp::Exception is raised.
+     */
+    std::size_t size(Tag const & tag) const;
+
+    /**
+     * @brief Access the given element.
+     *
+     * If the element is not in the data set, a dcmtkpp::Exception is raised.
+     */
+    Element const & operator[](Tag const & tag) const;
+
+    /**
+     * @brief Access the given element.
+     *
+     * If the element is not in the data set, a dcmtkpp::Exception is raised.
+     */
+    Element & operator[](Tag const & tag);
+
+    dcmtkppElementTypeMacro(int, Integers);
+    dcmtkppElementTypeMacro(real, Reals);
+    dcmtkppElementTypeMacro(string, Strings);
+    dcmtkppElementTypeMacro(data_set, DataSets);
+    dcmtkppElementTypeMacro(binary, Binary);
+
+    typedef std::map<Tag, Element>::const_iterator const_iterator;
+    const_iterator begin() const { return this->_elements.begin(); }
+    const_iterator end() const { return this->_elements.end(); }
+
+    // FIXME: AT, binary
+
+    /// @brief Equality test
+    bool operator==(DataSet const & other) const;
+
+    /// @brief Difference test
+    bool operator!=(DataSet const & other) const;
+
+private:
+    typedef std::map<Tag, Element> ElementMap;
+
+    ElementMap _elements;
+};
+
+}
+
+#endif // _8424446e_1153_4acc_9f57_e86faa7246e3
diff --git a/src/dcmtkpp/Element.cpp b/src/dcmtkpp/Element.cpp
new file mode 100644
index 0000000..ab58fd7
--- /dev/null
+++ b/src/dcmtkpp/Element.cpp
@@ -0,0 +1,236 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/Element.h"
+
+#include "dcmtkpp/Value.h"
+#include "dcmtkpp/DataSet.h"
+
+namespace dcmtkpp
+{
+
+Element
+::Element(Value const & value, VR const & vr)
+: _value(value), vr(vr)
+{
+    // Nothing else
+}
+
+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)
+: _value(value), vr(vr)
+{
+    // Nothing else
+}
+
+Element
+::Element(Value::DataSets const & value, VR const & vr)
+: _value(value), vr(vr)
+{
+    // Nothing else
+}
+
+Element
+::Element(Value::Binary const & value, VR const & vr)
+: _value(value), vr(vr)
+{
+    // Nothing else
+}
+
+Element
+::Element(std::initializer_list<int> const & value, VR const & vr)
+: _value(value), vr(vr)
+{
+    // 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)
+{
+    // Nothing else
+}
+
+bool
+Element
+::empty() const
+{
+    return (
+        (this->_value.get_type() == Value::Type::Empty) ||
+        apply_visitor(Empty(), this->_value));
+}
+
+std::size_t
+Element
+::size() const
+{
+    return (
+        (this->_value.get_type() == Value::Type::Empty)?0:
+        apply_visitor(Size(), this->_value));
+}
+
+Value const &
+Element
+::get_value() const
+{
+    return this->_value;
+}
+
+bool
+Element
+::is_int() const
+{
+    return (this->_value.get_type() == Value::Type::Integers);
+}
+
+Value::Integers const &
+Element
+::as_int() const
+{
+    return this->_value.as_integers();
+}
+
+Value::Integers &
+Element
+::as_int()
+{
+    return this->_value.as_integers();
+}
+
+bool
+Element
+::is_real() const
+{
+    return (this->_value.get_type() == Value::Type::Reals);
+}
+
+Value::Reals const &
+Element
+::as_real() const
+{
+    return this->_value.as_reals();
+}
+
+Value::Reals &
+Element
+::as_real()
+{
+    return this->_value.as_reals();
+}
+
+bool
+Element
+::is_string() const
+{
+    return (this->_value.get_type() == Value::Type::Strings);
+}
+
+Value::Strings const &
+Element
+::as_string() const
+{
+    return this->_value.as_strings();
+}
+
+Value::Strings &
+Element
+::as_string()
+{
+    return this->_value.as_strings();
+}
+
+bool
+Element
+::is_data_set() const
+{
+    return (this->_value.get_type() == Value::Type::DataSets);
+}
+
+Value::DataSets const &
+Element
+::as_data_set() const
+{
+    return this->_value.as_data_sets();
+}
+
+Value::DataSets &
+Element::as_data_set()
+{
+    return this->_value.as_data_sets();
+}
+
+bool
+Element
+::is_binary() const
+{
+    return (this->_value.get_type() == Value::Type::Binary);
+}
+
+Value::Binary const &
+Element
+::as_binary() const
+{
+    return this->_value.as_binary();
+}
+
+Value::Binary &
+Element::as_binary()
+{
+    return this->_value.as_binary();
+}
+
+bool
+Element
+::operator==(Element const & other) const
+{
+    return (this->vr == other.vr) && (this->_value == other._value);
+}
+
+bool
+Element
+::operator!=(Element const & other) const
+{
+    return !(*this == other);
+}
+
+}
diff --git a/src/dcmtkpp/Element.h b/src/dcmtkpp/Element.h
new file mode 100644
index 0000000..9959c3b
--- /dev/null
+++ b/src/dcmtkpp/Element.h
@@ -0,0 +1,212 @@
+/*************************************************************************
+ * dcmtkpp - 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 _9c3d8f32_0310_4e3a_b5d2_6d69f229a2cf
+#define _9c3d8f32_0310_4e3a_b5d2_6d69f229a2cf
+
+#include <cstddef>
+#include <initializer_list>
+
+#include "dcmtkpp/Tag.h"
+#include "dcmtkpp/Value.h"
+#include "dcmtkpp/VR.h"
+
+namespace dcmtkpp
+{
+
+/**
+ * @brief Element of a DICOM data set.
+ */
+class 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.
+    Element(Value::Reals const & value, VR const & vr=VR::INVALID);
+
+    /// @brief Constructor.
+    Element(Value::Strings const & value, VR const & vr=VR::INVALID);
+
+    /// @brief Constructor.
+    Element(Value::DataSets const & value, VR const & vr=VR::INVALID);
+
+    /// @brief Constructor.
+    Element(Value::Binary const & value, VR const & vr=VR::INVALID);
+
+    /// @brief Constructor.
+    Element(
+        std::initializer_list<int> const & value, VR const & vr=VR::INVALID);
+
+    /// @brief Constructor.
+    Element(
+        std::initializer_list<Value::Integer> 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);
+
+    /// @brief Test whether the element is empty.
+    bool empty() const;
+
+    /// @brief Return the number of items in the value.
+    std::size_t size() const;
+
+    Value const & get_value() const;
+
+    /// @brief Test whether the value contains integers.
+    bool is_int() const;
+
+    /**
+     * @brief Return the integers contained in the element.
+     *
+     * If the element does not contain integers, a dcmtkpp::Exception is raised.
+     */
+    Value::Integers const & as_int() const;
+
+    /**
+     * @brief Return the integers contained in the element.
+     *
+     * If the element does not contain integers, a dcmtkpp::Exception is raised.
+     */
+    Value::Integers & as_int();
+
+    /// @brief Test whether the value contains reals.
+    bool is_real() const;
+
+    /**
+     * @brief Return the reals contained in the element.
+     *
+     * If the element does not contain reals, a dcmtkpp::Exception is raised.
+     */
+    Value::Reals const & as_real() const;
+
+    /**
+     * @brief Return the reals contained in the element.
+     *
+     * If the element does not contain reals, a dcmtkpp::Exception is raised.
+     */
+    Value::Reals & as_real();
+
+    /// @brief Test whether the value contains strings.
+    bool is_string() const;
+
+    /**
+     * @brief Return the strings contained in the element.
+     *
+     * If the element does not contain strings, a dcmtkpp::Exception is raised.
+     */
+    Value::Strings const & as_string() const;
+
+    /**
+     * @brief Return the strings contained in the element.
+     *
+     * If the element does not contain strings, a dcmtkpp::Exception is raised.
+     */
+    Value::Strings & as_string();
+
+    /// @brief Test whether the value contains data sets.
+    bool is_data_set() const;
+
+    /**
+     * @brief Return the data sets contained in the element.
+     *
+     * If the element does not contain data sets, a dcmtkpp::Exception is raised.
+     */
+    Value::DataSets const & as_data_set() const;
+
+    /**
+     * @brief Return the data sets contained in the element.
+     *
+     * If the element does not contain data sets, a dcmtkpp::Exception is raised.
+     */
+    Value::DataSets & as_data_set();
+
+    /// @brief Test whether the value contains data sets.
+    bool is_binary() const;
+
+    /**
+     * @brief Return the binary data contained in the element.
+     *
+     * If the element does not contain binary data, a dcmtkpp::Exception is raised.
+     */
+    Value::Binary const & as_binary() const;
+
+    /**
+     * @brief Return the binary data contained in the element.
+     *
+     * If the element does not contain binary data, a dcmtkpp::Exception is raised.
+     */
+    Value::Binary & as_binary();
+
+    /// @brief Equality test
+    bool operator==(Element const & other) const;
+
+    /// @brief Difference test
+    bool operator!=(Element const & other) const;
+
+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;
+};
+
+/**
+ * @brief Visitor of elements.
+ */
+template<typename TVisitor>
+typename TVisitor::result_type
+apply_visitor(TVisitor const & visitor, Element const & element);
+
+
+}
+
+#include "dcmtkpp/Element.txx"
+
+#endif // _9c3d8f32_0310_4e3a_b5d2_6d69f229a2cf
diff --git a/src/dcmtkpp/Element.txx b/src/dcmtkpp/Element.txx
new file mode 100644
index 0000000..2ec2f54
--- /dev/null
+++ b/src/dcmtkpp/Element.txx
@@ -0,0 +1,57 @@
+/*************************************************************************
+ * dcmtkpp - 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 _feb2071a_de26_4adb_9305_59d0dd64c970
+#define _feb2071a_de26_4adb_9305_59d0dd64c970
+
+#include "dcmtkpp/Element.h"
+
+#include <vector>
+
+#include "dcmtkpp/Exception.h"
+
+namespace dcmtkpp
+{
+
+template<typename TVisitor>
+typename TVisitor::result_type
+apply_visitor(TVisitor const & visitor, Element const & element)
+{
+    if(element.empty())
+    {
+        return visitor(element.vr);
+    }
+    else if(is_string(element.vr))
+    {
+        return visitor(element.vr, element.as_string());
+    }
+    else if(is_real(element.vr))
+    {
+        return visitor(element.vr, element.as_real());
+    }
+    else if(is_int(element.vr))
+    {
+        return visitor(element.vr, element.as_int());
+    }
+    else if(element.vr == VR::SQ)
+    {
+        return visitor(element.vr, element.as_data_set());
+    }
+    else if(is_binary(element.vr))
+    {
+        return visitor(element.vr, element.as_binary());
+    }
+    else
+    {
+        throw Exception("Unknown VR: "+as_string(element.vr));
+    }
+}
+
+}
+
+#endif // _feb2071a_de26_4adb_9305_59d0dd64c970
diff --git a/src/dcmtkpp/ElementAccessor.cpp b/src/dcmtkpp/ElementAccessor.cpp
new file mode 100644
index 0000000..fa9e2c5
--- /dev/null
+++ b/src/dcmtkpp/ElementAccessor.cpp
@@ -0,0 +1,39 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/ElementAccessor.h"
+
+#include <string>
+#include <vector>
+
+namespace dcmtkpp
+{
+
+#define DEFINE_ELEMENT_ACCESSOR(TValueType, getter, setter) \
+template<> \
+ElementAccessor<TValueType>::GetterType const \
+ElementAccessor<TValueType>\
+::element_get = getter<TValueType>; \
+\
+template<> \
+ElementAccessor<TValueType>::SetterType const \
+ElementAccessor<TValueType>\
+::element_set = setter<TValueType>;
+
+DEFINE_ELEMENT_ACCESSOR(std::string, get_string, set_string)
+DEFINE_ELEMENT_ACCESSOR(std::vector<uint8_t>, get_binary, set_binary)
+DEFINE_ELEMENT_ACCESSOR(Float32, get_default, set_default)
+DEFINE_ELEMENT_ACCESSOR(Float64, get_default, set_default)
+DEFINE_ELEMENT_ACCESSOR(Sint16, get_default, set_default)
+DEFINE_ELEMENT_ACCESSOR(Sint32, get_default, set_default)
+DEFINE_ELEMENT_ACCESSOR(Uint16, get_default, set_default)
+DEFINE_ELEMENT_ACCESSOR(Uint32, get_default, set_default)
+
+#undef DEFINE_ELEMENT_ACCESSOR
+
+}
diff --git a/src/dcmtkpp/ElementAccessor.h b/src/dcmtkpp/ElementAccessor.h
new file mode 100644
index 0000000..784614c
--- /dev/null
+++ b/src/dcmtkpp/ElementAccessor.h
@@ -0,0 +1,63 @@
+/*************************************************************************
+ * dcmtkpp - 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 _dfa4858b_1c9d_4ce9_b220_a1c15d873602
+#define _dfa4858b_1c9d_4ce9_b220_a1c15d873602
+
+#include <functional>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcelem.h>
+#include <dcmtk/dcmdata/dcdatset.h>
+
+#include "dcmtkpp/ElementTraits.h"
+#include "dcmtkpp/Exception.h"
+
+namespace dcmtkpp
+{
+
+/// @brief Generic access to values in DcmElement.
+template<typename TValueType>
+struct ElementAccessor
+{
+    /// @brief C++ type of the VR.
+    typedef TValueType ValueType;
+
+    /// @brief Getter type.
+    typedef std::function<
+        ValueType(DcmElement const &, unsigned long const)> GetterType;
+
+    /// @brief Return the value in the element.
+    static 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;
+
+    /// @brief Test whether the data set contains a given tag.
+    static bool has(DcmDataset const & dataset, DcmTagKey const & tag);
+
+    /// @brief Return the value of an element in a dataset.
+    static ValueType get(
+        DcmDataset const & dataset,
+        DcmTagKey const tag, unsigned int const position=0);
+
+    /// @brief Set the value of an element in a dataset.
+    static void set(
+        DcmDataset & dataset,
+        DcmTagKey const tag, ValueType const & value, unsigned int const position=0);
+};
+
+}
+
+#include "ElementAccessor.txx"
+
+#endif // _dfa4858b_1c9d_4ce9_b220_a1c15d873602
diff --git a/src/dcmtkpp/ElementAccessor.txx b/src/dcmtkpp/ElementAccessor.txx
new file mode 100644
index 0000000..586280a
--- /dev/null
+++ b/src/dcmtkpp/ElementAccessor.txx
@@ -0,0 +1,207 @@
+/*************************************************************************
+ * dcmtkpp - 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 _f9af3e63_3597_4513_8c10_b55058f5370b
+#define _f9af3e63_3597_4513_8c10_b55058f5370b
+
+#include "ElementAccessor.h"
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcdatset.h>
+#include <dcmtk/dcmdata/dcelem.h>
+#include <dcmtk/dcmdata/dcerror.h>
+#include <dcmtk/ofstd/ofstring.h>
+
+namespace dcmtkpp
+{
+
+template<typename TValueType>
+bool
+ElementAccessor<TValueType>
+::has(DcmDataset const & dataset, DcmTagKey const & tag)
+{
+    DcmElement * dummy;
+    OFCondition const condition =
+        const_cast<DcmDataset&>(dataset).findAndGetElement(tag, dummy);
+    if(condition.good())
+    {
+        return true;
+    }
+    else if(condition == EC_TagNotFound)
+    {
+        return false;
+    }
+    else
+    {
+        throw Exception(condition);
+    }
+}
+
+template<typename TValueType>
+TValueType
+ElementAccessor<TValueType>
+::get(
+    DcmDataset const & dataset,
+    DcmTagKey const tag, unsigned int const position)
+{
+    DcmElement * element;
+    OFCondition const condition =
+        const_cast<DcmDataset &>(dataset).findAndGetElement(tag, element);
+    if(condition.bad())
+    {
+        throw Exception(condition);
+    }
+
+    return element_get(*element, position);
+}
+
+template<typename TValueType>
+void
+ElementAccessor<TValueType>
+::set(
+    DcmDataset & dataset,
+    DcmTagKey const tag, ValueType const & value, unsigned int const position)
+{
+    DcmElement * element;
+    OFCondition const get_condition = dataset.findAndGetElement(tag, element);
+    if(get_condition.bad())
+    {
+        OFCondition const insert_condition = dataset.insertEmptyElement(tag);
+        if(insert_condition.bad())
+        {
+            throw Exception(insert_condition);
+        }
+
+        OFCondition const new_get_condition =
+            dataset.findAndGetElement(tag, element);
+        if(new_get_condition.bad())
+        {
+            throw Exception(insert_condition);
+        }
+    }
+
+    element_set(*element, value, position);
+}
+
+template<typename TValueType>
+TValueType
+get_default(DcmElement const & element, unsigned long const position)
+{
+    TValueType value;
+    OFCondition const & condition =
+        ElementTraits<TValueType>::getter(
+            const_cast<DcmElement&>(element), value, position);
+    if(condition.bad())
+    {
+        throw Exception(condition);
+    }
+
+    return value;
+}
+
+template<typename TValueType>
+void
+set_default(
+    DcmElement & element, TValueType const & value,
+    unsigned long const position)
+{
+    OFCondition const condition = ElementTraits<TValueType>::setter(element, value, position);
+    if(condition.bad())
+    {
+        throw Exception(condition);
+    }
+}
+
+template<typename TValueType>
+TValueType
+get_string(DcmElement const & element, unsigned long const position)
+{
+    OFString value;
+    ElementTraits<OFString>::getter(const_cast<DcmElement&>(element), value, position);
+
+    return std::string(value.c_str());
+}
+
+template<typename TValueType>
+void
+set_string(
+    DcmElement & element, TValueType const & value,
+    unsigned long const position)
+{
+    OFString const value_dcmtk(value.c_str(), value.size());
+    OFCondition const condition = ElementTraits<OFString>::setter(
+        element, value_dcmtk, position);
+    if(condition.bad())
+    {
+        throw Exception(condition);
+    }
+}
+
+template<typename TValueType>
+TValueType
+get_binary(DcmElement const & element, unsigned long const position)
+{
+    if(position != 0)
+    {
+        throw Exception("Position must be 0 for binary VRs");
+    }
+
+    DcmEVR const evr = element.getTag().getVR().getValidEVR();
+
+    TValueType result;
+    OFCondition condition;
+
+    typename TValueType::value_type * data=NULL;
+    if(evr == EVR_OB || evr == EVR_UN)
+    {
+        Uint8 * typed_data;
+        condition = const_cast<DcmElement&>(element).getUint8Array(typed_data);
+        data = reinterpret_cast<typename TValueType::value_type *>(typed_data);
+    }
+    else if(evr == EVR_OW)
+    {
+        Uint16 * typed_data;
+        condition = const_cast<DcmElement&>(element).getUint16Array(typed_data);
+        data = reinterpret_cast<typename TValueType::value_type *>(typed_data);
+    }
+    else if(evr == EVR_OF)
+    {
+        Float32 * typed_data;
+        condition = const_cast<DcmElement&>(element).getFloat32Array(typed_data);
+        data = reinterpret_cast<typename TValueType::value_type *>(typed_data);
+    }
+    else
+    {
+        throw Exception(
+            std::string("Unknown VR: ") +
+            element.getTag().getVR().getValidVRName());
+    }
+
+    if(condition.bad())
+    {
+        throw Exception(condition);
+    }
+
+    result.resize(element.getLengthField());
+    std::copy(data, data+element.getLengthField(), result.begin());
+
+    return result;
+}
+
+template<typename TValueType>
+void
+set_binary(
+    DcmElement & element, TValueType const & value,
+    unsigned long const position)
+{
+
+}
+
+}
+
+#endif // _f9af3e63_3597_4513_8c10_b55058f5370b
diff --git a/src/dcmtkpp/ElementTraits.cpp b/src/dcmtkpp/ElementTraits.cpp
new file mode 100644
index 0000000..37492fd
--- /dev/null
+++ b/src/dcmtkpp/ElementTraits.cpp
@@ -0,0 +1,77 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/ElementTraits.h"
+
+#include <functional>
+#include <string>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcelem.h>
+#include <dcmtk/dcmdata/dcvr.h>
+
+#include "dcmtkpp/Exception.h"
+
+namespace dcmtkpp
+{
+
+OFCondition
+getString(DcmElement & element, OFString & value, unsigned long const position)
+{
+    OFCondition condition;
+
+    DcmEVR const evr = element.getTag().getVR().getValidEVR();
+    if(evr == EVR_OB || evr == EVR_OF || evr == EVR_OW || evr == EVR_UN)
+    {
+        if(position != 0)
+        {
+            throw Exception("Position must be 0 for binary VRs");
+        }
+        condition = element.getOFStringArray(value);
+    }
+    else
+    {
+         condition = element.getOFString(value, position);
+    }
+
+    return condition;
+}
+
+OFCondition
+putString(DcmElement & element, OFString const value, unsigned long const position)
+{
+    if(position != 0)
+    {
+        throw Exception("Position must be 0");
+    }
+
+    return element.putOFStringArray(value);
+}
+
+#define DEFINE_ELEMENT_TRAITS(TValueType, getter_, setter_) \
+template<> \
+ElementTraits<TValueType>::GetterType const \
+ElementTraits<TValueType>\
+::getter = getter_; \
+\
+template<> \
+ElementTraits<TValueType>::SetterType const \
+ElementTraits<TValueType>\
+::setter = setter_;
+
+DEFINE_ELEMENT_TRAITS(OFString, getString, putString)
+DEFINE_ELEMENT_TRAITS(Float32, &DcmElement::getFloat32, &DcmElement::putFloat32)
+DEFINE_ELEMENT_TRAITS(Float64, &DcmElement::getFloat64, &DcmElement::putFloat64)
+DEFINE_ELEMENT_TRAITS(Sint16, &DcmElement::getSint16, &DcmElement::putSint16)
+DEFINE_ELEMENT_TRAITS(Sint32, &DcmElement::getSint32, &DcmElement::putSint32)
+DEFINE_ELEMENT_TRAITS(Uint16, &DcmElement::getUint16, &DcmElement::putUint16)
+DEFINE_ELEMENT_TRAITS(Uint32, &DcmElement::getUint32, &DcmElement::putUint32)
+
+#undef DEFINE_ELEMENT_TRAITS
+
+}
diff --git a/src/dcmtkpp/ElementTraits.h b/src/dcmtkpp/ElementTraits.h
new file mode 100644
index 0000000..60c4904
--- /dev/null
+++ b/src/dcmtkpp/ElementTraits.h
@@ -0,0 +1,47 @@
+/*************************************************************************
+ * dcmtkpp - 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 _3ae28d18_6f01_4e10_98e2_1c0d21fdcab7
+#define _3ae28d18_6f01_4e10_98e2_1c0d21fdcab7
+
+#include <functional>
+#include <string>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcelem.h>
+#include <dcmtk/dcmdata/dcvr.h>
+
+namespace dcmtkpp
+{
+
+/**
+ * @class dcmtkpp::ElementTraits
+ * @brief Traits for generic data access to values of DcmElement.
+ *
+ * The members are:
+ * - GetterType: the type of the getter function
+ * - SetterType: the type of the setter function
+ * - getter: the getter function (one of the get??? functions of DcmElement)
+ * - setter: the setter function (one of the put??? functions of DcmElement)
+ */
+template<typename TValueType>
+struct ElementTraits
+{
+    /** @brief Type of the getter function. */
+    typedef std::function<OFCondition(DcmElement &, TValueType &, unsigned long const)> GetterType;
+    /** @brief Getter function (one of the get??? functions of DcmElement). */
+    static GetterType const getter;
+    /** @brief Type of the setter function. */
+    typedef std::function<OFCondition(DcmElement &, TValueType const, unsigned long const)> SetterType;
+    /** @brief Setter function (one of the put??? functions of DcmElement). */
+    static SetterType const setter;
+};
+
+}
+
+#endif // _3ae28d18_6f01_4e10_98e2_1c0d21fdcab7
diff --git a/src/dcmtkpp/Exception.cpp b/src/dcmtkpp/Exception.cpp
new file mode 100644
index 0000000..cfe9123
--- /dev/null
+++ b/src/dcmtkpp/Exception.cpp
@@ -0,0 +1,71 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/Exception.h"
+
+#include <string>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/ofstd/ofcond.h>
+
+namespace dcmtkpp
+{
+
+Exception
+::Exception(std::string const & message)
+: _source(Source::Message), _message(message), _condition()
+{
+    // Nothing else.
+}
+
+Exception
+::Exception(OFCondition const & condition)
+: _source(Source::Condition), _message(), _condition(condition)
+{
+    // Nothing else.
+}
+
+Exception
+::~Exception() throw()
+{
+    // Nothing to do.
+}
+
+char const * 
+Exception
+::what() const throw()
+{
+    if(this->_source == Source::Message)
+    {
+        return this->_message.c_str();
+    }
+    else if(this->_source == Source::Condition)
+    {
+        return this->_condition.text();
+    }
+}
+
+Exception::Source
+Exception
+::get_source() const
+{
+    return this->_source;
+}
+
+OFCondition const &
+Exception
+::get_condition() const
+{
+    if(this->_source != Source::Condition)
+    {
+        throw Exception("Wrong source");
+    }
+    return this->_condition;
+}
+
+}
diff --git a/src/dcmtkpp/Exception.h b/src/dcmtkpp/Exception.h
new file mode 100644
index 0000000..a4c9bc0
--- /dev/null
+++ b/src/dcmtkpp/Exception.h
@@ -0,0 +1,66 @@
+/*************************************************************************
+ * dcmtkpp - 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 _b9607695_cb3b_4188_8caa_bc8bb051ef28
+#define _b9607695_cb3b_4188_8caa_bc8bb051ef28
+
+#include <exception>
+#include <string>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/ofstd/ofcond.h>
+
+namespace dcmtkpp
+{
+
+/// @brief Base class for dcmtkpp exceptions.
+class Exception: public std::exception
+{
+public: 
+    /** 
+     * @brief Source of the Exception: either a message string or an 
+     * OFCondition.
+     */
+    enum class Source { Message, Condition };
+    
+    /// @brief Message string constructor, set the source to Source::Message.
+    Exception(std::string const & message);
+    
+    /// @brief Condition constructor, set the source to Source::Condition.
+    Exception(OFCondition const & condition);
+    
+    /// @brief Destructor.
+    virtual ~Exception() throw();
+    
+    /**
+     * @brief Return the reason for the exception.
+     * 
+     * The reason for the exception is set to the message (for Source::Message) or
+     * to the text of the condition (for Source::Condition).
+     */
+    virtual const char* what() const throw();
+    
+    /// @brief Return the exception source.
+    Source get_source() const;
+    
+    /**
+     * @brief Return the condition that was used to create this exception.
+     * 
+     * If the source is not Source::Condition, throw an exception.
+     */
+    OFCondition const & get_condition() const;
+
+private:
+    Source _source;
+    std::string _message;
+    OFCondition _condition;
+};
+
+}
+
+#endif // _b9607695_cb3b_4188_8caa_bc8bb051ef28
diff --git a/src/dcmtkpp/FindSCU.cpp b/src/dcmtkpp/FindSCU.cpp
new file mode 100644
index 0000000..e5650f0
--- /dev/null
+++ b/src/dcmtkpp/FindSCU.cpp
@@ -0,0 +1,87 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/FindSCU.h"
+
+#include <functional>
+#include <sstream>
+#include <vector>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/CFindRequest.h"
+#include "dcmtkpp/CFindResponse.h"
+
+namespace dcmtkpp
+{
+
+FindSCU
+::~FindSCU()
+{
+    // Nothing to do
+}
+
+void 
+FindSCU
+::find(DataSet const & query, Callback callback) const
+{
+    CFindRequest request(
+        this->_association->get_association()->nextMsgID++,
+        this->_affected_sop_class, Message::Priority::MEDIUM, query);
+    this->_send(request, this->_affected_sop_class);
+
+    // Receive the responses
+    bool done = false;
+    while(!done)
+    {
+        // FIXME: include progress callback
+        auto response = this->_receive<CFindResponse>();
+
+        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());
+        }
+        if(response.has_affected_sop_class_uid() &&
+           response.get_affected_sop_class_uid() != request.get_affected_sop_class_uid())
+        {
+            std::ostringstream message;
+            message << "DIMSE: Unexpected Response Affected SOP Class UID: "
+                    << response.get_affected_sop_class_uid()
+                    << " (expected: " << request.get_affected_sop_class_uid() << ")";
+            throw Exception(message.str());
+        }
+
+        done = !DICOM_PENDING_STATUS(response.get_status());
+        if(!done)
+        {
+            callback(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/dcmtkpp/FindSCU.h b/src/dcmtkpp/FindSCU.h
new file mode 100644
index 0000000..f1fa84e
--- /dev/null
+++ b/src/dcmtkpp/FindSCU.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ * dcmtkpp - 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 _0106eb3a_4e02_4d7c_93bf_4d53dcafbb05
+#define _0106eb3a_4e02_4d7c_93bf_4d53dcafbb05
+
+#include <vector>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/SCU.h"
+
+namespace dcmtkpp
+{
+
+/// @brief SCU for C-FIND services.
+class FindSCU: public SCU
+{
+public:
+    /// @brief Callback called when a response is received.
+    typedef std::function<void(DataSet const &)> Callback;
+    
+    /// @brief Destructor.
+    virtual ~FindSCU();
+    
+    /// @brief Perform the C-FIND using an optional callback.
+    void find(DataSet const & 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;
+};
+
+}
+
+#endif // _0106eb3a_4e02_4d7c_93bf_4d53dcafbb05
diff --git a/src/dcmtkpp/GetSCU.cpp b/src/dcmtkpp/GetSCU.cpp
new file mode 100644
index 0000000..52fa1fb
--- /dev/null
+++ b/src/dcmtkpp/GetSCU.cpp
@@ -0,0 +1,105 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/GetSCU.h"
+
+#include <functional>
+#include <sstream>
+#include <vector>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CGetRequest.h"
+#include "dcmtkpp/CGetResponse.h"
+#include "dcmtkpp/CStoreRequest.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+
+namespace dcmtkpp
+{
+
+GetSCU
+::~GetSCU()
+{
+    // Nothing to do
+}
+
+void 
+GetSCU
+::get(DataSet const & query, Callback callback) const
+{
+    // Send the request
+    CGetRequest request(this->_association->get_association()->nextMsgID++,
+        this->_affected_sop_class, Message::Priority::MEDIUM, query);
+    this->_send(request, this->_affected_sop_class);
+    
+    // Receive the responses
+    bool done = false;
+    while(!done)
+    {
+        Message const message = this->_receive();
+
+        if(message.get_command_field() == Message::Command::C_GET_RSP)
+        {
+            done = this->_get_response(CGetResponse(message));
+        }
+        else if(message.get_command_field() == Message::Command::C_STORE_RQ)
+        {
+            try
+            {
+                this->_store_request(CStoreRequest(message), callback);
+            }
+            catch(...)
+            {
+                // FIXME: logging
+                done = true;
+            }
+        }
+        else
+        {
+            std::ostringstream exception_message;
+            exception_message << "DIMSE: Unexpected Response Command Field: 0x"
+                              << std::hex << message.get_command_field();
+            throw Exception(exception_message.str());
+        }
+    }
+}
+
+std::vector<DataSet>
+GetSCU
+::get(DataSet const & query) const
+{
+    std::vector<DataSet> result;
+    auto callback = [&result](DataSet const & dataset) {
+        result.push_back(dataset);
+    };
+    this->get(query, callback);
+    
+    return result;
+}
+
+bool
+GetSCU
+::_get_response(CGetResponse const & response) const
+{
+    bool const done = (response.get_status() != STATUS_Pending);
+    return done;
+}
+
+void
+GetSCU
+::_store_request(CStoreRequest const & request, Callback callback) const
+{
+    StoreSCP scp;
+    scp.set_network(this->get_network());
+    scp.set_association(this->get_association());
+    scp.store(request, callback);
+}
+
+}
diff --git a/src/dcmtkpp/GetSCU.h b/src/dcmtkpp/GetSCU.h
new file mode 100644
index 0000000..acc72bf
--- /dev/null
+++ b/src/dcmtkpp/GetSCU.h
@@ -0,0 +1,49 @@
+/*************************************************************************
+ * dcmtkpp - 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 _f82a15e2_fd13_44b5_af7d_c6983494c9c6
+#define _f82a15e2_fd13_44b5_af7d_c6983494c9c6
+
+#include "SCU.h"
+
+#include <vector>
+
+#include "dcmtkpp/CGetResponse.h"
+#include "dcmtkpp/CStoreRequest.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/StoreSCP.h"
+
+namespace dcmtkpp
+{
+
+/// @brief SCU for C-GET services.
+class GetSCU: public SCU
+{
+public:
+    /// @brief Callback called when a response is received.
+    typedef StoreSCP::Callback Callback;
+    
+    /// @brief Destructor.
+    virtual ~GetSCU();
+    
+    /// @brief Perform the C-GET using an optional callback.
+    void get(DataSet const & query, Callback callback) const;
+    
+    /**
+     * @brief Return a list of datasets matching the query.
+     */
+    std::vector<DataSet> get(DataSet const & query) const;
+
+private:
+    bool _get_response(CGetResponse const & response) const;
+    void _store_request(CStoreRequest const & request, Callback callback) const;
+};
+
+}
+
+#endif // _f82a15e2_fd13_44b5_af7d_c6983494c9c6
diff --git a/src/dcmtkpp/Message.cpp b/src/dcmtkpp/Message.cpp
new file mode 100644
index 0000000..fed075c
--- /dev/null
+++ b/src/dcmtkpp/Message.cpp
@@ -0,0 +1,94 @@
+/*************************************************************************
+ * dcmtkpp - 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 "Message.h"
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+Message
+::Message()
+{
+    this->_command_set.add(registry::CommandDataSetType, { DataSetType::ABSENT });
+}
+
+Message
+::Message(DataSet const & command_set)
+: _command_set(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)
+{
+    if(!this->_command_set.has(registry::CommandDataSetType))
+    {
+        this->_command_set.add(registry::CommandDataSetType, VR::US);
+    }
+    this->set_data_set(data_set);
+}
+
+Message
+::~Message()
+{
+    // Nothing to do.
+}
+
+DataSet const &
+Message
+::get_command_set() const
+{
+    return this->_command_set;
+}
+
+bool
+Message
+::has_data_set() const
+{
+    return (this->_command_set.as_int(registry::CommandDataSetType, 0) == DataSetType::PRESENT);
+}
+
+DataSet const &
+Message
+::get_data_set() const
+{
+    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)
+{
+    this->_data_set = 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 };
+    this->_data_set = DataSet();
+}
+
+}
diff --git a/src/dcmtkpp/Message.h b/src/dcmtkpp/Message.h
new file mode 100644
index 0000000..d540fd6
--- /dev/null
+++ b/src/dcmtkpp/Message.h
@@ -0,0 +1,178 @@
+/*************************************************************************
+ * dcmtkpp - 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 _dcfa5213_ad7e_4194_8b4b_e630aa0df2e8
+#define _dcfa5213_ad7e_4194_8b4b_e630aa0df2e8
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+#define DCMTKPP_MESSAGE_MANDATORY_FIELD_MACRO(name, tag, TValueType, function) \
+    /** @brief Return the tag element of the command set. */ \
+    TValueType const & get_##name() const \
+    { \
+        auto const & data = this->_command_set.function(tag); \
+        if(data.empty()) \
+        { \
+            throw Exception("Empty element"); \
+        } \
+        return data[0]; \
+    } \
+    /** @brief Set the tag element of the command set. */ \
+    void set_##name(TValueType const & value) \
+    { \
+        if(!this->_command_set.has(tag)) \
+        { \
+            this->_command_set.add(tag); \
+        } \
+        this->_command_set.function(tag) = { value }; \
+    }
+
+#define DCMTKPP_MESSAGE_OPTIONAL_FIELD_MACRO(name, tag, TValueType, function) \
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_MACRO(name, tag, TValueType, function) \
+    bool has_##name() const \
+    { \
+        return this->_command_set.has(tag);; \
+    } \
+    void delete_##name() \
+    { \
+        this->_command_set.remove(tag); \
+    }
+
+#define DCMTKPP_MESSAGE_SET_OPTIONAL_FIELD_MACRO(dataset, name, tag, function) \
+    if(dataset.has(tag)) \
+    { \
+        this->set_##name(dataset.function(tag, 0)); \
+    }
+
+#define DCMTKPP_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(name, tag) \
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_MACRO(name, tag, Value::Integer, as_int)
+
+#define DCMTKPP_MESSAGE_MANDATORY_FIELD_STRING_MACRO(name, tag) \
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_MACRO(name, tag, Value::String, as_string)
+
+#define DCMTKPP_MESSAGE_OPTIONAL_FIELD_INTEGER_MACRO(name, tag) \
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_MACRO(name, tag, Value::Integer, as_int)
+
+#define DCMTKPP_MESSAGE_OPTIONAL_FIELD_STRING_MACRO(name, tag) \
+    DCMTKPP_MESSAGE_OPTIONAL_FIELD_MACRO(name, tag, Value::String, as_string)
+
+/**
+ * @brief Base class for all DIMSE messages.
+ */
+class Message
+{
+public:
+    struct Command
+    {
+        enum Type
+        {
+            C_STORE_RQ = 0x0001,
+            C_STORE_RSP = 0x8001,
+
+            C_FIND_RQ = 0x0020,
+            C_FIND_RSP = 0x8020,
+
+            C_CANCEL_RQ = 0x0FFF,
+
+            C_GET_RQ = 0x0010,
+            C_GET_RSP = 0x8010,
+
+            C_MOVE_RQ = 0x0021,
+            C_MOVE_RSP = 0x8021,
+
+            C_ECHO_RQ = 0x0030,
+            C_ECHO_RSP = 0x8030,
+
+            N_EVENT_REPORT_RQ = 0x0100,
+            N_EVENT_REPORT_RSP = 0x8100,
+
+            N_GET_RQ = 0x0110,
+            N_GET_RSP = 0x8110,
+
+            N_SET_RQ = 0x0120,
+            N_SET_RSP = 0x8120,
+
+            N_ACTION_RQ = 0x0130,
+            N_ACTION_RSP = 0x8130,
+
+            N_CREATE_RQ = 0x0140,
+            N_CREATE_RSP = 0x8140,
+
+            N_DELETE_RQ = 0x0150,
+            N_DELETE_RSP = 0x8150,
+        };
+    };
+
+    struct Priority
+    {
+        enum Type
+        {
+            LOW = 0x0002,
+            MEDIUM = 0x0000,
+            HIGH = 0x0001,
+        };
+    };
+
+    struct DataSetType
+    {
+        enum Type
+        {
+            PRESENT = 0x0000,
+            ABSENT = 0x0101,
+        };
+    };
+
+    /// @brief Create a message with an empty command set and an empty data set.
+    Message();
+
+    /// @brief Create a message from existing data.
+    Message(DataSet const & command_set);
+
+    /// @brief Create a message from existing data.
+    Message(DataSet const & command_set, DataSet const & data_set);
+
+    /// @brief Destructor;
+    virtual ~Message();
+    
+    /// @brief Return the command set of the message.
+    DataSet const & get_command_set() const;
+    
+    /// @brief Test whether as data set is present in the message.
+    bool has_data_set() const;
+
+    /**
+     * @brief Return the data set of the message, raise an exception if no
+     * data set is present.
+     */
+    DataSet const & get_data_set() const;
+    
+    /// @brief Set the data set of the message.
+    void set_data_set(DataSet const & data_set);
+
+    /// @brief Delete the data set in this message.
+    void delete_data_set();
+    
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(
+        command_field, registry::CommandField)
+
+protected:
+    /// @brief Command set of the message.
+    DataSet _command_set;
+    
+    /// @brief Data set of the message.
+    DataSet _data_set;
+};
+
+}
+
+#endif // _dcfa5213_ad7e_4194_8b4b_e630aa0df2e8
diff --git a/src/dcmtkpp/MoveSCU.cpp b/src/dcmtkpp/MoveSCU.cpp
new file mode 100644
index 0000000..9181523
--- /dev/null
+++ b/src/dcmtkpp/MoveSCU.cpp
@@ -0,0 +1,162 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/MoveSCU.h"
+
+#include <vector>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CMoveRequest.h"
+#include "dcmtkpp/CMoveResponse.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/StoreSCP.h"
+
+namespace dcmtkpp
+{
+
+MoveSCU
+::MoveSCU()
+: SCU(), _move_destination("")
+{
+    // Nothing else.
+}
+
+MoveSCU
+::~MoveSCU()
+{
+    // Nothing to do
+}
+
+std::string const & 
+MoveSCU
+::get_move_destination() const
+{
+    return this->_move_destination;
+}
+
+void
+MoveSCU
+::set_move_destination(std::string const & move_destination)
+{
+    this->_move_destination = move_destination;
+}
+
+void
+MoveSCU
+::move(DataSet const & query, Callback callback) const
+{
+    // Send the request
+    CMoveRequest const request(this->_association->get_association()->nextMsgID++,
+        this->_affected_sop_class, Message::Priority::MEDIUM,
+        this->_move_destination, query);
+    this->_send(request, this->_affected_sop_class);
+    
+    // Receive the responses
+    Association store_association;
+    bool done = false;
+    while(!done)
+    {
+        // Use a small timeout to avoid blocking for a long time.
+        if(!store_association.is_associated() && 
+           this->_network->is_association_waiting(1))
+        {
+            store_association.receive(*this->_network, true);
+        }
+        
+        done = this->_dispatch(store_association, callback);
+    }
+}
+
+std::vector<DataSet>
+MoveSCU
+::move(DataSet const & query) const
+{
+    std::vector<DataSet> result;
+    auto callback = [&result](DataSet const & dataset) {
+        result.push_back(dataset);
+    };
+    this->move(query, callback);
+    
+    return result;
+}
+
+bool 
+MoveSCU
+::_dispatch(Association & association, Callback callback) const
+{
+    T_ASC_Association *associations[2];
+    int size = 0;
+
+    associations[0] = this->_association->get_association();
+    size = 1;
+    associations[1] = association.get_association();
+    if(association.is_associated())
+    {
+        ++size;
+    }
+    
+    // At this point, we should have a readable association.
+    if(!ASC_selectReadableAssociation(associations, size, 1)) 
+    {
+        throw Exception("No readable association");
+    }
+    
+    bool move_finished;
+    
+    if(associations[0] != NULL) 
+    {
+        move_finished = this->_handle_main_association();
+    }
+    else if(associations[1] != NULL) 
+    {
+        bool const release = 
+            this->_handle_store_association(association, callback);
+        if(release)
+        {
+            association.drop();
+        }
+    }
+    
+    return move_finished;
+}
+
+bool
+MoveSCU
+::_handle_main_association() const
+{
+    Message const message = this->_receive();
+    
+    if(message.get_command_field() != Message::Command::C_MOVE_RSP)
+    {
+        std::ostringstream exception_message;
+        exception_message << "DIMSE: Unexpected Response Command Field: 0x"
+                << std::hex << message.get_command_field();
+        throw Exception(exception_message.str());
+    }
+    
+    CMoveResponse const response(message);
+    bool const done = (response.get_status() != STATUS_Pending);
+    
+    return done;
+}
+
+bool
+MoveSCU
+::_handle_store_association(Association & association, Callback callback) const
+{
+    StoreSCP scp;
+    scp.set_network(this->_network);
+    scp.set_association(&association);
+    return scp.store(callback);
+}
+
+}
diff --git a/src/dcmtkpp/MoveSCU.h b/src/dcmtkpp/MoveSCU.h
new file mode 100644
index 0000000..9189309
--- /dev/null
+++ b/src/dcmtkpp/MoveSCU.h
@@ -0,0 +1,60 @@
+/*************************************************************************
+ * dcmtkpp - 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 _5ff4d940_4db7_4d85_9d3a_230b944b31fe
+#define _5ff4d940_4db7_4d85_9d3a_230b944b31fe
+
+#include <string>
+#include <vector>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/SCU.h"
+#include "dcmtkpp/StoreSCP.h"
+
+namespace dcmtkpp
+{
+
+/// @brief SCU for C-MOVE services.
+class MoveSCU: public SCU
+{
+public:
+    /// @brief Callback called when a response is received.
+    typedef StoreSCP::Callback Callback;
+    
+    /// @brief Constructor.
+    MoveSCU();
+    
+    /// @brief Destructor.
+    virtual ~MoveSCU();
+    
+    /// @brief Return the AE title of the destination, defaults to "".
+    std::string const & get_move_destination() const;
+    /// @brief Set the AE title of the destination.
+    void set_move_destination(std::string const & move_destination);
+
+    /// @brief Perform the C-MOVE using a callback.
+    void move(DataSet const & query, Callback callback) const;
+    
+    /**
+     * @brief Return a list of datasets matching the query.
+     */
+    std::vector<DataSet> move(DataSet const & query) const;
+
+private:
+    std::string _move_destination;
+    
+    bool _dispatch(Association & association, Callback callback) const;
+    
+    bool _handle_main_association() const;
+    bool _handle_store_association(Association & association, Callback callback) const;
+};
+
+}
+
+#endif // _5ff4d940_4db7_4d85_9d3a_230b944b31fe
+
diff --git a/src/dcmtkpp/Network.cpp b/src/dcmtkpp/Network.cpp
new file mode 100644
index 0000000..218b4c3
--- /dev/null
+++ b/src/dcmtkpp/Network.cpp
@@ -0,0 +1,201 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/Network.h"
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmnet/assoc.h>
+#include <dcmtk/dcmnet/cond.h>
+
+#include "dcmtkpp/Exception.h"
+
+namespace dcmtkpp
+{
+
+Network
+::Network()
+: _role(NET_REQUESTOR), _port(0), _timeout(30), _options(0), _network(NULL)
+{
+    // Nothing else.
+}
+
+Network
+::Network(T_ASC_NetworkRole role, int port, int timeout, unsigned long options)
+: _role(role), _port(port), _timeout(timeout), _options(options), _network(NULL)
+{
+    // Nothing else.
+}
+
+Network
+::Network(Network const & other)
+: _role(other.get_role()), _port(other.get_port()), 
+  _timeout(other.get_timeout()), _options(other.get_options()), _network(NULL)
+{
+    // Nothing else
+}
+
+Network
+::~Network()
+{
+    if(this->is_initialized())
+    {
+        this->drop();
+    }
+}
+
+Network &
+Network
+::operator=(Network const & other)
+{
+    if(this != &other)
+    {
+        this->set_role(other.get_role());
+        this->set_port(other.get_port());
+        this->set_timeout(other.get_timeout());
+        this->set_options(other.get_options());
+    }
+    
+    return *this;
+}
+
+T_ASC_NetworkRole
+Network
+::get_role() const
+{
+    return this->_role;
+}
+
+void
+Network
+::set_role(T_ASC_NetworkRole role)
+{
+    if(this->is_initialized())
+    {
+        throw Exception("Cannot set member while initialized");
+    }
+    
+    this->_role = role;
+}
+
+int
+Network
+::get_port() const
+{
+    return this->_port;
+}
+
+void
+Network
+::set_port(int port)
+{
+    if(this->is_initialized())
+    {
+        throw Exception("Cannot set member while initialized");
+    }
+    
+    this->_port = port;
+}
+
+int
+Network
+::get_timeout() const
+{
+    return this->_timeout;
+}
+
+void
+Network
+::set_timeout(int timeout)
+{
+    if(this->is_initialized())
+    {
+        throw Exception("Cannot set member while initialized");
+    }
+    
+    this->_timeout = timeout;
+}
+
+unsigned long
+Network
+::get_options() const
+{
+    return this->_options;
+}
+
+void
+Network
+::set_options(unsigned long options)
+{
+    if(this->is_initialized())
+    {
+        throw Exception("Cannot set member while initialized");
+    }
+    
+    this->_options = options;
+}
+
+void
+Network
+::initialize()
+{
+    if(this->is_initialized())
+    {
+        throw Exception("Already initialized");
+    }
+    
+    OFCondition const condition = ASC_initializeNetwork(
+        this->_role, this->_port, this->_timeout, &this->_network, 
+        this->_options);
+    
+    if(condition.bad())
+    {
+        throw Exception(condition);
+    }
+}
+
+T_ASC_Network *
+Network
+::get_network()
+{
+    return this->_network;
+}
+
+bool 
+Network
+::is_association_waiting(int const timeout)
+{
+    return ASC_associationWaiting(this->_network, timeout);
+}
+
+void
+Network
+::drop()
+{
+    if(!this->is_initialized())
+    {
+        throw Exception("Not initialized");
+    }
+    
+    OFCondition const condition = ASC_dropNetwork(&this->_network);
+    
+    if(condition.bad())
+    {
+        throw Exception(condition);
+    }
+    
+    this->_network = NULL;
+}
+
+bool
+Network
+::is_initialized() const
+{
+    return (this->_network != NULL);
+}
+
+}
diff --git a/src/dcmtkpp/Network.h b/src/dcmtkpp/Network.h
new file mode 100644
index 0000000..7cf8acf
--- /dev/null
+++ b/src/dcmtkpp/Network.h
@@ -0,0 +1,91 @@
+/*************************************************************************
+ * dcmtkpp - 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 _fad49120_3f5c_447d_b0e9_72719087640c
+#define _fad49120_3f5c_447d_b0e9_72719087640c
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmnet/assoc.h>
+
+namespace dcmtkpp
+{
+
+/**
+ * @brief Wrapper around the T_ASC_Network class.
+ * 
+ * No member can be set while the network is initialized.
+ */
+class Network
+{
+public:
+    /// @brief Create a default, un-initialized, network.
+    Network();
+    
+    /// @brief Create an un-initialized network.
+    Network(T_ASC_NetworkRole role, int port, int timeout, unsigned long options=0);
+    
+    /// @brief Create an un-initialized network.
+    Network(Network const & other);
+    
+    /// @brief Destroy the network, dropping it if necessary.
+    ~Network();
+    
+    /// @brief Assing an un-initialized network; it remains un-initialized.
+    Network & operator=(Network const & other);
+    
+    /// @brief Return the role of the network, defaults to NET_REQUESTOR.
+    T_ASC_NetworkRole get_role() const;
+    
+    /// @brief Set the role of the network.
+    void set_role(T_ASC_NetworkRole role);
+    
+    /// @brief Return the port for acceptor role, defaults to 0.
+    int get_port() const;
+    
+    /// @brief Set the port for acceptor role.
+    void set_port(int port);
+    
+    /// @brief Return the timeout in seconds, defaults to 30.
+    int get_timeout() const;
+    
+    /// @brief Set the timeout in seconds.
+    void set_timeout(int timeout);
+    
+    /// @brief Return the options, defaults to 0.
+    unsigned long get_options() const;
+    
+    /// @brief the set options.
+    void set_options(unsigned long options);
+    
+    /// @brief Initialize the network.
+    void initialize();
+    
+    /// @brief Return the underlying DCMTK object.
+    T_ASC_Network * get_network();
+    
+    /// @brief Test whether an association request is waiting.
+    bool is_association_waiting(int const timeout);
+    
+    /// @brief Drop (i.e. un-initialize) the network.
+    void drop();
+    
+    /// @brief Test whether the network is initialized.
+    bool is_initialized() const;
+
+private:
+    T_ASC_NetworkRole _role;
+    int _port;
+    int _timeout;
+    unsigned long _options;
+    
+    T_ASC_Network * _network;
+};
+
+}
+
+#endif // _fad49120_3f5c_447d_b0e9_72719087640c
diff --git a/src/dcmtkpp/Request.cpp b/src/dcmtkpp/Request.cpp
new file mode 100644
index 0000000..403fbd0
--- /dev/null
+++ b/src/dcmtkpp/Request.cpp
@@ -0,0 +1,38 @@
+/*************************************************************************
+ * dcmtkpp - 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 "Request.h"
+
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+Request
+::Request(Value::Integer message_id)
+: Message()
+{
+    this->set_message_id(message_id);
+}
+
+Request
+::Request(Message const & message)
+: Message()
+{
+    this->set_message_id(message.get_command_set().as_int(registry::MessageID, 0));
+}
+
+Request
+::~Request()
+{
+    // Nothing to do.
+}
+
+}
diff --git a/src/dcmtkpp/Request.h b/src/dcmtkpp/Request.h
new file mode 100644
index 0000000..6b74ad2
--- /dev/null
+++ b/src/dcmtkpp/Request.h
@@ -0,0 +1,43 @@
+/*************************************************************************
+ * dcmtkpp - 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 _8d06a300_6aee_4d1f_bf10_ecdf4916ae9f
+#define _8d06a300_6aee_4d1f_bf10_ecdf4916ae9f
+
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief Base class for all DIMSE request messages.
+class Request: public Message
+{
+public:
+    /// @brief Create a request with given Message ID.
+    Request(Value::Integer message_id);
+
+    /**
+     * @brief Create a request from the Message ID stored in the message
+     * command set.
+     *
+     * Raise an exception is either of this element is missing.
+     */
+    Request(Message const & message);
+
+    /// @brief Destructor.
+    virtual ~Request();
+    
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(
+        message_id, registry::MessageID)
+};
+
+}
+
+#endif // _8d06a300_6aee_4d1f_bf10_ecdf4916ae9f
diff --git a/src/dcmtkpp/Response.cpp b/src/dcmtkpp/Response.cpp
new file mode 100644
index 0000000..f3c2e20
--- /dev/null
+++ b/src/dcmtkpp/Response.cpp
@@ -0,0 +1,43 @@
+/*************************************************************************
+ * dcmtkpp - 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 "Response.h"
+
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+Response
+::Response(Value::Integer message_id_being_responded_to, Value::Integer status)
+: Message()
+{
+    this->set_message_id_being_responded_to(message_id_being_responded_to);
+    this->set_status(status);
+}
+
+Response
+::Response(Message const & message)
+: Message()
+{
+    this->set_message_id_being_responded_to(
+        message.get_command_set().as_int(
+            registry::MessageIDBeingRespondedTo, 0));
+
+    this->set_status(message.get_command_set().as_int(registry::Status, 0));
+}
+
+Response
+::~Response()
+{
+    // Nothing to do.
+}
+
+}
diff --git a/src/dcmtkpp/Response.h b/src/dcmtkpp/Response.h
new file mode 100644
index 0000000..a1a66c4
--- /dev/null
+++ b/src/dcmtkpp/Response.h
@@ -0,0 +1,44 @@
+/*************************************************************************
+ * dcmtkpp - 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 _0dd2e31e_212a_494a_a8d3_93b235336658
+#define _0dd2e31e_212a_494a_a8d3_93b235336658
+
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/registry.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief Base class for all DIMSE response messages.
+class Response: public Message
+{
+public:
+    /// @brief Create a response with given message id and status;
+    Response(Value::Integer message_id_being_responded_to, Value::Integer status);
+
+    /**
+     * @brief Create a response from the Message ID Being Responded To and the
+     * Status stored in the message command set.
+     *
+     * Raise an exception is either of those elements is missing.
+     */
+    Response(Message const & message);
+
+    /// @brief Destructor.
+    virtual ~Response();
+    
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(
+        message_id_being_responded_to, registry::MessageIDBeingRespondedTo)
+    DCMTKPP_MESSAGE_MANDATORY_FIELD_INTEGER_MACRO(status, registry::Status)
+};
+
+}
+
+#endif // _0dd2e31e_212a_494a_a8d3_93b235336658
diff --git a/src/dcmtkpp/SCP.cpp b/src/dcmtkpp/SCP.cpp
new file mode 100644
index 0000000..d24e861
--- /dev/null
+++ b/src/dcmtkpp/SCP.cpp
@@ -0,0 +1,44 @@
+/*************************************************************************
+ * dcmtkpp - 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 "SCP.h"
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CEchoRequest.h"
+#include "dcmtkpp/CEchoResponse.h"
+#include "dcmtkpp/ServiceRole.h"
+
+namespace dcmtkpp
+{
+
+SCP
+::SCP()
+: ServiceRole()
+{
+    // Nothing else.
+}
+
+SCP
+::~SCP()
+{
+    // Nothing to do.
+}
+
+void
+SCP
+::_send_echo_response(CEchoRequest const & request) const
+{
+    CEchoResponse response(
+        request.get_message_id(), STATUS_Success,
+        request.get_affected_sop_class_uid());
+    this->_send(response, request.get_affected_sop_class_uid());
+}
+
+}
diff --git a/src/dcmtkpp/SCP.h b/src/dcmtkpp/SCP.h
new file mode 100644
index 0000000..d6130a3
--- /dev/null
+++ b/src/dcmtkpp/SCP.h
@@ -0,0 +1,31 @@
+/*************************************************************************
+ * dcmtkpp - 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 _f4680d8c_18a8_4317_956d_3ae238cb39cc
+#define _f4680d8c_18a8_4317_956d_3ae238cb39cc
+
+#include "dcmtkpp/CEchoRequest.h"
+#include "dcmtkpp/ServiceRole.h"
+
+namespace dcmtkpp
+{
+
+/// @brief Base class for all Service Class Providers.
+class SCP: public ServiceRole
+{
+public:
+    SCP();
+    virtual ~SCP();
+protected:
+    /// @brief Send a C-ECHO response.
+    void _send_echo_response(CEchoRequest const & request) const;
+};
+
+}
+
+#endif // _f4680d8c_18a8_4317_956d_3ae238cb39cc
diff --git a/src/dcmtkpp/SCU.cpp b/src/dcmtkpp/SCU.cpp
new file mode 100644
index 0000000..f455768
--- /dev/null
+++ b/src/dcmtkpp/SCU.cpp
@@ -0,0 +1,70 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/SCU.h"
+
+#include <string>
+
+#include <unistd.h>
+
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/CEchoRequest.h"
+#include "dcmtkpp/CEchoResponse.h"
+#include "dcmtkpp/Message.h"
+
+namespace dcmtkpp
+{
+
+SCU
+::SCU()
+: ServiceRole(), _affected_sop_class("")
+{
+    // Nothing else
+}
+
+SCU
+::~SCU()
+{
+    // Nothing to do.
+}
+
+std::string const &
+SCU
+::get_affected_sop_class() const
+{
+    return this->_affected_sop_class;
+}
+    
+void 
+SCU
+::set_affected_sop_class(std::string const & sop_class)
+{
+    this->_affected_sop_class = sop_class;
+}
+
+void
+SCU
+::echo() const
+{
+    Uint16 const message_id = this->_association->get_association()->nextMsgID++;
+    
+    CEchoRequest const request(message_id, UID_VerificationSOPClass);
+    this->_send(request, request.get_affected_sop_class_uid());
+    
+    CEchoResponse const response = this->_receive<CEchoResponse>();
+    if(response.get_message_id_being_responded_to() != message_id)
+    {
+        std::ostringstream message;
+        message << "DIMSE: Unexpected Response MsgId: "
+                << response.get_message_id_being_responded_to() 
+                << "(expected: " << message_id << ")";
+        throw Exception(message.str());
+    }
+}
+
+}
diff --git a/src/dcmtkpp/SCU.h b/src/dcmtkpp/SCU.h
new file mode 100644
index 0000000..efdd52c
--- /dev/null
+++ b/src/dcmtkpp/SCU.h
@@ -0,0 +1,41 @@
+/*************************************************************************
+ * dcmtkpp - 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 _ba1518e7_8123_46c9_81c0_65439717e40e
+#define _ba1518e7_8123_46c9_81c0_65439717e40e
+
+#include <string>
+
+#include "dcmtkpp/ServiceRole.h"
+
+namespace dcmtkpp
+{
+
+/// @brief Base class for all Service Class Users.
+class SCU: public ServiceRole
+{
+public:
+    SCU();
+    ~SCU();
+    
+    /// @brief Return the affected SOP class. Defaults to "".
+    std::string const & get_affected_sop_class() const;
+    /// @brief Set the affected SOP class
+    void set_affected_sop_class(std::string const & sop_class);
+    
+    /// @brief Perform DICOM ping
+    void echo() const;
+
+protected:
+    /// @brief Affected SOP class.
+    std::string _affected_sop_class;
+};
+
+}
+
+#endif // _ba1518e7_8123_46c9_81c0_65439717e40e
diff --git a/src/dcmtkpp/ServiceRole.cpp b/src/dcmtkpp/ServiceRole.cpp
new file mode 100644
index 0000000..41cc102
--- /dev/null
+++ b/src/dcmtkpp/ServiceRole.cpp
@@ -0,0 +1,632 @@
+/*************************************************************************
+ * dcmtkpp - 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 "ServiceRole.h"
+
+#include <unistd.h>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcdatset.h>
+#include <dcmtk/dcmdata/dcistrmb.h>
+#include <dcmtk/dcmdata/dcostrmb.h>
+#include <dcmtk/dcmdata/dctagkey.h>
+#include <dcmtk/dcmdata/dcwcache.h>
+#include <dcmtk/dcmdata/dcxfer.h>
+#include <dcmtk/dcmnet/assoc.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/conversion.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/ElementAccessor.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/registry.h"
+
+namespace dcmtkpp
+{
+
+ServiceRole
+::ServiceRole()
+: _association(NULL), _network(NULL)
+{
+    // Nothing else
+}
+
+ServiceRole
+::ServiceRole(ServiceRole const & other)
+: _association(other._association), _network(other._network)
+{
+    // Nothing else
+}
+
+ServiceRole const &
+ServiceRole
+::operator=(ServiceRole const & other)
+{
+    if(this != &other)
+    {
+        this->set_association(other.get_association());
+        this->set_network(other.get_network());
+    }
+    
+    return *this;
+}
+
+ServiceRole
+::~ServiceRole()
+{
+    // Nothing to do.
+}
+
+Network *
+ServiceRole
+::get_network() const
+{
+    return this->_network;
+}
+
+void
+ServiceRole
+::set_network(Network * network)
+{
+    this->_network = network;
+}
+
+Association *
+ServiceRole
+::get_association() const
+{
+    return this->_association;
+}
+
+void
+ServiceRole
+::set_association(Association * association)
+{
+    this->_association = association;
+}
+
+void 
+ServiceRole
+::_progress_callback_wrapper(void * data, unsigned long bytes_count)
+{
+    ProgressCallbackData * encapsulated = 
+        reinterpret_cast<ProgressCallbackData*>(data);
+    encapsulated->callback(encapsulated->data, bytes_count);
+}
+
+T_ASC_PresentationContextID
+ServiceRole
+::_find_presentation_context(std::string const & abstract_syntax) const
+{
+    T_ASC_PresentationContextID const presentation_id = 
+        ASC_findAcceptedPresentationContextID(
+            this->_association->get_association(), 
+            abstract_syntax.c_str());
+    if(presentation_id == 0) 
+    {
+        throw Exception("No Presentation Context for Get Operation");
+    }
+    
+    return presentation_id;
+}
+void
+ServiceRole
+::_send(
+    Message const & message, std::string const & abstract_syntax,
+    ProgressCallback callback, void* callback_data) const
+{
+    T_ASC_PresentationContextID const presentation_context = 
+        this->_find_presentation_context(abstract_syntax);
+    
+    DcmDataset * command_set = dynamic_cast<DcmDataset*>(
+        convert(message.get_command_set()));
+
+    this->_send(
+        command_set,
+        presentation_context, EXS_LittleEndianImplicit, 
+        DUL_COMMANDPDV, NULL, NULL);
+    if(message.has_data_set() && !message.get_data_set().empty())
+    {
+        DcmDataset * data_set = dynamic_cast<DcmDataset*>(
+            convert(message.get_data_set()));
+        // FIXME: transfer syntax
+        this->_send(
+            data_set,
+            presentation_context, EXS_LittleEndianImplicit, 
+            DUL_DATASETPDV, callback, callback_data);
+        delete data_set;
+    }
+
+    delete command_set;
+}
+
+Message
+ServiceRole
+::_receive(ProgressCallback callback, void* callback_data) const
+{
+    // Receive command set
+    std::pair<DcmDataset, DUL_DATAPDV> const command =
+        this->_receive_dataset(callback, callback_data);
+    if(command.second != DUL_COMMANDPDV)
+    {
+        throw Exception("Did not receive command set");
+    }
+    DataSet const command_set = convert(const_cast<DcmDataset*>(&command.first));
+    
+    // Receive potential data set
+    DataSet data_set;
+    bool has_data_set;
+    if(command_set.as_int(registry::CommandDataSetType, 0) != DIMSE_DATASET_NULL)
+    {
+        std::pair<DcmDataset, DUL_DATAPDV> const data =
+            this->_receive_dataset(callback, callback_data);
+        if(data.second != DUL_DATASETPDV)
+        {
+            throw Exception("Did not receive data set");
+        }
+        data_set = convert(const_cast<DcmDataset*>(&data.first));
+        has_data_set = true;
+    }
+    else
+    {
+        has_data_set = false;
+    }
+    
+    return has_data_set?Message(command_set, data_set):Message(command_set);
+}
+
+OFCondition
+ServiceRole
+::_send(
+    DcmDataset *obj, T_ASC_PresentationContextID presID,
+    E_TransferSyntax xferSyntax, DUL_DATAPDV pdvType,
+    ProgressCallback callback, void *callbackContext) const
+    /*
+     * This function sends all information which is included in a DcmDataset object over
+     * the network which is provided in assoc.
+     *
+     * Parameters:
+     *   obj             - [in] Contains the information which shall be sent over the network.
+     *   presId          - [in] The ID of the presentation context which shall be used
+     *   xferSyntax      - [in] The transfer syntax which shall be used.
+     *   pdvType         - [in] Specifies if the information in this DcmDataset object belongs to
+     *                          a DIMSE command (as for example C-STORE) (DUL_COMMANDPDV) or if
+     *                          the information is actual instance information (DUL_DATASETPDV).
+     *   callback        - [in] Pointer to a function which shall be called to indicate progress.
+     *   callbackContext - []
+     */
+{
+    OFBool written = OFFalse;
+    DcmWriteCache wcache;
+
+    /* we may wish to restrict output PDU size */
+    /* max PDV size is max PDU size minus 12 bytes PDU/PDV header */
+    unsigned long bufLen = this->_association->get_association()->sendPDVLength;
+    if (bufLen + 12 > dcmMaxOutgoingPDUSize.get())
+    {
+        bufLen = dcmMaxOutgoingPDUSize.get() - 12;
+    }
+
+    /* on the basis of the association's buffer, create a buffer variable that we can write to */
+    DcmOutputBufferStream outBuf(
+        this->_association->get_association()->sendPDVBuffer, bufLen);
+
+    /* prepare all elements in the DcmDataset variable for transfer */
+    obj->transferInit();
+
+    /* groupLength_encoding specifies what will be done concerning
+     * group length tags
+     */
+    E_GrpLenEncoding groupLength_encoding = g_dimse_send_groupLength_encoding;
+    /* Mind that commands must always include group length (0000,0000) and */
+    /* that commands do not contain sequences, yet */
+    if (pdvType == DUL_COMMANDPDV)
+    {
+        groupLength_encoding = EGL_withGL;
+    }
+
+    /* sequenceType_encoding specifies how sequences will be handled */
+    E_EncodingType const sequenceType_encoding = g_dimse_send_sequenceType_encoding;
+
+    /* start a loop: in each iteration information from the DcmDataset object (i.e. infor- */
+    /* mation which shall be sent) will be set in the buffer (we need more than one itera- */
+    /* tion if there is more information than the buffer can take at a time), a PDV object */
+    /* with the buffer's data will be created and assigned to a list, and finally the */
+    /* list's information will be sent over the network to the other DICOM application. */
+    OFBool last = OFFalse;
+    Uint32 bytesTransmitted = 0;
+    while (!last)
+    {
+        /* write data values which are contained in the DcmDataSet variable to the above created */
+        /* buffer. Mind the transfer syntax, the sequence type encoding, the group length encoding */
+        /* and remove all padding data elements. Depending on whether all information has been written */
+        /* to the buffer, update the variable that determines the end of the while loop. (Note that */
+        /* DcmDataset stores information about what of its content has already been sent to the buffer.) */
+        if (! written)
+        {
+            OFCondition const econd =
+                obj->write(outBuf, xferSyntax, sequenceType_encoding, &wcache,
+                groupLength_encoding, EPD_withoutPadding);
+            if (econd == EC_Normal)                   /* all contents have been written to the buffer */
+            {
+                written = OFTrue;
+            }
+            else if (econd == EC_StreamNotifyClient)  /* no more space in buffer, _not_ all elements have been written to it */
+            {
+                // nothing to do
+            }
+            else                                      /* some error has occurred */
+            {
+                //DCMNET_WARN(DIMSE_warn_str(assoc) << "writeBlock Failed (" << econd.text() << ")");
+                return DIMSE_SENDFAILED;
+            }
+        }
+
+        if (written)
+        {
+            outBuf.flush(); // flush stream including embedded compression codec.
+        }
+
+        /* get buffer and its length, assign to local variable */
+        void *fullBuf = NULL;
+        offile_off_t rtnLength;
+        outBuf.flushBuffer(fullBuf, rtnLength);
+
+        last = written && outBuf.isFlushed();
+
+        /* if the buffer is not empty, do something with its contents */
+        if (rtnLength > 0)
+        {
+            /* rtnLength could be odd */
+            if (rtnLength & 1)
+            {
+                /* this should only happen if we use a stream compressed transfer
+                 * syntax and then only at the very end of the stream. Everything
+                 * else is a failure.
+                 */
+                if (!last)
+                {
+                    return makeDcmnetCondition(
+                        DIMSEC_SENDFAILED, OF_error,
+                        "DIMSE Failed to send message: odd block length encountered");
+                }
+
+                /* since the block size is always even, block size must be larger
+                 * than rtnLength, so we can safely add a pad byte (and hope that
+                 * the pad byte will not confuse the receiver's decompressor).
+                 */
+                unsigned char *cbuf = (unsigned char *)fullBuf;
+                cbuf[rtnLength++] = 0; // add zero pad byte
+            }
+
+            /* initialize a DUL_PDV variable with the buffer's data */
+            DUL_PDV pdv;
+            pdv.fragmentLength = OFstatic_cast(unsigned long, rtnLength);
+            pdv.presentationContextID = presID;
+            pdv.pdvType = pdvType;
+            pdv.lastPDV = last;
+            pdv.data = fullBuf;
+
+            /* append this PDV to a PDV list structure, set the counter variable */
+            /* to 1 since this structure contains only 1 element */
+            DUL_PDVLIST pdvList;
+            pdvList.count = 1;
+            pdvList.pdv = &pdv;
+
+            /* send information over the network to the other DICOM application */
+            OFCondition const dulCond = DUL_WritePDVs(
+                &this->_association->get_association()->DULassociation,
+                &pdvList);
+            if (dulCond.bad())
+            {
+                return makeDcmnetSubCondition(DIMSEC_SENDFAILED, OF_error, "DIMSE Failed to send message", dulCond);
+            }
+
+            /* count the bytes and the amount of PDVs which were transmitted */
+            bytesTransmitted += OFstatic_cast(Uint32, rtnLength);
+
+            /* execute callback function to indicate progress */
+            if(callback)
+            {
+                callback(callbackContext, bytesTransmitted);
+            }
+        }
+    }
+
+    /* indicate the end of the transfer */
+    obj->transferEnd();
+
+    return EC_Normal;
+}
+
+
+std::pair<DcmDataset, DUL_DATAPDV>
+ServiceRole::_receive_dataset(
+    ProgressCallback callback, void *callbackContext) const
+{
+    DcmDataset dataset;
+    dataset.transferInit();
+    DcmInputBufferStream buffer;
+    if(!buffer.good())
+    {
+        throw Exception(
+            makeDcmnetCondition(
+                DIMSEC_PARSEFAILED, OF_error,
+                "DIMSE: receiveCommand: Failed to initialize cmdBuf"));
+    }
+
+    /* start a loop in which we want to read a DIMSE command from the incoming socket stream. */
+    /* Since the command could stretch over more than one PDU, the use of a loop is mandatory. */
+    DUL_DATAPDV type;
+    bool last = false;
+    DIC_UL pdvCount = 0;
+    T_ASC_PresentationContextID pid = 0;
+    while(!last)
+    {
+        /* make the stream remember any unread bytes */
+        buffer.releaseBuffer();
+
+        DUL_PDV const pdv = this->_read_next_pdv();
+
+        /* if this is the first loop iteration, get the presentation context ID
+         * which is captured in the current PDV. If this is not the first loop
+         * iteration, check if the presentation context IDs in the current PDV
+         * and in the last PDV are identical. If they are not, return an error.
+         */
+        if (pdvCount == 0)
+        {
+            pid = pdv.presentationContextID;
+        }
+        else if (pdv.presentationContextID != pid)
+        {
+            char buf1[256];
+            sprintf(buf1, "DIMSE: Different PresIDs inside Command Set: %d != %d", pid, pdv.presentationContextID);
+            OFCondition subCond = makeDcmnetCondition(DIMSEC_INVALIDPRESENTATIONCONTEXTID, OF_error, buf1);
+            throw Exception(
+                makeDcmnetSubCondition(
+                    DIMSEC_RECEIVEFAILED, OF_error,
+                    "DIMSE Failed to receive message", subCond));
+        }
+
+        /* check if the fragment length of the current PDV is odd. This should */
+        /* never happen (see DICOM standard (year 2000) part 7, annex F) (or */
+        /* the corresponding section in a later version of the standard.) */
+        if ((pdv.fragmentLength % 2) != 0)
+        {
+            /* This should NEVER happen.  See Part 7, Annex F. */
+            char buf2[256];
+            sprintf(buf2, "DIMSE: Odd Fragment Length: %lu", pdv.fragmentLength);
+            throw Exception(
+                makeDcmnetCondition(DIMSEC_RECEIVEFAILED, OF_error, buf2));
+        }
+
+        /* if information is contained the PDVs fragment, we want to insert
+         * this information into the buffer
+         */
+        if (pdv.fragmentLength > 0)
+        {
+            buffer.setBuffer(pdv.data, pdv.fragmentLength);
+        }
+
+        /* if this fragment contains the last fragment of the DIMSE command,
+         * set the end of the stream
+         */
+        if (pdv.lastPDV)
+        {
+            buffer.setEos();
+        }
+
+        E_TransferSyntax transfer_syntax;
+        E_GrpLenEncoding group_length_encoding;
+        if(pdv.pdvType == DUL_COMMANDPDV)
+        {
+            /* DIMSE commands are always specified in the little endian implicit
+             * transfer syntax. Additionally, we want to remove group length
+             * tags.
+             */
+            transfer_syntax = EXS_LittleEndianImplicit;
+            group_length_encoding = EGL_withoutGL;
+        }
+        else if(pdv.pdvType == DUL_DATASETPDV)
+        {
+            /* figure out if is this a valid presentation context */
+            T_ASC_PresentationContext pc;
+            OFCondition const cond =
+                ASC_findAcceptedPresentationContext(
+                    this->_association->get_association()->params, pid, &pc);
+            if (cond.bad())
+            {
+                throw Exception(makeDcmnetSubCondition(
+                    DIMSEC_RECEIVEFAILED, OF_error,
+                    "DIMSE Failed to receive message", cond));
+            }
+
+            /* determine the transfer syntax which is specified in the presentation context */
+            std::string const ts = pc.acceptedTransferSyntax;
+
+            /* create a DcmXfer object on the basis of the transfer syntax which was determined above */
+            DcmXfer xfer(ts.c_str());
+
+            /* check if the transfer syntax is supported by dcmtk */
+            transfer_syntax = xfer.getXfer();
+            switch (transfer_syntax)
+            {
+                case EXS_LittleEndianImplicit:
+                case EXS_LittleEndianExplicit:
+                case EXS_BigEndianExplicit:
+                case EXS_JPEGProcess1TransferSyntax:
+                case EXS_JPEGProcess2_4TransferSyntax:
+                case EXS_JPEGProcess3_5TransferSyntax:
+                case EXS_JPEGProcess6_8TransferSyntax:
+                case EXS_JPEGProcess7_9TransferSyntax:
+                case EXS_JPEGProcess10_12TransferSyntax:
+                case EXS_JPEGProcess11_13TransferSyntax:
+                case EXS_JPEGProcess14TransferSyntax:
+                case EXS_JPEGProcess15TransferSyntax:
+                case EXS_JPEGProcess16_18TransferSyntax:
+                case EXS_JPEGProcess17_19TransferSyntax:
+                case EXS_JPEGProcess20_22TransferSyntax:
+                case EXS_JPEGProcess21_23TransferSyntax:
+                case EXS_JPEGProcess24_26TransferSyntax:
+                case EXS_JPEGProcess25_27TransferSyntax:
+                case EXS_JPEGProcess28TransferSyntax:
+                case EXS_JPEGProcess29TransferSyntax:
+                case EXS_JPEGProcess14SV1TransferSyntax:
+                case EXS_RLELossless:
+                case EXS_JPEGLSLossless:
+                case EXS_JPEGLSLossy:
+                case EXS_JPEG2000LosslessOnly:
+                case EXS_JPEG2000:
+                case EXS_MPEG2MainProfileAtMainLevel:
+                case EXS_MPEG2MainProfileAtHighLevel:
+                case EXS_JPEG2000MulticomponentLosslessOnly:
+                case EXS_JPEG2000Multicomponent:
+        #ifdef WITH_ZLIB
+                case EXS_DeflatedLittleEndianExplicit:
+        #endif
+                    /* OK, these can be supported */
+                    break;
+                default:
+                /* all other transfer syntaxes are not supported; hence, set the error indicator variable */
+                {
+                    char buf[256];
+                    sprintf(
+                        buf, "DIMSE Unsupported transfer syntax: %s",
+                        ts.c_str());
+                    OFCondition subCond = makeDcmnetCondition(
+                        DIMSEC_UNSUPPORTEDTRANSFERSYNTAX, OF_error, buf);
+                    throw Exception(makeDcmnetSubCondition(
+                        DIMSEC_RECEIVEFAILED, OF_error,
+                        "DIMSE Failed to receive message", subCond));
+                }
+                break;
+            }
+            group_length_encoding = EGL_noChange;
+        }
+        else
+        {
+            throw Exception("Unkown PDV type");
+        }
+
+        OFCondition const econd = dataset.read(
+            buffer, transfer_syntax, group_length_encoding);
+        if (econd != EC_Normal && econd != EC_StreamNotifyClient)
+        {
+            throw Exception(
+                makeDcmnetSubCondition(
+                    DIMSEC_RECEIVEFAILED, OF_error,
+                    "DIMSE: receiveCommand: cmdSet->read() Failed", econd));
+        }
+
+        /* update the following variables which will be evaluated at the beginning of each loop iteration. */
+        last = pdv.lastPDV;
+        type = pdv.pdvType;
+
+        /* update the counter that counts how many PDVs were received on the incoming */
+        /* socket stream. This variable will be used for determining the first */
+        /* loop iteration and dumping general information. */
+        pdvCount++;
+    }
+
+    dataset.transferEnd();
+
+    return std::make_pair(dataset, type);
+}
+
+DUL_PDV
+ServiceRole
+::_read_next_pdv() const
+    /*
+     * This function returns the next PDV which was (earlier or just now) received on the incoming
+     * socket stream. If there are no PDVs (which were already received earlier) waiting to be picked
+     * up, this function will go ahead and read a new PDU (containing one or more new PDVs) from the
+     * incoming socket stream.
+     */
+{
+    /* get the next PDV from the association, in case there are still some PDVs waiting to be picked up */
+    DUL_PDV pdv;
+    OFCondition cond = DUL_NextPDV(
+        &this->_association->get_association()->DULassociation, &pdv);
+
+    if (cond.bad())
+    {
+        /* in case DUL_NextPDV(...) did not return DUL_NORMAL, the association */
+        /* did not contain any more PDVs that are waiting to be picked up. Hence, */
+        /* we need to read new PDVs from the incoming socket stream. */
+
+        /* if the blocking mode is DIMSE_NONBLOCKING and there is no data waiting after timeout seconds, report an error */
+        if(!ASC_dataWaiting(
+            this->_association->get_association(), this->_network->get_timeout()))
+        {
+            throw Exception(DIMSE_NODATAAVAILABLE);
+        }
+
+        /* try to receive new PDVs on the incoming socket stream (in detail, try to receive one PDU) */
+        cond = DUL_ReadPDVs(
+            &this->_association->get_association()->DULassociation, NULL,
+            DUL_BLOCK, this->_network->get_timeout());
+
+        /* check return value, if it is different from DUL_PDATAPDUARRIVED, an error occurred */
+        if (cond != DUL_PDATAPDUARRIVED)
+        {
+            if (cond == DUL_NULLKEY || cond == DUL_ILLEGALKEY)
+            {
+                throw Exception(DIMSE_ILLEGALASSOCIATION);
+            }
+            else if (cond == DUL_PEERREQUESTEDRELEASE ||
+                cond == DUL_PEERABORTEDASSOCIATION)
+            {
+                throw Exception(cond);
+            }
+            else
+            {
+                throw Exception(
+                    makeDcmnetSubCondition(
+                        DIMSEC_READPDVFAILED, OF_error,
+                        "DIMSE Read PDV failed", cond));
+            }
+        }
+
+        /* get the next PDV, assign it to pdv */
+        cond = DUL_NextPDV(
+            &this->_association->get_association()->DULassociation, &pdv);
+        if (cond.bad())
+        {
+            throw Exception(
+                makeDcmnetSubCondition(
+                    DIMSEC_READPDVFAILED, OF_error,
+                    "DIMSE Read PDV failed", cond));
+        }
+    }
+
+    return pdv;
+}
+
+void
+ServiceRole
+::_check_dimse_ready() const
+{
+    if(this->_network == NULL)
+    {
+        throw Exception("No network");
+    }
+    else if(!this->_network->is_initialized())
+    {
+        throw Exception("Network is not initialized");
+    }
+    else if(this->_association == NULL)
+    {
+        throw Exception("No association");
+    }
+    else if(!this->_association->is_associated())
+    {
+        throw Exception("Not associated");
+    }
+}
+
+}
diff --git a/src/dcmtkpp/ServiceRole.h b/src/dcmtkpp/ServiceRole.h
new file mode 100644
index 0000000..ec4fc93
--- /dev/null
+++ b/src/dcmtkpp/ServiceRole.h
@@ -0,0 +1,114 @@
+/*************************************************************************
+ * dcmtkpp - 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 _fa7d372a_dd27_4a1e_9b29_be9d5fbe602a
+#define _fa7d372a_dd27_4a1e_9b29_be9d5fbe602a
+
+#include <functional>
+#include <utility>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcdatset.h>
+#include <dcmtk/dcmnet/assoc.h>
+
+#include "dcmtkpp/Association.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/Network.h"
+
+namespace dcmtkpp
+{
+
+/// @brief Base class for all Service Class Users and Providers.
+class ServiceRole
+{
+public:
+    /// @brief Progress callback, following the semantics of DCMTK.
+    typedef std::function<void(void *, unsigned long)> ProgressCallback;
+    
+    /// @brief Create a default Service Role with no network and no association.
+    ServiceRole();
+    
+    /// @brief Copy the other service role.
+    ServiceRole(ServiceRole const & other);
+    
+    /// @brief Copy the other service role.
+    ServiceRole const & operator=(ServiceRole const & other);
+    
+    /// @brief Destructor, network and association are not modified.
+    virtual ~ServiceRole();
+    
+    /// @brief Return the network used by the ServiceRole.
+    Network * get_network() const;
+    /// @brief Set the network used by the ServiceRole.
+    void set_network(Network * network);
+    
+    /// @brief Return the association used by the ServiceRole.
+    Association * get_association() const;
+    /// @brief Set the association used by the ServiceRole.
+    void set_association(Association * association);
+
+protected:
+    /// @brief Wrapper class for DMCTK progress callbacks.
+    struct ProgressCallbackData
+    {
+        /// @brief Callback function.
+        ProgressCallback callback;
+        
+        /// @brief Callback data.
+        void * data;
+    };
+    
+    /// @brief Network used by the ServiceRole.
+    Network * _network;
+    
+    /// @brief Association used by the ServiceRole.
+    Association * _association;
+
+    /// @brief Wrapper from ProgressCallback to DIMSE_ProgressCallback.
+    static void _progress_callback_wrapper(void * data, unsigned long bytes_count);
+    
+    /// @brief Find an accepted presentation context.
+    T_ASC_PresentationContextID _find_presentation_context(
+        std::string const & abstract_syntax) const;
+    
+    /// @brief Send a DIMSE message.
+    void _send(
+        Message const & message, std::string const & abstract_syntax,
+        ProgressCallback callback=NULL, void* callback_data=NULL) const;
+    
+    /// @brief Receive a generic DIMSE message.
+    Message _receive(ProgressCallback callback=NULL, void* callback_data=NULL) const;
+    
+    /**
+     * @brief Receive a DIMSE message of specific type.
+     *
+     * Throw an exception if the received message is not of the requested type.
+     */
+    template<typename TMessage>
+    TMessage _receive(ProgressCallback callback=NULL, void* callback_data=NULL) const;
+
+private:
+    OFCondition _send(
+        DcmDataset *obj, T_ASC_PresentationContextID presID,
+        E_TransferSyntax xferSyntax, DUL_DATAPDV pdvType,
+        ProgressCallback callback, void *callbackContext) const;
+
+    std::pair<DcmDataset, DUL_DATAPDV> _receive_dataset(
+        ProgressCallback callback, void *callbackContext) const;
+    
+    DUL_PDV _read_next_pdv() const;
+
+    void _check_dimse_ready() const;
+};
+
+}
+
+#include "ServiceRole.txx"
+
+#endif // _fa7d372a_dd27_4a1e_9b29_be9d5fbe602a
diff --git a/src/dcmtkpp/ServiceRole.txx b/src/dcmtkpp/ServiceRole.txx
new file mode 100644
index 0000000..8e8ccca
--- /dev/null
+++ b/src/dcmtkpp/ServiceRole.txx
@@ -0,0 +1,39 @@
+/*************************************************************************
+ * dcmtkpp - 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 _8ac39caa_b7b1_44a8_82fc_e8e3de18b2f8
+#define _8ac39caa_b7b1_44a8_82fc_e8e3de18b2f8
+
+#include "ServiceRole.h"
+
+#include <functional>
+#include <utility>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcdatset.h>
+#include <dcmtk/dcmnet/assoc.h>
+
+#include "dcmtkpp/Association.h"
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/Network.h"
+
+namespace dcmtkpp
+{
+
+template<typename TMessage>
+TMessage
+ServiceRole
+::_receive(ProgressCallback callback, void* callback_data) const
+{
+    Message const message = this->_receive(callback, callback_data);
+    return TMessage(message);
+}
+
+}
+
+#endif // _8ac39caa_b7b1_44a8_82fc_e8e3de18b2f8
diff --git a/src/dcmtkpp/StoreSCP.cpp b/src/dcmtkpp/StoreSCP.cpp
new file mode 100644
index 0000000..c6d152b
--- /dev/null
+++ b/src/dcmtkpp/StoreSCP.cpp
@@ -0,0 +1,94 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/StoreSCP.h"
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CStoreRequest.h"
+#include "dcmtkpp/CStoreResponse.h"
+#include "dcmtkpp/DataSet.h"
+
+namespace dcmtkpp
+{
+
+bool 
+StoreSCP
+::store(Callback callback) const
+{
+    Message request;
+    try
+    {
+        request = this->_receive();
+    }
+    catch(Exception const & e)
+    {
+        if(e.get_source() != Exception::Source::Condition ||
+           e.get_condition() != DUL_PEERREQUESTEDRELEASE)
+        {
+            throw;
+        }
+        else
+        {
+            return true;
+        }
+    }
+    
+    if(request.get_command_field() == Message::Command::C_ECHO_RQ)
+    {
+        this->_send_echo_response(CEchoRequest(request));
+    }
+    else if(request.get_command_field() == Message::Command::C_STORE_RQ)
+    {
+        this->store(CStoreRequest(request), callback);
+        request.delete_data_set();
+    }
+    else
+    {
+        std::ostringstream message;
+        message << "DIMSE: Unexpected Response Command Field: 0x" 
+                << std::hex << request.get_command_field();
+        throw Exception(message.str());
+    }
+    
+    return false;
+}
+
+void
+StoreSCP
+::store(CStoreRequest const & request, Callback callback) const
+{
+    // Execute user callback
+    Uint16 status = STATUS_Success;
+    if(!request.has_data_set() || request.get_data_set().empty())
+    {
+        status = STATUS_STORE_Error_CannotUnderstand;
+    }
+    else
+    {
+        try
+        {
+            callback(request.get_data_set());
+        }
+        catch(...)
+        {
+            // FIXME: logging
+            status = STATUS_STORE_Error_CannotUnderstand;
+        }
+    }
+    
+    // Send store response
+    CStoreResponse response(request.get_message_id(), status);
+    response.set_affected_sop_class_uid(request.get_affected_sop_class_uid());
+    response.set_affected_sop_instance_uid(
+        request.get_affected_sop_instance_uid());
+    this->_send(response, request.get_affected_sop_class_uid());
+}
+
+}
diff --git a/src/dcmtkpp/StoreSCP.h b/src/dcmtkpp/StoreSCP.h
new file mode 100644
index 0000000..9d6c8ed
--- /dev/null
+++ b/src/dcmtkpp/StoreSCP.h
@@ -0,0 +1,43 @@
+/*************************************************************************
+ * dcmtkpp - 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 _fdbf3f51_91f5_464a_b449_c3f994297210
+#define _fdbf3f51_91f5_464a_b449_c3f994297210
+
+#include <functional>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/CStoreRequest.h"
+#include "dcmtkpp/SCP.h"
+
+namespace dcmtkpp
+{
+
+class StoreSCP: public SCP
+{
+public:
+    /// @brief Callback called when a response is received.
+    typedef std::function<void(DataSet const &)> Callback;
+    
+    /**
+     * @brief Receive a store request and respond to it.
+     * @param callback function called with the dataset to be stored.
+     */
+    bool store(Callback callback) const;
+    
+    /**
+     * @brief Respond to a store request.
+     * @param request
+     * @param callback function called with the dataset to be stored.
+     */
+    void store(CStoreRequest const & request, Callback callback) const;
+};
+
+}
+
+#endif // _fdbf3f51_91f5_464a_b449_c3f994297210
diff --git a/src/dcmtkpp/StoreSCU.cpp b/src/dcmtkpp/StoreSCU.cpp
new file mode 100644
index 0000000..3df3abe
--- /dev/null
+++ b/src/dcmtkpp/StoreSCU.cpp
@@ -0,0 +1,209 @@
+/*************************************************************************
+ * dcmtkpp - 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 "StoreSCU.h"
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcuid.h>
+
+#include "dcmtkpp/CStoreRequest.h"
+#include "dcmtkpp/CStoreResponse.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/registry.h"
+
+namespace dcmtkpp
+{
+
+StoreSCU
+::~StoreSCU()
+{
+    // Nothing to do.
+}
+
+void 
+StoreSCU
+::set_affected_sop_class(DataSet const & dataset)
+{
+    auto const & sop_class_uid = dataset.as_string(registry::SOPClassUID, 0);
+    
+    // From dcuid.h
+    std::vector<std::string> const storage = {
+        UID_RETIRED_StoredPrintStorage,
+        UID_RETIRED_HardcopyGrayscaleImageStorage,
+        UID_RETIRED_HardcopyColorImageStorage,
+        UID_ComputedRadiographyImageStorage,
+        UID_DigitalXRayImageStorageForPresentation,
+        UID_DigitalXRayImageStorageForProcessing,
+        UID_DigitalMammographyXRayImageStorageForPresentation,
+        UID_DigitalMammographyXRayImageStorageForProcessing,
+        UID_DigitalIntraOralXRayImageStorageForPresentation,
+        UID_DigitalIntraOralXRayImageStorageForProcessing,
+        UID_CTImageStorage,
+        UID_EnhancedCTImageStorage,
+        UID_RETIRED_UltrasoundMultiframeImageStorage,
+        UID_UltrasoundMultiframeImageStorage,
+        UID_MRImageStorage,
+        UID_EnhancedMRImageStorage,
+        UID_MRSpectroscopyStorage,
+        UID_EnhancedMRColorImageStorage,
+        UID_RETIRED_NuclearMedicineImageStorage,
+        UID_RETIRED_UltrasoundImageStorage,
+        UID_UltrasoundImageStorage,
+        UID_EnhancedUSVolumeStorage,
+        UID_SecondaryCaptureImageStorage,
+        UID_MultiframeSingleBitSecondaryCaptureImageStorage,
+        UID_MultiframeGrayscaleByteSecondaryCaptureImageStorage,
+        UID_MultiframeGrayscaleWordSecondaryCaptureImageStorage,
+        UID_MultiframeTrueColorSecondaryCaptureImageStorage,
+        UID_RETIRED_StandaloneOverlayStorage,
+        UID_RETIRED_StandaloneCurveStorage,
+        UID_TwelveLeadECGWaveformStorage,
+        UID_GeneralECGWaveformStorage,
+        UID_AmbulatoryECGWaveformStorage,
+        UID_HemodynamicWaveformStorage,
+        UID_CardiacElectrophysiologyWaveformStorage,
+        UID_BasicVoiceAudioWaveformStorage,
+        UID_GeneralAudioWaveformStorage,
+        UID_ArterialPulseWaveformStorage,
+        UID_RespiratoryWaveformStorage,
+        UID_RETIRED_StandaloneModalityLUTStorage,
+        UID_RETIRED_StandaloneVOILUTStorage,
+        UID_GrayscaleSoftcopyPresentationStateStorage,
+        UID_ColorSoftcopyPresentationStateStorage,
+        UID_PseudoColorSoftcopyPresentationStateStorage,
+        UID_BlendingSoftcopyPresentationStateStorage,
+        UID_XAXRFGrayscaleSoftcopyPresentationStateStorage,
+        UID_XRayAngiographicImageStorage,
+        UID_EnhancedXAImageStorage,
+        UID_XRayRadiofluoroscopicImageStorage,
+        UID_EnhancedXRFImageStorage,
+        UID_XRay3DAngiographicImageStorage,
+        UID_XRay3DCraniofacialImageStorage,
+        UID_BreastTomosynthesisImageStorage,
+        UID_RETIRED_XRayAngiographicBiPlaneImageStorage,
+        UID_NuclearMedicineImageStorage,
+        UID_RawDataStorage,
+        UID_SpatialRegistrationStorage,
+        UID_SpatialFiducialsStorage,
+        UID_DeformableSpatialRegistrationStorage,
+        UID_SegmentationStorage,
+        UID_SurfaceSegmentationStorage,
+        UID_RealWorldValueMappingStorage,
+        UID_RETIRED_VLImageStorage,
+        UID_VLEndoscopicImageStorage,
+        UID_VideoEndoscopicImageStorage,
+        UID_VLMicroscopicImageStorage,
+        UID_VideoMicroscopicImageStorage,
+        UID_VLSlideCoordinatesMicroscopicImageStorage,
+        UID_VLPhotographicImageStorage,
+        UID_VideoPhotographicImageStorage,
+        UID_OphthalmicPhotography8BitImageStorage,
+        UID_OphthalmicPhotography16BitImageStorage,
+        UID_StereometricRelationshipStorage,
+        UID_OphthalmicTomographyImageStorage,
+        UID_VLWholeSlideMicroscopyImageStorage,
+        UID_RETIRED_VLMultiFrameImageStorage,
+        UID_LensometryMeasurementsStorage,
+        UID_AutorefractionMeasurementsStorage,
+        UID_KeratometryMeasurementsStorage,
+        UID_SubjectiveRefractionMeasurementsStorage,
+        UID_VisualAcuityMeasurementsStorage,
+        UID_SpectaclePrescriptionReportStorage,
+        UID_OphthalmicAxialMeasurementsStorage,
+        UID_IntraocularLensCalculationsStorage,
+        UID_MacularGridThicknessAndVolumeReportStorage,
+        UID_OphthalmicVisualFieldStaticPerimetryMeasurementsStorage,
+        UID_BasicTextSRStorage,
+        UID_EnhancedSRStorage,
+        UID_ComprehensiveSRStorage,
+        UID_ProcedureLogStorage,
+        UID_MammographyCADSRStorage,
+        UID_KeyObjectSelectionDocumentStorage,
+        UID_ChestCADSRStorage,
+        UID_XRayRadiationDoseSRStorage,
+        UID_ColonCADSRStorage,
+        UID_ImplantationPlanSRDocumentStorage,
+        UID_EncapsulatedPDFStorage,
+        UID_EncapsulatedCDAStorage,
+        UID_PositronEmissionTomographyImageStorage,
+        UID_RETIRED_StandalonePETCurveStorage,
+        UID_EnhancedPETImageStorage,
+        UID_BasicStructuredDisplayStorage,
+        UID_RTImageStorage,
+        UID_RTDoseStorage,
+        UID_RTStructureSetStorage,
+        UID_RTBeamsTreatmentRecordStorage,
+        UID_RTPlanStorage,
+        UID_RTBrachyTreatmentRecordStorage,
+        UID_RTTreatmentSummaryRecordStorage,
+        UID_RTIonPlanStorage,
+        UID_RTIonBeamsTreatmentRecordStorage,
+        UID_GenericImplantTemplateStorage,
+        UID_ImplantAssemblyTemplateStorage,
+        UID_ImplantTemplateGroupStorage
+    };
+
+    if(std::find(storage.begin(), storage.end(), sop_class_uid) != storage.end())
+    {
+        this->SCU::set_affected_sop_class(sop_class_uid);
+    }
+    else
+    {
+        throw Exception("Could not guess affected SOP class from dataset");
+    }
+}
+
+void 
+StoreSCU
+::store(DataSet const & dataset, ProgressCallback callback, void * data) const
+{
+    CStoreRequest const request(
+        this->_association->get_association()->nextMsgID++,
+        this->_affected_sop_class,
+        dataset.as_string(registry::SOPInstanceUID, 0),
+        Message::Priority::MEDIUM,
+        dataset);
+    this->_send(request, this->_affected_sop_class, callback, data);
+    
+    CStoreResponse const response = this->_receive<CStoreResponse>();
+
+    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());
+    }
+
+    if(response.has_affected_sop_class_uid() &&
+       response.get_affected_sop_class_uid() != request.get_affected_sop_class_uid())
+    {
+        std::ostringstream message;
+        message << "DIMSE: Unexpected Response Affected SOP Class UID: "
+                << response.get_affected_sop_class_uid()
+                << " (expected: " << request.get_affected_sop_class_uid() << ")";
+        throw Exception(message.str());
+    }
+    if(response.has_affected_sop_instance_uid() &&
+       response.get_affected_sop_instance_uid() != request.get_affected_sop_instance_uid())
+    {
+        std::ostringstream message;
+        message << "DIMSE: Unexpected Response Affected SOP Instance UID: "
+                << response.get_affected_sop_instance_uid()
+                << " (expected: " << request.get_affected_sop_instance_uid() << ")";
+        throw Exception(message.str());
+    }
+}
+
+}
diff --git a/src/dcmtkpp/StoreSCU.h b/src/dcmtkpp/StoreSCU.h
new file mode 100644
index 0000000..d805a73
--- /dev/null
+++ b/src/dcmtkpp/StoreSCU.h
@@ -0,0 +1,36 @@
+/*************************************************************************
+ * dcmtkpp - 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 _1b2f876e_1ad2_464d_9423_28181320aed0
+#define _1b2f876e_1ad2_464d_9423_28181320aed0
+
+#include "SCU.h"
+
+#include "dcmtkpp/DataSet.h"
+
+namespace dcmtkpp
+{
+
+/// @brief SCU for C-Store services.
+class StoreSCU: public SCU
+{
+public:
+    /// @brief Destructor.
+    virtual ~StoreSCU();
+    
+    /// @brief Set the affected SOP class based on the dataset.
+    void set_affected_sop_class(DataSet const & dataset);
+    
+    /// @brief Perform the C-STORE using an optional callback.
+    void store(DataSet const & dataset,
+        ProgressCallback callback=NULL, void * data=NULL) const;
+};
+
+}
+
+#endif // _1b2f876e_1ad2_464d_9423_28181320aed0
diff --git a/src/dcmtkpp/Tag.cpp b/src/dcmtkpp/Tag.cpp
new file mode 100644
index 0000000..c142a52
--- /dev/null
+++ b/src/dcmtkpp/Tag.cpp
@@ -0,0 +1,198 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/Tag.h"
+
+#include <iomanip>
+#include <ostream>
+#include <sstream>
+#include <string>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcdicent.h>
+#include <dcmtk/dcmdata/dcdict.h>
+#include <dcmtk/dcmdata/dctagkey.h>
+
+#include "dcmtkpp/Exception.h"
+
+namespace dcmtkpp
+{
+
+Tag
+::Tag(uint16_t group, uint16_t element)
+: group(group), element(element)
+{
+    // Nothing else
+}
+
+Tag
+::Tag(uint32_t tag)
+: group(tag >> 16), element(tag & 0xffff)
+{
+    // Nothing else
+}
+
+Tag
+::Tag(std::string const & string)
+{
+    this->_from_string(string);
+}
+
+Tag
+::Tag(char const * string)
+{
+    this->_from_string(string);
+}
+
+bool
+Tag
+::is_private() const
+{
+    return (this->group%2 == 1);
+}
+
+std::string
+Tag
+::get_name() const
+{
+    DcmTagKey const tag(this->group, this->element);
+    DcmDictEntry const * entry = dcmDataDict.rdlock().findEntry(tag, NULL);
+    if(entry == NULL)
+    {
+        throw Exception("No such element");
+    }
+
+    return entry->getTagName();
+}
+
+bool
+Tag
+::operator==(Tag const & other) const
+{
+    return ((this->group == other.group) && (this->element == other.element));
+}
+
+bool
+Tag
+::operator!=(Tag const & other) const
+{
+    return !(*this == other);
+}
+
+bool
+Tag
+::operator<(Tag const & other) const
+{
+    return (
+        (this->group < other.group) ||
+        (this->group == other.group && this->element < other.element));
+}
+
+bool
+Tag
+::operator>(Tag const & other) const
+{
+    return (
+        (this->group > other.group) ||
+        (this->group == other.group && this->element > other.element));
+}
+
+bool
+Tag
+::operator<=(Tag const & other) const
+{
+    return !(*this > other);
+}
+
+bool
+Tag
+::operator>=(Tag const & other) const
+{
+    return !(*this < other);
+}
+
+void
+Tag
+::_from_string(std::string const & string)
+{
+    DcmDictEntry const * entry = dcmDataDict.rdlock().findEntry(string.c_str());
+    if(entry == NULL)
+    {
+        // Try with string form of numeric tag
+        uint16_t group;
+        uint16_t element;
+        bool parsed = true;
+
+        if(string.size() != 8)
+        {
+            parsed = false;
+        }
+        else
+        {
+            std::string const first = string.substr(0, 4);
+            char * endptr;
+            group = strtol(first.c_str(), &endptr, 16);
+            if(*endptr != '\0')
+            {
+                parsed = false;
+            }
+            else
+            {
+                std::string const second = string.substr(4, 4);
+                element = strtol(second.c_str(), &endptr, 16);
+                if(*endptr != '\0')
+                {
+                    parsed = false;
+                }
+            }
+        }
+
+        if(!parsed)
+        {
+            throw Exception("No such element: "+string);
+        }
+        else
+        {
+            this->group = group;
+            this->element = element;
+        }
+    }
+    else
+    {
+        DcmTagKey const tag = entry->getKey();
+        this->group = tag.getGroup();
+        this->element = tag.getElement();
+    }
+}
+
+Tag
+::operator std::string() const
+{
+    std::ostringstream stream;
+    stream << (*this);
+    return stream.str();
+}
+
+std::ostream & operator<<(std::ostream & stream, Tag const & tag)
+{
+    std::ostream::char_type const old_fill = stream.fill();
+    std::streamsize const old_width = stream.width();
+    std::ios::fmtflags const flags = stream.flags();
+
+    stream << std::hex
+           << std::setw(4) << std::setfill('0') << tag.group
+           << std::setw(4) << std::setfill('0') << tag.element;
+
+    stream.setf(flags);
+    stream.width(old_width);
+    stream.fill(old_fill);
+
+    return stream;
+}
+
+}
diff --git a/src/dcmtkpp/Tag.h b/src/dcmtkpp/Tag.h
new file mode 100644
index 0000000..12ec1d6
--- /dev/null
+++ b/src/dcmtkpp/Tag.h
@@ -0,0 +1,97 @@
+/*************************************************************************
+ * dcmtkpp - 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 _5faf4691_e936_476e_8ad3_40f36a167a74
+#define _5faf4691_e936_476e_8ad3_40f36a167a74
+
+#include <cstddef>
+#include <ostream>
+#include <string>
+
+namespace dcmtkpp
+{
+
+/**
+ * @brief A DICOM element tag.
+ */
+class Tag
+{
+public:
+    /// @brief Create a tag based on its group and element as two 16-bits words.
+    Tag(uint16_t group, uint16_t element);
+
+    /// @brief Create a tag based on its group and element as one 32-bits word.
+    Tag(uint32_t tag);
+
+    /**
+     * @brief Create a tag based on its name or string representation of its
+     * numeric value.
+     *
+     * If the name cannot be found in the public data dictionary, or if the
+     * string is not the representation of a numeric value, a dcmtkpp::Exception
+     * is raised.
+     */
+    Tag(std::string const & name);
+
+    /**
+     * @brief Create a tag based on its name or string representation of its
+     * numeric value.
+     *
+     * If the name cannot be found in the public data dictionary, or if the
+     * string is not the representation of a numeric value, a dcmtkpp::Exception
+     * is raised.
+     */
+    Tag(char const * name);
+
+    /// @brief Group of the tag.
+    uint16_t group;
+
+    /// @brief Element of the tag.
+    uint16_t element;
+
+    bool is_private() const;
+
+    /**
+     * @brief Return the name of the tag.
+     *
+     * If the tag cannot be found in the public data dictionary,
+     * a dcmtkpp::Exception is raised.
+     */
+    std::string get_name() const;
+
+    /// @brief Equality test.
+    bool operator==(Tag const & other) const;
+
+    /// @brief Difference test.
+    bool operator!=(Tag const & other) const;
+
+    /// @brief Strict inferiority test.
+    bool operator<(Tag const & other) const;
+
+    /// @brief Strict superiority test.
+    bool operator>(Tag const & other) const;
+
+    /// @brief Loose inferiority test.
+    bool operator<=(Tag const & other) const;
+
+    /// @brief Loose superiority test.
+    bool operator>=(Tag const & other) const;
+
+    /// @brief Convert to string
+    operator std::string() const;
+
+private:
+    void _from_string(std::string const & string);
+};
+
+/// @brief Stream inserter
+std::ostream & operator<<(std::ostream & stream, Tag const & tag);
+
+}
+
+#endif // _5faf4691_e936_476e_8ad3_40f36a167a74
diff --git a/src/dcmtkpp/VR.cpp b/src/dcmtkpp/VR.cpp
new file mode 100644
index 0000000..05b2a7f
--- /dev/null
+++ b/src/dcmtkpp/VR.cpp
@@ -0,0 +1,151 @@
+#include <dcmtkpp/VR.h>
+
+#include <map>
+#include <stdexcept>
+#include <string>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcdicent.h>
+#include <dcmtk/dcmdata/dcdict.h>
+#include <dcmtk/dcmdata/dctagkey.h>
+
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/Tag.h"
+
+// Anonymous namespace, should not be publicly accessed
+namespace
+{
+
+#define ADD_TO_MAP(map, vr) map[dcmtkpp::VR::vr] = #vr
+
+std::map<dcmtkpp::VR, std::string>
+_build_enum_to_name()
+{
+    std::map<dcmtkpp::VR, std::string> result;
+    ADD_TO_MAP(result, AE);
+    ADD_TO_MAP(result, AS);
+    ADD_TO_MAP(result, AT);
+    ADD_TO_MAP(result, CS);
+    ADD_TO_MAP(result, DA);
+    ADD_TO_MAP(result, DS);
+    ADD_TO_MAP(result, DT);
+    ADD_TO_MAP(result, FL);
+    ADD_TO_MAP(result, FD);
+    ADD_TO_MAP(result, IS);
+    ADD_TO_MAP(result, LO);
+    ADD_TO_MAP(result, LT);
+    ADD_TO_MAP(result, PN);
+    ADD_TO_MAP(result, OB);
+    ADD_TO_MAP(result, OF);
+    ADD_TO_MAP(result, OW);
+    ADD_TO_MAP(result, SH);
+    ADD_TO_MAP(result, SL);
+    ADD_TO_MAP(result, SQ);
+    ADD_TO_MAP(result, SS);
+    ADD_TO_MAP(result, ST);
+    ADD_TO_MAP(result, TM);
+    ADD_TO_MAP(result, UC);
+    ADD_TO_MAP(result, UI);
+    ADD_TO_MAP(result, UL);
+    ADD_TO_MAP(result, UN);
+    ADD_TO_MAP(result, UR);
+    ADD_TO_MAP(result, US);
+    ADD_TO_MAP(result, UT);
+
+    return result;
+}
+
+#undef ADD_TO_MAP
+
+std::map<std::string, dcmtkpp::VR>
+_build_name_to_enum()
+{
+    std::map<dcmtkpp::VR, std::string> const enum_to_name = _build_enum_to_name();
+
+    std::map<std::string, dcmtkpp::VR> result;
+    for(std::map<dcmtkpp::VR, std::string>::const_iterator it = enum_to_name.begin();
+        it != enum_to_name.end(); ++it)
+    {
+        result[it->second] = it->first;
+    }
+
+    return result;
+}
+
+std::map<dcmtkpp::VR, std::string> const
+_enum_to_name = _build_enum_to_name();
+
+std::map<std::string, dcmtkpp::VR> const
+_name_to_enum = _build_name_to_enum();
+
+}
+
+namespace dcmtkpp
+{
+
+std::string as_string(VR vr)
+{
+    try
+    {
+        return _enum_to_name.at(vr);
+    }
+    catch(std::out_of_range const &)
+    {
+        throw Exception("Unknown VR");
+    }
+}
+
+VR as_vr(std::string const vr)
+{
+    try
+    {
+        return _name_to_enum.at(vr);
+    }
+    catch(std::out_of_range const &)
+    {
+        throw Exception("Unknown VR: "+vr);
+    }
+}
+
+VR as_vr(Tag const & tag)
+{
+    DcmTagKey const dcmtk_tag(tag.group, tag.element);
+    DcmDictEntry const * entry = dcmDataDict.rdlock().findEntry(dcmtk_tag, NULL);
+    if(entry == NULL)
+    {
+        throw Exception("No such element");
+    }
+
+    VR const vr(as_vr(std::string(entry->getVR().getValidVRName())));
+
+    return vr;
+}
+
+bool is_int(VR vr)
+{
+    return (
+        vr == VR::IS || vr == VR::SL || vr == VR::SS || vr == VR::UL ||
+        vr == VR::US);
+}
+
+bool is_real(VR vr)
+{
+    return (vr == VR::DS || vr == VR::FL || vr == VR::FD);
+}
+
+bool is_string(VR vr)
+{
+    return (
+        vr == VR::AE || vr == VR::AS || vr == VR::CS || vr == VR::DA ||
+        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);
+}
+
+bool is_binary(VR vr)
+{
+    return (vr == VR::OB || vr == VR::OF || vr == VR::OW || vr == VR::UN);
+}
+
+
+}
diff --git a/src/dcmtkpp/VR.h b/src/dcmtkpp/VR.h
new file mode 100644
index 0000000..f60b4b0
--- /dev/null
+++ b/src/dcmtkpp/VR.h
@@ -0,0 +1,59 @@
+/*************************************************************************
+ * dcmtkpp - 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 _998aa43a_9e90_4d39_a074_a7074ac5c9b8
+#define _998aa43a_9e90_4d39_a074_a7074ac5c9b8
+
+#include <string>
+
+namespace dcmtkpp
+{
+
+class Tag;
+
+/// @brief Value representations of DICOM.
+enum class VR
+{
+    UNKNOWN,
+    AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, PN, OB, OF, OW, SH, SL,
+    SQ, SS, ST, TM, UC, UI, UL, UN, UR, US, UT,
+    INVALID
+};
+
+/// @brief Convert a VR to its string representation.
+std::string as_string(VR vr);
+
+/**
+ * @brief Convert a string to its VR.
+ *
+ * If the string does not represent a VR, a dcmtkpp::Exception is raised.
+ */
+VR as_vr(std::string const vr);
+
+/**
+ * @brief Guess a VR from a tag.
+ *
+ * If the VR cannot be guessed, a dcmtkpp::Exception is raised.
+ */
+VR as_vr(Tag const & tag);
+
+/// @brief Test whether a VR contains integers.
+bool is_int(VR vr);
+
+/// @brief Test whether a VR contains rel numbers.
+bool is_real(VR vr);
+
+/// @brief Test whether a VR contains text.
+bool is_string(VR vr);
+
+/// @brief Test whether a VR contains binary data.
+bool is_binary(VR vr);
+
+}
+
+#endif // _998aa43a_9e90_4d39_a074_a7074ac5c9b8
diff --git a/src/dcmtkpp/VRTraits.h b/src/dcmtkpp/VRTraits.h
new file mode 100644
index 0000000..feb3491
--- /dev/null
+++ b/src/dcmtkpp/VRTraits.h
@@ -0,0 +1,66 @@
+/*************************************************************************
+ * dcmtkpp - 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 _4f556093_02e3_4659_9026_2b16bc2c8a51
+#define _4f556093_02e3_4659_9026_2b16bc2c8a51
+
+namespace dcmtkpp
+{
+
+/**
+ * @class dcmtkpp::VRTraits
+ * @brief Information related to VR.
+ *
+ * The members are:
+ * - ValueType: the DCMTK type of the VR
+ */
+template<DcmEVR VR>
+struct VRTraits;
+
+#define DECLARE_VR_TRAITS(vr, value_type) \
+/** @brief Traits for generic data access to values of DcmElement. */ \
+template<> \
+struct VRTraits<vr> \
+{ \
+    /** @brief Type associated to the VR. */ \
+    typedef value_type ValueType; \
+};
+
+DECLARE_VR_TRAITS(EVR_AE, std::string)
+DECLARE_VR_TRAITS(EVR_AS, std::string)
+//DECLARE_VR_TRAITS(EVR_AT
+DECLARE_VR_TRAITS(EVR_CS, std::string)
+DECLARE_VR_TRAITS(EVR_DA, std::string)
+DECLARE_VR_TRAITS(EVR_DS, Float64)
+DECLARE_VR_TRAITS(EVR_DT, std::string)
+DECLARE_VR_TRAITS(EVR_FD, Float64)
+DECLARE_VR_TRAITS(EVR_FL, Float32)
+DECLARE_VR_TRAITS(EVR_IS, Sint32)
+DECLARE_VR_TRAITS(EVR_LO, std::string)
+DECLARE_VR_TRAITS(EVR_LT, std::string)
+DECLARE_VR_TRAITS(EVR_OB, std::vector<unsigned char>)
+DECLARE_VR_TRAITS(EVR_OF, std::vector<unsigned char>)
+DECLARE_VR_TRAITS(EVR_OW, std::vector<unsigned char>)
+DECLARE_VR_TRAITS(EVR_PN, std::string)
+DECLARE_VR_TRAITS(EVR_SH, std::string)
+DECLARE_VR_TRAITS(EVR_SL, Sint32)
+//DECLARE_VR_TRAITS(EVR_SQ
+DECLARE_VR_TRAITS(EVR_SS, Sint16)
+DECLARE_VR_TRAITS(EVR_ST, std::string)
+DECLARE_VR_TRAITS(EVR_TM, std::string)
+DECLARE_VR_TRAITS(EVR_UI, std::string)
+DECLARE_VR_TRAITS(EVR_UL, Uint32)
+DECLARE_VR_TRAITS(EVR_UN, std::vector<unsigned char>)
+DECLARE_VR_TRAITS(EVR_US, Uint16)
+DECLARE_VR_TRAITS(EVR_UT, std::string)
+
+#undef DECLARE_VR_TRAITS
+
+}
+
+#endif // _4f556093_02e3_4659_9026_2b16bc2c8a51
diff --git a/src/dcmtkpp/Value.cpp b/src/dcmtkpp/Value.cpp
new file mode 100644
index 0000000..6bac089
--- /dev/null
+++ b/src/dcmtkpp/Value.cpp
@@ -0,0 +1,196 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/Value.h"
+
+#include <cstdint>
+#include <initializer_list>
+#include <string>
+#include <vector>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+
+namespace dcmtkpp
+{
+
+Value
+::Value()
+: _type(Type::Empty)
+{
+    // Nothing else.
+}
+
+Value
+::Value(Integers const & integers)
+: _type(Type::Integers), _integers(integers)
+{
+    // Nothing else.
+}
+
+Value
+::Value(Reals const & reals)
+: _type(Type::Reals), _reals(reals)
+{
+    // Nothing else.
+}
+
+Value
+::Value(Strings const & strings)
+: _type(Type::Strings), _strings(strings)
+{
+    // Nothing else.
+}
+
+Value
+::Value(DataSets const & datasets)
+: _type(Type::DataSets), _data_sets(datasets)
+{
+    // Nothing else.
+}
+
+Value
+::Value(Binary const & binary)
+: _type(Type::Binary), _binary(binary)
+{
+    // Nothing else.
+}
+
+Value
+::Value(std::initializer_list<int> const & list)
+: _type(Type::Integers)
+{
+    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)
+{
+    // Nothing else
+}
+
+Value
+::Value(std::initializer_list<Real> const & list)
+: _type(Type::Reals), _reals(list)
+{
+    // Nothing else
+}
+
+Value
+::Value(std::initializer_list<String> const & list)
+: _type(Type::Strings), _strings(list)
+{
+    // Nothing else
+}
+
+Value
+::Value(std::initializer_list<DataSet> const & list)
+: _type(Type::DataSets), _data_sets(list)
+{
+    // Nothing else
+}
+
+Value::Type
+Value
+::get_type() const
+{
+    return this->_type;
+}
+
+#define DECLARE_CONST_ACCESSOR(type, name) \
+Value::type const & \
+Value \
+::as_##name() const \
+{ \
+    if(this->get_type() != Type::type) \
+    { \
+        throw Exception("Type mismatch"); \
+    } \
+    return this->_##name; \
+}
+
+#define DECLARE_NON_CONST_ACCESSOR(type, name) \
+Value::type & \
+Value \
+::as_##name() \
+{ \
+    if(this->get_type() != Type::type) \
+    { \
+        throw Exception("Type mismatch"); \
+    } \
+    return this->_##name; \
+}
+
+DECLARE_CONST_ACCESSOR(Integers, integers)
+DECLARE_NON_CONST_ACCESSOR(Integers, integers)
+
+DECLARE_CONST_ACCESSOR(Reals, reals)
+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)
+
+DECLARE_CONST_ACCESSOR(Binary, binary)
+DECLARE_NON_CONST_ACCESSOR(Binary, binary)
+
+#undef DECLARE_NON_CONST_ACCESSOR
+#undef DECLARE_CONST_ACCESSOR
+
+bool
+Value
+::operator==(Value const & other) const
+{
+    if(this->_type != other._type)
+    {
+        return false;
+    }
+    else if(this->_type == Value::Type::Empty)
+    {
+        return true;
+    }
+    else if(this->_type == Value::Type::Integers)
+    {
+        return this->_integers == other._integers;
+    }
+    else if(this->_type == Value::Type::Reals)
+    {
+        return this->_reals == other._reals;
+    }
+    else if(this->_type == Value::Type::Strings)
+    {
+        return this->_strings == other._strings;
+    }
+    else if(this->_type == Value::Type::DataSets)
+    {
+        return this->_data_sets == other._data_sets;
+    }
+    else if(this->_type == Value::Type::Binary)
+    {
+        return this->_binary == other._binary;
+    }
+    else
+    {
+        throw Exception("Unknown type");
+    }
+}
+
+bool
+Value
+::operator!=(Value const & other) const
+{
+    return !(*this == other);
+}
+
+
+
+}
diff --git a/src/dcmtkpp/Value.h b/src/dcmtkpp/Value.h
new file mode 100644
index 0000000..5e7c1ed
--- /dev/null
+++ b/src/dcmtkpp/Value.h
@@ -0,0 +1,193 @@
+/*************************************************************************
+ * dcmtkpp - 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 _dca5b15b_b8df_4925_a446_d42efe06c923
+#define _dca5b15b_b8df_4925_a446_d42efe06c923
+
+#include <cstdint>
+#include <initializer_list>
+#include <string>
+#include <vector>
+
+namespace dcmtkpp
+{
+
+class DataSet;
+
+/**
+ * @brief A value held in a DICOM element.
+ */
+class Value
+{
+public:
+    /// @brief Possible types stored in the value.
+    enum class Type
+    {
+        Empty,
+        Integers,
+        Reals,
+        Strings,
+        DataSets,
+        Binary
+    };
+
+    typedef int64_t Integer;
+
+    typedef double Real;
+
+    typedef std::string String;
+
+    /// @brief Integer container.
+    typedef std::vector<Integer> Integers;
+
+    /// @brief Real container.
+    typedef std::vector<Real> Reals;
+
+    /// @brief String container.
+    typedef std::vector<String> Strings;
+
+    /// @brief Data sets container.
+    typedef std::vector<DataSet> DataSets;
+
+    /// @brief Binary data container.
+    typedef 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);
+
+    /// @brief Build a value from integers.
+    Value(std::initializer_list<Integer> const & list);
+
+    /// @brief Build a value from reals.
+    Value(std::initializer_list<Real> const & list);
+
+    /// @brief Build a value from strings.
+    Value(std::initializer_list<String> const & list);
+
+    /// @brief Build a value from data sets.
+    Value(std::initializer_list<DataSet> const & list);
+
+    /// @brief Return the type store in the value.
+    Type get_type() const;
+
+    /**
+     * @brief Return the integers contained in the value.
+     *
+     * If the value does not contain integers, a dcmtkpp::Exception is raised.
+     */
+    Integers const & as_integers() const;
+
+    /**
+     * @brief Return the integers contained in the value.
+     *
+     * If the value does not contain integers, a dcmtkpp::Exception is raised.
+     */
+    Integers & as_integers();
+
+    /**
+     * @brief Return the reals contained in the value.
+     *
+     * If the value does not contain reals, a dcmtkpp::Exception is raised.
+     */
+    Reals const & as_reals() const;
+
+    /**
+     * @brief Return the reals contained in the value.
+     *
+     * If the value does not contain reals, a dcmtkpp::Exception is raised.
+     */
+    Reals & as_reals();
+
+    /**
+     * @brief Return the strings contained in the value.
+     *
+     * If the value does not contain strings, a dcmtkpp::Exception is raised.
+     */
+    Strings const & as_strings() const;
+
+    /**
+     * @brief Return the strings contained in the value.
+     *
+     * If the value does not contain strings, a dcmtkpp::Exception is raised.
+     */
+    Strings & as_strings();
+
+    /**
+     * @brief Return the data sets contained in the value.
+     *
+     * If the value does not contain data sets, a dcmtkpp::Exception is raised.
+     */
+    DataSets const & as_data_sets() const;
+
+    /**
+     * @brief Return the data sets contained in the value.
+     *
+     * If the value does not contain data sets, a dcmtkpp::Exception is raised.
+     */
+    DataSets & as_data_sets();
+
+    /**
+     * @brief Return the binary data contained in the value.
+     *
+     * If the value does not contain binary data, a dcmtkpp::Exception is raised.
+     */
+    Binary const & as_binary() const;
+
+    /**
+     * @brief Return the binary data contained in the value.
+     *
+     * If the value does not contain binary data, a dcmtkpp::Exception is raised.
+     */
+    Binary & as_binary();
+
+    /// @brief Equality test.
+    bool operator==(Value const & other) const;
+
+    /// @brief Difference test.
+    bool operator!=(Value const & other) const;
+
+private:
+    Integers _integers;
+    Reals _reals;
+    Strings _strings;
+    DataSets _data_sets;
+    Binary _binary;
+
+    Type _type;
+};
+
+/**
+ * @brief Visitor of values.
+ */
+template<typename TVisitor>
+typename TVisitor::result_type
+apply_visitor(TVisitor const & visitor, Value const & value);
+
+}
+
+#include "dcmtkpp/Value.txx"
+
+#endif // _dca5b15b_b8df_4925_a446_d42efe06c923
diff --git a/src/dcmtkpp/Value.txx b/src/dcmtkpp/Value.txx
new file mode 100644
index 0000000..55745c8
--- /dev/null
+++ b/src/dcmtkpp/Value.txx
@@ -0,0 +1,54 @@
+/*************************************************************************
+ * dcmtkpp - 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 _de64b8e1_4116_41f8_a085_dabfdc6c63c3
+#define _de64b8e1_4116_41f8_a085_dabfdc6c63c3
+
+#include "dcmtkpp/Value.h"
+
+#include "dcmtkpp/Exception.h"
+
+namespace dcmtkpp
+{
+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)
+    {
+        return visitor(value.as_integers());
+    }
+    else if(value.get_type() == Value::Type::Reals)
+    {
+        return visitor(value.as_reals());
+    }
+    else if(value.get_type() == Value::Type::Strings)
+    {
+        return visitor(value.as_strings());
+    }
+    else if(value.get_type() == Value::Type::DataSets)
+    {
+        return visitor(value.as_data_sets());
+    }
+    else if(value.get_type() == Value::Type::Binary)
+    {
+        return visitor(value.as_binary());
+    }
+    else
+    {
+        throw Exception("Unknown value type");
+    }
+}
+
+}
+
+#endif // _de64b8e1_4116_41f8_a085_dabfdc6c63c3
diff --git a/src/dcmtkpp/conversion.cpp b/src/dcmtkpp/conversion.cpp
new file mode 100644
index 0000000..d1da178
--- /dev/null
+++ b/src/dcmtkpp/conversion.cpp
@@ -0,0 +1,485 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/conversion.h"
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dctk.h>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Element.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/Tag.h"
+#include "dcmtkpp/VR.h"
+
+namespace dcmtkpp
+{
+
+DcmEVR convert(VR vr)
+{
+    if(vr == VR::AE) { return EVR_AE; }
+    else if(vr == VR::AS) { return EVR_AS; }
+    else if(vr == VR::AT) { return EVR_AT; }
+    else if(vr == VR::CS) { return EVR_CS; }
+    else if(vr == VR::DA) { return EVR_DA; }
+    else if(vr == VR::DS) { return EVR_DS; }
+    else if(vr == VR::DT) { return EVR_DT; }
+    else if(vr == VR::FL) { return EVR_FL; }
+    else if(vr == VR::FD) { return EVR_FD; }
+    else if(vr == VR::IS) { return EVR_IS; }
+    else if(vr == VR::LO) { return EVR_LO; }
+    else if(vr == VR::LT) { return EVR_LT; }
+    else if(vr == VR::OB) { return EVR_OB; }
+    else if(vr == VR::OF) { return EVR_OF; }
+    else if(vr == VR::OW) { return EVR_OW; }
+    else if(vr == VR::PN) { return EVR_PN; }
+    else if(vr == VR::SH) { return EVR_SH; }
+    else if(vr == VR::SL) { return EVR_SL; }
+    else if(vr == VR::SQ) { return EVR_SQ; }
+    else if(vr == VR::SS) { return EVR_SS; }
+    else if(vr == VR::ST) { return EVR_ST; }
+    else if(vr == VR::TM) { return EVR_TM; }
+    else if(vr == VR::UI) { return EVR_UI; }
+    else if(vr == VR::UL) { return EVR_UL; }
+    else if(vr == VR::UN) { return EVR_UN; }
+    else if(vr == VR::US) { return EVR_US; }
+    else if(vr == VR::UT) { return EVR_UT; }
+    else
+    {
+        throw Exception("Unknown VR");
+    }
+}
+
+VR convert(DcmEVR evr)
+{
+    if(evr == EVR_AE) { return VR::AE; }
+    else if(evr == EVR_AS) { return VR::AS; }
+    else if(evr == EVR_AT) { return VR::AT; }
+    else if(evr == EVR_CS) { return VR::CS; }
+    else if(evr == EVR_DA) { return VR::DA; }
+    else if(evr == EVR_DS) { return VR::DS; }
+    else if(evr == EVR_DT) { return VR::DT; }
+    else if(evr == EVR_FL) { return VR::FL; }
+    else if(evr == EVR_FD) { return VR::FD; }
+    else if(evr == EVR_IS) { return VR::IS; }
+    else if(evr == EVR_LO) { return VR::LO; }
+    else if(evr == EVR_LT) { return VR::LT; }
+    else if(evr == EVR_OB) { return VR::OB; }
+    else if(evr == EVR_OF) { return VR::OF; }
+    else if(evr == EVR_OW) { return VR::OW; }
+    else if(evr == EVR_PN) { return VR::PN; }
+    else if(evr == EVR_SH) { return VR::SH; }
+    else if(evr == EVR_SL) { return VR::SL; }
+    else if(evr == EVR_SQ) { return VR::SQ; }
+    else if(evr == EVR_SS) { return VR::SS; }
+    else if(evr == EVR_ST) { return VR::ST; }
+    else if(evr == EVR_TM) { return VR::TM; }
+    else if(evr == EVR_UI) { return VR::UI; }
+    else if(evr == EVR_UL) { return VR::UL; }
+    else if(evr == EVR_UN) { return VR::UN; }
+    else if(evr == EVR_US) { return VR::US; }
+    else if(evr == EVR_UT) { return VR::UT; }
+    else
+    {
+        throw Exception("Unknown VR");
+    }
+}
+
+DcmTagKey convert(Tag const & tag)
+{
+    return DcmTagKey(tag.group, tag.element);
+}
+
+Tag convert(DcmTagKey const & tag)
+{
+    return Tag(tag.getGroup(), tag.getElement());
+}
+
+DcmElement * convert(const Tag & tag, Element const & source)
+{
+    DcmTag const destination_tag(convert(tag), convert(source.vr));
+
+    DcmElement * destination = NULL;
+    if(source.vr == VR::AE)
+    {
+        destination = new DcmApplicationEntity(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else if (source.vr == VR::AS)
+    {
+        destination = new DcmAgeString(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else if(source.vr == VR::AT)
+    {
+        destination = new DcmAttributeTag(destination_tag);
+        if(!source.empty())
+        {
+            for(unsigned int i=0; i<source.as_string().size(); ++i)
+            {
+                Tag const source_tag(source.as_string()[i]);
+                DcmTagKey const destination_tag = convert(source_tag);
+                destination->putTagVal(destination_tag, i);
+            }
+        }
+    }
+    else if (source.vr == VR::CS)
+    {
+        destination = new DcmCodeString(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else if (source.vr == VR::DA)
+    {
+        destination = new DcmDate(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else if (source.vr == VR::DS)
+    {
+        destination = new DcmDecimalString(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Reals>(source, destination, &Element::as_real);
+        }
+    }
+    else if (source.vr == VR::DT)
+    {
+        destination = new DcmDateTime(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else if (source.vr == VR::FD)
+    {
+        destination = new DcmFloatingPointDouble(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Reals, Float64>(source, destination, &Element::as_real);
+        }
+    }
+    else if (source.vr == VR::FL)
+    {
+        destination = new DcmFloatingPointSingle(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Reals, Float32>(source, destination, &Element::as_real);
+        }
+    }
+    else if (source.vr == VR::IS)
+    {
+        destination = new DcmIntegerString(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Integers>(source, destination, &Element::as_int);
+        }
+    }
+    else if (source.vr == VR::LO)
+    {
+        destination = new DcmLongString(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else if (source.vr == VR::LT)
+    {
+        destination = new DcmLongText(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else if (source.vr == VR::OB || source.vr == VR::OW)
+    {
+        destination = new DcmOtherByteOtherWord(destination_tag);
+        if(!source.empty())
+        {
+            convert(source, static_cast<DcmOtherByteOtherWord*>(destination));
+        }
+    }
+    // OF
+    else if (source.vr == VR::PN)
+    {
+        destination = new DcmPersonName(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else if (source.vr == VR::SH)
+    {
+        destination = new DcmShortString(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else if (source.vr == VR::SL)
+    {
+        destination = new DcmSignedLong(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Integers, Sint32>(source, destination, &Element::as_int);
+        }
+    }
+    else if(source.vr == VR::SQ)
+    {
+        DcmSequenceOfItems * sequence = new DcmSequenceOfItems(destination_tag);
+        if(!source.empty())
+        {
+            for(auto const & source_item: source.as_data_set())
+            {
+                DcmItem * destination_item = convert(source_item);
+                sequence->append(destination_item);
+            }
+        }
+        destination = sequence;
+    }
+    else if (source.vr == VR::SS)
+    {
+        destination = new DcmSignedShort(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Integers, Sint16>(source, destination, &Element::as_int);
+        }
+    }
+    else if (source.vr == VR::ST)
+    {
+        destination = new DcmShortText(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else if (source.vr == VR::TM)
+    {
+        destination = new DcmTime(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else if (source.vr == VR::UI)
+    {
+        destination = new DcmUniqueIdentifier(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else if (source.vr == VR::UL)
+    {
+        destination = new DcmUnsignedLong(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Integers, Uint32>(source, destination, &Element::as_int);
+        }
+    }
+    // UN
+    else if (source.vr == VR::US)
+    {
+        destination = new DcmUnsignedShort(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Integers, Uint16>(source, destination, &Element::as_int);
+        }
+    }
+    else if (source.vr == VR::UT)
+    {
+        destination = new DcmUnlimitedText(destination_tag);
+        if(!source.empty())
+        {
+            convert<Value::Strings>(source, destination, &Element::as_string);
+        }
+    }
+    else
+    {
+        throw Exception("Unknown VR");
+    }
+
+    return destination;
+}
+
+template<>
+void convert<std::vector<uint8_t>, Value::Binary>(
+    DcmElement * source, Element & destination,
+    Value::Binary & (Element::*getter)())
+{
+    auto & destination_values = (destination.*getter)();
+    destination_values =
+        dcmtkpp::ElementAccessor<std::vector<uint8_t>>::element_get(*source, 0);
+}
+
+Element convert(DcmElement * source)
+{
+    Element destination;
+
+    DcmEVR const source_vr = source->getTag().getVR().getValidEVR();
+    VR const destination_vr = convert(source_vr);
+
+    if(source_vr == EVR_AE || source_vr == EVR_AS || source_vr == EVR_CS ||
+       source_vr == EVR_DA || source_vr == EVR_DT || source_vr == EVR_LO ||
+       source_vr == EVR_LT || source_vr == EVR_PN || source_vr == EVR_SH ||
+       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);
+    }
+    else if(source_vr == EVR_AT)
+    {
+        destination = Element(Value::Strings(), destination_vr);
+        destination.as_string().reserve(source->getVM());
+        for(unsigned int i=0; i<source->getVM(); ++i)
+        {
+            DcmTagKey source_tag;
+            OFCondition const condition = source->getTagVal(source_tag, i);
+            if(condition.bad())
+            {
+                throw Exception(condition);
+            }
+            Tag const destination_tag = convert(source_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);
+    }
+    else if(source_vr == EVR_FL)
+    {
+        destination = 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);
+    }
+    else if(source_vr == EVR_SQ)
+    {
+        destination = 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();
+
+        destination_value.reserve(sequence->card());
+        for(unsigned int i=0; i<sequence->card(); ++i)
+        {
+            DcmItem * source_item = sequence->getItem(i);
+            DataSet const destination_item = convert(source_item);
+            destination_value.push_back(destination_item);
+        }
+    }
+    else if(source_vr == EVR_SS)
+    {
+        destination = 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);
+    }
+    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);
+    }
+    else if(source_vr == EVR_US)
+    {
+        destination = Element(Value::Integers(), destination_vr);
+        convert<Uint16, Value::Integers>(source, destination, &Element::as_int);
+    }
+    else
+    {
+        throw Exception("Unknown VR");
+    }
+
+    return destination;
+}
+
+void convert(Element const & source, DcmOtherByteOtherWord * destination)
+{
+    auto const & value = source.as_binary();
+
+    Uint8 * output;
+    OFCondition condition;
+    if(destination->getTag().getVR().getValidEVR() == EVR_OB)
+    {
+        condition = destination->createUint8Array(source.size(), output);
+    }
+    else
+    {
+        Uint16* temp;
+        condition = destination->createUint16Array(source.size()/2, temp);
+        output = reinterpret_cast<Uint8*>(temp);
+    }
+
+    if(condition.bad())
+    {
+        throw Exception(condition);
+    }
+
+    std::copy(value.begin(), value.end(), output);
+}
+
+void convert(Element const & source, DcmOtherFloat * destination)
+{
+    auto const & value = source.as_binary();
+}
+
+DcmItem * convert(DataSet const & source)
+{
+    DcmDataset * destination = new DcmDataset();
+
+    for(auto const & iterator: source)
+    {
+        auto const destination_element = convert(
+            iterator.first, iterator.second);
+        destination->insert(destination_element);
+    }
+
+    return destination;
+}
+
+DataSet convert(DcmItem * source)
+{
+    DataSet destination;
+
+    for(unsigned long i=0; i<source->card(); ++i)
+    {
+        auto const source_element = source->getElement(i);
+
+        auto const destination_tag = convert(source_element->getTag());
+        auto const destination_element = convert(source_element);
+
+        destination.add(destination_tag, destination_element);
+    }
+    return destination;
+}
+
+}
diff --git a/src/dcmtkpp/conversion.h b/src/dcmtkpp/conversion.h
new file mode 100644
index 0000000..b39bf9a
--- /dev/null
+++ b/src/dcmtkpp/conversion.h
@@ -0,0 +1,72 @@
+/*************************************************************************
+ * dcmtkpp - 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 _d5ecacb8_04ff_48b0_8026_570c9b2ae360
+#define _d5ecacb8_04ff_48b0_8026_570c9b2ae360
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dctk.h>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Element.h"
+#include "dcmtkpp/Tag.h"
+#include "dcmtkpp/VR.h"
+
+namespace dcmtkpp
+{
+
+/// @brief Convert a dcmtkpp::VR to a DcmVR.
+DcmEVR convert(VR vr);
+
+/// @brief Convert a DcmVR to a dcmtkpp::VR.
+VR convert(DcmEVR evr);
+
+/// @brief Convert a dcmtkpp::Tag to a DcmTagKey.
+DcmTagKey convert(Tag const & tag);
+
+/// @brief Convert a DcmTagKey to a dcmtkpp::Tag.
+Tag convert(DcmTagKey const & tag);
+
+/// @brief Convert a dcmtkpp::Element to a DcmElement.
+DcmElement * convert(Tag const & tag, Element const & source);
+
+/// @brief Low-level element converter.
+template<typename TSourceType, typename TDestinationType>
+void convert(
+    Element const & source, DcmElement * destination,
+    TSourceType const & (Element::*getter)() const);
+
+/// @brief Convert a DcmElement to a dcmtkpp::Element.
+Element convert(DcmElement * source);
+
+/// @brief Low-level element converter.
+template<typename TSourceType>
+void convert(
+    Element const & source, DcmElement * destination,
+    TSourceType const & (Element::*getter)() const);
+
+/// @brief Low-level element converver.
+void convert(Element const & source, DcmOtherByteOtherWord * destination);
+
+/// @brief Low-level element converter.
+template<typename TSourceType, typename TDestinationType>
+void convert(
+    DcmElement * source, Element & destination,
+    TDestinationType & (Element::*getter)());
+
+/// @brief Convert a dcmtkpp::DataSet to a DcmDataset.
+DcmItem * convert(DataSet const & source);
+
+/// @brief Convert a DcmDataset to a dcmtkpp::DataSet.
+DataSet convert(DcmItem * source);
+
+}
+
+#include <dcmtkpp/conversion.txx>
+
+#endif // _d5ecacb8_04ff_48b0_8026_570c9b2ae360
diff --git a/src/dcmtkpp/conversion.txx b/src/dcmtkpp/conversion.txx
new file mode 100644
index 0000000..0c296eb
--- /dev/null
+++ b/src/dcmtkpp/conversion.txx
@@ -0,0 +1,82 @@
+/*************************************************************************
+ * dcmtkpp - 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 _665b5269_140c_4320_94f2_ad8a7c052e9b
+#define _665b5269_140c_4320_94f2_ad8a7c052e9b
+
+#include "dcmtkpp/conversion.h"
+
+#include <sstream>
+
+#include "dcmtkpp/Element.h"
+#include "dcmtkpp/ElementAccessor.h"
+
+namespace dcmtkpp
+{
+
+template<typename TSourceType, typename TDestinationType>
+void convert(
+    Element const & source, DcmElement * destination,
+    TSourceType const & (Element::*getter)() const)
+{
+    auto const & source_values = (source.*getter)();
+    for(auto i = 0; i<source_values.size(); ++i)
+    {
+        ElementAccessor<TDestinationType>::element_set(
+            *destination, source_values[i], i);
+    }
+}
+
+template<typename TSourceType>
+void convert(
+    Element const & source, DcmElement * destination,
+    TSourceType const & (Element::*getter)() const)
+{
+    OFString destination_value;
+
+    auto const & source_values = (source.*getter)();
+    if(!source_values.empty())
+    {
+        auto const last_it = --source_values.end();
+        auto it = source_values.begin();
+        while(it != last_it)
+        {
+            std::ostringstream stream;
+            stream << *it;
+            destination_value += stream.str().c_str();
+            destination_value += "\\";
+            ++it;
+        }
+
+        std::ostringstream stream;
+        stream << *last_it;
+        destination_value += stream.str().c_str();
+    }
+
+    destination->putOFStringArray(destination_value);
+}
+
+template<typename TSourceType, typename TDestinationType>
+void convert(
+    DcmElement * source, Element & destination,
+    TDestinationType & (Element::*getter)())
+{
+    auto & destination_values = (destination.*getter)();
+
+    destination_values.reserve(source->getVM());
+
+    for(auto i = 0; i<source->getVM(); ++i)
+    {
+        destination_values.push_back(
+            dcmtkpp::ElementAccessor<TSourceType>::element_get(*source, i));
+    }
+}
+
+}
+
+#endif // _665b5269_140c_4320_94f2_ad8a7c052e9b
diff --git a/src/dcmtkpp/json_converter.cpp b/src/dcmtkpp/json_converter.cpp
new file mode 100644
index 0000000..ac53f04
--- /dev/null
+++ b/src/dcmtkpp/json_converter.cpp
@@ -0,0 +1,280 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/json_converter.h"
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/ofstd/ofstd.h>
+#include <dcmtk/ofstd/ofstream.h>
+#include <jsoncpp/json/json.h>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/Value.h"
+#include "dcmtkpp/VR.h"
+
+namespace dcmtkpp
+{
+
+struct ToJSONVisitor
+{
+    typedef Json::Value result_type;
+
+    result_type operator()(VR const vr) const
+    {
+        result_type result;
+
+        result["vr"] = as_string(vr);
+
+        return result;
+    }
+
+    template<typename T>
+    result_type operator()(VR const vr, T const & value) const
+    {
+        result_type result;
+
+        result["vr"] = as_string(vr);
+
+        for(auto const & item: value)
+        {
+            result["Value"].append(item);
+        }
+
+        return result;
+    }
+
+    result_type operator()(VR const vr, Value::Integers const & value) const
+    {
+        result_type result;
+
+        result["vr"] = as_string(vr);
+
+        for(auto const & item: value)
+        {
+            result["Value"].append(Json::Int64(item));
+        }
+        return result;
+    }
+
+    result_type operator()(VR const vr, Value::Strings const & value) const
+    {
+        result_type result;
+
+        result["vr"] = as_string(vr);
+
+        if(vr == VR::PN)
+        {
+            auto const fields = { "Alphabetic", "Ideographic", "Phonetic" };
+
+            for(auto const item: value)
+            {
+                auto fields_it = fields.begin();
+
+                Json::Value json_item;
+
+                std::string::size_type begin=0;
+                while(begin != std::string::npos)
+                {
+                    std::string::size_type const end = item.find("=", begin);
+
+                    std::string::size_type size = 0;
+                    if(end != std::string::npos)
+                    {
+                        size = end-begin;
+                    }
+                    else
+                    {
+                        size = std::string::npos;
+                    }
+
+                    json_item[*fields_it] = item.substr(begin, size);
+
+                    if(end != std::string::npos)
+                    {
+                        begin = end+1;
+                        ++fields_it;
+                        if(fields_it == fields.end())
+                        {
+                            throw Exception("Invalid Person Name");
+                        }
+                    }
+                    else
+                    {
+                        begin = end;
+                    }
+                }
+                result["Value"].append(json_item);
+            }
+        }
+        else
+        {
+            for(auto const & item: value)
+            {
+                result["Value"].append(item);
+            }
+        }
+        return result;
+    }
+
+    result_type operator()(VR const vr, Value::DataSets const & value) const
+    {
+        result_type result;
+
+        result["vr"] = as_string(vr);
+
+        for(auto const & item: value)
+        {
+            result["Value"].append(as_json(item));
+        }
+        return result;
+    }
+
+    result_type operator()(VR const vr, Value::Binary const & value) const
+    {
+        result_type result;
+
+        result["vr"] = as_string(vr);
+
+        unsigned char const * data =
+            reinterpret_cast<unsigned char const *>(&value[0]);
+        OFStringStream stream;
+        OFStandard::encodeBase64(stream, data, value.size());
+        result["InlineBinary"] = stream.str().c_str();
+
+        return result;
+    }
+
+};
+
+Json::Value as_json(DataSet const & data_set)
+{
+    Json::Value json;
+
+    for(auto const & it: data_set)
+    {
+        auto const & tag = it.first;
+        auto const & element = it.second;
+
+        std::string const key(tag);
+        auto const value = apply_visitor(ToJSONVisitor(), element);
+        json[key] = value;
+    }
+
+    return json;
+}
+
+DataSet as_dataset(Json::Value const & json)
+{
+    DataSet data_set;
+
+    for(Json::Value::const_iterator it=json.begin(); it != json.end(); ++it)
+    {
+        Tag const tag(it.memberName());
+
+        Json::Value const & json_element = *it;
+        VR const vr = as_vr(json_element["vr"].asString());
+
+        Element element;
+
+        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)
+        {
+            element = Element(Value::Strings(), vr);
+
+            auto const & json_value = json_element["Value"];
+            for(auto const & json_item: json_value)
+            {
+                element.as_string().push_back(json_item.asString());
+            }
+        }
+        else if(vr == VR::PN)
+        {
+            element = Element(Value::Strings(), vr);
+            auto const & json_value = json_element["Value"];
+            for(auto const & json_item: json_value)
+            {   
+                Value::Strings::value_type dicom_item;
+                auto const fields = { "Alphabetic", "Ideographic", "Phonetic" };
+                for(auto const & field: fields)
+                {
+                    if(json_item.isMember(field))
+                    {
+                        dicom_item += json_item[field].asString();
+                    }
+                    dicom_item += "=";
+                }
+
+                while(*dicom_item.rbegin() == '=')
+                {
+                    dicom_item = dicom_item.substr(0, dicom_item.size()-1);
+                }
+
+                element.as_string().push_back(dicom_item);
+            }
+        }
+        else if(vr == VR::DS || vr == VR::FD || vr == VR::FL)
+        {
+            element = Element(Value::Reals(), vr);
+
+            auto const & json_value = json_element["Value"];
+            for(auto const & json_item: json_value)
+            {
+                element.as_real().push_back(json_item.asDouble());
+            }
+        }
+        else if(vr == VR::IS || vr == VR::SL || vr == VR::SS ||
+                vr == VR::UL || vr == VR::US)
+        {
+            element = Element(Value::Integers(), vr);
+
+            auto const & json_value = json_element["Value"];
+            for(auto const & json_item: json_value)
+            {
+                element.as_int().push_back(json_item.asInt64());
+            }
+        }
+        else if(vr == VR::SQ)
+        {
+            element = Element(Value::DataSets(), vr);
+            auto const & json_value = json_element["Value"];
+            for(auto const & json_item: json_value)
+            {
+                auto const dicom_item = as_dataset(json_item);
+                element.as_data_set().push_back(dicom_item);
+            }
+        }
+        else if(vr == VR::OB || vr == VR::OF || vr == VR::OW || vr == VR::UN)
+        {
+            element = Element(Value::Binary(), vr);
+
+            auto const & encoded = json_element["InlineBinary"].asString();
+            OFString const encoded_dcmtk(encoded.c_str());
+            unsigned char * decoded;
+            size_t const decoded_size =
+                OFStandard::decodeBase64(encoded_dcmtk, decoded);
+
+            element.as_binary().resize(decoded_size);
+            std::copy(decoded, decoded+decoded_size, element.as_binary().begin());
+
+            delete[] decoded;
+        }
+        else
+        {
+            throw Exception("Unknown VR: "+as_string(vr));
+        }
+
+        data_set.add(tag, element);
+    }
+
+    return data_set;
+}
+
+}
diff --git a/src/dcmtkpp/json_converter.h b/src/dcmtkpp/json_converter.h
new file mode 100644
index 0000000..b80c478
--- /dev/null
+++ b/src/dcmtkpp/json_converter.h
@@ -0,0 +1,26 @@
+/*************************************************************************
+ * dcmtkpp - 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 _6f5dc463_a89a_4f77_a0ed_36dca74b9e59
+#define _6f5dc463_a89a_4f77_a0ed_36dca74b9e59
+
+#include <jsoncpp/json/json.h>
+#include "dcmtkpp/DataSet.h"
+
+namespace dcmtkpp
+{
+
+/// @brief Convert a data set to its JSON representation.
+Json::Value as_json(DataSet const & data_set);
+
+/// @brief Create a data set from its JSON representation.
+DataSet as_dataset(Json::Value const & json);
+
+}
+
+#endif // _6f5dc463_a89a_4f77_a0ed_36dca74b9e59
diff --git a/src/dcmtkpp/registry.h b/src/dcmtkpp/registry.h
new file mode 100644
index 0000000..279d7d8
--- /dev/null
+++ b/src/dcmtkpp/registry.h
@@ -0,0 +1,3867 @@
+/*************************************************************************
+* dcmtkpp - 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 _afc7b2d7_0869_4fea_9a9b_7fe6228baca9
+#define _afc7b2d7_0869_4fea_9a9b_7fe6228baca9
+
+#include "dcmtkpp/Tag.h"
+
+namespace dcmtkpp
+{
+
+namespace registry
+{
+    Tag const CommandGroupLength(0x0000, 0x0000);
+    Tag const AffectedSOPClassUID(0x0000, 0x0002);
+    Tag const RequestedSOPClassUID(0x0000, 0x0003);
+    Tag const CommandField(0x0000, 0x0100);
+    Tag const MessageID(0x0000, 0x0110);
+    Tag const MessageIDBeingRespondedTo(0x0000, 0x0120);
+    Tag const MoveDestination(0x0000, 0x0600);
+    Tag const Priority(0x0000, 0x0700);
+    Tag const CommandDataSetType(0x0000, 0x0800);
+    Tag const Status(0x0000, 0x0900);
+    Tag const OffendingElement(0x0000, 0x0901);
+    Tag const ErrorComment(0x0000, 0x0902);
+    Tag const ErrorID(0x0000, 0x0903);
+    Tag const AffectedSOPInstanceUID(0x0000, 0x1000);
+    Tag const RequestedSOPInstanceUID(0x0000, 0x1001);
+    Tag const EventTypeID(0x0000, 0x1002);
+    Tag const AttributeIdentifierList(0x0000, 0x1005);
+    Tag const ActionTypeID(0x0000, 0x1008);
+    Tag const NumberOfRemainingSuboperations(0x0000, 0x1020);
+    Tag const NumberOfCompletedSuboperations(0x0000, 0x1021);
+    Tag const NumberOfFailedSuboperations(0x0000, 0x1022);
+    Tag const NumberOfWarningSuboperations(0x0000, 0x1023);
+    Tag const MoveOriginatorApplicationEntityTitle(0x0000, 0x1030);
+    Tag const MoveOriginatorMessageID(0x0000, 0x1031);
+    Tag const FileMetaInformationGroupLength(0x0002, 0x0000);
+    Tag const FileMetaInformationVersion(0x0002, 0x0001);
+    Tag const MediaStorageSOPClassUID(0x0002, 0x0002);
+    Tag const MediaStorageSOPInstanceUID(0x0002, 0x0003);
+    Tag const TransferSyntaxUID(0x0002, 0x0010);
+    Tag const ImplementationClassUID(0x0002, 0x0012);
+    Tag const ImplementationVersionName(0x0002, 0x0013);
+    Tag const SourceApplicationEntityTitle(0x0002, 0x0016);
+    Tag const SendingApplicationEntityTitle(0x0002, 0x0017);
+    Tag const ReceivingApplicationEntityTitle(0x0002, 0x0018);
+    Tag const PrivateInformationCreatorUID(0x0002, 0x0100);
+    Tag const PrivateInformation(0x0002, 0x0102);
+    Tag const FileSetID(0x0004, 0x1130);
+    Tag const FileSetDescriptorFileID(0x0004, 0x1141);
+    Tag const SpecificCharacterSetOfFileSetDescriptorFile(0x0004, 0x1142);
+    Tag const OffsetOfTheFirstDirectoryRecordOfTheRootDirectoryEntity(0x0004, 0x1200);
+    Tag const OffsetOfTheLastDirectoryRecordOfTheRootDirectoryEntity(0x0004, 0x1202);
+    Tag const FileSetConsistencyFlag(0x0004, 0x1212);
+    Tag const DirectoryRecordSequence(0x0004, 0x1220);
+    Tag const OffsetOfTheNextDirectoryRecord(0x0004, 0x1400);
+    Tag const RecordInUseFlag(0x0004, 0x1410);
+    Tag const OffsetOfReferencedLowerLevelDirectoryEntity(0x0004, 0x1420);
+    Tag const DirectoryRecordType(0x0004, 0x1430);
+    Tag const PrivateRecordUID(0x0004, 0x1432);
+    Tag const ReferencedFileID(0x0004, 0x1500);
+    Tag const MRDRDirectoryRecordOffset(0x0004, 0x1504);
+    Tag const ReferencedSOPClassUIDInFile(0x0004, 0x1510);
+    Tag const ReferencedSOPInstanceUIDInFile(0x0004, 0x1511);
+    Tag const ReferencedTransferSyntaxUIDInFile(0x0004, 0x1512);
+    Tag const ReferencedRelatedGeneralSOPClassUIDInFile(0x0004, 0x151a);
+    Tag const NumberOfReferences(0x0004, 0x1600);
+    Tag const LengthToEnd(0x0008, 0x0001);
+    Tag const SpecificCharacterSet(0x0008, 0x0005);
+    Tag const LanguageCodeSequence(0x0008, 0x0006);
+    Tag const ImageType(0x0008, 0x0008);
+    Tag const RecognitionCode(0x0008, 0x0010);
+    Tag const InstanceCreationDate(0x0008, 0x0012);
+    Tag const InstanceCreationTime(0x0008, 0x0013);
+    Tag const InstanceCreatorUID(0x0008, 0x0014);
+    Tag const InstanceCoercionDateTime(0x0008, 0x0015);
+    Tag const SOPClassUID(0x0008, 0x0016);
+    Tag const SOPInstanceUID(0x0008, 0x0018);
+    Tag const RelatedGeneralSOPClassUID(0x0008, 0x001a);
+    Tag const OriginalSpecializedSOPClassUID(0x0008, 0x001b);
+    Tag const StudyDate(0x0008, 0x0020);
+    Tag const SeriesDate(0x0008, 0x0021);
+    Tag const AcquisitionDate(0x0008, 0x0022);
+    Tag const ContentDate(0x0008, 0x0023);
+    Tag const OverlayDate(0x0008, 0x0024);
+    Tag const CurveDate(0x0008, 0x0025);
+    Tag const AcquisitionDateTime(0x0008, 0x002a);
+    Tag const StudyTime(0x0008, 0x0030);
+    Tag const SeriesTime(0x0008, 0x0031);
+    Tag const AcquisitionTime(0x0008, 0x0032);
+    Tag const ContentTime(0x0008, 0x0033);
+    Tag const OverlayTime(0x0008, 0x0034);
+    Tag const CurveTime(0x0008, 0x0035);
+    Tag const DataSetType(0x0008, 0x0040);
+    Tag const DataSetSubtype(0x0008, 0x0041);
+    Tag const NuclearMedicineSeriesType(0x0008, 0x0042);
+    Tag const AccessionNumber(0x0008, 0x0050);
+    Tag const IssuerOfAccessionNumberSequence(0x0008, 0x0051);
+    Tag const QueryRetrieveLevel(0x0008, 0x0052);
+    Tag const QueryRetrieveView(0x0008, 0x0053);
+    Tag const RetrieveAETitle(0x0008, 0x0054);
+    Tag const InstanceAvailability(0x0008, 0x0056);
+    Tag const FailedSOPInstanceUIDList(0x0008, 0x0058);
+    Tag const Modality(0x0008, 0x0060);
+    Tag const ModalitiesInStudy(0x0008, 0x0061);
+    Tag const SOPClassesInStudy(0x0008, 0x0062);
+    Tag const ConversionType(0x0008, 0x0064);
+    Tag const PresentationIntentType(0x0008, 0x0068);
+    Tag const Manufacturer(0x0008, 0x0070);
+    Tag const InstitutionName(0x0008, 0x0080);
+    Tag const InstitutionAddress(0x0008, 0x0081);
+    Tag const InstitutionCodeSequence(0x0008, 0x0082);
+    Tag const ReferringPhysicianName(0x0008, 0x0090);
+    Tag const ReferringPhysicianAddress(0x0008, 0x0092);
+    Tag const ReferringPhysicianTelephoneNumbers(0x0008, 0x0094);
+    Tag const ReferringPhysicianIdentificationSequence(0x0008, 0x0096);
+    Tag const CodeValue(0x0008, 0x0100);
+    Tag const ExtendedCodeValue(0x0008, 0x0101);
+    Tag const CodingSchemeDesignator(0x0008, 0x0102);
+    Tag const CodingSchemeVersion(0x0008, 0x0103);
+    Tag const CodeMeaning(0x0008, 0x0104);
+    Tag const MappingResource(0x0008, 0x0105);
+    Tag const ContextGroupVersion(0x0008, 0x0106);
+    Tag const ContextGroupLocalVersion(0x0008, 0x0107);
+    Tag const ExtendedCodeMeaning(0x0008, 0x0108);
+    Tag const ContextGroupExtensionFlag(0x0008, 0x010b);
+    Tag const CodingSchemeUID(0x0008, 0x010c);
+    Tag const ContextGroupExtensionCreatorUID(0x0008, 0x010d);
+    Tag const ContextIdentifier(0x0008, 0x010f);
+    Tag const CodingSchemeIdentificationSequence(0x0008, 0x0110);
+    Tag const CodingSchemeRegistry(0x0008, 0x0112);
+    Tag const CodingSchemeExternalID(0x0008, 0x0114);
+    Tag const CodingSchemeName(0x0008, 0x0115);
+    Tag const CodingSchemeResponsibleOrganization(0x0008, 0x0116);
+    Tag const ContextUID(0x0008, 0x0117);
+    Tag const MappingResourceUID(0x0008, 0x0118);
+    Tag const LongCodeValue(0x0008, 0x0119);
+    Tag const URNCodeValue(0x0008, 0x0120);
+    Tag const EquivalentCodeSequence(0x0008, 0x0121);
+    Tag const TimezoneOffsetFromUTC(0x0008, 0x0201);
+    Tag const NetworkID(0x0008, 0x1000);
+    Tag const StationName(0x0008, 0x1010);
+    Tag const StudyDescription(0x0008, 0x1030);
+    Tag const ProcedureCodeSequence(0x0008, 0x1032);
+    Tag const SeriesDescription(0x0008, 0x103e);
+    Tag const SeriesDescriptionCodeSequence(0x0008, 0x103f);
+    Tag const InstitutionalDepartmentName(0x0008, 0x1040);
+    Tag const PhysiciansOfRecord(0x0008, 0x1048);
+    Tag const PhysiciansOfRecordIdentificationSequence(0x0008, 0x1049);
+    Tag const PerformingPhysicianName(0x0008, 0x1050);
+    Tag const PerformingPhysicianIdentificationSequence(0x0008, 0x1052);
+    Tag const NameOfPhysiciansReadingStudy(0x0008, 0x1060);
+    Tag const PhysiciansReadingStudyIdentificationSequence(0x0008, 0x1062);
+    Tag const OperatorsName(0x0008, 0x1070);
+    Tag const OperatorIdentificationSequence(0x0008, 0x1072);
+    Tag const AdmittingDiagnosesDescription(0x0008, 0x1080);
+    Tag const AdmittingDiagnosesCodeSequence(0x0008, 0x1084);
+    Tag const ManufacturerModelName(0x0008, 0x1090);
+    Tag const ReferencedResultsSequence(0x0008, 0x1100);
+    Tag const ReferencedStudySequence(0x0008, 0x1110);
+    Tag const ReferencedPerformedProcedureStepSequence(0x0008, 0x1111);
+    Tag const ReferencedSeriesSequence(0x0008, 0x1115);
+    Tag const ReferencedPatientSequence(0x0008, 0x1120);
+    Tag const ReferencedVisitSequence(0x0008, 0x1125);
+    Tag const ReferencedOverlaySequence(0x0008, 0x1130);
+    Tag const ReferencedStereometricInstanceSequence(0x0008, 0x1134);
+    Tag const ReferencedWaveformSequence(0x0008, 0x113a);
+    Tag const ReferencedImageSequence(0x0008, 0x1140);
+    Tag const ReferencedCurveSequence(0x0008, 0x1145);
+    Tag const ReferencedInstanceSequence(0x0008, 0x114a);
+    Tag const ReferencedRealWorldValueMappingInstanceSequence(0x0008, 0x114b);
+    Tag const ReferencedSOPClassUID(0x0008, 0x1150);
+    Tag const ReferencedSOPInstanceUID(0x0008, 0x1155);
+    Tag const SOPClassesSupported(0x0008, 0x115a);
+    Tag const ReferencedFrameNumber(0x0008, 0x1160);
+    Tag const SimpleFrameList(0x0008, 0x1161);
+    Tag const CalculatedFrameList(0x0008, 0x1162);
+    Tag const TimeRange(0x0008, 0x1163);
+    Tag const FrameExtractionSequence(0x0008, 0x1164);
+    Tag const MultiFrameSourceSOPInstanceUID(0x0008, 0x1167);
+    Tag const RetrieveURL(0x0008, 0x1190);
+    Tag const TransactionUID(0x0008, 0x1195);
+    Tag const WarningReason(0x0008, 0x1196);
+    Tag const FailureReason(0x0008, 0x1197);
+    Tag const FailedSOPSequence(0x0008, 0x1198);
+    Tag const ReferencedSOPSequence(0x0008, 0x1199);
+    Tag const StudiesContainingOtherReferencedInstancesSequence(0x0008, 0x1200);
+    Tag const RelatedSeriesSequence(0x0008, 0x1250);
+    Tag const LossyImageCompressionRetired(0x0008, 0x2110);
+    Tag const DerivationDescription(0x0008, 0x2111);
+    Tag const SourceImageSequence(0x0008, 0x2112);
+    Tag const StageName(0x0008, 0x2120);
+    Tag const StageNumber(0x0008, 0x2122);
+    Tag const NumberOfStages(0x0008, 0x2124);
+    Tag const ViewName(0x0008, 0x2127);
+    Tag const ViewNumber(0x0008, 0x2128);
+    Tag const NumberOfEventTimers(0x0008, 0x2129);
+    Tag const NumberOfViewsInStage(0x0008, 0x212a);
+    Tag const EventElapsedTimes(0x0008, 0x2130);
+    Tag const EventTimerNames(0x0008, 0x2132);
+    Tag const EventTimerSequence(0x0008, 0x2133);
+    Tag const EventTimeOffset(0x0008, 0x2134);
+    Tag const EventCodeSequence(0x0008, 0x2135);
+    Tag const StartTrim(0x0008, 0x2142);
+    Tag const StopTrim(0x0008, 0x2143);
+    Tag const RecommendedDisplayFrameRate(0x0008, 0x2144);
+    Tag const TransducerPosition(0x0008, 0x2200);
+    Tag const TransducerOrientation(0x0008, 0x2204);
+    Tag const AnatomicStructure(0x0008, 0x2208);
+    Tag const AnatomicRegionSequence(0x0008, 0x2218);
+    Tag const AnatomicRegionModifierSequence(0x0008, 0x2220);
+    Tag const PrimaryAnatomicStructureSequence(0x0008, 0x2228);
+    Tag const AnatomicStructureSpaceOrRegionSequence(0x0008, 0x2229);
+    Tag const PrimaryAnatomicStructureModifierSequence(0x0008, 0x2230);
+    Tag const TransducerPositionSequence(0x0008, 0x2240);
+    Tag const TransducerPositionModifierSequence(0x0008, 0x2242);
+    Tag const TransducerOrientationSequence(0x0008, 0x2244);
+    Tag const TransducerOrientationModifierSequence(0x0008, 0x2246);
+    Tag const AnatomicStructureSpaceOrRegionCodeSequenceTrial(0x0008, 0x2251);
+    Tag const AnatomicPortalOfEntranceCodeSequenceTrial(0x0008, 0x2253);
+    Tag const AnatomicApproachDirectionCodeSequenceTrial(0x0008, 0x2255);
+    Tag const AnatomicPerspectiveDescriptionTrial(0x0008, 0x2256);
+    Tag const AnatomicPerspectiveCodeSequenceTrial(0x0008, 0x2257);
+    Tag const AnatomicLocationOfExaminingInstrumentDescriptionTrial(0x0008, 0x2258);
+    Tag const AnatomicLocationOfExaminingInstrumentCodeSequenceTrial(0x0008, 0x2259);
+    Tag const AnatomicStructureSpaceOrRegionModifierCodeSequenceTrial(0x0008, 0x225a);
+    Tag const OnAxisBackgroundAnatomicStructureCodeSequenceTrial(0x0008, 0x225c);
+    Tag const AlternateRepresentationSequence(0x0008, 0x3001);
+    Tag const IrradiationEventUID(0x0008, 0x3010);
+    Tag const SourceIrradiationEventSequence(0x0008, 0x3011);
+    Tag const RadiopharmaceuticalAdministrationEventUID(0x0008, 0x3012);
+    Tag const IdentifyingComments(0x0008, 0x4000);
+    Tag const FrameType(0x0008, 0x9007);
+    Tag const ReferencedImageEvidenceSequence(0x0008, 0x9092);
+    Tag const ReferencedRawDataSequence(0x0008, 0x9121);
+    Tag const CreatorVersionUID(0x0008, 0x9123);
+    Tag const DerivationImageSequence(0x0008, 0x9124);
+    Tag const SourceImageEvidenceSequence(0x0008, 0x9154);
+    Tag const PixelPresentation(0x0008, 0x9205);
+    Tag const VolumetricProperties(0x0008, 0x9206);
+    Tag const VolumeBasedCalculationTechnique(0x0008, 0x9207);
+    Tag const ComplexImageComponent(0x0008, 0x9208);
+    Tag const AcquisitionContrast(0x0008, 0x9209);
+    Tag const DerivationCodeSequence(0x0008, 0x9215);
+    Tag const ReferencedPresentationStateSequence(0x0008, 0x9237);
+    Tag const ReferencedOtherPlaneSequence(0x0008, 0x9410);
+    Tag const FrameDisplaySequence(0x0008, 0x9458);
+    Tag const RecommendedDisplayFrameRateInFloat(0x0008, 0x9459);
+    Tag const SkipFrameRangeFlag(0x0008, 0x9460);
+    Tag const PatientName(0x0010, 0x0010);
+    Tag const PatientID(0x0010, 0x0020);
+    Tag const IssuerOfPatientID(0x0010, 0x0021);
+    Tag const TypeOfPatientID(0x0010, 0x0022);
+    Tag const IssuerOfPatientIDQualifiersSequence(0x0010, 0x0024);
+    Tag const PatientBirthDate(0x0010, 0x0030);
+    Tag const PatientBirthTime(0x0010, 0x0032);
+    Tag const PatientSex(0x0010, 0x0040);
+    Tag const PatientInsurancePlanCodeSequence(0x0010, 0x0050);
+    Tag const PatientPrimaryLanguageCodeSequence(0x0010, 0x0101);
+    Tag const PatientPrimaryLanguageModifierCodeSequence(0x0010, 0x0102);
+    Tag const QualityControlSubject(0x0010, 0x0200);
+    Tag const QualityControlSubjectTypeCodeSequence(0x0010, 0x0201);
+    Tag const OtherPatientIDs(0x0010, 0x1000);
+    Tag const OtherPatientNames(0x0010, 0x1001);
+    Tag const OtherPatientIDsSequence(0x0010, 0x1002);
+    Tag const PatientBirthName(0x0010, 0x1005);
+    Tag const PatientAge(0x0010, 0x1010);
+    Tag const PatientSize(0x0010, 0x1020);
+    Tag const PatientSizeCodeSequence(0x0010, 0x1021);
+    Tag const PatientWeight(0x0010, 0x1030);
+    Tag const PatientAddress(0x0010, 0x1040);
+    Tag const InsurancePlanIdentification(0x0010, 0x1050);
+    Tag const PatientMotherBirthName(0x0010, 0x1060);
+    Tag const MilitaryRank(0x0010, 0x1080);
+    Tag const BranchOfService(0x0010, 0x1081);
+    Tag const MedicalRecordLocator(0x0010, 0x1090);
+    Tag const ReferencedPatientPhotoSequence(0x0010, 0x1100);
+    Tag const MedicalAlerts(0x0010, 0x2000);
+    Tag const Allergies(0x0010, 0x2110);
+    Tag const CountryOfResidence(0x0010, 0x2150);
+    Tag const RegionOfResidence(0x0010, 0x2152);
+    Tag const PatientTelephoneNumbers(0x0010, 0x2154);
+    Tag const EthnicGroup(0x0010, 0x2160);
+    Tag const Occupation(0x0010, 0x2180);
+    Tag const SmokingStatus(0x0010, 0x21a0);
+    Tag const AdditionalPatientHistory(0x0010, 0x21b0);
+    Tag const PregnancyStatus(0x0010, 0x21c0);
+    Tag const LastMenstrualDate(0x0010, 0x21d0);
+    Tag const PatientReligiousPreference(0x0010, 0x21f0);
+    Tag const PatientSpeciesDescription(0x0010, 0x2201);
+    Tag const PatientSpeciesCodeSequence(0x0010, 0x2202);
+    Tag const PatientSexNeutered(0x0010, 0x2203);
+    Tag const AnatomicalOrientationType(0x0010, 0x2210);
+    Tag const PatientBreedDescription(0x0010, 0x2292);
+    Tag const PatientBreedCodeSequence(0x0010, 0x2293);
+    Tag const BreedRegistrationSequence(0x0010, 0x2294);
+    Tag const BreedRegistrationNumber(0x0010, 0x2295);
+    Tag const BreedRegistryCodeSequence(0x0010, 0x2296);
+    Tag const ResponsiblePerson(0x0010, 0x2297);
+    Tag const ResponsiblePersonRole(0x0010, 0x2298);
+    Tag const ResponsibleOrganization(0x0010, 0x2299);
+    Tag const PatientComments(0x0010, 0x4000);
+    Tag const ExaminedBodyThickness(0x0010, 0x9431);
+    Tag const ClinicalTrialSponsorName(0x0012, 0x0010);
+    Tag const ClinicalTrialProtocolID(0x0012, 0x0020);
+    Tag const ClinicalTrialProtocolName(0x0012, 0x0021);
+    Tag const ClinicalTrialSiteID(0x0012, 0x0030);
+    Tag const ClinicalTrialSiteName(0x0012, 0x0031);
+    Tag const ClinicalTrialSubjectID(0x0012, 0x0040);
+    Tag const ClinicalTrialSubjectReadingID(0x0012, 0x0042);
+    Tag const ClinicalTrialTimePointID(0x0012, 0x0050);
+    Tag const ClinicalTrialTimePointDescription(0x0012, 0x0051);
+    Tag const ClinicalTrialCoordinatingCenterName(0x0012, 0x0060);
+    Tag const PatientIdentityRemoved(0x0012, 0x0062);
+    Tag const DeidentificationMethod(0x0012, 0x0063);
+    Tag const DeidentificationMethodCodeSequence(0x0012, 0x0064);
+    Tag const ClinicalTrialSeriesID(0x0012, 0x0071);
+    Tag const ClinicalTrialSeriesDescription(0x0012, 0x0072);
+    Tag const ClinicalTrialProtocolEthicsCommitteeName(0x0012, 0x0081);
+    Tag const ClinicalTrialProtocolEthicsCommitteeApprovalNumber(0x0012, 0x0082);
+    Tag const ConsentForClinicalTrialUseSequence(0x0012, 0x0083);
+    Tag const DistributionType(0x0012, 0x0084);
+    Tag const ConsentForDistributionFlag(0x0012, 0x0085);
+    Tag const CADFileFormat(0x0014, 0x0023);
+    Tag const ComponentReferenceSystem(0x0014, 0x0024);
+    Tag const ComponentManufacturingProcedure(0x0014, 0x0025);
+    Tag const ComponentManufacturer(0x0014, 0x0028);
+    Tag const MaterialThickness(0x0014, 0x0030);
+    Tag const MaterialPipeDiameter(0x0014, 0x0032);
+    Tag const MaterialIsolationDiameter(0x0014, 0x0034);
+    Tag const MaterialGrade(0x0014, 0x0042);
+    Tag const MaterialPropertiesDescription(0x0014, 0x0044);
+    Tag const MaterialPropertiesFileFormatRetired(0x0014, 0x0045);
+    Tag const MaterialNotes(0x0014, 0x0046);
+    Tag const ComponentShape(0x0014, 0x0050);
+    Tag const CurvatureType(0x0014, 0x0052);
+    Tag const OuterDiameter(0x0014, 0x0054);
+    Tag const InnerDiameter(0x0014, 0x0056);
+    Tag const ActualEnvironmentalConditions(0x0014, 0x1010);
+    Tag const ExpiryDate(0x0014, 0x1020);
+    Tag const EnvironmentalConditions(0x0014, 0x1040);
+    Tag const EvaluatorSequence(0x0014, 0x2002);
+    Tag const EvaluatorNumber(0x0014, 0x2004);
+    Tag const EvaluatorName(0x0014, 0x2006);
+    Tag const EvaluationAttempt(0x0014, 0x2008);
+    Tag const IndicationSequence(0x0014, 0x2012);
+    Tag const IndicationNumber(0x0014, 0x2014);
+    Tag const IndicationLabel(0x0014, 0x2016);
+    Tag const IndicationDescription(0x0014, 0x2018);
+    Tag const IndicationType(0x0014, 0x201a);
+    Tag const IndicationDisposition(0x0014, 0x201c);
+    Tag const IndicationROISequence(0x0014, 0x201e);
+    Tag const IndicationPhysicalPropertySequence(0x0014, 0x2030);
+    Tag const PropertyLabel(0x0014, 0x2032);
+    Tag const CoordinateSystemNumberOfAxes(0x0014, 0x2202);
+    Tag const CoordinateSystemAxesSequence(0x0014, 0x2204);
+    Tag const CoordinateSystemAxisDescription(0x0014, 0x2206);
+    Tag const CoordinateSystemDataSetMapping(0x0014, 0x2208);
+    Tag const CoordinateSystemAxisNumber(0x0014, 0x220a);
+    Tag const CoordinateSystemAxisType(0x0014, 0x220c);
+    Tag const CoordinateSystemAxisUnits(0x0014, 0x220e);
+    Tag const CoordinateSystemAxisValues(0x0014, 0x2210);
+    Tag const CoordinateSystemTransformSequence(0x0014, 0x2220);
+    Tag const TransformDescription(0x0014, 0x2222);
+    Tag const TransformNumberOfAxes(0x0014, 0x2224);
+    Tag const TransformOrderOfAxes(0x0014, 0x2226);
+    Tag const TransformedAxisUnits(0x0014, 0x2228);
+    Tag const CoordinateSystemTransformRotationAndScaleMatrix(0x0014, 0x222a);
+    Tag const CoordinateSystemTransformTranslationMatrix(0x0014, 0x222c);
+    Tag const InternalDetectorFrameTime(0x0014, 0x3011);
+    Tag const NumberOfFramesIntegrated(0x0014, 0x3012);
+    Tag const DetectorTemperatureSequence(0x0014, 0x3020);
+    Tag const SensorName(0x0014, 0x3022);
+    Tag const HorizontalOffsetOfSensor(0x0014, 0x3024);
+    Tag const VerticalOffsetOfSensor(0x0014, 0x3026);
+    Tag const SensorTemperature(0x0014, 0x3028);
+    Tag const DarkCurrentSequence(0x0014, 0x3040);
+    Tag const DarkCurrentCounts(0x0014, 0x3050);
+    Tag const GainCorrectionReferenceSequence(0x0014, 0x3060);
+    Tag const AirCounts(0x0014, 0x3070);
+    Tag const KVUsedInGainCalibration(0x0014, 0x3071);
+    Tag const MAUsedInGainCalibration(0x0014, 0x3072);
+    Tag const NumberOfFramesUsedForIntegration(0x0014, 0x3073);
+    Tag const FilterMaterialUsedInGainCalibration(0x0014, 0x3074);
+    Tag const FilterThicknessUsedInGainCalibration(0x0014, 0x3075);
+    Tag const DateOfGainCalibration(0x0014, 0x3076);
+    Tag const TimeOfGainCalibration(0x0014, 0x3077);
+    Tag const BadPixelImage(0x0014, 0x3080);
+    Tag const CalibrationNotes(0x0014, 0x3099);
+    Tag const PulserEquipmentSequence(0x0014, 0x4002);
+    Tag const PulserType(0x0014, 0x4004);
+    Tag const PulserNotes(0x0014, 0x4006);
+    Tag const ReceiverEquipmentSequence(0x0014, 0x4008);
+    Tag const AmplifierType(0x0014, 0x400a);
+    Tag const ReceiverNotes(0x0014, 0x400c);
+    Tag const PreAmplifierEquipmentSequence(0x0014, 0x400e);
+    Tag const PreAmplifierNotes(0x0014, 0x400f);
+    Tag const TransmitTransducerSequence(0x0014, 0x4010);
+    Tag const ReceiveTransducerSequence(0x0014, 0x4011);
+    Tag const NumberOfElements(0x0014, 0x4012);
+    Tag const ElementShape(0x0014, 0x4013);
+    Tag const ElementDimensionA(0x0014, 0x4014);
+    Tag const ElementDimensionB(0x0014, 0x4015);
+    Tag const ElementPitchA(0x0014, 0x4016);
+    Tag const MeasuredBeamDimensionA(0x0014, 0x4017);
+    Tag const MeasuredBeamDimensionB(0x0014, 0x4018);
+    Tag const LocationOfMeasuredBeamDiameter(0x0014, 0x4019);
+    Tag const NominalFrequency(0x0014, 0x401a);
+    Tag const MeasuredCenterFrequency(0x0014, 0x401b);
+    Tag const MeasuredBandwidth(0x0014, 0x401c);
+    Tag const ElementPitchB(0x0014, 0x401d);
+    Tag const PulserSettingsSequence(0x0014, 0x4020);
+    Tag const PulseWidth(0x0014, 0x4022);
+    Tag const ExcitationFrequency(0x0014, 0x4024);
+    Tag const ModulationType(0x0014, 0x4026);
+    Tag const Damping(0x0014, 0x4028);
+    Tag const ReceiverSettingsSequence(0x0014, 0x4030);
+    Tag const AcquiredSoundpathLength(0x0014, 0x4031);
+    Tag const AcquisitionCompressionType(0x0014, 0x4032);
+    Tag const AcquisitionSampleSize(0x0014, 0x4033);
+    Tag const RectifierSmoothing(0x0014, 0x4034);
+    Tag const DACSequence(0x0014, 0x4035);
+    Tag const DACType(0x0014, 0x4036);
+    Tag const DACGainPoints(0x0014, 0x4038);
+    Tag const DACTimePoints(0x0014, 0x403a);
+    Tag const DACAmplitude(0x0014, 0x403c);
+    Tag const PreAmplifierSettingsSequence(0x0014, 0x4040);
+    Tag const TransmitTransducerSettingsSequence(0x0014, 0x4050);
+    Tag const ReceiveTransducerSettingsSequence(0x0014, 0x4051);
+    Tag const IncidentAngle(0x0014, 0x4052);
+    Tag const CouplingTechnique(0x0014, 0x4054);
+    Tag const CouplingMedium(0x0014, 0x4056);
+    Tag const CouplingVelocity(0x0014, 0x4057);
+    Tag const ProbeCenterLocationX(0x0014, 0x4058);
+    Tag const ProbeCenterLocationZ(0x0014, 0x4059);
+    Tag const SoundPathLength(0x0014, 0x405a);
+    Tag const DelayLawIdentifier(0x0014, 0x405c);
+    Tag const GateSettingsSequence(0x0014, 0x4060);
+    Tag const GateThreshold(0x0014, 0x4062);
+    Tag const VelocityOfSound(0x0014, 0x4064);
+    Tag const CalibrationSettingsSequence(0x0014, 0x4070);
+    Tag const CalibrationProcedure(0x0014, 0x4072);
+    Tag const ProcedureVersion(0x0014, 0x4074);
+    Tag const ProcedureCreationDate(0x0014, 0x4076);
+    Tag const ProcedureExpirationDate(0x0014, 0x4078);
+    Tag const ProcedureLastModifiedDate(0x0014, 0x407a);
+    Tag const CalibrationTime(0x0014, 0x407c);
+    Tag const CalibrationDate(0x0014, 0x407e);
+    Tag const ProbeDriveEquipmentSequence(0x0014, 0x4080);
+    Tag const DriveType(0x0014, 0x4081);
+    Tag const ProbeDriveNotes(0x0014, 0x4082);
+    Tag const DriveProbeSequence(0x0014, 0x4083);
+    Tag const ProbeInductance(0x0014, 0x4084);
+    Tag const ProbeResistance(0x0014, 0x4085);
+    Tag const ReceiveProbeSequence(0x0014, 0x4086);
+    Tag const ProbeDriveSettingsSequence(0x0014, 0x4087);
+    Tag const BridgeResistors(0x0014, 0x4088);
+    Tag const ProbeOrientationAngle(0x0014, 0x4089);
+    Tag const UserSelectedGainY(0x0014, 0x408b);
+    Tag const UserSelectedPhase(0x0014, 0x408c);
+    Tag const UserSelectedOffsetX(0x0014, 0x408d);
+    Tag const UserSelectedOffsetY(0x0014, 0x408e);
+    Tag const ChannelSettingsSequence(0x0014, 0x4091);
+    Tag const ChannelThreshold(0x0014, 0x4092);
+    Tag const ScannerSettingsSequence(0x0014, 0x409a);
+    Tag const ScanProcedure(0x0014, 0x409b);
+    Tag const TranslationRateX(0x0014, 0x409c);
+    Tag const TranslationRateY(0x0014, 0x409d);
+    Tag const ChannelOverlap(0x0014, 0x409f);
+    Tag const ImageQualityIndicatorType(0x0014, 0x40a0);
+    Tag const ImageQualityIndicatorMaterial(0x0014, 0x40a1);
+    Tag const ImageQualityIndicatorSize(0x0014, 0x40a2);
+    Tag const LINACEnergy(0x0014, 0x5002);
+    Tag const LINACOutput(0x0014, 0x5004);
+    Tag const ActiveAperture(0x0014, 0x5100);
+    Tag const TotalAperture(0x0014, 0x5101);
+    Tag const ApertureElevation(0x0014, 0x5102);
+    Tag const MainLobeAngle(0x0014, 0x5103);
+    Tag const MainRoofAngle(0x0014, 0x5104);
+    Tag const ConnectorType(0x0014, 0x5105);
+    Tag const WedgeModelNumber(0x0014, 0x5106);
+    Tag const WedgeAngleFloat(0x0014, 0x5107);
+    Tag const WedgeRoofAngle(0x0014, 0x5108);
+    Tag const WedgeElement1Position(0x0014, 0x5109);
+    Tag const WedgeMaterialVelocity(0x0014, 0x510a);
+    Tag const WedgeMaterial(0x0014, 0x510b);
+    Tag const WedgeOffsetZ(0x0014, 0x510c);
+    Tag const WedgeOriginOffsetX(0x0014, 0x510d);
+    Tag const WedgeTimeDelay(0x0014, 0x510e);
+    Tag const WedgeName(0x0014, 0x510f);
+    Tag const WedgeManufacturerName(0x0014, 0x5110);
+    Tag const WedgeDescription(0x0014, 0x5111);
+    Tag const NominalBeamAngle(0x0014, 0x5112);
+    Tag const WedgeOffsetX(0x0014, 0x5113);
+    Tag const WedgeOffsetY(0x0014, 0x5114);
+    Tag const WedgeTotalLength(0x0014, 0x5115);
+    Tag const WedgeInContactLength(0x0014, 0x5116);
+    Tag const WedgeFrontGap(0x0014, 0x5117);
+    Tag const WedgeTotalHeight(0x0014, 0x5118);
+    Tag const WedgeFrontHeight(0x0014, 0x5119);
+    Tag const WedgeRearHeight(0x0014, 0x511a);
+    Tag const WedgeTotalWidth(0x0014, 0x511b);
+    Tag const WedgeInContactWidth(0x0014, 0x511c);
+    Tag const WedgeChamferHeight(0x0014, 0x511d);
+    Tag const WedgeCurve(0x0014, 0x511e);
+    Tag const RadiusAlongWedge(0x0014, 0x511f);
+    Tag const ContrastBolusAgent(0x0018, 0x0010);
+    Tag const ContrastBolusAgentSequence(0x0018, 0x0012);
+    Tag const ContrastBolusT1Relaxivity(0x0018, 0x0013);
+    Tag const ContrastBolusAdministrationRouteSequence(0x0018, 0x0014);
+    Tag const BodyPartExamined(0x0018, 0x0015);
+    Tag const ScanningSequence(0x0018, 0x0020);
+    Tag const SequenceVariant(0x0018, 0x0021);
+    Tag const ScanOptions(0x0018, 0x0022);
+    Tag const MRAcquisitionType(0x0018, 0x0023);
+    Tag const SequenceName(0x0018, 0x0024);
+    Tag const AngioFlag(0x0018, 0x0025);
+    Tag const InterventionDrugInformationSequence(0x0018, 0x0026);
+    Tag const InterventionDrugStopTime(0x0018, 0x0027);
+    Tag const InterventionDrugDose(0x0018, 0x0028);
+    Tag const InterventionDrugCodeSequence(0x0018, 0x0029);
+    Tag const AdditionalDrugSequence(0x0018, 0x002a);
+    Tag const Radionuclide(0x0018, 0x0030);
+    Tag const Radiopharmaceutical(0x0018, 0x0031);
+    Tag const EnergyWindowCenterline(0x0018, 0x0032);
+    Tag const EnergyWindowTotalWidth(0x0018, 0x0033);
+    Tag const InterventionDrugName(0x0018, 0x0034);
+    Tag const InterventionDrugStartTime(0x0018, 0x0035);
+    Tag const InterventionSequence(0x0018, 0x0036);
+    Tag const TherapyType(0x0018, 0x0037);
+    Tag const InterventionStatus(0x0018, 0x0038);
+    Tag const TherapyDescription(0x0018, 0x0039);
+    Tag const InterventionDescription(0x0018, 0x003a);
+    Tag const CineRate(0x0018, 0x0040);
+    Tag const InitialCineRunState(0x0018, 0x0042);
+    Tag const SliceThickness(0x0018, 0x0050);
+    Tag const KVP(0x0018, 0x0060);
+    Tag const CountsAccumulated(0x0018, 0x0070);
+    Tag const AcquisitionTerminationCondition(0x0018, 0x0071);
+    Tag const EffectiveDuration(0x0018, 0x0072);
+    Tag const AcquisitionStartCondition(0x0018, 0x0073);
+    Tag const AcquisitionStartConditionData(0x0018, 0x0074);
+    Tag const AcquisitionTerminationConditionData(0x0018, 0x0075);
+    Tag const RepetitionTime(0x0018, 0x0080);
+    Tag const EchoTime(0x0018, 0x0081);
+    Tag const InversionTime(0x0018, 0x0082);
+    Tag const NumberOfAverages(0x0018, 0x0083);
+    Tag const ImagingFrequency(0x0018, 0x0084);
+    Tag const ImagedNucleus(0x0018, 0x0085);
+    Tag const EchoNumbers(0x0018, 0x0086);
+    Tag const MagneticFieldStrength(0x0018, 0x0087);
+    Tag const SpacingBetweenSlices(0x0018, 0x0088);
+    Tag const NumberOfPhaseEncodingSteps(0x0018, 0x0089);
+    Tag const DataCollectionDiameter(0x0018, 0x0090);
+    Tag const EchoTrainLength(0x0018, 0x0091);
+    Tag const PercentSampling(0x0018, 0x0093);
+    Tag const PercentPhaseFieldOfView(0x0018, 0x0094);
+    Tag const PixelBandwidth(0x0018, 0x0095);
+    Tag const DeviceSerialNumber(0x0018, 0x1000);
+    Tag const DeviceUID(0x0018, 0x1002);
+    Tag const DeviceID(0x0018, 0x1003);
+    Tag const PlateID(0x0018, 0x1004);
+    Tag const GeneratorID(0x0018, 0x1005);
+    Tag const GridID(0x0018, 0x1006);
+    Tag const CassetteID(0x0018, 0x1007);
+    Tag const GantryID(0x0018, 0x1008);
+    Tag const SecondaryCaptureDeviceID(0x0018, 0x1010);
+    Tag const HardcopyCreationDeviceID(0x0018, 0x1011);
+    Tag const DateOfSecondaryCapture(0x0018, 0x1012);
+    Tag const TimeOfSecondaryCapture(0x0018, 0x1014);
+    Tag const SecondaryCaptureDeviceManufacturer(0x0018, 0x1016);
+    Tag const HardcopyDeviceManufacturer(0x0018, 0x1017);
+    Tag const SecondaryCaptureDeviceManufacturerModelName(0x0018, 0x1018);
+    Tag const SecondaryCaptureDeviceSoftwareVersions(0x0018, 0x1019);
+    Tag const HardcopyDeviceSoftwareVersion(0x0018, 0x101a);
+    Tag const HardcopyDeviceManufacturerModelName(0x0018, 0x101b);
+    Tag const SoftwareVersions(0x0018, 0x1020);
+    Tag const VideoImageFormatAcquired(0x0018, 0x1022);
+    Tag const DigitalImageFormatAcquired(0x0018, 0x1023);
+    Tag const ProtocolName(0x0018, 0x1030);
+    Tag const ContrastBolusRoute(0x0018, 0x1040);
+    Tag const ContrastBolusVolume(0x0018, 0x1041);
+    Tag const ContrastBolusStartTime(0x0018, 0x1042);
+    Tag const ContrastBolusStopTime(0x0018, 0x1043);
+    Tag const ContrastBolusTotalDose(0x0018, 0x1044);
+    Tag const SyringeCounts(0x0018, 0x1045);
+    Tag const ContrastFlowRate(0x0018, 0x1046);
+    Tag const ContrastFlowDuration(0x0018, 0x1047);
+    Tag const ContrastBolusIngredient(0x0018, 0x1048);
+    Tag const ContrastBolusIngredientConcentration(0x0018, 0x1049);
+    Tag const SpatialResolution(0x0018, 0x1050);
+    Tag const TriggerTime(0x0018, 0x1060);
+    Tag const TriggerSourceOrType(0x0018, 0x1061);
+    Tag const NominalInterval(0x0018, 0x1062);
+    Tag const FrameTime(0x0018, 0x1063);
+    Tag const CardiacFramingType(0x0018, 0x1064);
+    Tag const FrameTimeVector(0x0018, 0x1065);
+    Tag const FrameDelay(0x0018, 0x1066);
+    Tag const ImageTriggerDelay(0x0018, 0x1067);
+    Tag const MultiplexGroupTimeOffset(0x0018, 0x1068);
+    Tag const TriggerTimeOffset(0x0018, 0x1069);
+    Tag const SynchronizationTrigger(0x0018, 0x106a);
+    Tag const SynchronizationChannel(0x0018, 0x106c);
+    Tag const TriggerSamplePosition(0x0018, 0x106e);
+    Tag const RadiopharmaceuticalRoute(0x0018, 0x1070);
+    Tag const RadiopharmaceuticalVolume(0x0018, 0x1071);
+    Tag const RadiopharmaceuticalStartTime(0x0018, 0x1072);
+    Tag const RadiopharmaceuticalStopTime(0x0018, 0x1073);
+    Tag const RadionuclideTotalDose(0x0018, 0x1074);
+    Tag const RadionuclideHalfLife(0x0018, 0x1075);
+    Tag const RadionuclidePositronFraction(0x0018, 0x1076);
+    Tag const RadiopharmaceuticalSpecificActivity(0x0018, 0x1077);
+    Tag const RadiopharmaceuticalStartDateTime(0x0018, 0x1078);
+    Tag const RadiopharmaceuticalStopDateTime(0x0018, 0x1079);
+    Tag const BeatRejectionFlag(0x0018, 0x1080);
+    Tag const LowRRValue(0x0018, 0x1081);
+    Tag const HighRRValue(0x0018, 0x1082);
+    Tag const IntervalsAcquired(0x0018, 0x1083);
+    Tag const IntervalsRejected(0x0018, 0x1084);
+    Tag const PVCRejection(0x0018, 0x1085);
+    Tag const SkipBeats(0x0018, 0x1086);
+    Tag const HeartRate(0x0018, 0x1088);
+    Tag const CardiacNumberOfImages(0x0018, 0x1090);
+    Tag const TriggerWindow(0x0018, 0x1094);
+    Tag const ReconstructionDiameter(0x0018, 0x1100);
+    Tag const DistanceSourceToDetector(0x0018, 0x1110);
+    Tag const DistanceSourceToPatient(0x0018, 0x1111);
+    Tag const EstimatedRadiographicMagnificationFactor(0x0018, 0x1114);
+    Tag const GantryDetectorTilt(0x0018, 0x1120);
+    Tag const GantryDetectorSlew(0x0018, 0x1121);
+    Tag const TableHeight(0x0018, 0x1130);
+    Tag const TableTraverse(0x0018, 0x1131);
+    Tag const TableMotion(0x0018, 0x1134);
+    Tag const TableVerticalIncrement(0x0018, 0x1135);
+    Tag const TableLateralIncrement(0x0018, 0x1136);
+    Tag const TableLongitudinalIncrement(0x0018, 0x1137);
+    Tag const TableAngle(0x0018, 0x1138);
+    Tag const TableType(0x0018, 0x113a);
+    Tag const RotationDirection(0x0018, 0x1140);
+    Tag const AngularPosition(0x0018, 0x1141);
+    Tag const RadialPosition(0x0018, 0x1142);
+    Tag const ScanArc(0x0018, 0x1143);
+    Tag const AngularStep(0x0018, 0x1144);
+    Tag const CenterOfRotationOffset(0x0018, 0x1145);
+    Tag const RotationOffset(0x0018, 0x1146);
+    Tag const FieldOfViewShape(0x0018, 0x1147);
+    Tag const FieldOfViewDimensions(0x0018, 0x1149);
+    Tag const ExposureTime(0x0018, 0x1150);
+    Tag const XRayTubeCurrent(0x0018, 0x1151);
+    Tag const Exposure(0x0018, 0x1152);
+    Tag const ExposureInuAs(0x0018, 0x1153);
+    Tag const AveragePulseWidth(0x0018, 0x1154);
+    Tag const RadiationSetting(0x0018, 0x1155);
+    Tag const RectificationType(0x0018, 0x1156);
+    Tag const RadiationMode(0x0018, 0x115a);
+    Tag const ImageAndFluoroscopyAreaDoseProduct(0x0018, 0x115e);
+    Tag const FilterType(0x0018, 0x1160);
+    Tag const TypeOfFilters(0x0018, 0x1161);
+    Tag const IntensifierSize(0x0018, 0x1162);
+    Tag const ImagerPixelSpacing(0x0018, 0x1164);
+    Tag const Grid(0x0018, 0x1166);
+    Tag const GeneratorPower(0x0018, 0x1170);
+    Tag const CollimatorGridName(0x0018, 0x1180);
+    Tag const CollimatorType(0x0018, 0x1181);
+    Tag const FocalDistance(0x0018, 0x1182);
+    Tag const XFocusCenter(0x0018, 0x1183);
+    Tag const YFocusCenter(0x0018, 0x1184);
+    Tag const FocalSpots(0x0018, 0x1190);
+    Tag const AnodeTargetMaterial(0x0018, 0x1191);
+    Tag const BodyPartThickness(0x0018, 0x11a0);
+    Tag const CompressionForce(0x0018, 0x11a2);
+    Tag const PaddleDescription(0x0018, 0x11a4);
+    Tag const DateOfLastCalibration(0x0018, 0x1200);
+    Tag const TimeOfLastCalibration(0x0018, 0x1201);
+    Tag const DateTimeOfLastCalibration(0x0018, 0x1202);
+    Tag const ConvolutionKernel(0x0018, 0x1210);
+    Tag const UpperLowerPixelValues(0x0018, 0x1240);
+    Tag const ActualFrameDuration(0x0018, 0x1242);
+    Tag const CountRate(0x0018, 0x1243);
+    Tag const PreferredPlaybackSequencing(0x0018, 0x1244);
+    Tag const ReceiveCoilName(0x0018, 0x1250);
+    Tag const TransmitCoilName(0x0018, 0x1251);
+    Tag const PlateType(0x0018, 0x1260);
+    Tag const PhosphorType(0x0018, 0x1261);
+    Tag const ScanVelocity(0x0018, 0x1300);
+    Tag const WholeBodyTechnique(0x0018, 0x1301);
+    Tag const ScanLength(0x0018, 0x1302);
+    Tag const AcquisitionMatrix(0x0018, 0x1310);
+    Tag const InPlanePhaseEncodingDirection(0x0018, 0x1312);
+    Tag const FlipAngle(0x0018, 0x1314);
+    Tag const VariableFlipAngleFlag(0x0018, 0x1315);
+    Tag const SAR(0x0018, 0x1316);
+    Tag const dBdt(0x0018, 0x1318);
+    Tag const AcquisitionDeviceProcessingDescription(0x0018, 0x1400);
+    Tag const AcquisitionDeviceProcessingCode(0x0018, 0x1401);
+    Tag const CassetteOrientation(0x0018, 0x1402);
+    Tag const CassetteSize(0x0018, 0x1403);
+    Tag const ExposuresOnPlate(0x0018, 0x1404);
+    Tag const RelativeXRayExposure(0x0018, 0x1405);
+    Tag const ExposureIndex(0x0018, 0x1411);
+    Tag const TargetExposureIndex(0x0018, 0x1412);
+    Tag const DeviationIndex(0x0018, 0x1413);
+    Tag const ColumnAngulation(0x0018, 0x1450);
+    Tag const TomoLayerHeight(0x0018, 0x1460);
+    Tag const TomoAngle(0x0018, 0x1470);
+    Tag const TomoTime(0x0018, 0x1480);
+    Tag const TomoType(0x0018, 0x1490);
+    Tag const TomoClass(0x0018, 0x1491);
+    Tag const NumberOfTomosynthesisSourceImages(0x0018, 0x1495);
+    Tag const PositionerMotion(0x0018, 0x1500);
+    Tag const PositionerType(0x0018, 0x1508);
+    Tag const PositionerPrimaryAngle(0x0018, 0x1510);
+    Tag const PositionerSecondaryAngle(0x0018, 0x1511);
+    Tag const PositionerPrimaryAngleIncrement(0x0018, 0x1520);
+    Tag const PositionerSecondaryAngleIncrement(0x0018, 0x1521);
+    Tag const DetectorPrimaryAngle(0x0018, 0x1530);
+    Tag const DetectorSecondaryAngle(0x0018, 0x1531);
+    Tag const ShutterShape(0x0018, 0x1600);
+    Tag const ShutterLeftVerticalEdge(0x0018, 0x1602);
+    Tag const ShutterRightVerticalEdge(0x0018, 0x1604);
+    Tag const ShutterUpperHorizontalEdge(0x0018, 0x1606);
+    Tag const ShutterLowerHorizontalEdge(0x0018, 0x1608);
+    Tag const CenterOfCircularShutter(0x0018, 0x1610);
+    Tag const RadiusOfCircularShutter(0x0018, 0x1612);
+    Tag const VerticesOfThePolygonalShutter(0x0018, 0x1620);
+    Tag const ShutterPresentationValue(0x0018, 0x1622);
+    Tag const ShutterOverlayGroup(0x0018, 0x1623);
+    Tag const ShutterPresentationColorCIELabValue(0x0018, 0x1624);
+    Tag const CollimatorShape(0x0018, 0x1700);
+    Tag const CollimatorLeftVerticalEdge(0x0018, 0x1702);
+    Tag const CollimatorRightVerticalEdge(0x0018, 0x1704);
+    Tag const CollimatorUpperHorizontalEdge(0x0018, 0x1706);
+    Tag const CollimatorLowerHorizontalEdge(0x0018, 0x1708);
+    Tag const CenterOfCircularCollimator(0x0018, 0x1710);
+    Tag const RadiusOfCircularCollimator(0x0018, 0x1712);
+    Tag const VerticesOfThePolygonalCollimator(0x0018, 0x1720);
+    Tag const AcquisitionTimeSynchronized(0x0018, 0x1800);
+    Tag const TimeSource(0x0018, 0x1801);
+    Tag const TimeDistributionProtocol(0x0018, 0x1802);
+    Tag const NTPSourceAddress(0x0018, 0x1803);
+    Tag const PageNumberVector(0x0018, 0x2001);
+    Tag const FrameLabelVector(0x0018, 0x2002);
+    Tag const FramePrimaryAngleVector(0x0018, 0x2003);
+    Tag const FrameSecondaryAngleVector(0x0018, 0x2004);
+    Tag const SliceLocationVector(0x0018, 0x2005);
+    Tag const DisplayWindowLabelVector(0x0018, 0x2006);
+    Tag const NominalScannedPixelSpacing(0x0018, 0x2010);
+    Tag const DigitizingDeviceTransportDirection(0x0018, 0x2020);
+    Tag const RotationOfScannedFilm(0x0018, 0x2030);
+    Tag const BiopsyTargetSequence(0x0018, 0x2041);
+    Tag const TargetUID(0x0018, 0x2042);
+    Tag const LocalizingCursorPosition(0x0018, 0x2043);
+    Tag const CalculatedTargetPosition(0x0018, 0x2044);
+    Tag const TargetLabel(0x0018, 0x2045);
+    Tag const DisplayedZValue(0x0018, 0x2046);
+    Tag const IVUSAcquisition(0x0018, 0x3100);
+    Tag const IVUSPullbackRate(0x0018, 0x3101);
+    Tag const IVUSGatedRate(0x0018, 0x3102);
+    Tag const IVUSPullbackStartFrameNumber(0x0018, 0x3103);
+    Tag const IVUSPullbackStopFrameNumber(0x0018, 0x3104);
+    Tag const LesionNumber(0x0018, 0x3105);
+    Tag const AcquisitionComments(0x0018, 0x4000);
+    Tag const OutputPower(0x0018, 0x5000);
+    Tag const TransducerData(0x0018, 0x5010);
+    Tag const FocusDepth(0x0018, 0x5012);
+    Tag const ProcessingFunction(0x0018, 0x5020);
+    Tag const PostprocessingFunction(0x0018, 0x5021);
+    Tag const MechanicalIndex(0x0018, 0x5022);
+    Tag const BoneThermalIndex(0x0018, 0x5024);
+    Tag const CranialThermalIndex(0x0018, 0x5026);
+    Tag const SoftTissueThermalIndex(0x0018, 0x5027);
+    Tag const SoftTissueFocusThermalIndex(0x0018, 0x5028);
+    Tag const SoftTissueSurfaceThermalIndex(0x0018, 0x5029);
+    Tag const DynamicRange(0x0018, 0x5030);
+    Tag const TotalGain(0x0018, 0x5040);
+    Tag const DepthOfScanField(0x0018, 0x5050);
+    Tag const PatientPosition(0x0018, 0x5100);
+    Tag const ViewPosition(0x0018, 0x5101);
+    Tag const ProjectionEponymousNameCodeSequence(0x0018, 0x5104);
+    Tag const ImageTransformationMatrix(0x0018, 0x5210);
+    Tag const ImageTranslationVector(0x0018, 0x5212);
+    Tag const Sensitivity(0x0018, 0x6000);
+    Tag const SequenceOfUltrasoundRegions(0x0018, 0x6011);
+    Tag const RegionSpatialFormat(0x0018, 0x6012);
+    Tag const RegionDataType(0x0018, 0x6014);
+    Tag const RegionFlags(0x0018, 0x6016);
+    Tag const RegionLocationMinX0(0x0018, 0x6018);
+    Tag const RegionLocationMinY0(0x0018, 0x601a);
+    Tag const RegionLocationMaxX1(0x0018, 0x601c);
+    Tag const RegionLocationMaxY1(0x0018, 0x601e);
+    Tag const ReferencePixelX0(0x0018, 0x6020);
+    Tag const ReferencePixelY0(0x0018, 0x6022);
+    Tag const PhysicalUnitsXDirection(0x0018, 0x6024);
+    Tag const PhysicalUnitsYDirection(0x0018, 0x6026);
+    Tag const ReferencePixelPhysicalValueX(0x0018, 0x6028);
+    Tag const ReferencePixelPhysicalValueY(0x0018, 0x602a);
+    Tag const PhysicalDeltaX(0x0018, 0x602c);
+    Tag const PhysicalDeltaY(0x0018, 0x602e);
+    Tag const TransducerFrequency(0x0018, 0x6030);
+    Tag const TransducerType(0x0018, 0x6031);
+    Tag const PulseRepetitionFrequency(0x0018, 0x6032);
+    Tag const DopplerCorrectionAngle(0x0018, 0x6034);
+    Tag const SteeringAngle(0x0018, 0x6036);
+    Tag const DopplerSampleVolumeXPositionRetired(0x0018, 0x6038);
+    Tag const DopplerSampleVolumeXPosition(0x0018, 0x6039);
+    Tag const DopplerSampleVolumeYPositionRetired(0x0018, 0x603a);
+    Tag const DopplerSampleVolumeYPosition(0x0018, 0x603b);
+    Tag const TMLinePositionX0Retired(0x0018, 0x603c);
+    Tag const TMLinePositionX0(0x0018, 0x603d);
+    Tag const TMLinePositionY0Retired(0x0018, 0x603e);
+    Tag const TMLinePositionY0(0x0018, 0x603f);
+    Tag const TMLinePositionX1Retired(0x0018, 0x6040);
+    Tag const TMLinePositionX1(0x0018, 0x6041);
+    Tag const TMLinePositionY1Retired(0x0018, 0x6042);
+    Tag const TMLinePositionY1(0x0018, 0x6043);
+    Tag const PixelComponentOrganization(0x0018, 0x6044);
+    Tag const PixelComponentMask(0x0018, 0x6046);
+    Tag const PixelComponentRangeStart(0x0018, 0x6048);
+    Tag const PixelComponentRangeStop(0x0018, 0x604a);
+    Tag const PixelComponentPhysicalUnits(0x0018, 0x604c);
+    Tag const PixelComponentDataType(0x0018, 0x604e);
+    Tag const NumberOfTableBreakPoints(0x0018, 0x6050);
+    Tag const TableOfXBreakPoints(0x0018, 0x6052);
+    Tag const TableOfYBreakPoints(0x0018, 0x6054);
+    Tag const NumberOfTableEntries(0x0018, 0x6056);
+    Tag const TableOfPixelValues(0x0018, 0x6058);
+    Tag const TableOfParameterValues(0x0018, 0x605a);
+    Tag const RWaveTimeVector(0x0018, 0x6060);
+    Tag const DetectorConditionsNominalFlag(0x0018, 0x7000);
+    Tag const DetectorTemperature(0x0018, 0x7001);
+    Tag const DetectorType(0x0018, 0x7004);
+    Tag const DetectorConfiguration(0x0018, 0x7005);
+    Tag const DetectorDescription(0x0018, 0x7006);
+    Tag const DetectorMode(0x0018, 0x7008);
+    Tag const DetectorID(0x0018, 0x700a);
+    Tag const DateOfLastDetectorCalibration(0x0018, 0x700c);
+    Tag const TimeOfLastDetectorCalibration(0x0018, 0x700e);
+    Tag const ExposuresOnDetectorSinceLastCalibration(0x0018, 0x7010);
+    Tag const ExposuresOnDetectorSinceManufactured(0x0018, 0x7011);
+    Tag const DetectorTimeSinceLastExposure(0x0018, 0x7012);
+    Tag const DetectorActiveTime(0x0018, 0x7014);
+    Tag const DetectorActivationOffsetFromExposure(0x0018, 0x7016);
+    Tag const DetectorBinning(0x0018, 0x701a);
+    Tag const DetectorElementPhysicalSize(0x0018, 0x7020);
+    Tag const DetectorElementSpacing(0x0018, 0x7022);
+    Tag const DetectorActiveShape(0x0018, 0x7024);
+    Tag const DetectorActiveDimensions(0x0018, 0x7026);
+    Tag const DetectorActiveOrigin(0x0018, 0x7028);
+    Tag const DetectorManufacturerName(0x0018, 0x702a);
+    Tag const DetectorManufacturerModelName(0x0018, 0x702b);
+    Tag const FieldOfViewOrigin(0x0018, 0x7030);
+    Tag const FieldOfViewRotation(0x0018, 0x7032);
+    Tag const FieldOfViewHorizontalFlip(0x0018, 0x7034);
+    Tag const PixelDataAreaOriginRelativeToFOV(0x0018, 0x7036);
+    Tag const PixelDataAreaRotationAngleRelativeToFOV(0x0018, 0x7038);
+    Tag const GridAbsorbingMaterial(0x0018, 0x7040);
+    Tag const GridSpacingMaterial(0x0018, 0x7041);
+    Tag const GridThickness(0x0018, 0x7042);
+    Tag const GridPitch(0x0018, 0x7044);
+    Tag const GridAspectRatio(0x0018, 0x7046);
+    Tag const GridPeriod(0x0018, 0x7048);
+    Tag const GridFocalDistance(0x0018, 0x704c);
+    Tag const FilterMaterial(0x0018, 0x7050);
+    Tag const FilterThicknessMinimum(0x0018, 0x7052);
+    Tag const FilterThicknessMaximum(0x0018, 0x7054);
+    Tag const FilterBeamPathLengthMinimum(0x0018, 0x7056);
+    Tag const FilterBeamPathLengthMaximum(0x0018, 0x7058);
+    Tag const ExposureControlMode(0x0018, 0x7060);
+    Tag const ExposureControlModeDescription(0x0018, 0x7062);
+    Tag const ExposureStatus(0x0018, 0x7064);
+    Tag const PhototimerSetting(0x0018, 0x7065);
+    Tag const ExposureTimeInuS(0x0018, 0x8150);
+    Tag const XRayTubeCurrentInuA(0x0018, 0x8151);
+    Tag const ContentQualification(0x0018, 0x9004);
+    Tag const PulseSequenceName(0x0018, 0x9005);
+    Tag const MRImagingModifierSequence(0x0018, 0x9006);
+    Tag const EchoPulseSequence(0x0018, 0x9008);
+    Tag const InversionRecovery(0x0018, 0x9009);
+    Tag const FlowCompensation(0x0018, 0x9010);
+    Tag const MultipleSpinEcho(0x0018, 0x9011);
+    Tag const MultiPlanarExcitation(0x0018, 0x9012);
+    Tag const PhaseContrast(0x0018, 0x9014);
+    Tag const TimeOfFlightContrast(0x0018, 0x9015);
+    Tag const Spoiling(0x0018, 0x9016);
+    Tag const SteadyStatePulseSequence(0x0018, 0x9017);
+    Tag const EchoPlanarPulseSequence(0x0018, 0x9018);
+    Tag const TagAngleFirstAxis(0x0018, 0x9019);
+    Tag const MagnetizationTransfer(0x0018, 0x9020);
+    Tag const T2Preparation(0x0018, 0x9021);
+    Tag const BloodSignalNulling(0x0018, 0x9022);
+    Tag const SaturationRecovery(0x0018, 0x9024);
+    Tag const SpectrallySelectedSuppression(0x0018, 0x9025);
+    Tag const SpectrallySelectedExcitation(0x0018, 0x9026);
+    Tag const SpatialPresaturation(0x0018, 0x9027);
+    Tag const Tagging(0x0018, 0x9028);
+    Tag const OversamplingPhase(0x0018, 0x9029);
+    Tag const TagSpacingFirstDimension(0x0018, 0x9030);
+    Tag const GeometryOfKSpaceTraversal(0x0018, 0x9032);
+    Tag const SegmentedKSpaceTraversal(0x0018, 0x9033);
+    Tag const RectilinearPhaseEncodeReordering(0x0018, 0x9034);
+    Tag const TagThickness(0x0018, 0x9035);
+    Tag const PartialFourierDirection(0x0018, 0x9036);
+    Tag const CardiacSynchronizationTechnique(0x0018, 0x9037);
+    Tag const ReceiveCoilManufacturerName(0x0018, 0x9041);
+    Tag const MRReceiveCoilSequence(0x0018, 0x9042);
+    Tag const ReceiveCoilType(0x0018, 0x9043);
+    Tag const QuadratureReceiveCoil(0x0018, 0x9044);
+    Tag const MultiCoilDefinitionSequence(0x0018, 0x9045);
+    Tag const MultiCoilConfiguration(0x0018, 0x9046);
+    Tag const MultiCoilElementName(0x0018, 0x9047);
+    Tag const MultiCoilElementUsed(0x0018, 0x9048);
+    Tag const MRTransmitCoilSequence(0x0018, 0x9049);
+    Tag const TransmitCoilManufacturerName(0x0018, 0x9050);
+    Tag const TransmitCoilType(0x0018, 0x9051);
+    Tag const SpectralWidth(0x0018, 0x9052);
+    Tag const ChemicalShiftReference(0x0018, 0x9053);
+    Tag const VolumeLocalizationTechnique(0x0018, 0x9054);
+    Tag const MRAcquisitionFrequencyEncodingSteps(0x0018, 0x9058);
+    Tag const Decoupling(0x0018, 0x9059);
+    Tag const DecoupledNucleus(0x0018, 0x9060);
+    Tag const DecouplingFrequency(0x0018, 0x9061);
+    Tag const DecouplingMethod(0x0018, 0x9062);
+    Tag const DecouplingChemicalShiftReference(0x0018, 0x9063);
+    Tag const KSpaceFiltering(0x0018, 0x9064);
+    Tag const TimeDomainFiltering(0x0018, 0x9065);
+    Tag const NumberOfZeroFills(0x0018, 0x9066);
+    Tag const BaselineCorrection(0x0018, 0x9067);
+    Tag const ParallelReductionFactorInPlane(0x0018, 0x9069);
+    Tag const CardiacRRIntervalSpecified(0x0018, 0x9070);
+    Tag const AcquisitionDuration(0x0018, 0x9073);
+    Tag const FrameAcquisitionDateTime(0x0018, 0x9074);
+    Tag const DiffusionDirectionality(0x0018, 0x9075);
+    Tag const DiffusionGradientDirectionSequence(0x0018, 0x9076);
+    Tag const ParallelAcquisition(0x0018, 0x9077);
+    Tag const ParallelAcquisitionTechnique(0x0018, 0x9078);
+    Tag const InversionTimes(0x0018, 0x9079);
+    Tag const MetaboliteMapDescription(0x0018, 0x9080);
+    Tag const PartialFourier(0x0018, 0x9081);
+    Tag const EffectiveEchoTime(0x0018, 0x9082);
+    Tag const MetaboliteMapCodeSequence(0x0018, 0x9083);
+    Tag const ChemicalShiftSequence(0x0018, 0x9084);
+    Tag const CardiacSignalSource(0x0018, 0x9085);
+    Tag const DiffusionBValue(0x0018, 0x9087);
+    Tag const DiffusionGradientOrientation(0x0018, 0x9089);
+    Tag const VelocityEncodingDirection(0x0018, 0x9090);
+    Tag const VelocityEncodingMinimumValue(0x0018, 0x9091);
+    Tag const VelocityEncodingAcquisitionSequence(0x0018, 0x9092);
+    Tag const NumberOfKSpaceTrajectories(0x0018, 0x9093);
+    Tag const CoverageOfKSpace(0x0018, 0x9094);
+    Tag const SpectroscopyAcquisitionPhaseRows(0x0018, 0x9095);
+    Tag const ParallelReductionFactorInPlaneRetired(0x0018, 0x9096);
+    Tag const TransmitterFrequency(0x0018, 0x9098);
+    Tag const ResonantNucleus(0x0018, 0x9100);
+    Tag const FrequencyCorrection(0x0018, 0x9101);
+    Tag const MRSpectroscopyFOVGeometrySequence(0x0018, 0x9103);
+    Tag const SlabThickness(0x0018, 0x9104);
+    Tag const SlabOrientation(0x0018, 0x9105);
+    Tag const MidSlabPosition(0x0018, 0x9106);
+    Tag const MRSpatialSaturationSequence(0x0018, 0x9107);
+    Tag const MRTimingAndRelatedParametersSequence(0x0018, 0x9112);
+    Tag const MREchoSequence(0x0018, 0x9114);
+    Tag const MRModifierSequence(0x0018, 0x9115);
+    Tag const MRDiffusionSequence(0x0018, 0x9117);
+    Tag const CardiacSynchronizationSequence(0x0018, 0x9118);
+    Tag const MRAveragesSequence(0x0018, 0x9119);
+    Tag const MRFOVGeometrySequence(0x0018, 0x9125);
+    Tag const VolumeLocalizationSequence(0x0018, 0x9126);
+    Tag const SpectroscopyAcquisitionDataColumns(0x0018, 0x9127);
+    Tag const DiffusionAnisotropyType(0x0018, 0x9147);
+    Tag const FrameReferenceDateTime(0x0018, 0x9151);
+    Tag const MRMetaboliteMapSequence(0x0018, 0x9152);
+    Tag const ParallelReductionFactorOutOfPlane(0x0018, 0x9155);
+    Tag const SpectroscopyAcquisitionOutOfPlanePhaseSteps(0x0018, 0x9159);
+    Tag const BulkMotionStatus(0x0018, 0x9166);
+    Tag const ParallelReductionFactorSecondInPlane(0x0018, 0x9168);
+    Tag const CardiacBeatRejectionTechnique(0x0018, 0x9169);
+    Tag const RespiratoryMotionCompensationTechnique(0x0018, 0x9170);
+    Tag const RespiratorySignalSource(0x0018, 0x9171);
+    Tag const BulkMotionCompensationTechnique(0x0018, 0x9172);
+    Tag const BulkMotionSignalSource(0x0018, 0x9173);
+    Tag const ApplicableSafetyStandardAgency(0x0018, 0x9174);
+    Tag const ApplicableSafetyStandardDescription(0x0018, 0x9175);
+    Tag const OperatingModeSequence(0x0018, 0x9176);
+    Tag const OperatingModeType(0x0018, 0x9177);
+    Tag const OperatingMode(0x0018, 0x9178);
+    Tag const SpecificAbsorptionRateDefinition(0x0018, 0x9179);
+    Tag const GradientOutputType(0x0018, 0x9180);
+    Tag const SpecificAbsorptionRateValue(0x0018, 0x9181);
+    Tag const GradientOutput(0x0018, 0x9182);
+    Tag const FlowCompensationDirection(0x0018, 0x9183);
+    Tag const TaggingDelay(0x0018, 0x9184);
+    Tag const RespiratoryMotionCompensationTechniqueDescription(0x0018, 0x9185);
+    Tag const RespiratorySignalSourceID(0x0018, 0x9186);
+    Tag const ChemicalShiftMinimumIntegrationLimitInHz(0x0018, 0x9195);
+    Tag const ChemicalShiftMaximumIntegrationLimitInHz(0x0018, 0x9196);
+    Tag const MRVelocityEncodingSequence(0x0018, 0x9197);
+    Tag const FirstOrderPhaseCorrection(0x0018, 0x9198);
+    Tag const WaterReferencedPhaseCorrection(0x0018, 0x9199);
+    Tag const MRSpectroscopyAcquisitionType(0x0018, 0x9200);
+    Tag const RespiratoryCyclePosition(0x0018, 0x9214);
+    Tag const VelocityEncodingMaximumValue(0x0018, 0x9217);
+    Tag const TagSpacingSecondDimension(0x0018, 0x9218);
+    Tag const TagAngleSecondAxis(0x0018, 0x9219);
+    Tag const FrameAcquisitionDuration(0x0018, 0x9220);
+    Tag const MRImageFrameTypeSequence(0x0018, 0x9226);
+    Tag const MRSpectroscopyFrameTypeSequence(0x0018, 0x9227);
+    Tag const MRAcquisitionPhaseEncodingStepsInPlane(0x0018, 0x9231);
+    Tag const MRAcquisitionPhaseEncodingStepsOutOfPlane(0x0018, 0x9232);
+    Tag const SpectroscopyAcquisitionPhaseColumns(0x0018, 0x9234);
+    Tag const CardiacCyclePosition(0x0018, 0x9236);
+    Tag const SpecificAbsorptionRateSequence(0x0018, 0x9239);
+    Tag const RFEchoTrainLength(0x0018, 0x9240);
+    Tag const GradientEchoTrainLength(0x0018, 0x9241);
+    Tag const ArterialSpinLabelingContrast(0x0018, 0x9250);
+    Tag const MRArterialSpinLabelingSequence(0x0018, 0x9251);
+    Tag const ASLTechniqueDescription(0x0018, 0x9252);
+    Tag const ASLSlabNumber(0x0018, 0x9253);
+    Tag const ASLSlabThickness(0x0018, 0x9254);
+    Tag const ASLSlabOrientation(0x0018, 0x9255);
+    Tag const ASLMidSlabPosition(0x0018, 0x9256);
+    Tag const ASLContext(0x0018, 0x9257);
+    Tag const ASLPulseTrainDuration(0x0018, 0x9258);
+    Tag const ASLCrusherFlag(0x0018, 0x9259);
+    Tag const ASLCrusherFlowLimit(0x0018, 0x925a);
+    Tag const ASLCrusherDescription(0x0018, 0x925b);
+    Tag const ASLBolusCutoffFlag(0x0018, 0x925c);
+    Tag const ASLBolusCutoffTimingSequence(0x0018, 0x925d);
+    Tag const ASLBolusCutoffTechnique(0x0018, 0x925e);
+    Tag const ASLBolusCutoffDelayTime(0x0018, 0x925f);
+    Tag const ASLSlabSequence(0x0018, 0x9260);
+    Tag const ChemicalShiftMinimumIntegrationLimitInppm(0x0018, 0x9295);
+    Tag const ChemicalShiftMaximumIntegrationLimitInppm(0x0018, 0x9296);
+    Tag const WaterReferenceAcquisition(0x0018, 0x9297);
+    Tag const EchoPeakPosition(0x0018, 0x9298);
+    Tag const CTAcquisitionTypeSequence(0x0018, 0x9301);
+    Tag const AcquisitionType(0x0018, 0x9302);
+    Tag const TubeAngle(0x0018, 0x9303);
+    Tag const CTAcquisitionDetailsSequence(0x0018, 0x9304);
+    Tag const RevolutionTime(0x0018, 0x9305);
+    Tag const SingleCollimationWidth(0x0018, 0x9306);
+    Tag const TotalCollimationWidth(0x0018, 0x9307);
+    Tag const CTTableDynamicsSequence(0x0018, 0x9308);
+    Tag const TableSpeed(0x0018, 0x9309);
+    Tag const TableFeedPerRotation(0x0018, 0x9310);
+    Tag const SpiralPitchFactor(0x0018, 0x9311);
+    Tag const CTGeometrySequence(0x0018, 0x9312);
+    Tag const DataCollectionCenterPatient(0x0018, 0x9313);
+    Tag const CTReconstructionSequence(0x0018, 0x9314);
+    Tag const ReconstructionAlgorithm(0x0018, 0x9315);
+    Tag const ConvolutionKernelGroup(0x0018, 0x9316);
+    Tag const ReconstructionFieldOfView(0x0018, 0x9317);
+    Tag const ReconstructionTargetCenterPatient(0x0018, 0x9318);
+    Tag const ReconstructionAngle(0x0018, 0x9319);
+    Tag const ImageFilter(0x0018, 0x9320);
+    Tag const CTExposureSequence(0x0018, 0x9321);
+    Tag const ReconstructionPixelSpacing(0x0018, 0x9322);
+    Tag const ExposureModulationType(0x0018, 0x9323);
+    Tag const EstimatedDoseSaving(0x0018, 0x9324);
+    Tag const CTXRayDetailsSequence(0x0018, 0x9325);
+    Tag const CTPositionSequence(0x0018, 0x9326);
+    Tag const TablePosition(0x0018, 0x9327);
+    Tag const ExposureTimeInms(0x0018, 0x9328);
+    Tag const CTImageFrameTypeSequence(0x0018, 0x9329);
+    Tag const XRayTubeCurrentInmA(0x0018, 0x9330);
+    Tag const ExposureInmAs(0x0018, 0x9332);
+    Tag const ConstantVolumeFlag(0x0018, 0x9333);
+    Tag const FluoroscopyFlag(0x0018, 0x9334);
+    Tag const DistanceSourceToDataCollectionCenter(0x0018, 0x9335);
+    Tag const ContrastBolusAgentNumber(0x0018, 0x9337);
+    Tag const ContrastBolusIngredientCodeSequence(0x0018, 0x9338);
+    Tag const ContrastAdministrationProfileSequence(0x0018, 0x9340);
+    Tag const ContrastBolusUsageSequence(0x0018, 0x9341);
+    Tag const ContrastBolusAgentAdministered(0x0018, 0x9342);
+    Tag const ContrastBolusAgentDetected(0x0018, 0x9343);
+    Tag const ContrastBolusAgentPhase(0x0018, 0x9344);
+    Tag const CTDIvol(0x0018, 0x9345);
+    Tag const CTDIPhantomTypeCodeSequence(0x0018, 0x9346);
+    Tag const CalciumScoringMassFactorPatient(0x0018, 0x9351);
+    Tag const CalciumScoringMassFactorDevice(0x0018, 0x9352);
+    Tag const EnergyWeightingFactor(0x0018, 0x9353);
+    Tag const CTAdditionalXRaySourceSequence(0x0018, 0x9360);
+    Tag const ProjectionPixelCalibrationSequence(0x0018, 0x9401);
+    Tag const DistanceSourceToIsocenter(0x0018, 0x9402);
+    Tag const DistanceObjectToTableTop(0x0018, 0x9403);
+    Tag const ObjectPixelSpacingInCenterOfBeam(0x0018, 0x9404);
+    Tag const PositionerPositionSequence(0x0018, 0x9405);
+    Tag const TablePositionSequence(0x0018, 0x9406);
+    Tag const CollimatorShapeSequence(0x0018, 0x9407);
+    Tag const PlanesInAcquisition(0x0018, 0x9410);
+    Tag const XAXRFFrameCharacteristicsSequence(0x0018, 0x9412);
+    Tag const FrameAcquisitionSequence(0x0018, 0x9417);
+    Tag const XRayReceptorType(0x0018, 0x9420);
+    Tag const AcquisitionProtocolName(0x0018, 0x9423);
+    Tag const AcquisitionProtocolDescription(0x0018, 0x9424);
+    Tag const ContrastBolusIngredientOpaque(0x0018, 0x9425);
+    Tag const DistanceReceptorPlaneToDetectorHousing(0x0018, 0x9426);
+    Tag const IntensifierActiveShape(0x0018, 0x9427);
+    Tag const IntensifierActiveDimensions(0x0018, 0x9428);
+    Tag const PhysicalDetectorSize(0x0018, 0x9429);
+    Tag const PositionOfIsocenterProjection(0x0018, 0x9430);
+    Tag const FieldOfViewSequence(0x0018, 0x9432);
+    Tag const FieldOfViewDescription(0x0018, 0x9433);
+    Tag const ExposureControlSensingRegionsSequence(0x0018, 0x9434);
+    Tag const ExposureControlSensingRegionShape(0x0018, 0x9435);
+    Tag const ExposureControlSensingRegionLeftVerticalEdge(0x0018, 0x9436);
+    Tag const ExposureControlSensingRegionRightVerticalEdge(0x0018, 0x9437);
+    Tag const ExposureControlSensingRegionUpperHorizontalEdge(0x0018, 0x9438);
+    Tag const ExposureControlSensingRegionLowerHorizontalEdge(0x0018, 0x9439);
+    Tag const CenterOfCircularExposureControlSensingRegion(0x0018, 0x9440);
+    Tag const RadiusOfCircularExposureControlSensingRegion(0x0018, 0x9441);
+    Tag const VerticesOfThePolygonalExposureControlSensingRegion(0x0018, 0x9442);
+    Tag const ColumnAngulationPatient(0x0018, 0x9447);
+    Tag const BeamAngle(0x0018, 0x9449);
+    Tag const FrameDetectorParametersSequence(0x0018, 0x9451);
+    Tag const CalculatedAnatomyThickness(0x0018, 0x9452);
+    Tag const CalibrationSequence(0x0018, 0x9455);
+    Tag const ObjectThicknessSequence(0x0018, 0x9456);
+    Tag const PlaneIdentification(0x0018, 0x9457);
+    Tag const FieldOfViewDimensionsInFloat(0x0018, 0x9461);
+    Tag const IsocenterReferenceSystemSequence(0x0018, 0x9462);
+    Tag const PositionerIsocenterPrimaryAngle(0x0018, 0x9463);
+    Tag const PositionerIsocenterSecondaryAngle(0x0018, 0x9464);
+    Tag const PositionerIsocenterDetectorRotationAngle(0x0018, 0x9465);
+    Tag const TableXPositionToIsocenter(0x0018, 0x9466);
+    Tag const TableYPositionToIsocenter(0x0018, 0x9467);
+    Tag const TableZPositionToIsocenter(0x0018, 0x9468);
+    Tag const TableHorizontalRotationAngle(0x0018, 0x9469);
+    Tag const TableHeadTiltAngle(0x0018, 0x9470);
+    Tag const TableCradleTiltAngle(0x0018, 0x9471);
+    Tag const FrameDisplayShutterSequence(0x0018, 0x9472);
+    Tag const AcquiredImageAreaDoseProduct(0x0018, 0x9473);
+    Tag const CArmPositionerTabletopRelationship(0x0018, 0x9474);
+    Tag const XRayGeometrySequence(0x0018, 0x9476);
+    Tag const IrradiationEventIdentificationSequence(0x0018, 0x9477);
+    Tag const XRay3DFrameTypeSequence(0x0018, 0x9504);
+    Tag const ContributingSourcesSequence(0x0018, 0x9506);
+    Tag const XRay3DAcquisitionSequence(0x0018, 0x9507);
+    Tag const PrimaryPositionerScanArc(0x0018, 0x9508);
+    Tag const SecondaryPositionerScanArc(0x0018, 0x9509);
+    Tag const PrimaryPositionerScanStartAngle(0x0018, 0x9510);
+    Tag const SecondaryPositionerScanStartAngle(0x0018, 0x9511);
+    Tag const PrimaryPositionerIncrement(0x0018, 0x9514);
+    Tag const SecondaryPositionerIncrement(0x0018, 0x9515);
+    Tag const StartAcquisitionDateTime(0x0018, 0x9516);
+    Tag const EndAcquisitionDateTime(0x0018, 0x9517);
+    Tag const PrimaryPositionerIncrementSign(0x0018, 0x9518);
+    Tag const SecondaryPositionerIncrementSign(0x0018, 0x9519);
+    Tag const ApplicationName(0x0018, 0x9524);
+    Tag const ApplicationVersion(0x0018, 0x9525);
+    Tag const ApplicationManufacturer(0x0018, 0x9526);
+    Tag const AlgorithmType(0x0018, 0x9527);
+    Tag const AlgorithmDescription(0x0018, 0x9528);
+    Tag const XRay3DReconstructionSequence(0x0018, 0x9530);
+    Tag const ReconstructionDescription(0x0018, 0x9531);
+    Tag const PerProjectionAcquisitionSequence(0x0018, 0x9538);
+    Tag const DetectorPositionSequence(0x0018, 0x9541);
+    Tag const XRayAcquisitionDoseSequence(0x0018, 0x9542);
+    Tag const XRaySourceIsocenterPrimaryAngle(0x0018, 0x9543);
+    Tag const XRaySourceIsocenterSecondaryAngle(0x0018, 0x9544);
+    Tag const BreastSupportIsocenterPrimaryAngle(0x0018, 0x9545);
+    Tag const BreastSupportIsocenterSecondaryAngle(0x0018, 0x9546);
+    Tag const BreastSupportXPositionToIsocenter(0x0018, 0x9547);
+    Tag const BreastSupportYPositionToIsocenter(0x0018, 0x9548);
+    Tag const BreastSupportZPositionToIsocenter(0x0018, 0x9549);
+    Tag const DetectorIsocenterPrimaryAngle(0x0018, 0x9550);
+    Tag const DetectorIsocenterSecondaryAngle(0x0018, 0x9551);
+    Tag const DetectorXPositionToIsocenter(0x0018, 0x9552);
+    Tag const DetectorYPositionToIsocenter(0x0018, 0x9553);
+    Tag const DetectorZPositionToIsocenter(0x0018, 0x9554);
+    Tag const XRayGridSequence(0x0018, 0x9555);
+    Tag const XRayFilterSequence(0x0018, 0x9556);
+    Tag const DetectorActiveAreaTLHCPosition(0x0018, 0x9557);
+    Tag const DetectorActiveAreaOrientation(0x0018, 0x9558);
+    Tag const PositionerPrimaryAngleDirection(0x0018, 0x9559);
+    Tag const DiffusionBMatrixSequence(0x0018, 0x9601);
+    Tag const DiffusionBValueXX(0x0018, 0x9602);
+    Tag const DiffusionBValueXY(0x0018, 0x9603);
+    Tag const DiffusionBValueXZ(0x0018, 0x9604);
+    Tag const DiffusionBValueYY(0x0018, 0x9605);
+    Tag const DiffusionBValueYZ(0x0018, 0x9606);
+    Tag const DiffusionBValueZZ(0x0018, 0x9607);
+    Tag const DecayCorrectionDateTime(0x0018, 0x9701);
+    Tag const StartDensityThreshold(0x0018, 0x9715);
+    Tag const StartRelativeDensityDifferenceThreshold(0x0018, 0x9716);
+    Tag const StartCardiacTriggerCountThreshold(0x0018, 0x9717);
+    Tag const StartRespiratoryTriggerCountThreshold(0x0018, 0x9718);
+    Tag const TerminationCountsThreshold(0x0018, 0x9719);
+    Tag const TerminationDensityThreshold(0x0018, 0x9720);
+    Tag const TerminationRelativeDensityThreshold(0x0018, 0x9721);
+    Tag const TerminationTimeThreshold(0x0018, 0x9722);
+    Tag const TerminationCardiacTriggerCountThreshold(0x0018, 0x9723);
+    Tag const TerminationRespiratoryTriggerCountThreshold(0x0018, 0x9724);
+    Tag const DetectorGeometry(0x0018, 0x9725);
+    Tag const TransverseDetectorSeparation(0x0018, 0x9726);
+    Tag const AxialDetectorDimension(0x0018, 0x9727);
+    Tag const RadiopharmaceuticalAgentNumber(0x0018, 0x9729);
+    Tag const PETFrameAcquisitionSequence(0x0018, 0x9732);
+    Tag const PETDetectorMotionDetailsSequence(0x0018, 0x9733);
+    Tag const PETTableDynamicsSequence(0x0018, 0x9734);
+    Tag const PETPositionSequence(0x0018, 0x9735);
+    Tag const PETFrameCorrectionFactorsSequence(0x0018, 0x9736);
+    Tag const RadiopharmaceuticalUsageSequence(0x0018, 0x9737);
+    Tag const AttenuationCorrectionSource(0x0018, 0x9738);
+    Tag const NumberOfIterations(0x0018, 0x9739);
+    Tag const NumberOfSubsets(0x0018, 0x9740);
+    Tag const PETReconstructionSequence(0x0018, 0x9749);
+    Tag const PETFrameTypeSequence(0x0018, 0x9751);
+    Tag const TimeOfFlightInformationUsed(0x0018, 0x9755);
+    Tag const ReconstructionType(0x0018, 0x9756);
+    Tag const DecayCorrected(0x0018, 0x9758);
+    Tag const AttenuationCorrected(0x0018, 0x9759);
+    Tag const ScatterCorrected(0x0018, 0x9760);
+    Tag const DeadTimeCorrected(0x0018, 0x9761);
+    Tag const GantryMotionCorrected(0x0018, 0x9762);
+    Tag const PatientMotionCorrected(0x0018, 0x9763);
+    Tag const CountLossNormalizationCorrected(0x0018, 0x9764);
+    Tag const RandomsCorrected(0x0018, 0x9765);
+    Tag const NonUniformRadialSamplingCorrected(0x0018, 0x9766);
+    Tag const SensitivityCalibrated(0x0018, 0x9767);
+    Tag const DetectorNormalizationCorrection(0x0018, 0x9768);
+    Tag const IterativeReconstructionMethod(0x0018, 0x9769);
+    Tag const AttenuationCorrectionTemporalRelationship(0x0018, 0x9770);
+    Tag const PatientPhysiologicalStateSequence(0x0018, 0x9771);
+    Tag const PatientPhysiologicalStateCodeSequence(0x0018, 0x9772);
+    Tag const DepthsOfFocus(0x0018, 0x9801);
+    Tag const ExcludedIntervalsSequence(0x0018, 0x9803);
+    Tag const ExclusionStartDateTime(0x0018, 0x9804);
+    Tag const ExclusionDuration(0x0018, 0x9805);
+    Tag const USImageDescriptionSequence(0x0018, 0x9806);
+    Tag const ImageDataTypeSequence(0x0018, 0x9807);
+    Tag const DataType(0x0018, 0x9808);
+    Tag const TransducerScanPatternCodeSequence(0x0018, 0x9809);
+    Tag const AliasedDataType(0x0018, 0x980b);
+    Tag const PositionMeasuringDeviceUsed(0x0018, 0x980c);
+    Tag const TransducerGeometryCodeSequence(0x0018, 0x980d);
+    Tag const TransducerBeamSteeringCodeSequence(0x0018, 0x980e);
+    Tag const TransducerApplicationCodeSequence(0x0018, 0x980f);
+    Tag const ZeroVelocityPixelValue(0x0018, 0x9810);
+    Tag const ContributingEquipmentSequence(0x0018, 0xa001);
+    Tag const ContributionDateTime(0x0018, 0xa002);
+    Tag const ContributionDescription(0x0018, 0xa003);
+    Tag const StudyInstanceUID(0x0020, 0x000d);
+    Tag const SeriesInstanceUID(0x0020, 0x000e);
+    Tag const StudyID(0x0020, 0x0010);
+    Tag const SeriesNumber(0x0020, 0x0011);
+    Tag const AcquisitionNumber(0x0020, 0x0012);
+    Tag const InstanceNumber(0x0020, 0x0013);
+    Tag const IsotopeNumber(0x0020, 0x0014);
+    Tag const PhaseNumber(0x0020, 0x0015);
+    Tag const IntervalNumber(0x0020, 0x0016);
+    Tag const TimeSlotNumber(0x0020, 0x0017);
+    Tag const AngleNumber(0x0020, 0x0018);
+    Tag const ItemNumber(0x0020, 0x0019);
+    Tag const PatientOrientation(0x0020, 0x0020);
+    Tag const OverlayNumber(0x0020, 0x0022);
+    Tag const CurveNumber(0x0020, 0x0024);
+    Tag const LUTNumber(0x0020, 0x0026);
+    Tag const ImagePosition(0x0020, 0x0030);
+    Tag const ImagePositionPatient(0x0020, 0x0032);
+    Tag const ImageOrientation(0x0020, 0x0035);
+    Tag const ImageOrientationPatient(0x0020, 0x0037);
+    Tag const Location(0x0020, 0x0050);
+    Tag const FrameOfReferenceUID(0x0020, 0x0052);
+    Tag const Laterality(0x0020, 0x0060);
+    Tag const ImageLaterality(0x0020, 0x0062);
+    Tag const ImageGeometryType(0x0020, 0x0070);
+    Tag const MaskingImage(0x0020, 0x0080);
+    Tag const ReportNumber(0x0020, 0x00aa);
+    Tag const TemporalPositionIdentifier(0x0020, 0x0100);
+    Tag const NumberOfTemporalPositions(0x0020, 0x0105);
+    Tag const TemporalResolution(0x0020, 0x0110);
+    Tag const SynchronizationFrameOfReferenceUID(0x0020, 0x0200);
+    Tag const SOPInstanceUIDOfConcatenationSource(0x0020, 0x0242);
+    Tag const SeriesInStudy(0x0020, 0x1000);
+    Tag const AcquisitionsInSeries(0x0020, 0x1001);
+    Tag const ImagesInAcquisition(0x0020, 0x1002);
+    Tag const ImagesInSeries(0x0020, 0x1003);
+    Tag const AcquisitionsInStudy(0x0020, 0x1004);
+    Tag const ImagesInStudy(0x0020, 0x1005);
+    Tag const Reference(0x0020, 0x1020);
+    Tag const PositionReferenceIndicator(0x0020, 0x1040);
+    Tag const SliceLocation(0x0020, 0x1041);
+    Tag const OtherStudyNumbers(0x0020, 0x1070);
+    Tag const NumberOfPatientRelatedStudies(0x0020, 0x1200);
+    Tag const NumberOfPatientRelatedSeries(0x0020, 0x1202);
+    Tag const NumberOfPatientRelatedInstances(0x0020, 0x1204);
+    Tag const NumberOfStudyRelatedSeries(0x0020, 0x1206);
+    Tag const NumberOfStudyRelatedInstances(0x0020, 0x1208);
+    Tag const NumberOfSeriesRelatedInstances(0x0020, 0x1209);
+    Tag const ModifyingDeviceID(0x0020, 0x3401);
+    Tag const ModifiedImageID(0x0020, 0x3402);
+    Tag const ModifiedImageDate(0x0020, 0x3403);
+    Tag const ModifyingDeviceManufacturer(0x0020, 0x3404);
+    Tag const ModifiedImageTime(0x0020, 0x3405);
+    Tag const ModifiedImageDescription(0x0020, 0x3406);
+    Tag const ImageComments(0x0020, 0x4000);
+    Tag const OriginalImageIdentification(0x0020, 0x5000);
+    Tag const OriginalImageIdentificationNomenclature(0x0020, 0x5002);
+    Tag const StackID(0x0020, 0x9056);
+    Tag const InStackPositionNumber(0x0020, 0x9057);
+    Tag const FrameAnatomySequence(0x0020, 0x9071);
+    Tag const FrameLaterality(0x0020, 0x9072);
+    Tag const FrameContentSequence(0x0020, 0x9111);
+    Tag const PlanePositionSequence(0x0020, 0x9113);
+    Tag const PlaneOrientationSequence(0x0020, 0x9116);
+    Tag const TemporalPositionIndex(0x0020, 0x9128);
+    Tag const NominalCardiacTriggerDelayTime(0x0020, 0x9153);
+    Tag const NominalCardiacTriggerTimePriorToRPeak(0x0020, 0x9154);
+    Tag const ActualCardiacTriggerTimePriorToRPeak(0x0020, 0x9155);
+    Tag const FrameAcquisitionNumber(0x0020, 0x9156);
+    Tag const DimensionIndexValues(0x0020, 0x9157);
+    Tag const FrameComments(0x0020, 0x9158);
+    Tag const ConcatenationUID(0x0020, 0x9161);
+    Tag const InConcatenationNumber(0x0020, 0x9162);
+    Tag const InConcatenationTotalNumber(0x0020, 0x9163);
+    Tag const DimensionOrganizationUID(0x0020, 0x9164);
+    Tag const DimensionIndexPointer(0x0020, 0x9165);
+    Tag const FunctionalGroupPointer(0x0020, 0x9167);
+    Tag const UnassignedSharedConvertedAttributesSequence(0x0020, 0x9170);
+    Tag const UnassignedPerFrameConvertedAttributesSequence(0x0020, 0x9171);
+    Tag const ConversionSourceAttributesSequence(0x0020, 0x9172);
+    Tag const DimensionIndexPrivateCreator(0x0020, 0x9213);
+    Tag const DimensionOrganizationSequence(0x0020, 0x9221);
+    Tag const DimensionIndexSequence(0x0020, 0x9222);
+    Tag const ConcatenationFrameOffsetNumber(0x0020, 0x9228);
+    Tag const FunctionalGroupPrivateCreator(0x0020, 0x9238);
+    Tag const NominalPercentageOfCardiacPhase(0x0020, 0x9241);
+    Tag const NominalPercentageOfRespiratoryPhase(0x0020, 0x9245);
+    Tag const StartingRespiratoryAmplitude(0x0020, 0x9246);
+    Tag const StartingRespiratoryPhase(0x0020, 0x9247);
+    Tag const EndingRespiratoryAmplitude(0x0020, 0x9248);
+    Tag const EndingRespiratoryPhase(0x0020, 0x9249);
+    Tag const RespiratoryTriggerType(0x0020, 0x9250);
+    Tag const RRIntervalTimeNominal(0x0020, 0x9251);
+    Tag const ActualCardiacTriggerDelayTime(0x0020, 0x9252);
+    Tag const RespiratorySynchronizationSequence(0x0020, 0x9253);
+    Tag const RespiratoryIntervalTime(0x0020, 0x9254);
+    Tag const NominalRespiratoryTriggerDelayTime(0x0020, 0x9255);
+    Tag const RespiratoryTriggerDelayThreshold(0x0020, 0x9256);
+    Tag const ActualRespiratoryTriggerDelayTime(0x0020, 0x9257);
+    Tag const ImagePositionVolume(0x0020, 0x9301);
+    Tag const ImageOrientationVolume(0x0020, 0x9302);
+    Tag const UltrasoundAcquisitionGeometry(0x0020, 0x9307);
+    Tag const ApexPosition(0x0020, 0x9308);
+    Tag const VolumeToTransducerMappingMatrix(0x0020, 0x9309);
+    Tag const VolumeToTableMappingMatrix(0x0020, 0x930a);
+    Tag const VolumeToTransducerRelationship(0x0020, 0x930b);
+    Tag const PatientFrameOfReferenceSource(0x0020, 0x930c);
+    Tag const TemporalPositionTimeOffset(0x0020, 0x930d);
+    Tag const PlanePositionVolumeSequence(0x0020, 0x930e);
+    Tag const PlaneOrientationVolumeSequence(0x0020, 0x930f);
+    Tag const TemporalPositionSequence(0x0020, 0x9310);
+    Tag const DimensionOrganizationType(0x0020, 0x9311);
+    Tag const VolumeFrameOfReferenceUID(0x0020, 0x9312);
+    Tag const TableFrameOfReferenceUID(0x0020, 0x9313);
+    Tag const DimensionDescriptionLabel(0x0020, 0x9421);
+    Tag const PatientOrientationInFrameSequence(0x0020, 0x9450);
+    Tag const FrameLabel(0x0020, 0x9453);
+    Tag const AcquisitionIndex(0x0020, 0x9518);
+    Tag const ContributingSOPInstancesReferenceSequence(0x0020, 0x9529);
+    Tag const ReconstructionIndex(0x0020, 0x9536);
+    Tag const LightPathFilterPassThroughWavelength(0x0022, 0x0001);
+    Tag const LightPathFilterPassBand(0x0022, 0x0002);
+    Tag const ImagePathFilterPassThroughWavelength(0x0022, 0x0003);
+    Tag const ImagePathFilterPassBand(0x0022, 0x0004);
+    Tag const PatientEyeMovementCommanded(0x0022, 0x0005);
+    Tag const PatientEyeMovementCommandCodeSequence(0x0022, 0x0006);
+    Tag const SphericalLensPower(0x0022, 0x0007);
+    Tag const CylinderLensPower(0x0022, 0x0008);
+    Tag const CylinderAxis(0x0022, 0x0009);
+    Tag const EmmetropicMagnification(0x0022, 0x000a);
+    Tag const IntraOcularPressure(0x0022, 0x000b);
+    Tag const HorizontalFieldOfView(0x0022, 0x000c);
+    Tag const PupilDilated(0x0022, 0x000d);
+    Tag const DegreeOfDilation(0x0022, 0x000e);
+    Tag const StereoBaselineAngle(0x0022, 0x0010);
+    Tag const StereoBaselineDisplacement(0x0022, 0x0011);
+    Tag const StereoHorizontalPixelOffset(0x0022, 0x0012);
+    Tag const StereoVerticalPixelOffset(0x0022, 0x0013);
+    Tag const StereoRotation(0x0022, 0x0014);
+    Tag const AcquisitionDeviceTypeCodeSequence(0x0022, 0x0015);
+    Tag const IlluminationTypeCodeSequence(0x0022, 0x0016);
+    Tag const LightPathFilterTypeStackCodeSequence(0x0022, 0x0017);
+    Tag const ImagePathFilterTypeStackCodeSequence(0x0022, 0x0018);
+    Tag const LensesCodeSequence(0x0022, 0x0019);
+    Tag const ChannelDescriptionCodeSequence(0x0022, 0x001a);
+    Tag const RefractiveStateSequence(0x0022, 0x001b);
+    Tag const MydriaticAgentCodeSequence(0x0022, 0x001c);
+    Tag const RelativeImagePositionCodeSequence(0x0022, 0x001d);
+    Tag const CameraAngleOfView(0x0022, 0x001e);
+    Tag const StereoPairsSequence(0x0022, 0x0020);
+    Tag const LeftImageSequence(0x0022, 0x0021);
+    Tag const RightImageSequence(0x0022, 0x0022);
+    Tag const AxialLengthOfTheEye(0x0022, 0x0030);
+    Tag const OphthalmicFrameLocationSequence(0x0022, 0x0031);
+    Tag const ReferenceCoordinates(0x0022, 0x0032);
+    Tag const DepthSpatialResolution(0x0022, 0x0035);
+    Tag const MaximumDepthDistortion(0x0022, 0x0036);
+    Tag const AlongScanSpatialResolution(0x0022, 0x0037);
+    Tag const MaximumAlongScanDistortion(0x0022, 0x0038);
+    Tag const OphthalmicImageOrientation(0x0022, 0x0039);
+    Tag const DepthOfTransverseImage(0x0022, 0x0041);
+    Tag const MydriaticAgentConcentrationUnitsSequence(0x0022, 0x0042);
+    Tag const AcrossScanSpatialResolution(0x0022, 0x0048);
+    Tag const MaximumAcrossScanDistortion(0x0022, 0x0049);
+    Tag const MydriaticAgentConcentration(0x0022, 0x004e);
+    Tag const IlluminationWaveLength(0x0022, 0x0055);
+    Tag const IlluminationPower(0x0022, 0x0056);
+    Tag const IlluminationBandwidth(0x0022, 0x0057);
+    Tag const MydriaticAgentSequence(0x0022, 0x0058);
+    Tag const OphthalmicAxialMeasurementsRightEyeSequence(0x0022, 0x1007);
+    Tag const OphthalmicAxialMeasurementsLeftEyeSequence(0x0022, 0x1008);
+    Tag const OphthalmicAxialMeasurementsDeviceType(0x0022, 0x1009);
+    Tag const OphthalmicAxialLengthMeasurementsType(0x0022, 0x1010);
+    Tag const OphthalmicAxialLengthSequence(0x0022, 0x1012);
+    Tag const OphthalmicAxialLength(0x0022, 0x1019);
+    Tag const LensStatusCodeSequence(0x0022, 0x1024);
+    Tag const VitreousStatusCodeSequence(0x0022, 0x1025);
+    Tag const IOLFormulaCodeSequence(0x0022, 0x1028);
+    Tag const IOLFormulaDetail(0x0022, 0x1029);
+    Tag const KeratometerIndex(0x0022, 0x1033);
+    Tag const SourceOfOphthalmicAxialLengthCodeSequence(0x0022, 0x1035);
+    Tag const TargetRefraction(0x0022, 0x1037);
+    Tag const RefractiveProcedureOccurred(0x0022, 0x1039);
+    Tag const RefractiveSurgeryTypeCodeSequence(0x0022, 0x1040);
+    Tag const OphthalmicUltrasoundMethodCodeSequence(0x0022, 0x1044);
+    Tag const OphthalmicAxialLengthMeasurementsSequence(0x0022, 0x1050);
+    Tag const IOLPower(0x0022, 0x1053);
+    Tag const PredictedRefractiveError(0x0022, 0x1054);
+    Tag const OphthalmicAxialLengthVelocity(0x0022, 0x1059);
+    Tag const LensStatusDescription(0x0022, 0x1065);
+    Tag const VitreousStatusDescription(0x0022, 0x1066);
+    Tag const IOLPowerSequence(0x0022, 0x1090);
+    Tag const LensConstantSequence(0x0022, 0x1092);
+    Tag const IOLManufacturer(0x0022, 0x1093);
+    Tag const LensConstantDescription(0x0022, 0x1094);
+    Tag const ImplantName(0x0022, 0x1095);
+    Tag const KeratometryMeasurementTypeCodeSequence(0x0022, 0x1096);
+    Tag const ImplantPartNumber(0x0022, 0x1097);
+    Tag const ReferencedOphthalmicAxialMeasurementsSequence(0x0022, 0x1100);
+    Tag const OphthalmicAxialLengthMeasurementsSegmentNameCodeSequence(0x0022, 0x1101);
+    Tag const RefractiveErrorBeforeRefractiveSurgeryCodeSequence(0x0022, 0x1103);
+    Tag const IOLPowerForExactEmmetropia(0x0022, 0x1121);
+    Tag const IOLPowerForExactTargetRefraction(0x0022, 0x1122);
+    Tag const AnteriorChamberDepthDefinitionCodeSequence(0x0022, 0x1125);
+    Tag const LensThicknessSequence(0x0022, 0x1127);
+    Tag const AnteriorChamberDepthSequence(0x0022, 0x1128);
+    Tag const LensThickness(0x0022, 0x1130);
+    Tag const AnteriorChamberDepth(0x0022, 0x1131);
+    Tag const SourceOfLensThicknessDataCodeSequence(0x0022, 0x1132);
+    Tag const SourceOfAnteriorChamberDepthDataCodeSequence(0x0022, 0x1133);
+    Tag const SourceOfRefractiveMeasurementsSequence(0x0022, 0x1134);
+    Tag const SourceOfRefractiveMeasurementsCodeSequence(0x0022, 0x1135);
+    Tag const OphthalmicAxialLengthMeasurementModified(0x0022, 0x1140);
+    Tag const OphthalmicAxialLengthDataSourceCodeSequence(0x0022, 0x1150);
+    Tag const OphthalmicAxialLengthAcquisitionMethodCodeSequence(0x0022, 0x1153);
+    Tag const SignalToNoiseRatio(0x0022, 0x1155);
+    Tag const OphthalmicAxialLengthDataSourceDescription(0x0022, 0x1159);
+    Tag const OphthalmicAxialLengthMeasurementsTotalLengthSequence(0x0022, 0x1210);
+    Tag const OphthalmicAxialLengthMeasurementsSegmentalLengthSequence(0x0022, 0x1211);
+    Tag const OphthalmicAxialLengthMeasurementsLengthSummationSequence(0x0022, 0x1212);
+    Tag const UltrasoundOphthalmicAxialLengthMeasurementsSequence(0x0022, 0x1220);
+    Tag const OpticalOphthalmicAxialLengthMeasurementsSequence(0x0022, 0x1225);
+    Tag const UltrasoundSelectedOphthalmicAxialLengthSequence(0x0022, 0x1230);
+    Tag const OphthalmicAxialLengthSelectionMethodCodeSequence(0x0022, 0x1250);
+    Tag const OpticalSelectedOphthalmicAxialLengthSequence(0x0022, 0x1255);
+    Tag const SelectedSegmentalOphthalmicAxialLengthSequence(0x0022, 0x1257);
+    Tag const SelectedTotalOphthalmicAxialLengthSequence(0x0022, 0x1260);
+    Tag const OphthalmicAxialLengthQualityMetricSequence(0x0022, 0x1262);
+    Tag const OphthalmicAxialLengthQualityMetricTypeCodeSequence(0x0022, 0x1265);
+    Tag const OphthalmicAxialLengthQualityMetricTypeDescription(0x0022, 0x1273);
+    Tag const IntraocularLensCalculationsRightEyeSequence(0x0022, 0x1300);
+    Tag const IntraocularLensCalculationsLeftEyeSequence(0x0022, 0x1310);
+    Tag const ReferencedOphthalmicAxialLengthMeasurementQCImageSequence(0x0022, 0x1330);
+    Tag const OphthalmicMappingDeviceType(0x0022, 0x1415);
+    Tag const AcquisitionMethodCodeSequence(0x0022, 0x1420);
+    Tag const AcquisitionMethodAlgorithmSequence(0x0022, 0x1423);
+    Tag const OphthalmicThicknessMapTypeCodeSequence(0x0022, 0x1436);
+    Tag const OphthalmicThicknessMappingNormalsSequence(0x0022, 0x1443);
+    Tag const RetinalThicknessDefinitionCodeSequence(0x0022, 0x1445);
+    Tag const PixelValueMappingToCodedConceptSequence(0x0022, 0x1450);
+    Tag const MappedPixelValue(0x0022, 0x1452);
+    Tag const PixelValueMappingExplanation(0x0022, 0x1454);
+    Tag const OphthalmicThicknessMapQualityThresholdSequence(0x0022, 0x1458);
+    Tag const OphthalmicThicknessMapThresholdQualityRating(0x0022, 0x1460);
+    Tag const AnatomicStructureReferencePoint(0x0022, 0x1463);
+    Tag const RegistrationToLocalizerSequence(0x0022, 0x1465);
+    Tag const RegisteredLocalizerUnits(0x0022, 0x1466);
+    Tag const RegisteredLocalizerTopLeftHandCorner(0x0022, 0x1467);
+    Tag const RegisteredLocalizerBottomRightHandCorner(0x0022, 0x1468);
+    Tag const OphthalmicThicknessMapQualityRatingSequence(0x0022, 0x1470);
+    Tag const RelevantOPTAttributesSequence(0x0022, 0x1472);
+    Tag const TransformationMethodCodeSequence(0x0022, 0x1512);
+    Tag const TransformationAlgorithmSequence(0x0022, 0x1513);
+    Tag const OphthalmicAxialLengthMethod(0x0022, 0x1515);
+    Tag const OphthalmicFOV(0x0022, 0x1517);
+    Tag const TwoDimensionalToThreeDimensionalMapSequence(0x0022, 0x1518);
+    Tag const WideFieldOphthalmicPhotographyQualityRatingSequence(0x0022, 0x1525);
+    Tag const WideFieldOphthalmicPhotographyQualityThresholdSequence(0x0022, 0x1526);
+    Tag const WideFieldOphthalmicPhotographyThresholdQualityRating(0x0022, 0x1527);
+    Tag const XCoordinatesCenterPixelViewAngle(0x0022, 0x1528);
+    Tag const YCoordinatesCenterPixelViewAngle(0x0022, 0x1529);
+    Tag const NumberOfMapPoints(0x0022, 0x1530);
+    Tag const TwoDimensionalToThreeDimensionalMapData(0x0022, 0x1531);
+    Tag const VisualFieldHorizontalExtent(0x0024, 0x0010);
+    Tag const VisualFieldVerticalExtent(0x0024, 0x0011);
+    Tag const VisualFieldShape(0x0024, 0x0012);
+    Tag const ScreeningTestModeCodeSequence(0x0024, 0x0016);
+    Tag const MaximumStimulusLuminance(0x0024, 0x0018);
+    Tag const BackgroundLuminance(0x0024, 0x0020);
+    Tag const StimulusColorCodeSequence(0x0024, 0x0021);
+    Tag const BackgroundIlluminationColorCodeSequence(0x0024, 0x0024);
+    Tag const StimulusArea(0x0024, 0x0025);
+    Tag const StimulusPresentationTime(0x0024, 0x0028);
+    Tag const FixationSequence(0x0024, 0x0032);
+    Tag const FixationMonitoringCodeSequence(0x0024, 0x0033);
+    Tag const VisualFieldCatchTrialSequence(0x0024, 0x0034);
+    Tag const FixationCheckedQuantity(0x0024, 0x0035);
+    Tag const PatientNotProperlyFixatedQuantity(0x0024, 0x0036);
+    Tag const PresentedVisualStimuliDataFlag(0x0024, 0x0037);
+    Tag const NumberOfVisualStimuli(0x0024, 0x0038);
+    Tag const ExcessiveFixationLossesDataFlag(0x0024, 0x0039);
+    Tag const ExcessiveFixationLosses(0x0024, 0x0040);
+    Tag const StimuliRetestingQuantity(0x0024, 0x0042);
+    Tag const CommentsOnPatientPerformanceOfVisualField(0x0024, 0x0044);
+    Tag const FalseNegativesEstimateFlag(0x0024, 0x0045);
+    Tag const FalseNegativesEstimate(0x0024, 0x0046);
+    Tag const NegativeCatchTrialsQuantity(0x0024, 0x0048);
+    Tag const FalseNegativesQuantity(0x0024, 0x0050);
+    Tag const ExcessiveFalseNegativesDataFlag(0x0024, 0x0051);
+    Tag const ExcessiveFalseNegatives(0x0024, 0x0052);
+    Tag const FalsePositivesEstimateFlag(0x0024, 0x0053);
+    Tag const FalsePositivesEstimate(0x0024, 0x0054);
+    Tag const CatchTrialsDataFlag(0x0024, 0x0055);
+    Tag const PositiveCatchTrialsQuantity(0x0024, 0x0056);
+    Tag const TestPointNormalsDataFlag(0x0024, 0x0057);
+    Tag const TestPointNormalsSequence(0x0024, 0x0058);
+    Tag const GlobalDeviationProbabilityNormalsFlag(0x0024, 0x0059);
+    Tag const FalsePositivesQuantity(0x0024, 0x0060);
+    Tag const ExcessiveFalsePositivesDataFlag(0x0024, 0x0061);
+    Tag const ExcessiveFalsePositives(0x0024, 0x0062);
+    Tag const VisualFieldTestNormalsFlag(0x0024, 0x0063);
+    Tag const ResultsNormalsSequence(0x0024, 0x0064);
+    Tag const AgeCorrectedSensitivityDeviationAlgorithmSequence(0x0024, 0x0065);
+    Tag const GlobalDeviationFromNormal(0x0024, 0x0066);
+    Tag const GeneralizedDefectSensitivityDeviationAlgorithmSequence(0x0024, 0x0067);
+    Tag const LocalizedDeviationFromNormal(0x0024, 0x0068);
+    Tag const PatientReliabilityIndicator(0x0024, 0x0069);
+    Tag const VisualFieldMeanSensitivity(0x0024, 0x0070);
+    Tag const GlobalDeviationProbability(0x0024, 0x0071);
+    Tag const LocalDeviationProbabilityNormalsFlag(0x0024, 0x0072);
+    Tag const LocalizedDeviationProbability(0x0024, 0x0073);
+    Tag const ShortTermFluctuationCalculated(0x0024, 0x0074);
+    Tag const ShortTermFluctuation(0x0024, 0x0075);
+    Tag const ShortTermFluctuationProbabilityCalculated(0x0024, 0x0076);
+    Tag const ShortTermFluctuationProbability(0x0024, 0x0077);
+    Tag const CorrectedLocalizedDeviationFromNormalCalculated(0x0024, 0x0078);
+    Tag const CorrectedLocalizedDeviationFromNormal(0x0024, 0x0079);
+    Tag const CorrectedLocalizedDeviationFromNormalProbabilityCalculated(0x0024, 0x0080);
+    Tag const CorrectedLocalizedDeviationFromNormalProbability(0x0024, 0x0081);
+    Tag const GlobalDeviationProbabilitySequence(0x0024, 0x0083);
+    Tag const LocalizedDeviationProbabilitySequence(0x0024, 0x0085);
+    Tag const FovealSensitivityMeasured(0x0024, 0x0086);
+    Tag const FovealSensitivity(0x0024, 0x0087);
+    Tag const VisualFieldTestDuration(0x0024, 0x0088);
+    Tag const VisualFieldTestPointSequence(0x0024, 0x0089);
+    Tag const VisualFieldTestPointXCoordinate(0x0024, 0x0090);
+    Tag const VisualFieldTestPointYCoordinate(0x0024, 0x0091);
+    Tag const AgeCorrectedSensitivityDeviationValue(0x0024, 0x0092);
+    Tag const StimulusResults(0x0024, 0x0093);
+    Tag const SensitivityValue(0x0024, 0x0094);
+    Tag const RetestStimulusSeen(0x0024, 0x0095);
+    Tag const RetestSensitivityValue(0x0024, 0x0096);
+    Tag const VisualFieldTestPointNormalsSequence(0x0024, 0x0097);
+    Tag const QuantifiedDefect(0x0024, 0x0098);
+    Tag const AgeCorrectedSensitivityDeviationProbabilityValue(0x0024, 0x0100);
+    Tag const GeneralizedDefectCorrectedSensitivityDeviationFlag(0x0024, 0x0102);
+    Tag const GeneralizedDefectCorrectedSensitivityDeviationValue(0x0024, 0x0103);
+    Tag const GeneralizedDefectCorrectedSensitivityDeviationProbabilityValue(0x0024, 0x0104);
+    Tag const MinimumSensitivityValue(0x0024, 0x0105);
+    Tag const BlindSpotLocalized(0x0024, 0x0106);
+    Tag const BlindSpotXCoordinate(0x0024, 0x0107);
+    Tag const BlindSpotYCoordinate(0x0024, 0x0108);
+    Tag const VisualAcuityMeasurementSequence(0x0024, 0x0110);
+    Tag const RefractiveParametersUsedOnPatientSequence(0x0024, 0x0112);
+    Tag const MeasurementLaterality(0x0024, 0x0113);
+    Tag const OphthalmicPatientClinicalInformationLeftEyeSequence(0x0024, 0x0114);
+    Tag const OphthalmicPatientClinicalInformationRightEyeSequence(0x0024, 0x0115);
+    Tag const FovealPointNormativeDataFlag(0x0024, 0x0117);
+    Tag const FovealPointProbabilityValue(0x0024, 0x0118);
+    Tag const ScreeningBaselineMeasured(0x0024, 0x0120);
+    Tag const ScreeningBaselineMeasuredSequence(0x0024, 0x0122);
+    Tag const ScreeningBaselineType(0x0024, 0x0124);
+    Tag const ScreeningBaselineValue(0x0024, 0x0126);
+    Tag const AlgorithmSource(0x0024, 0x0202);
+    Tag const DataSetName(0x0024, 0x0306);
+    Tag const DataSetVersion(0x0024, 0x0307);
+    Tag const DataSetSource(0x0024, 0x0308);
+    Tag const DataSetDescription(0x0024, 0x0309);
+    Tag const VisualFieldTestReliabilityGlobalIndexSequence(0x0024, 0x0317);
+    Tag const VisualFieldGlobalResultsIndexSequence(0x0024, 0x0320);
+    Tag const DataObservationSequence(0x0024, 0x0325);
+    Tag const IndexNormalsFlag(0x0024, 0x0338);
+    Tag const IndexProbability(0x0024, 0x0341);
+    Tag const IndexProbabilitySequence(0x0024, 0x0344);
+    Tag const SamplesPerPixel(0x0028, 0x0002);
+    Tag const SamplesPerPixelUsed(0x0028, 0x0003);
+    Tag const PhotometricInterpretation(0x0028, 0x0004);
+    Tag const ImageDimensions(0x0028, 0x0005);
+    Tag const PlanarConfiguration(0x0028, 0x0006);
+    Tag const NumberOfFrames(0x0028, 0x0008);
+    Tag const FrameIncrementPointer(0x0028, 0x0009);
+    Tag const FrameDimensionPointer(0x0028, 0x000a);
+    Tag const Rows(0x0028, 0x0010);
+    Tag const Columns(0x0028, 0x0011);
+    Tag const Planes(0x0028, 0x0012);
+    Tag const UltrasoundColorDataPresent(0x0028, 0x0014);
+    Tag const PixelSpacing(0x0028, 0x0030);
+    Tag const ZoomFactor(0x0028, 0x0031);
+    Tag const ZoomCenter(0x0028, 0x0032);
+    Tag const PixelAspectRatio(0x0028, 0x0034);
+    Tag const ImageFormat(0x0028, 0x0040);
+    Tag const ManipulatedImage(0x0028, 0x0050);
+    Tag const CorrectedImage(0x0028, 0x0051);
+    Tag const CompressionRecognitionCode(0x0028, 0x005f);
+    Tag const CompressionCode(0x0028, 0x0060);
+    Tag const CompressionOriginator(0x0028, 0x0061);
+    Tag const CompressionLabel(0x0028, 0x0062);
+    Tag const CompressionDescription(0x0028, 0x0063);
+    Tag const CompressionSequence(0x0028, 0x0065);
+    Tag const CompressionStepPointers(0x0028, 0x0066);
+    Tag const RepeatInterval(0x0028, 0x0068);
+    Tag const BitsGrouped(0x0028, 0x0069);
+    Tag const PerimeterTable(0x0028, 0x0070);
+    Tag const PerimeterValue(0x0028, 0x0071);
+    Tag const PredictorRows(0x0028, 0x0080);
+    Tag const PredictorColumns(0x0028, 0x0081);
+    Tag const PredictorConstants(0x0028, 0x0082);
+    Tag const BlockedPixels(0x0028, 0x0090);
+    Tag const BlockRows(0x0028, 0x0091);
+    Tag const BlockColumns(0x0028, 0x0092);
+    Tag const RowOverlap(0x0028, 0x0093);
+    Tag const ColumnOverlap(0x0028, 0x0094);
+    Tag const BitsAllocated(0x0028, 0x0100);
+    Tag const BitsStored(0x0028, 0x0101);
+    Tag const HighBit(0x0028, 0x0102);
+    Tag const PixelRepresentation(0x0028, 0x0103);
+    Tag const SmallestValidPixelValue(0x0028, 0x0104);
+    Tag const LargestValidPixelValue(0x0028, 0x0105);
+    Tag const SmallestImagePixelValue(0x0028, 0x0106);
+    Tag const LargestImagePixelValue(0x0028, 0x0107);
+    Tag const SmallestPixelValueInSeries(0x0028, 0x0108);
+    Tag const LargestPixelValueInSeries(0x0028, 0x0109);
+    Tag const SmallestImagePixelValueInPlane(0x0028, 0x0110);
+    Tag const LargestImagePixelValueInPlane(0x0028, 0x0111);
+    Tag const PixelPaddingValue(0x0028, 0x0120);
+    Tag const PixelPaddingRangeLimit(0x0028, 0x0121);
+    Tag const FloatPixelPaddingValue(0x0028, 0x0122);
+    Tag const DoubleFloatPixelPaddingValue(0x0028, 0x0123);
+    Tag const FloatPixelPaddingRangeLimit(0x0028, 0x0124);
+    Tag const DoubleFloatPixelPaddingRangeLimit(0x0028, 0x0125);
+    Tag const ImageLocation(0x0028, 0x0200);
+    Tag const QualityControlImage(0x0028, 0x0300);
+    Tag const BurnedInAnnotation(0x0028, 0x0301);
+    Tag const RecognizableVisualFeatures(0x0028, 0x0302);
+    Tag const LongitudinalTemporalInformationModified(0x0028, 0x0303);
+    Tag const ReferencedColorPaletteInstanceUID(0x0028, 0x0304);
+    Tag const TransformLabel(0x0028, 0x0400);
+    Tag const TransformVersionNumber(0x0028, 0x0401);
+    Tag const NumberOfTransformSteps(0x0028, 0x0402);
+    Tag const SequenceOfCompressedData(0x0028, 0x0403);
+    Tag const DetailsOfCoefficients(0x0028, 0x0404);
+    Tag const DCTLabel(0x0028, 0x0700);
+    Tag const DataBlockDescription(0x0028, 0x0701);
+    Tag const DataBlock(0x0028, 0x0702);
+    Tag const NormalizationFactorFormat(0x0028, 0x0710);
+    Tag const ZonalMapNumberFormat(0x0028, 0x0720);
+    Tag const ZonalMapLocation(0x0028, 0x0721);
+    Tag const ZonalMapFormat(0x0028, 0x0722);
+    Tag const AdaptiveMapFormat(0x0028, 0x0730);
+    Tag const CodeNumberFormat(0x0028, 0x0740);
+    Tag const PixelSpacingCalibrationType(0x0028, 0x0a02);
+    Tag const PixelSpacingCalibrationDescription(0x0028, 0x0a04);
+    Tag const PixelIntensityRelationship(0x0028, 0x1040);
+    Tag const PixelIntensityRelationshipSign(0x0028, 0x1041);
+    Tag const WindowCenter(0x0028, 0x1050);
+    Tag const WindowWidth(0x0028, 0x1051);
+    Tag const RescaleIntercept(0x0028, 0x1052);
+    Tag const RescaleSlope(0x0028, 0x1053);
+    Tag const RescaleType(0x0028, 0x1054);
+    Tag const WindowCenterWidthExplanation(0x0028, 0x1055);
+    Tag const VOILUTFunction(0x0028, 0x1056);
+    Tag const GrayScale(0x0028, 0x1080);
+    Tag const RecommendedViewingMode(0x0028, 0x1090);
+    Tag const GrayLookupTableDescriptor(0x0028, 0x1100);
+    Tag const RedPaletteColorLookupTableDescriptor(0x0028, 0x1101);
+    Tag const GreenPaletteColorLookupTableDescriptor(0x0028, 0x1102);
+    Tag const BluePaletteColorLookupTableDescriptor(0x0028, 0x1103);
+    Tag const AlphaPaletteColorLookupTableDescriptor(0x0028, 0x1104);
+    Tag const LargeRedPaletteColorLookupTableDescriptor(0x0028, 0x1111);
+    Tag const LargeGreenPaletteColorLookupTableDescriptor(0x0028, 0x1112);
+    Tag const LargeBluePaletteColorLookupTableDescriptor(0x0028, 0x1113);
+    Tag const PaletteColorLookupTableUID(0x0028, 0x1199);
+    Tag const GrayLookupTableData(0x0028, 0x1200);
+    Tag const RedPaletteColorLookupTableData(0x0028, 0x1201);
+    Tag const GreenPaletteColorLookupTableData(0x0028, 0x1202);
+    Tag const BluePaletteColorLookupTableData(0x0028, 0x1203);
+    Tag const AlphaPaletteColorLookupTableData(0x0028, 0x1204);
+    Tag const LargeRedPaletteColorLookupTableData(0x0028, 0x1211);
+    Tag const LargeGreenPaletteColorLookupTableData(0x0028, 0x1212);
+    Tag const LargeBluePaletteColorLookupTableData(0x0028, 0x1213);
+    Tag const LargePaletteColorLookupTableUID(0x0028, 0x1214);
+    Tag const SegmentedRedPaletteColorLookupTableData(0x0028, 0x1221);
+    Tag const SegmentedGreenPaletteColorLookupTableData(0x0028, 0x1222);
+    Tag const SegmentedBluePaletteColorLookupTableData(0x0028, 0x1223);
+    Tag const BreastImplantPresent(0x0028, 0x1300);
+    Tag const PartialView(0x0028, 0x1350);
+    Tag const PartialViewDescription(0x0028, 0x1351);
+    Tag const PartialViewCodeSequence(0x0028, 0x1352);
+    Tag const SpatialLocationsPreserved(0x0028, 0x135a);
+    Tag const DataFrameAssignmentSequence(0x0028, 0x1401);
+    Tag const DataPathAssignment(0x0028, 0x1402);
+    Tag const BitsMappedToColorLookupTable(0x0028, 0x1403);
+    Tag const BlendingLUT1Sequence(0x0028, 0x1404);
+    Tag const BlendingLUT1TransferFunction(0x0028, 0x1405);
+    Tag const BlendingWeightConstant(0x0028, 0x1406);
+    Tag const BlendingLookupTableDescriptor(0x0028, 0x1407);
+    Tag const BlendingLookupTableData(0x0028, 0x1408);
+    Tag const EnhancedPaletteColorLookupTableSequence(0x0028, 0x140b);
+    Tag const BlendingLUT2Sequence(0x0028, 0x140c);
+    Tag const BlendingLUT2TransferFunction(0x0028, 0x140d);
+    Tag const DataPathID(0x0028, 0x140e);
+    Tag const RGBLUTTransferFunction(0x0028, 0x140f);
+    Tag const AlphaLUTTransferFunction(0x0028, 0x1410);
+    Tag const ICCProfile(0x0028, 0x2000);
+    Tag const LossyImageCompression(0x0028, 0x2110);
+    Tag const LossyImageCompressionRatio(0x0028, 0x2112);
+    Tag const LossyImageCompressionMethod(0x0028, 0x2114);
+    Tag const ModalityLUTSequence(0x0028, 0x3000);
+    Tag const LUTDescriptor(0x0028, 0x3002);
+    Tag const LUTExplanation(0x0028, 0x3003);
+    Tag const ModalityLUTType(0x0028, 0x3004);
+    Tag const LUTData(0x0028, 0x3006);
+    Tag const VOILUTSequence(0x0028, 0x3010);
+    Tag const SoftcopyVOILUTSequence(0x0028, 0x3110);
+    Tag const ImagePresentationComments(0x0028, 0x4000);
+    Tag const BiPlaneAcquisitionSequence(0x0028, 0x5000);
+    Tag const RepresentativeFrameNumber(0x0028, 0x6010);
+    Tag const FrameNumbersOfInterest(0x0028, 0x6020);
+    Tag const FrameOfInterestDescription(0x0028, 0x6022);
+    Tag const FrameOfInterestType(0x0028, 0x6023);
+    Tag const MaskPointers(0x0028, 0x6030);
+    Tag const RWavePointer(0x0028, 0x6040);
+    Tag const MaskSubtractionSequence(0x0028, 0x6100);
+    Tag const MaskOperation(0x0028, 0x6101);
+    Tag const ApplicableFrameRange(0x0028, 0x6102);
+    Tag const MaskFrameNumbers(0x0028, 0x6110);
+    Tag const ContrastFrameAveraging(0x0028, 0x6112);
+    Tag const MaskSubPixelShift(0x0028, 0x6114);
+    Tag const TIDOffset(0x0028, 0x6120);
+    Tag const MaskOperationExplanation(0x0028, 0x6190);
+    Tag const EquipmentAdministratorSequence(0x0028, 0x7000);
+    Tag const NumberOfDisplaySubsystems(0x0028, 0x7001);
+    Tag const CurrentConfigurationID(0x0028, 0x7002);
+    Tag const DisplaySubsystemID(0x0028, 0x7003);
+    Tag const DisplaySubsystemName(0x0028, 0x7004);
+    Tag const DisplaySubsystemDescription(0x0028, 0x7005);
+    Tag const SystemStatus(0x0028, 0x7006);
+    Tag const SystemStatusComment(0x0028, 0x7007);
+    Tag const TargetLuminanceCharacteristicsSequence(0x0028, 0x7008);
+    Tag const LuminanceCharacteristicsID(0x0028, 0x7009);
+    Tag const DisplaySubsystemConfigurationSequence(0x0028, 0x700a);
+    Tag const ConfigurationID(0x0028, 0x700b);
+    Tag const ConfigurationName(0x0028, 0x700c);
+    Tag const ConfigurationDescription(0x0028, 0x700d);
+    Tag const ReferencedTargetLuminanceCharacteristicsID(0x0028, 0x700e);
+    Tag const QAResultsSequence(0x0028, 0x700f);
+    Tag const DisplaySubsystemQAResultsSequence(0x0028, 0x7010);
+    Tag const ConfigurationQAResultsSequence(0x0028, 0x7011);
+    Tag const MeasurementEquipmentSequence(0x0028, 0x7012);
+    Tag const MeasurementFunctions(0x0028, 0x7013);
+    Tag const MeasurementEquipmentType(0x0028, 0x7014);
+    Tag const VisualEvaluationResultSequence(0x0028, 0x7015);
+    Tag const DisplayCalibrationResultSequence(0x0028, 0x7016);
+    Tag const DDLValue(0x0028, 0x7017);
+    Tag const CIExyWhitePoint(0x0028, 0x7018);
+    Tag const DisplayFunctionType(0x0028, 0x7019);
+    Tag const GammaValue(0x0028, 0x701a);
+    Tag const NumberOfLuminancePoints(0x0028, 0x701b);
+    Tag const LuminanceResponseSequence(0x0028, 0x701c);
+    Tag const TargetMinimumLuminance(0x0028, 0x701d);
+    Tag const TargetMaximumLuminance(0x0028, 0x701e);
+    Tag const LuminanceValue(0x0028, 0x701f);
+    Tag const LuminanceResponseDescription(0x0028, 0x7020);
+    Tag const WhitePointFlag(0x0028, 0x7021);
+    Tag const DisplayDeviceTypeCodeSequence(0x0028, 0x7022);
+    Tag const DisplaySubsystemSequence(0x0028, 0x7023);
+    Tag const LuminanceResultSequence(0x0028, 0x7024);
+    Tag const AmbientLightValueSource(0x0028, 0x7025);
+    Tag const MeasuredCharacteristics(0x0028, 0x7026);
+    Tag const LuminanceUniformityResultSequence(0x0028, 0x7027);
+    Tag const VisualEvaluationTestSequence(0x0028, 0x7028);
+    Tag const TestResult(0x0028, 0x7029);
+    Tag const TestResultComment(0x0028, 0x702a);
+    Tag const TestImageValidation(0x0028, 0x702b);
+    Tag const TestPatternCodeSequence(0x0028, 0x702c);
+    Tag const MeasurementPatternCodeSequence(0x0028, 0x702d);
+    Tag const VisualEvaluationMethodCodeSequence(0x0028, 0x702e);
+    Tag const PixelDataProviderURL(0x0028, 0x7fe0);
+    Tag const DataPointRows(0x0028, 0x9001);
+    Tag const DataPointColumns(0x0028, 0x9002);
+    Tag const SignalDomainColumns(0x0028, 0x9003);
+    Tag const LargestMonochromePixelValue(0x0028, 0x9099);
+    Tag const DataRepresentation(0x0028, 0x9108);
+    Tag const PixelMeasuresSequence(0x0028, 0x9110);
+    Tag const FrameVOILUTSequence(0x0028, 0x9132);
+    Tag const PixelValueTransformationSequence(0x0028, 0x9145);
+    Tag const SignalDomainRows(0x0028, 0x9235);
+    Tag const DisplayFilterPercentage(0x0028, 0x9411);
+    Tag const FramePixelShiftSequence(0x0028, 0x9415);
+    Tag const SubtractionItemID(0x0028, 0x9416);
+    Tag const PixelIntensityRelationshipLUTSequence(0x0028, 0x9422);
+    Tag const FramePixelDataPropertiesSequence(0x0028, 0x9443);
+    Tag const GeometricalProperties(0x0028, 0x9444);
+    Tag const GeometricMaximumDistortion(0x0028, 0x9445);
+    Tag const ImageProcessingApplied(0x0028, 0x9446);
+    Tag const MaskSelectionMode(0x0028, 0x9454);
+    Tag const LUTFunction(0x0028, 0x9474);
+    Tag const MaskVisibilityPercentage(0x0028, 0x9478);
+    Tag const PixelShiftSequence(0x0028, 0x9501);
+    Tag const RegionPixelShiftSequence(0x0028, 0x9502);
+    Tag const VerticesOfTheRegion(0x0028, 0x9503);
+    Tag const MultiFramePresentationSequence(0x0028, 0x9505);
+    Tag const PixelShiftFrameRange(0x0028, 0x9506);
+    Tag const LUTFrameRange(0x0028, 0x9507);
+    Tag const ImageToEquipmentMappingMatrix(0x0028, 0x9520);
+    Tag const EquipmentCoordinateSystemIdentification(0x0028, 0x9537);
+    Tag const StudyStatusID(0x0032, 0x000a);
+    Tag const StudyPriorityID(0x0032, 0x000c);
+    Tag const StudyIDIssuer(0x0032, 0x0012);
+    Tag const StudyVerifiedDate(0x0032, 0x0032);
+    Tag const StudyVerifiedTime(0x0032, 0x0033);
+    Tag const StudyReadDate(0x0032, 0x0034);
+    Tag const StudyReadTime(0x0032, 0x0035);
+    Tag const ScheduledStudyStartDate(0x0032, 0x1000);
+    Tag const ScheduledStudyStartTime(0x0032, 0x1001);
+    Tag const ScheduledStudyStopDate(0x0032, 0x1010);
+    Tag const ScheduledStudyStopTime(0x0032, 0x1011);
+    Tag const ScheduledStudyLocation(0x0032, 0x1020);
+    Tag const ScheduledStudyLocationAETitle(0x0032, 0x1021);
+    Tag const ReasonForStudy(0x0032, 0x1030);
+    Tag const RequestingPhysicianIdentificationSequence(0x0032, 0x1031);
+    Tag const RequestingPhysician(0x0032, 0x1032);
+    Tag const RequestingService(0x0032, 0x1033);
+    Tag const RequestingServiceCodeSequence(0x0032, 0x1034);
+    Tag const StudyArrivalDate(0x0032, 0x1040);
+    Tag const StudyArrivalTime(0x0032, 0x1041);
+    Tag const StudyCompletionDate(0x0032, 0x1050);
+    Tag const StudyCompletionTime(0x0032, 0x1051);
+    Tag const StudyComponentStatusID(0x0032, 0x1055);
+    Tag const RequestedProcedureDescription(0x0032, 0x1060);
+    Tag const RequestedProcedureCodeSequence(0x0032, 0x1064);
+    Tag const RequestedContrastAgent(0x0032, 0x1070);
+    Tag const StudyComments(0x0032, 0x4000);
+    Tag const ReferencedPatientAliasSequence(0x0038, 0x0004);
+    Tag const VisitStatusID(0x0038, 0x0008);
+    Tag const AdmissionID(0x0038, 0x0010);
+    Tag const IssuerOfAdmissionID(0x0038, 0x0011);
+    Tag const IssuerOfAdmissionIDSequence(0x0038, 0x0014);
+    Tag const RouteOfAdmissions(0x0038, 0x0016);
+    Tag const ScheduledAdmissionDate(0x0038, 0x001a);
+    Tag const ScheduledAdmissionTime(0x0038, 0x001b);
+    Tag const ScheduledDischargeDate(0x0038, 0x001c);
+    Tag const ScheduledDischargeTime(0x0038, 0x001d);
+    Tag const ScheduledPatientInstitutionResidence(0x0038, 0x001e);
+    Tag const AdmittingDate(0x0038, 0x0020);
+    Tag const AdmittingTime(0x0038, 0x0021);
+    Tag const DischargeDate(0x0038, 0x0030);
+    Tag const DischargeTime(0x0038, 0x0032);
+    Tag const DischargeDiagnosisDescription(0x0038, 0x0040);
+    Tag const DischargeDiagnosisCodeSequence(0x0038, 0x0044);
+    Tag const SpecialNeeds(0x0038, 0x0050);
+    Tag const ServiceEpisodeID(0x0038, 0x0060);
+    Tag const IssuerOfServiceEpisodeID(0x0038, 0x0061);
+    Tag const ServiceEpisodeDescription(0x0038, 0x0062);
+    Tag const IssuerOfServiceEpisodeIDSequence(0x0038, 0x0064);
+    Tag const PertinentDocumentsSequence(0x0038, 0x0100);
+    Tag const PertinentResourcesSequence(0x0038, 0x0101);
+    Tag const ResourceDescription(0x0038, 0x0102);
+    Tag const CurrentPatientLocation(0x0038, 0x0300);
+    Tag const PatientInstitutionResidence(0x0038, 0x0400);
+    Tag const PatientState(0x0038, 0x0500);
+    Tag const PatientClinicalTrialParticipationSequence(0x0038, 0x0502);
+    Tag const VisitComments(0x0038, 0x4000);
+    Tag const WaveformOriginality(0x003a, 0x0004);
+    Tag const NumberOfWaveformChannels(0x003a, 0x0005);
+    Tag const NumberOfWaveformSamples(0x003a, 0x0010);
+    Tag const SamplingFrequency(0x003a, 0x001a);
+    Tag const MultiplexGroupLabel(0x003a, 0x0020);
+    Tag const ChannelDefinitionSequence(0x003a, 0x0200);
+    Tag const WaveformChannelNumber(0x003a, 0x0202);
+    Tag const ChannelLabel(0x003a, 0x0203);
+    Tag const ChannelStatus(0x003a, 0x0205);
+    Tag const ChannelSourceSequence(0x003a, 0x0208);
+    Tag const ChannelSourceModifiersSequence(0x003a, 0x0209);
+    Tag const SourceWaveformSequence(0x003a, 0x020a);
+    Tag const ChannelDerivationDescription(0x003a, 0x020c);
+    Tag const ChannelSensitivity(0x003a, 0x0210);
+    Tag const ChannelSensitivityUnitsSequence(0x003a, 0x0211);
+    Tag const ChannelSensitivityCorrectionFactor(0x003a, 0x0212);
+    Tag const ChannelBaseline(0x003a, 0x0213);
+    Tag const ChannelTimeSkew(0x003a, 0x0214);
+    Tag const ChannelSampleSkew(0x003a, 0x0215);
+    Tag const ChannelOffset(0x003a, 0x0218);
+    Tag const WaveformBitsStored(0x003a, 0x021a);
+    Tag const FilterLowFrequency(0x003a, 0x0220);
+    Tag const FilterHighFrequency(0x003a, 0x0221);
+    Tag const NotchFilterFrequency(0x003a, 0x0222);
+    Tag const NotchFilterBandwidth(0x003a, 0x0223);
+    Tag const WaveformDataDisplayScale(0x003a, 0x0230);
+    Tag const WaveformDisplayBackgroundCIELabValue(0x003a, 0x0231);
+    Tag const WaveformPresentationGroupSequence(0x003a, 0x0240);
+    Tag const PresentationGroupNumber(0x003a, 0x0241);
+    Tag const ChannelDisplaySequence(0x003a, 0x0242);
+    Tag const ChannelRecommendedDisplayCIELabValue(0x003a, 0x0244);
+    Tag const ChannelPosition(0x003a, 0x0245);
+    Tag const DisplayShadingFlag(0x003a, 0x0246);
+    Tag const FractionalChannelDisplayScale(0x003a, 0x0247);
+    Tag const AbsoluteChannelDisplayScale(0x003a, 0x0248);
+    Tag const MultiplexedAudioChannelsDescriptionCodeSequence(0x003a, 0x0300);
+    Tag const ChannelIdentificationCode(0x003a, 0x0301);
+    Tag const ChannelMode(0x003a, 0x0302);
+    Tag const ScheduledStationAETitle(0x0040, 0x0001);
+    Tag const ScheduledProcedureStepStartDate(0x0040, 0x0002);
+    Tag const ScheduledProcedureStepStartTime(0x0040, 0x0003);
+    Tag const ScheduledProcedureStepEndDate(0x0040, 0x0004);
+    Tag const ScheduledProcedureStepEndTime(0x0040, 0x0005);
+    Tag const ScheduledPerformingPhysicianName(0x0040, 0x0006);
+    Tag const ScheduledProcedureStepDescription(0x0040, 0x0007);
+    Tag const ScheduledProtocolCodeSequence(0x0040, 0x0008);
+    Tag const ScheduledProcedureStepID(0x0040, 0x0009);
+    Tag const StageCodeSequence(0x0040, 0x000a);
+    Tag const ScheduledPerformingPhysicianIdentificationSequence(0x0040, 0x000b);
+    Tag const ScheduledStationName(0x0040, 0x0010);
+    Tag const ScheduledProcedureStepLocation(0x0040, 0x0011);
+    Tag const PreMedication(0x0040, 0x0012);
+    Tag const ScheduledProcedureStepStatus(0x0040, 0x0020);
+    Tag const OrderPlacerIdentifierSequence(0x0040, 0x0026);
+    Tag const OrderFillerIdentifierSequence(0x0040, 0x0027);
+    Tag const LocalNamespaceEntityID(0x0040, 0x0031);
+    Tag const UniversalEntityID(0x0040, 0x0032);
+    Tag const UniversalEntityIDType(0x0040, 0x0033);
+    Tag const IdentifierTypeCode(0x0040, 0x0035);
+    Tag const AssigningFacilitySequence(0x0040, 0x0036);
+    Tag const AssigningJurisdictionCodeSequence(0x0040, 0x0039);
+    Tag const AssigningAgencyOrDepartmentCodeSequence(0x0040, 0x003a);
+    Tag const ScheduledProcedureStepSequence(0x0040, 0x0100);
+    Tag const ReferencedNonImageCompositeSOPInstanceSequence(0x0040, 0x0220);
+    Tag const PerformedStationAETitle(0x0040, 0x0241);
+    Tag const PerformedStationName(0x0040, 0x0242);
+    Tag const PerformedLocation(0x0040, 0x0243);
+    Tag const PerformedProcedureStepStartDate(0x0040, 0x0244);
+    Tag const PerformedProcedureStepStartTime(0x0040, 0x0245);
+    Tag const PerformedProcedureStepEndDate(0x0040, 0x0250);
+    Tag const PerformedProcedureStepEndTime(0x0040, 0x0251);
+    Tag const PerformedProcedureStepStatus(0x0040, 0x0252);
+    Tag const PerformedProcedureStepID(0x0040, 0x0253);
+    Tag const PerformedProcedureStepDescription(0x0040, 0x0254);
+    Tag const PerformedProcedureTypeDescription(0x0040, 0x0255);
+    Tag const PerformedProtocolCodeSequence(0x0040, 0x0260);
+    Tag const PerformedProtocolType(0x0040, 0x0261);
+    Tag const ScheduledStepAttributesSequence(0x0040, 0x0270);
+    Tag const RequestAttributesSequence(0x0040, 0x0275);
+    Tag const CommentsOnThePerformedProcedureStep(0x0040, 0x0280);
+    Tag const PerformedProcedureStepDiscontinuationReasonCodeSequence(0x0040, 0x0281);
+    Tag const QuantitySequence(0x0040, 0x0293);
+    Tag const Quantity(0x0040, 0x0294);
+    Tag const MeasuringUnitsSequence(0x0040, 0x0295);
+    Tag const BillingItemSequence(0x0040, 0x0296);
+    Tag const TotalTimeOfFluoroscopy(0x0040, 0x0300);
+    Tag const TotalNumberOfExposures(0x0040, 0x0301);
+    Tag const EntranceDose(0x0040, 0x0302);
+    Tag const ExposedArea(0x0040, 0x0303);
+    Tag const DistanceSourceToEntrance(0x0040, 0x0306);
+    Tag const DistanceSourceToSupport(0x0040, 0x0307);
+    Tag const ExposureDoseSequence(0x0040, 0x030e);
+    Tag const CommentsOnRadiationDose(0x0040, 0x0310);
+    Tag const XRayOutput(0x0040, 0x0312);
+    Tag const HalfValueLayer(0x0040, 0x0314);
+    Tag const OrganDose(0x0040, 0x0316);
+    Tag const OrganExposed(0x0040, 0x0318);
+    Tag const BillingProcedureStepSequence(0x0040, 0x0320);
+    Tag const FilmConsumptionSequence(0x0040, 0x0321);
+    Tag const BillingSuppliesAndDevicesSequence(0x0040, 0x0324);
+    Tag const ReferencedProcedureStepSequence(0x0040, 0x0330);
+    Tag const PerformedSeriesSequence(0x0040, 0x0340);
+    Tag const CommentsOnTheScheduledProcedureStep(0x0040, 0x0400);
+    Tag const ProtocolContextSequence(0x0040, 0x0440);
+    Tag const ContentItemModifierSequence(0x0040, 0x0441);
+    Tag const ScheduledSpecimenSequence(0x0040, 0x0500);
+    Tag const SpecimenAccessionNumber(0x0040, 0x050a);
+    Tag const ContainerIdentifier(0x0040, 0x0512);
+    Tag const IssuerOfTheContainerIdentifierSequence(0x0040, 0x0513);
+    Tag const AlternateContainerIdentifierSequence(0x0040, 0x0515);
+    Tag const ContainerTypeCodeSequence(0x0040, 0x0518);
+    Tag const ContainerDescription(0x0040, 0x051a);
+    Tag const ContainerComponentSequence(0x0040, 0x0520);
+    Tag const SpecimenSequence(0x0040, 0x0550);
+    Tag const SpecimenIdentifier(0x0040, 0x0551);
+    Tag const SpecimenDescriptionSequenceTrial(0x0040, 0x0552);
+    Tag const SpecimenDescriptionTrial(0x0040, 0x0553);
+    Tag const SpecimenUID(0x0040, 0x0554);
+    Tag const AcquisitionContextSequence(0x0040, 0x0555);
+    Tag const AcquisitionContextDescription(0x0040, 0x0556);
+    Tag const SpecimenTypeCodeSequence(0x0040, 0x059a);
+    Tag const SpecimenDescriptionSequence(0x0040, 0x0560);
+    Tag const IssuerOfTheSpecimenIdentifierSequence(0x0040, 0x0562);
+    Tag const SpecimenShortDescription(0x0040, 0x0600);
+    Tag const SpecimenDetailedDescription(0x0040, 0x0602);
+    Tag const SpecimenPreparationSequence(0x0040, 0x0610);
+    Tag const SpecimenPreparationStepContentItemSequence(0x0040, 0x0612);
+    Tag const SpecimenLocalizationContentItemSequence(0x0040, 0x0620);
+    Tag const SlideIdentifier(0x0040, 0x06fa);
+    Tag const ImageCenterPointCoordinatesSequence(0x0040, 0x071a);
+    Tag const XOffsetInSlideCoordinateSystem(0x0040, 0x072a);
+    Tag const YOffsetInSlideCoordinateSystem(0x0040, 0x073a);
+    Tag const ZOffsetInSlideCoordinateSystem(0x0040, 0x074a);
+    Tag const PixelSpacingSequence(0x0040, 0x08d8);
+    Tag const CoordinateSystemAxisCodeSequence(0x0040, 0x08da);
+    Tag const MeasurementUnitsCodeSequence(0x0040, 0x08ea);
+    Tag const VitalStainCodeSequenceTrial(0x0040, 0x09f8);
+    Tag const RequestedProcedureID(0x0040, 0x1001);
+    Tag const ReasonForTheRequestedProcedure(0x0040, 0x1002);
+    Tag const RequestedProcedurePriority(0x0040, 0x1003);
+    Tag const PatientTransportArrangements(0x0040, 0x1004);
+    Tag const RequestedProcedureLocation(0x0040, 0x1005);
+    Tag const PlacerOrderNumberProcedure(0x0040, 0x1006);
+    Tag const FillerOrderNumberProcedure(0x0040, 0x1007);
+    Tag const ConfidentialityCode(0x0040, 0x1008);
+    Tag const ReportingPriority(0x0040, 0x1009);
+    Tag const ReasonForRequestedProcedureCodeSequence(0x0040, 0x100a);
+    Tag const NamesOfIntendedRecipientsOfResults(0x0040, 0x1010);
+    Tag const IntendedRecipientsOfResultsIdentificationSequence(0x0040, 0x1011);
+    Tag const ReasonForPerformedProcedureCodeSequence(0x0040, 0x1012);
+    Tag const RequestedProcedureDescriptionTrial(0x0040, 0x1060);
+    Tag const PersonIdentificationCodeSequence(0x0040, 0x1101);
+    Tag const PersonAddress(0x0040, 0x1102);
+    Tag const PersonTelephoneNumbers(0x0040, 0x1103);
+    Tag const RequestedProcedureComments(0x0040, 0x1400);
+    Tag const ReasonForTheImagingServiceRequest(0x0040, 0x2001);
+    Tag const IssueDateOfImagingServiceRequest(0x0040, 0x2004);
+    Tag const IssueTimeOfImagingServiceRequest(0x0040, 0x2005);
+    Tag const PlacerOrderNumberImagingServiceRequestRetired(0x0040, 0x2006);
+    Tag const FillerOrderNumberImagingServiceRequestRetired(0x0040, 0x2007);
+    Tag const OrderEnteredBy(0x0040, 0x2008);
+    Tag const OrderEntererLocation(0x0040, 0x2009);
+    Tag const OrderCallbackPhoneNumber(0x0040, 0x2010);
+    Tag const PlacerOrderNumberImagingServiceRequest(0x0040, 0x2016);
+    Tag const FillerOrderNumberImagingServiceRequest(0x0040, 0x2017);
+    Tag const ImagingServiceRequestComments(0x0040, 0x2400);
+    Tag const ConfidentialityConstraintOnPatientDataDescription(0x0040, 0x3001);
+    Tag const GeneralPurposeScheduledProcedureStepStatus(0x0040, 0x4001);
+    Tag const GeneralPurposePerformedProcedureStepStatus(0x0040, 0x4002);
+    Tag const GeneralPurposeScheduledProcedureStepPriority(0x0040, 0x4003);
+    Tag const ScheduledProcessingApplicationsCodeSequence(0x0040, 0x4004);
+    Tag const ScheduledProcedureStepStartDateTime(0x0040, 0x4005);
+    Tag const MultipleCopiesFlag(0x0040, 0x4006);
+    Tag const PerformedProcessingApplicationsCodeSequence(0x0040, 0x4007);
+    Tag const HumanPerformerCodeSequence(0x0040, 0x4009);
+    Tag const ScheduledProcedureStepModificationDateTime(0x0040, 0x4010);
+    Tag const ExpectedCompletionDateTime(0x0040, 0x4011);
+    Tag const ResultingGeneralPurposePerformedProcedureStepsSequence(0x0040, 0x4015);
+    Tag const ReferencedGeneralPurposeScheduledProcedureStepSequence(0x0040, 0x4016);
+    Tag const ScheduledWorkitemCodeSequence(0x0040, 0x4018);
+    Tag const PerformedWorkitemCodeSequence(0x0040, 0x4019);
+    Tag const InputAvailabilityFlag(0x0040, 0x4020);
+    Tag const InputInformationSequence(0x0040, 0x4021);
+    Tag const RelevantInformationSequence(0x0040, 0x4022);
+    Tag const ReferencedGeneralPurposeScheduledProcedureStepTransactionUID(0x0040, 0x4023);
+    Tag const ScheduledStationNameCodeSequence(0x0040, 0x4025);
+    Tag const ScheduledStationClassCodeSequence(0x0040, 0x4026);
+    Tag const ScheduledStationGeographicLocationCodeSequence(0x0040, 0x4027);
+    Tag const PerformedStationNameCodeSequence(0x0040, 0x4028);
+    Tag const PerformedStationClassCodeSequence(0x0040, 0x4029);
+    Tag const PerformedStationGeographicLocationCodeSequence(0x0040, 0x4030);
+    Tag const RequestedSubsequentWorkitemCodeSequence(0x0040, 0x4031);
+    Tag const NonDICOMOutputCodeSequence(0x0040, 0x4032);
+    Tag const OutputInformationSequence(0x0040, 0x4033);
+    Tag const ScheduledHumanPerformersSequence(0x0040, 0x4034);
+    Tag const ActualHumanPerformersSequence(0x0040, 0x4035);
+    Tag const HumanPerformerOrganization(0x0040, 0x4036);
+    Tag const HumanPerformerName(0x0040, 0x4037);
+    Tag const RawDataHandling(0x0040, 0x4040);
+    Tag const InputReadinessState(0x0040, 0x4041);
+    Tag const PerformedProcedureStepStartDateTime(0x0040, 0x4050);
+    Tag const PerformedProcedureStepEndDateTime(0x0040, 0x4051);
+    Tag const ProcedureStepCancellationDateTime(0x0040, 0x4052);
+    Tag const EntranceDoseInmGy(0x0040, 0x8302);
+    Tag const ParametricMapFrameTypeSequence(0x0040, 0x9092);
+    Tag const ReferencedImageRealWorldValueMappingSequence(0x0040, 0x9094);
+    Tag const RealWorldValueMappingSequence(0x0040, 0x9096);
+    Tag const PixelValueMappingCodeSequence(0x0040, 0x9098);
+    Tag const LUTLabel(0x0040, 0x9210);
+    Tag const RealWorldValueLastValueMapped(0x0040, 0x9211);
+    Tag const RealWorldValueLUTData(0x0040, 0x9212);
+    Tag const RealWorldValueFirstValueMapped(0x0040, 0x9216);
+    Tag const QuantityDefinitionSequence(0x0040, 0x9220);
+    Tag const RealWorldValueIntercept(0x0040, 0x9224);
+    Tag const RealWorldValueSlope(0x0040, 0x9225);
+    Tag const FindingsFlagTrial(0x0040, 0xa007);
+    Tag const RelationshipType(0x0040, 0xa010);
+    Tag const FindingsSequenceTrial(0x0040, 0xa020);
+    Tag const FindingsGroupUIDTrial(0x0040, 0xa021);
+    Tag const ReferencedFindingsGroupUIDTrial(0x0040, 0xa022);
+    Tag const FindingsGroupRecordingDateTrial(0x0040, 0xa023);
+    Tag const FindingsGroupRecordingTimeTrial(0x0040, 0xa024);
+    Tag const FindingsSourceCategoryCodeSequenceTrial(0x0040, 0xa026);
+    Tag const VerifyingOrganization(0x0040, 0xa027);
+    Tag const DocumentingOrganizationIdentifierCodeSequenceTrial(0x0040, 0xa028);
+    Tag const VerificationDateTime(0x0040, 0xa030);
+    Tag const ObservationDateTime(0x0040, 0xa032);
+    Tag const ValueType(0x0040, 0xa040);
+    Tag const ConceptNameCodeSequence(0x0040, 0xa043);
+    Tag const MeasurementPrecisionDescriptionTrial(0x0040, 0xa047);
+    Tag const ContinuityOfContent(0x0040, 0xa050);
+    Tag const UrgencyOrPriorityAlertsTrial(0x0040, 0xa057);
+    Tag const SequencingIndicatorTrial(0x0040, 0xa060);
+    Tag const DocumentIdentifierCodeSequenceTrial(0x0040, 0xa066);
+    Tag const DocumentAuthorTrial(0x0040, 0xa067);
+    Tag const DocumentAuthorIdentifierCodeSequenceTrial(0x0040, 0xa068);
+    Tag const IdentifierCodeSequenceTrial(0x0040, 0xa070);
+    Tag const VerifyingObserverSequence(0x0040, 0xa073);
+    Tag const ObjectBinaryIdentifierTrial(0x0040, 0xa074);
+    Tag const VerifyingObserverName(0x0040, 0xa075);
+    Tag const DocumentingObserverIdentifierCodeSequenceTrial(0x0040, 0xa076);
+    Tag const AuthorObserverSequence(0x0040, 0xa078);
+    Tag const ParticipantSequence(0x0040, 0xa07a);
+    Tag const CustodialOrganizationSequence(0x0040, 0xa07c);
+    Tag const ParticipationType(0x0040, 0xa080);
+    Tag const ParticipationDateTime(0x0040, 0xa082);
+    Tag const ObserverType(0x0040, 0xa084);
+    Tag const ProcedureIdentifierCodeSequenceTrial(0x0040, 0xa085);
+    Tag const VerifyingObserverIdentificationCodeSequence(0x0040, 0xa088);
+    Tag const ObjectDirectoryBinaryIdentifierTrial(0x0040, 0xa089);
+    Tag const EquivalentCDADocumentSequence(0x0040, 0xa090);
+    Tag const ReferencedWaveformChannels(0x0040, 0xa0b0);
+    Tag const DateOfDocumentOrVerbalTransactionTrial(0x0040, 0xa110);
+    Tag const TimeOfDocumentCreationOrVerbalTransactionTrial(0x0040, 0xa112);
+    Tag const DateTime(0x0040, 0xa120);
+    Tag const Date(0x0040, 0xa121);
+    Tag const Time(0x0040, 0xa122);
+    Tag const PersonName(0x0040, 0xa123);
+    Tag const UID(0x0040, 0xa124);
+    Tag const ReportStatusIDTrial(0x0040, 0xa125);
+    Tag const TemporalRangeType(0x0040, 0xa130);
+    Tag const ReferencedSamplePositions(0x0040, 0xa132);
+    Tag const ReferencedFrameNumbers(0x0040, 0xa136);
+    Tag const ReferencedTimeOffsets(0x0040, 0xa138);
+    Tag const ReferencedDateTime(0x0040, 0xa13a);
+    Tag const TextValue(0x0040, 0xa160);
+    Tag const FloatingPointValue(0x0040, 0xa161);
+    Tag const RationalNumeratorValue(0x0040, 0xa162);
+    Tag const RationalDenominatorValue(0x0040, 0xa163);
+    Tag const ObservationCategoryCodeSequenceTrial(0x0040, 0xa167);
+    Tag const ConceptCodeSequence(0x0040, 0xa168);
+    Tag const BibliographicCitationTrial(0x0040, 0xa16a);
+    Tag const PurposeOfReferenceCodeSequence(0x0040, 0xa170);
+    Tag const ObservationUID(0x0040, 0xa171);
+    Tag const ReferencedObservationUIDTrial(0x0040, 0xa172);
+    Tag const ReferencedObservationClassTrial(0x0040, 0xa173);
+    Tag const ReferencedObjectObservationClassTrial(0x0040, 0xa174);
+    Tag const AnnotationGroupNumber(0x0040, 0xa180);
+    Tag const ObservationDateTrial(0x0040, 0xa192);
+    Tag const ObservationTimeTrial(0x0040, 0xa193);
+    Tag const MeasurementAutomationTrial(0x0040, 0xa194);
+    Tag const ModifierCodeSequence(0x0040, 0xa195);
+    Tag const IdentificationDescriptionTrial(0x0040, 0xa224);
+    Tag const CoordinatesSetGeometricTypeTrial(0x0040, 0xa290);
+    Tag const AlgorithmCodeSequenceTrial(0x0040, 0xa296);
+    Tag const AlgorithmDescriptionTrial(0x0040, 0xa297);
+    Tag const PixelCoordinatesSetTrial(0x0040, 0xa29a);
+    Tag const MeasuredValueSequence(0x0040, 0xa300);
+    Tag const NumericValueQualifierCodeSequence(0x0040, 0xa301);
+    Tag const CurrentObserverTrial(0x0040, 0xa307);
+    Tag const NumericValue(0x0040, 0xa30a);
+    Tag const ReferencedAccessionSequenceTrial(0x0040, 0xa313);
+    Tag const ReportStatusCommentTrial(0x0040, 0xa33a);
+    Tag const ProcedureContextSequenceTrial(0x0040, 0xa340);
+    Tag const VerbalSourceTrial(0x0040, 0xa352);
+    Tag const AddressTrial(0x0040, 0xa353);
+    Tag const TelephoneNumberTrial(0x0040, 0xa354);
+    Tag const VerbalSourceIdentifierCodeSequenceTrial(0x0040, 0xa358);
+    Tag const PredecessorDocumentsSequence(0x0040, 0xa360);
+    Tag const ReferencedRequestSequence(0x0040, 0xa370);
+    Tag const PerformedProcedureCodeSequence(0x0040, 0xa372);
+    Tag const CurrentRequestedProcedureEvidenceSequence(0x0040, 0xa375);
+    Tag const ReportDetailSequenceTrial(0x0040, 0xa380);
+    Tag const PertinentOtherEvidenceSequence(0x0040, 0xa385);
+    Tag const HL7StructuredDocumentReferenceSequence(0x0040, 0xa390);
+    Tag const ObservationSubjectUIDTrial(0x0040, 0xa402);
+    Tag const ObservationSubjectClassTrial(0x0040, 0xa403);
+    Tag const ObservationSubjectTypeCodeSequenceTrial(0x0040, 0xa404);
+    Tag const CompletionFlag(0x0040, 0xa491);
+    Tag const CompletionFlagDescription(0x0040, 0xa492);
+    Tag const VerificationFlag(0x0040, 0xa493);
+    Tag const ArchiveRequested(0x0040, 0xa494);
+    Tag const PreliminaryFlag(0x0040, 0xa496);
+    Tag const ContentTemplateSequence(0x0040, 0xa504);
+    Tag const IdenticalDocumentsSequence(0x0040, 0xa525);
+    Tag const ObservationSubjectContextFlagTrial(0x0040, 0xa600);
+    Tag const ObserverContextFlagTrial(0x0040, 0xa601);
+    Tag const ProcedureContextFlagTrial(0x0040, 0xa603);
+    Tag const ContentSequence(0x0040, 0xa730);
+    Tag const RelationshipSequenceTrial(0x0040, 0xa731);
+    Tag const RelationshipTypeCodeSequenceTrial(0x0040, 0xa732);
+    Tag const LanguageCodeSequenceTrial(0x0040, 0xa744);
+    Tag const UniformResourceLocatorTrial(0x0040, 0xa992);
+    Tag const WaveformAnnotationSequence(0x0040, 0xb020);
+    Tag const TemplateIdentifier(0x0040, 0xdb00);
+    Tag const TemplateVersion(0x0040, 0xdb06);
+    Tag const TemplateLocalVersion(0x0040, 0xdb07);
+    Tag const TemplateExtensionFlag(0x0040, 0xdb0b);
+    Tag const TemplateExtensionOrganizationUID(0x0040, 0xdb0c);
+    Tag const TemplateExtensionCreatorUID(0x0040, 0xdb0d);
+    Tag const ReferencedContentItemIdentifier(0x0040, 0xdb73);
+    Tag const HL7InstanceIdentifier(0x0040, 0xe001);
+    Tag const HL7DocumentEffectiveTime(0x0040, 0xe004);
+    Tag const HL7DocumentTypeCodeSequence(0x0040, 0xe006);
+    Tag const DocumentClassCodeSequence(0x0040, 0xe008);
+    Tag const RetrieveURI(0x0040, 0xe010);
+    Tag const RetrieveLocationUID(0x0040, 0xe011);
+    Tag const TypeOfInstances(0x0040, 0xe020);
+    Tag const DICOMRetrievalSequence(0x0040, 0xe021);
+    Tag const DICOMMediaRetrievalSequence(0x0040, 0xe022);
+    Tag const WADORetrievalSequence(0x0040, 0xe023);
+    Tag const XDSRetrievalSequence(0x0040, 0xe024);
+    Tag const WADORSRetrievalSequence(0x0040, 0xe025);
+    Tag const RepositoryUniqueID(0x0040, 0xe030);
+    Tag const HomeCommunityID(0x0040, 0xe031);
+    Tag const DocumentTitle(0x0042, 0x0010);
+    Tag const EncapsulatedDocument(0x0042, 0x0011);
+    Tag const MIMETypeOfEncapsulatedDocument(0x0042, 0x0012);
+    Tag const SourceInstanceSequence(0x0042, 0x0013);
+    Tag const ListOfMIMETypes(0x0042, 0x0014);
+    Tag const ProductPackageIdentifier(0x0044, 0x0001);
+    Tag const SubstanceAdministrationApproval(0x0044, 0x0002);
+    Tag const ApprovalStatusFurtherDescription(0x0044, 0x0003);
+    Tag const ApprovalStatusDateTime(0x0044, 0x0004);
+    Tag const ProductTypeCodeSequence(0x0044, 0x0007);
+    Tag const ProductName(0x0044, 0x0008);
+    Tag const ProductDescription(0x0044, 0x0009);
+    Tag const ProductLotIdentifier(0x0044, 0x000a);
+    Tag const ProductExpirationDateTime(0x0044, 0x000b);
+    Tag const SubstanceAdministrationDateTime(0x0044, 0x0010);
+    Tag const SubstanceAdministrationNotes(0x0044, 0x0011);
+    Tag const SubstanceAdministrationDeviceID(0x0044, 0x0012);
+    Tag const ProductParameterSequence(0x0044, 0x0013);
+    Tag const SubstanceAdministrationParameterSequence(0x0044, 0x0019);
+    Tag const LensDescription(0x0046, 0x0012);
+    Tag const RightLensSequence(0x0046, 0x0014);
+    Tag const LeftLensSequence(0x0046, 0x0015);
+    Tag const UnspecifiedLateralityLensSequence(0x0046, 0x0016);
+    Tag const CylinderSequence(0x0046, 0x0018);
+    Tag const PrismSequence(0x0046, 0x0028);
+    Tag const HorizontalPrismPower(0x0046, 0x0030);
+    Tag const HorizontalPrismBase(0x0046, 0x0032);
+    Tag const VerticalPrismPower(0x0046, 0x0034);
+    Tag const VerticalPrismBase(0x0046, 0x0036);
+    Tag const LensSegmentType(0x0046, 0x0038);
+    Tag const OpticalTransmittance(0x0046, 0x0040);
+    Tag const ChannelWidth(0x0046, 0x0042);
+    Tag const PupilSize(0x0046, 0x0044);
+    Tag const CornealSize(0x0046, 0x0046);
+    Tag const AutorefractionRightEyeSequence(0x0046, 0x0050);
+    Tag const AutorefractionLeftEyeSequence(0x0046, 0x0052);
+    Tag const DistancePupillaryDistance(0x0046, 0x0060);
+    Tag const NearPupillaryDistance(0x0046, 0x0062);
+    Tag const IntermediatePupillaryDistance(0x0046, 0x0063);
+    Tag const OtherPupillaryDistance(0x0046, 0x0064);
+    Tag const KeratometryRightEyeSequence(0x0046, 0x0070);
+    Tag const KeratometryLeftEyeSequence(0x0046, 0x0071);
+    Tag const SteepKeratometricAxisSequence(0x0046, 0x0074);
+    Tag const RadiusOfCurvature(0x0046, 0x0075);
+    Tag const KeratometricPower(0x0046, 0x0076);
+    Tag const KeratometricAxis(0x0046, 0x0077);
+    Tag const FlatKeratometricAxisSequence(0x0046, 0x0080);
+    Tag const BackgroundColor(0x0046, 0x0092);
+    Tag const Optotype(0x0046, 0x0094);
+    Tag const OptotypePresentation(0x0046, 0x0095);
+    Tag const SubjectiveRefractionRightEyeSequence(0x0046, 0x0097);
+    Tag const SubjectiveRefractionLeftEyeSequence(0x0046, 0x0098);
+    Tag const AddNearSequence(0x0046, 0x0100);
+    Tag const AddIntermediateSequence(0x0046, 0x0101);
+    Tag const AddOtherSequence(0x0046, 0x0102);
+    Tag const AddPower(0x0046, 0x0104);
+    Tag const ViewingDistance(0x0046, 0x0106);
+    Tag const VisualAcuityTypeCodeSequence(0x0046, 0x0121);
+    Tag const VisualAcuityRightEyeSequence(0x0046, 0x0122);
+    Tag const VisualAcuityLeftEyeSequence(0x0046, 0x0123);
+    Tag const VisualAcuityBothEyesOpenSequence(0x0046, 0x0124);
+    Tag const ViewingDistanceType(0x0046, 0x0125);
+    Tag const VisualAcuityModifiers(0x0046, 0x0135);
+    Tag const DecimalVisualAcuity(0x0046, 0x0137);
+    Tag const OptotypeDetailedDefinition(0x0046, 0x0139);
+    Tag const ReferencedRefractiveMeasurementsSequence(0x0046, 0x0145);
+    Tag const SpherePower(0x0046, 0x0146);
+    Tag const CylinderPower(0x0046, 0x0147);
+    Tag const CornealTopographySurface(0x0046, 0x0201);
+    Tag const CornealVertexLocation(0x0046, 0x0202);
+    Tag const PupilCentroidXCoordinate(0x0046, 0x0203);
+    Tag const PupilCentroidYCoordinate(0x0046, 0x0204);
+    Tag const EquivalentPupilRadius(0x0046, 0x0205);
+    Tag const CornealTopographyMapTypeCodeSequence(0x0046, 0x0207);
+    Tag const VerticesOfTheOutlineOfPupil(0x0046, 0x0208);
+    Tag const CornealTopographyMappingNormalsSequence(0x0046, 0x0210);
+    Tag const MaximumCornealCurvatureSequence(0x0046, 0x0211);
+    Tag const MaximumCornealCurvature(0x0046, 0x0212);
+    Tag const MaximumCornealCurvatureLocation(0x0046, 0x0213);
+    Tag const MinimumKeratometricSequence(0x0046, 0x0215);
+    Tag const SimulatedKeratometricCylinderSequence(0x0046, 0x0218);
+    Tag const AverageCornealPower(0x0046, 0x0220);
+    Tag const CornealISValue(0x0046, 0x0224);
+    Tag const AnalyzedArea(0x0046, 0x0227);
+    Tag const SurfaceRegularityIndex(0x0046, 0x0230);
+    Tag const SurfaceAsymmetryIndex(0x0046, 0x0232);
+    Tag const CornealEccentricityIndex(0x0046, 0x0234);
+    Tag const KeratoconusPredictionIndex(0x0046, 0x0236);
+    Tag const DecimalPotentialVisualAcuity(0x0046, 0x0238);
+    Tag const CornealTopographyMapQualityEvaluation(0x0046, 0x0242);
+    Tag const SourceImageCornealProcessedDataSequence(0x0046, 0x0244);
+    Tag const CornealPointLocation(0x0046, 0x0247);
+    Tag const CornealPointEstimated(0x0046, 0x0248);
+    Tag const AxialPower(0x0046, 0x0249);
+    Tag const TangentialPower(0x0046, 0x0250);
+    Tag const RefractivePower(0x0046, 0x0251);
+    Tag const RelativeElevation(0x0046, 0x0252);
+    Tag const CornealWavefront(0x0046, 0x0253);
+    Tag const ImagedVolumeWidth(0x0048, 0x0001);
+    Tag const ImagedVolumeHeight(0x0048, 0x0002);
+    Tag const ImagedVolumeDepth(0x0048, 0x0003);
+    Tag const TotalPixelMatrixColumns(0x0048, 0x0006);
+    Tag const TotalPixelMatrixRows(0x0048, 0x0007);
+    Tag const TotalPixelMatrixOriginSequence(0x0048, 0x0008);
+    Tag const SpecimenLabelInImage(0x0048, 0x0010);
+    Tag const FocusMethod(0x0048, 0x0011);
+    Tag const ExtendedDepthOfField(0x0048, 0x0012);
+    Tag const NumberOfFocalPlanes(0x0048, 0x0013);
+    Tag const DistanceBetweenFocalPlanes(0x0048, 0x0014);
+    Tag const RecommendedAbsentPixelCIELabValue(0x0048, 0x0015);
+    Tag const IlluminatorTypeCodeSequence(0x0048, 0x0100);
+    Tag const ImageOrientationSlide(0x0048, 0x0102);
+    Tag const OpticalPathSequence(0x0048, 0x0105);
+    Tag const OpticalPathIdentifier(0x0048, 0x0106);
+    Tag const OpticalPathDescription(0x0048, 0x0107);
+    Tag const IlluminationColorCodeSequence(0x0048, 0x0108);
+    Tag const SpecimenReferenceSequence(0x0048, 0x0110);
+    Tag const CondenserLensPower(0x0048, 0x0111);
+    Tag const ObjectiveLensPower(0x0048, 0x0112);
+    Tag const ObjectiveLensNumericalAperture(0x0048, 0x0113);
+    Tag const PaletteColorLookupTableSequence(0x0048, 0x0120);
+    Tag const ReferencedImageNavigationSequence(0x0048, 0x0200);
+    Tag const TopLeftHandCornerOfLocalizerArea(0x0048, 0x0201);
+    Tag const BottomRightHandCornerOfLocalizerArea(0x0048, 0x0202);
+    Tag const OpticalPathIdentificationSequence(0x0048, 0x0207);
+    Tag const PlanePositionSlideSequence(0x0048, 0x021a);
+    Tag const ColumnPositionInTotalImagePixelMatrix(0x0048, 0x021e);
+    Tag const RowPositionInTotalImagePixelMatrix(0x0048, 0x021f);
+    Tag const PixelOriginInterpretation(0x0048, 0x0301);
+    Tag const CalibrationImage(0x0050, 0x0004);
+    Tag const DeviceSequence(0x0050, 0x0010);
+    Tag const ContainerComponentTypeCodeSequence(0x0050, 0x0012);
+    Tag const ContainerComponentThickness(0x0050, 0x0013);
+    Tag const DeviceLength(0x0050, 0x0014);
+    Tag const ContainerComponentWidth(0x0050, 0x0015);
+    Tag const DeviceDiameter(0x0050, 0x0016);
+    Tag const DeviceDiameterUnits(0x0050, 0x0017);
+    Tag const DeviceVolume(0x0050, 0x0018);
+    Tag const InterMarkerDistance(0x0050, 0x0019);
+    Tag const ContainerComponentMaterial(0x0050, 0x001a);
+    Tag const ContainerComponentID(0x0050, 0x001b);
+    Tag const ContainerComponentLength(0x0050, 0x001c);
+    Tag const ContainerComponentDiameter(0x0050, 0x001d);
+    Tag const ContainerComponentDescription(0x0050, 0x001e);
+    Tag const DeviceDescription(0x0050, 0x0020);
+    Tag const ContrastBolusIngredientPercentByVolume(0x0052, 0x0001);
+    Tag const OCTFocalDistance(0x0052, 0x0002);
+    Tag const BeamSpotSize(0x0052, 0x0003);
+    Tag const EffectiveRefractiveIndex(0x0052, 0x0004);
+    Tag const OCTAcquisitionDomain(0x0052, 0x0006);
+    Tag const OCTOpticalCenterWavelength(0x0052, 0x0007);
+    Tag const AxialResolution(0x0052, 0x0008);
+    Tag const RangingDepth(0x0052, 0x0009);
+    Tag const ALineRate(0x0052, 0x0011);
+    Tag const ALinesPerFrame(0x0052, 0x0012);
+    Tag const CatheterRotationalRate(0x0052, 0x0013);
+    Tag const ALinePixelSpacing(0x0052, 0x0014);
+    Tag const ModeOfPercutaneousAccessSequence(0x0052, 0x0016);
+    Tag const IntravascularOCTFrameTypeSequence(0x0052, 0x0025);
+    Tag const OCTZOffsetApplied(0x0052, 0x0026);
+    Tag const IntravascularFrameContentSequence(0x0052, 0x0027);
+    Tag const IntravascularLongitudinalDistance(0x0052, 0x0028);
+    Tag const IntravascularOCTFrameContentSequence(0x0052, 0x0029);
+    Tag const OCTZOffsetCorrection(0x0052, 0x0030);
+    Tag const CatheterDirectionOfRotation(0x0052, 0x0031);
+    Tag const SeamLineLocation(0x0052, 0x0033);
+    Tag const FirstALineLocation(0x0052, 0x0034);
+    Tag const SeamLineIndex(0x0052, 0x0036);
+    Tag const NumberOfPaddedALines(0x0052, 0x0038);
+    Tag const InterpolationType(0x0052, 0x0039);
+    Tag const RefractiveIndexApplied(0x0052, 0x003a);
+    Tag const EnergyWindowVector(0x0054, 0x0010);
+    Tag const NumberOfEnergyWindows(0x0054, 0x0011);
+    Tag const EnergyWindowInformationSequence(0x0054, 0x0012);
+    Tag const EnergyWindowRangeSequence(0x0054, 0x0013);
+    Tag const EnergyWindowLowerLimit(0x0054, 0x0014);
+    Tag const EnergyWindowUpperLimit(0x0054, 0x0015);
+    Tag const RadiopharmaceuticalInformationSequence(0x0054, 0x0016);
+    Tag const ResidualSyringeCounts(0x0054, 0x0017);
+    Tag const EnergyWindowName(0x0054, 0x0018);
+    Tag const DetectorVector(0x0054, 0x0020);
+    Tag const NumberOfDetectors(0x0054, 0x0021);
+    Tag const DetectorInformationSequence(0x0054, 0x0022);
+    Tag const PhaseVector(0x0054, 0x0030);
+    Tag const NumberOfPhases(0x0054, 0x0031);
+    Tag const PhaseInformationSequence(0x0054, 0x0032);
+    Tag const NumberOfFramesInPhase(0x0054, 0x0033);
+    Tag const PhaseDelay(0x0054, 0x0036);
+    Tag const PauseBetweenFrames(0x0054, 0x0038);
+    Tag const PhaseDescription(0x0054, 0x0039);
+    Tag const RotationVector(0x0054, 0x0050);
+    Tag const NumberOfRotations(0x0054, 0x0051);
+    Tag const RotationInformationSequence(0x0054, 0x0052);
+    Tag const NumberOfFramesInRotation(0x0054, 0x0053);
+    Tag const RRIntervalVector(0x0054, 0x0060);
+    Tag const NumberOfRRIntervals(0x0054, 0x0061);
+    Tag const GatedInformationSequence(0x0054, 0x0062);
+    Tag const DataInformationSequence(0x0054, 0x0063);
+    Tag const TimeSlotVector(0x0054, 0x0070);
+    Tag const NumberOfTimeSlots(0x0054, 0x0071);
+    Tag const TimeSlotInformationSequence(0x0054, 0x0072);
+    Tag const TimeSlotTime(0x0054, 0x0073);
+    Tag const SliceVector(0x0054, 0x0080);
+    Tag const NumberOfSlices(0x0054, 0x0081);
+    Tag const AngularViewVector(0x0054, 0x0090);
+    Tag const TimeSliceVector(0x0054, 0x0100);
+    Tag const NumberOfTimeSlices(0x0054, 0x0101);
+    Tag const StartAngle(0x0054, 0x0200);
+    Tag const TypeOfDetectorMotion(0x0054, 0x0202);
+    Tag const TriggerVector(0x0054, 0x0210);
+    Tag const NumberOfTriggersInPhase(0x0054, 0x0211);
+    Tag const ViewCodeSequence(0x0054, 0x0220);
+    Tag const ViewModifierCodeSequence(0x0054, 0x0222);
+    Tag const RadionuclideCodeSequence(0x0054, 0x0300);
+    Tag const AdministrationRouteCodeSequence(0x0054, 0x0302);
+    Tag const RadiopharmaceuticalCodeSequence(0x0054, 0x0304);
+    Tag const CalibrationDataSequence(0x0054, 0x0306);
+    Tag const EnergyWindowNumber(0x0054, 0x0308);
+    Tag const ImageID(0x0054, 0x0400);
+    Tag const PatientOrientationCodeSequence(0x0054, 0x0410);
+    Tag const PatientOrientationModifierCodeSequence(0x0054, 0x0412);
+    Tag const PatientGantryRelationshipCodeSequence(0x0054, 0x0414);
+    Tag const SliceProgressionDirection(0x0054, 0x0500);
+    Tag const ScanProgressionDirection(0x0054, 0x0501);
+    Tag const SeriesType(0x0054, 0x1000);
+    Tag const Units(0x0054, 0x1001);
+    Tag const CountsSource(0x0054, 0x1002);
+    Tag const ReprojectionMethod(0x0054, 0x1004);
+    Tag const SUVType(0x0054, 0x1006);
+    Tag const RandomsCorrectionMethod(0x0054, 0x1100);
+    Tag const AttenuationCorrectionMethod(0x0054, 0x1101);
+    Tag const DecayCorrection(0x0054, 0x1102);
+    Tag const ReconstructionMethod(0x0054, 0x1103);
+    Tag const DetectorLinesOfResponseUsed(0x0054, 0x1104);
+    Tag const ScatterCorrectionMethod(0x0054, 0x1105);
+    Tag const AxialAcceptance(0x0054, 0x1200);
+    Tag const AxialMash(0x0054, 0x1201);
+    Tag const TransverseMash(0x0054, 0x1202);
+    Tag const DetectorElementSize(0x0054, 0x1203);
+    Tag const CoincidenceWindowWidth(0x0054, 0x1210);
+    Tag const SecondaryCountsType(0x0054, 0x1220);
+    Tag const FrameReferenceTime(0x0054, 0x1300);
+    Tag const PrimaryPromptsCountsAccumulated(0x0054, 0x1310);
+    Tag const SecondaryCountsAccumulated(0x0054, 0x1311);
+    Tag const SliceSensitivityFactor(0x0054, 0x1320);
+    Tag const DecayFactor(0x0054, 0x1321);
+    Tag const DoseCalibrationFactor(0x0054, 0x1322);
+    Tag const ScatterFractionFactor(0x0054, 0x1323);
+    Tag const DeadTimeFactor(0x0054, 0x1324);
+    Tag const ImageIndex(0x0054, 0x1330);
+    Tag const CountsIncluded(0x0054, 0x1400);
+    Tag const DeadTimeCorrectionFlag(0x0054, 0x1401);
+    Tag const HistogramSequence(0x0060, 0x3000);
+    Tag const HistogramNumberOfBins(0x0060, 0x3002);
+    Tag const HistogramFirstBinValue(0x0060, 0x3004);
+    Tag const HistogramLastBinValue(0x0060, 0x3006);
+    Tag const HistogramBinWidth(0x0060, 0x3008);
+    Tag const HistogramExplanation(0x0060, 0x3010);
+    Tag const HistogramData(0x0060, 0x3020);
+    Tag const SegmentationType(0x0062, 0x0001);
+    Tag const SegmentSequence(0x0062, 0x0002);
+    Tag const SegmentedPropertyCategoryCodeSequence(0x0062, 0x0003);
+    Tag const SegmentNumber(0x0062, 0x0004);
+    Tag const SegmentLabel(0x0062, 0x0005);
+    Tag const SegmentDescription(0x0062, 0x0006);
+    Tag const SegmentAlgorithmType(0x0062, 0x0008);
+    Tag const SegmentAlgorithmName(0x0062, 0x0009);
+    Tag const SegmentIdentificationSequence(0x0062, 0x000a);
+    Tag const ReferencedSegmentNumber(0x0062, 0x000b);
+    Tag const RecommendedDisplayGrayscaleValue(0x0062, 0x000c);
+    Tag const RecommendedDisplayCIELabValue(0x0062, 0x000d);
+    Tag const MaximumFractionalValue(0x0062, 0x000e);
+    Tag const SegmentedPropertyTypeCodeSequence(0x0062, 0x000f);
+    Tag const SegmentationFractionalType(0x0062, 0x0010);
+    Tag const SegmentedPropertyTypeModifierCodeSequence(0x0062, 0x0011);
+    Tag const UsedSegmentsSequence(0x0062, 0x0012);
+    Tag const DeformableRegistrationSequence(0x0064, 0x0002);
+    Tag const SourceFrameOfReferenceUID(0x0064, 0x0003);
+    Tag const DeformableRegistrationGridSequence(0x0064, 0x0005);
+    Tag const GridDimensions(0x0064, 0x0007);
+    Tag const GridResolution(0x0064, 0x0008);
+    Tag const VectorGridData(0x0064, 0x0009);
+    Tag const PreDeformationMatrixRegistrationSequence(0x0064, 0x000f);
+    Tag const PostDeformationMatrixRegistrationSequence(0x0064, 0x0010);
+    Tag const NumberOfSurfaces(0x0066, 0x0001);
+    Tag const SurfaceSequence(0x0066, 0x0002);
+    Tag const SurfaceNumber(0x0066, 0x0003);
+    Tag const SurfaceComments(0x0066, 0x0004);
+    Tag const SurfaceProcessing(0x0066, 0x0009);
+    Tag const SurfaceProcessingRatio(0x0066, 0x000a);
+    Tag const SurfaceProcessingDescription(0x0066, 0x000b);
+    Tag const RecommendedPresentationOpacity(0x0066, 0x000c);
+    Tag const RecommendedPresentationType(0x0066, 0x000d);
+    Tag const FiniteVolume(0x0066, 0x000e);
+    Tag const Manifold(0x0066, 0x0010);
+    Tag const SurfacePointsSequence(0x0066, 0x0011);
+    Tag const SurfacePointsNormalsSequence(0x0066, 0x0012);
+    Tag const SurfaceMeshPrimitivesSequence(0x0066, 0x0013);
+    Tag const NumberOfSurfacePoints(0x0066, 0x0015);
+    Tag const PointCoordinatesData(0x0066, 0x0016);
+    Tag const PointPositionAccuracy(0x0066, 0x0017);
+    Tag const MeanPointDistance(0x0066, 0x0018);
+    Tag const MaximumPointDistance(0x0066, 0x0019);
+    Tag const PointsBoundingBoxCoordinates(0x0066, 0x001a);
+    Tag const AxisOfRotation(0x0066, 0x001b);
+    Tag const CenterOfRotation(0x0066, 0x001c);
+    Tag const NumberOfVectors(0x0066, 0x001e);
+    Tag const VectorDimensionality(0x0066, 0x001f);
+    Tag const VectorAccuracy(0x0066, 0x0020);
+    Tag const VectorCoordinateData(0x0066, 0x0021);
+    Tag const TrianglePointIndexList(0x0066, 0x0023);
+    Tag const EdgePointIndexList(0x0066, 0x0024);
+    Tag const VertexPointIndexList(0x0066, 0x0025);
+    Tag const TriangleStripSequence(0x0066, 0x0026);
+    Tag const TriangleFanSequence(0x0066, 0x0027);
+    Tag const LineSequence(0x0066, 0x0028);
+    Tag const PrimitivePointIndexList(0x0066, 0x0029);
+    Tag const SurfaceCount(0x0066, 0x002a);
+    Tag const ReferencedSurfaceSequence(0x0066, 0x002b);
+    Tag const ReferencedSurfaceNumber(0x0066, 0x002c);
+    Tag const SegmentSurfaceGenerationAlgorithmIdentificationSequence(0x0066, 0x002d);
+    Tag const SegmentSurfaceSourceInstanceSequence(0x0066, 0x002e);
+    Tag const AlgorithmFamilyCodeSequence(0x0066, 0x002f);
+    Tag const AlgorithmNameCodeSequence(0x0066, 0x0030);
+    Tag const AlgorithmVersion(0x0066, 0x0031);
+    Tag const AlgorithmParameters(0x0066, 0x0032);
+    Tag const FacetSequence(0x0066, 0x0034);
+    Tag const SurfaceProcessingAlgorithmIdentificationSequence(0x0066, 0x0035);
+    Tag const AlgorithmName(0x0066, 0x0036);
+    Tag const RecommendedPointRadius(0x0066, 0x0037);
+    Tag const RecommendedLineThickness(0x0066, 0x0038);
+    Tag const LongPrimitivePointIndexList(0x0066, 0x0040);
+    Tag const LongTrianglePointIndexList(0x0066, 0x0041);
+    Tag const LongEdgePointIndexList(0x0066, 0x0042);
+    Tag const LongVertexPointIndexList(0x0066, 0x0043);
+    Tag const ImplantSize(0x0068, 0x6210);
+    Tag const ImplantTemplateVersion(0x0068, 0x6221);
+    Tag const ReplacedImplantTemplateSequence(0x0068, 0x6222);
+    Tag const ImplantType(0x0068, 0x6223);
+    Tag const DerivationImplantTemplateSequence(0x0068, 0x6224);
+    Tag const OriginalImplantTemplateSequence(0x0068, 0x6225);
+    Tag const EffectiveDateTime(0x0068, 0x6226);
+    Tag const ImplantTargetAnatomySequence(0x0068, 0x6230);
+    Tag const InformationFromManufacturerSequence(0x0068, 0x6260);
+    Tag const NotificationFromManufacturerSequence(0x0068, 0x6265);
+    Tag const InformationIssueDateTime(0x0068, 0x6270);
+    Tag const InformationSummary(0x0068, 0x6280);
+    Tag const ImplantRegulatoryDisapprovalCodeSequence(0x0068, 0x62a0);
+    Tag const OverallTemplateSpatialTolerance(0x0068, 0x62a5);
+    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 HPGLDocumentScaling(0x0068, 0x62f2);
+    Tag const HPGLDocument(0x0068, 0x6300);
+    Tag const HPGLContourPenNumber(0x0068, 0x6310);
+    Tag const HPGLPenSequence(0x0068, 0x6320);
+    Tag const HPGLPenNumber(0x0068, 0x6330);
+    Tag const HPGLPenLabel(0x0068, 0x6340);
+    Tag const HPGLPenDescription(0x0068, 0x6345);
+    Tag const RecommendedRotationPoint(0x0068, 0x6346);
+    Tag const BoundingRectangle(0x0068, 0x6347);
+    Tag const ImplantTemplate3DModelSurfaceNumber(0x0068, 0x6350);
+    Tag const SurfaceModelDescriptionSequence(0x0068, 0x6360);
+    Tag const SurfaceModelLabel(0x0068, 0x6380);
+    Tag const SurfaceModelScalingFactor(0x0068, 0x6390);
+    Tag const MaterialsCodeSequence(0x0068, 0x63a0);
+    Tag const CoatingMaterialsCodeSequence(0x0068, 0x63a4);
+    Tag const ImplantTypeCodeSequence(0x0068, 0x63a8);
+    Tag const FixationMethodCodeSequence(0x0068, 0x63ac);
+    Tag const MatingFeatureSetsSequence(0x0068, 0x63b0);
+    Tag const MatingFeatureSetID(0x0068, 0x63c0);
+    Tag const MatingFeatureSetLabel(0x0068, 0x63d0);
+    Tag const MatingFeatureSequence(0x0068, 0x63e0);
+    Tag const MatingFeatureID(0x0068, 0x63f0);
+    Tag const MatingFeatureDegreeOfFreedomSequence(0x0068, 0x6400);
+    Tag const DegreeOfFreedomID(0x0068, 0x6410);
+    Tag const DegreeOfFreedomType(0x0068, 0x6420);
+    Tag const TwoDMatingFeatureCoordinatesSequence(0x0068, 0x6430);
+    Tag const ReferencedHPGLDocumentID(0x0068, 0x6440);
+    Tag const TwoDMatingPoint(0x0068, 0x6450);
+    Tag const TwoDMatingAxes(0x0068, 0x6460);
+    Tag const TwoDDegreeOfFreedomSequence(0x0068, 0x6470);
+    Tag const ThreeDDegreeOfFreedomAxis(0x0068, 0x6490);
+    Tag const RangeOfFreedom(0x0068, 0x64a0);
+    Tag const ThreeDMatingPoint(0x0068, 0x64c0);
+    Tag const ThreeDMatingAxes(0x0068, 0x64d0);
+    Tag const TwoDDegreeOfFreedomAxis(0x0068, 0x64f0);
+    Tag const PlanningLandmarkPointSequence(0x0068, 0x6500);
+    Tag const PlanningLandmarkLineSequence(0x0068, 0x6510);
+    Tag const PlanningLandmarkPlaneSequence(0x0068, 0x6520);
+    Tag const PlanningLandmarkID(0x0068, 0x6530);
+    Tag const PlanningLandmarkDescription(0x0068, 0x6540);
+    Tag const PlanningLandmarkIdentificationCodeSequence(0x0068, 0x6545);
+    Tag const TwoDPointCoordinatesSequence(0x0068, 0x6550);
+    Tag const TwoDPointCoordinates(0x0068, 0x6560);
+    Tag const ThreeDPointCoordinates(0x0068, 0x6590);
+    Tag const TwoDLineCoordinatesSequence(0x0068, 0x65a0);
+    Tag const TwoDLineCoordinates(0x0068, 0x65b0);
+    Tag const ThreeDLineCoordinates(0x0068, 0x65d0);
+    Tag const TwoDPlaneCoordinatesSequence(0x0068, 0x65e0);
+    Tag const TwoDPlaneIntersection(0x0068, 0x65f0);
+    Tag const ThreeDPlaneOrigin(0x0068, 0x6610);
+    Tag const ThreeDPlaneNormal(0x0068, 0x6620);
+    Tag const GraphicAnnotationSequence(0x0070, 0x0001);
+    Tag const GraphicLayer(0x0070, 0x0002);
+    Tag const BoundingBoxAnnotationUnits(0x0070, 0x0003);
+    Tag const AnchorPointAnnotationUnits(0x0070, 0x0004);
+    Tag const GraphicAnnotationUnits(0x0070, 0x0005);
+    Tag const UnformattedTextValue(0x0070, 0x0006);
+    Tag const TextObjectSequence(0x0070, 0x0008);
+    Tag const GraphicObjectSequence(0x0070, 0x0009);
+    Tag const BoundingBoxTopLeftHandCorner(0x0070, 0x0010);
+    Tag const BoundingBoxBottomRightHandCorner(0x0070, 0x0011);
+    Tag const BoundingBoxTextHorizontalJustification(0x0070, 0x0012);
+    Tag const AnchorPoint(0x0070, 0x0014);
+    Tag const AnchorPointVisibility(0x0070, 0x0015);
+    Tag const GraphicDimensions(0x0070, 0x0020);
+    Tag const NumberOfGraphicPoints(0x0070, 0x0021);
+    Tag const GraphicData(0x0070, 0x0022);
+    Tag const GraphicType(0x0070, 0x0023);
+    Tag const GraphicFilled(0x0070, 0x0024);
+    Tag const ImageRotationRetired(0x0070, 0x0040);
+    Tag const ImageHorizontalFlip(0x0070, 0x0041);
+    Tag const ImageRotation(0x0070, 0x0042);
+    Tag const DisplayedAreaTopLeftHandCornerTrial(0x0070, 0x0050);
+    Tag const DisplayedAreaBottomRightHandCornerTrial(0x0070, 0x0051);
+    Tag const DisplayedAreaTopLeftHandCorner(0x0070, 0x0052);
+    Tag const DisplayedAreaBottomRightHandCorner(0x0070, 0x0053);
+    Tag const DisplayedAreaSelectionSequence(0x0070, 0x005a);
+    Tag const GraphicLayerSequence(0x0070, 0x0060);
+    Tag const GraphicLayerOrder(0x0070, 0x0062);
+    Tag const GraphicLayerRecommendedDisplayGrayscaleValue(0x0070, 0x0066);
+    Tag const GraphicLayerRecommendedDisplayRGBValue(0x0070, 0x0067);
+    Tag const GraphicLayerDescription(0x0070, 0x0068);
+    Tag const ContentLabel(0x0070, 0x0080);
+    Tag const ContentDescription(0x0070, 0x0081);
+    Tag const PresentationCreationDate(0x0070, 0x0082);
+    Tag const PresentationCreationTime(0x0070, 0x0083);
+    Tag const ContentCreatorName(0x0070, 0x0084);
+    Tag const ContentCreatorIdentificationCodeSequence(0x0070, 0x0086);
+    Tag const AlternateContentDescriptionSequence(0x0070, 0x0087);
+    Tag const PresentationSizeMode(0x0070, 0x0100);
+    Tag const PresentationPixelSpacing(0x0070, 0x0101);
+    Tag const PresentationPixelAspectRatio(0x0070, 0x0102);
+    Tag const PresentationPixelMagnificationRatio(0x0070, 0x0103);
+    Tag const GraphicGroupLabel(0x0070, 0x0207);
+    Tag const GraphicGroupDescription(0x0070, 0x0208);
+    Tag const CompoundGraphicSequence(0x0070, 0x0209);
+    Tag const CompoundGraphicInstanceID(0x0070, 0x0226);
+    Tag const FontName(0x0070, 0x0227);
+    Tag const FontNameType(0x0070, 0x0228);
+    Tag const CSSFontName(0x0070, 0x0229);
+    Tag const RotationAngle(0x0070, 0x0230);
+    Tag const TextStyleSequence(0x0070, 0x0231);
+    Tag const LineStyleSequence(0x0070, 0x0232);
+    Tag const FillStyleSequence(0x0070, 0x0233);
+    Tag const GraphicGroupSequence(0x0070, 0x0234);
+    Tag const TextColorCIELabValue(0x0070, 0x0241);
+    Tag const HorizontalAlignment(0x0070, 0x0242);
+    Tag const VerticalAlignment(0x0070, 0x0243);
+    Tag const ShadowStyle(0x0070, 0x0244);
+    Tag const ShadowOffsetX(0x0070, 0x0245);
+    Tag const ShadowOffsetY(0x0070, 0x0246);
+    Tag const ShadowColorCIELabValue(0x0070, 0x0247);
+    Tag const Underlined(0x0070, 0x0248);
+    Tag const Bold(0x0070, 0x0249);
+    Tag const Italic(0x0070, 0x0250);
+    Tag const PatternOnColorCIELabValue(0x0070, 0x0251);
+    Tag const PatternOffColorCIELabValue(0x0070, 0x0252);
+    Tag const LineThickness(0x0070, 0x0253);
+    Tag const LineDashingStyle(0x0070, 0x0254);
+    Tag const LinePattern(0x0070, 0x0255);
+    Tag const FillPattern(0x0070, 0x0256);
+    Tag const FillMode(0x0070, 0x0257);
+    Tag const ShadowOpacity(0x0070, 0x0258);
+    Tag const GapLength(0x0070, 0x0261);
+    Tag const DiameterOfVisibility(0x0070, 0x0262);
+    Tag const RotationPoint(0x0070, 0x0273);
+    Tag const TickAlignment(0x0070, 0x0274);
+    Tag const ShowTickLabel(0x0070, 0x0278);
+    Tag const TickLabelAlignment(0x0070, 0x0279);
+    Tag const CompoundGraphicUnits(0x0070, 0x0282);
+    Tag const PatternOnOpacity(0x0070, 0x0284);
+    Tag const PatternOffOpacity(0x0070, 0x0285);
+    Tag const MajorTicksSequence(0x0070, 0x0287);
+    Tag const TickPosition(0x0070, 0x0288);
+    Tag const TickLabel(0x0070, 0x0289);
+    Tag const CompoundGraphicType(0x0070, 0x0294);
+    Tag const GraphicGroupID(0x0070, 0x0295);
+    Tag const ShapeType(0x0070, 0x0306);
+    Tag const RegistrationSequence(0x0070, 0x0308);
+    Tag const MatrixRegistrationSequence(0x0070, 0x0309);
+    Tag const MatrixSequence(0x0070, 0x030a);
+    Tag const FrameOfReferenceTransformationMatrixType(0x0070, 0x030c);
+    Tag const RegistrationTypeCodeSequence(0x0070, 0x030d);
+    Tag const FiducialDescription(0x0070, 0x030f);
+    Tag const FiducialIdentifier(0x0070, 0x0310);
+    Tag const FiducialIdentifierCodeSequence(0x0070, 0x0311);
+    Tag const ContourUncertaintyRadius(0x0070, 0x0312);
+    Tag const UsedFiducialsSequence(0x0070, 0x0314);
+    Tag const GraphicCoordinatesDataSequence(0x0070, 0x0318);
+    Tag const FiducialUID(0x0070, 0x031a);
+    Tag const FiducialSetSequence(0x0070, 0x031c);
+    Tag const FiducialSequence(0x0070, 0x031e);
+    Tag const GraphicLayerRecommendedDisplayCIELabValue(0x0070, 0x0401);
+    Tag const BlendingSequence(0x0070, 0x0402);
+    Tag const RelativeOpacity(0x0070, 0x0403);
+    Tag const ReferencedSpatialRegistrationSequence(0x0070, 0x0404);
+    Tag const BlendingPosition(0x0070, 0x0405);
+    Tag const HangingProtocolName(0x0072, 0x0002);
+    Tag const HangingProtocolDescription(0x0072, 0x0004);
+    Tag const HangingProtocolLevel(0x0072, 0x0006);
+    Tag const HangingProtocolCreator(0x0072, 0x0008);
+    Tag const HangingProtocolCreationDateTime(0x0072, 0x000a);
+    Tag const HangingProtocolDefinitionSequence(0x0072, 0x000c);
+    Tag const HangingProtocolUserIdentificationCodeSequence(0x0072, 0x000e);
+    Tag const HangingProtocolUserGroupName(0x0072, 0x0010);
+    Tag const SourceHangingProtocolSequence(0x0072, 0x0012);
+    Tag const NumberOfPriorsReferenced(0x0072, 0x0014);
+    Tag const ImageSetsSequence(0x0072, 0x0020);
+    Tag const ImageSetSelectorSequence(0x0072, 0x0022);
+    Tag const ImageSetSelectorUsageFlag(0x0072, 0x0024);
+    Tag const SelectorAttribute(0x0072, 0x0026);
+    Tag const SelectorValueNumber(0x0072, 0x0028);
+    Tag const TimeBasedImageSetsSequence(0x0072, 0x0030);
+    Tag const ImageSetNumber(0x0072, 0x0032);
+    Tag const ImageSetSelectorCategory(0x0072, 0x0034);
+    Tag const RelativeTime(0x0072, 0x0038);
+    Tag const RelativeTimeUnits(0x0072, 0x003a);
+    Tag const AbstractPriorValue(0x0072, 0x003c);
+    Tag const AbstractPriorCodeSequence(0x0072, 0x003e);
+    Tag const ImageSetLabel(0x0072, 0x0040);
+    Tag const SelectorAttributeVR(0x0072, 0x0050);
+    Tag const SelectorSequencePointer(0x0072, 0x0052);
+    Tag const SelectorSequencePointerPrivateCreator(0x0072, 0x0054);
+    Tag const SelectorAttributePrivateCreator(0x0072, 0x0056);
+    Tag const SelectorATValue(0x0072, 0x0060);
+    Tag const SelectorCSValue(0x0072, 0x0062);
+    Tag const SelectorISValue(0x0072, 0x0064);
+    Tag const SelectorLOValue(0x0072, 0x0066);
+    Tag const SelectorLTValue(0x0072, 0x0068);
+    Tag const SelectorPNValue(0x0072, 0x006a);
+    Tag const SelectorSHValue(0x0072, 0x006c);
+    Tag const SelectorSTValue(0x0072, 0x006e);
+    Tag const SelectorUTValue(0x0072, 0x0070);
+    Tag const SelectorDSValue(0x0072, 0x0072);
+    Tag const SelectorFDValue(0x0072, 0x0074);
+    Tag const SelectorFLValue(0x0072, 0x0076);
+    Tag const SelectorULValue(0x0072, 0x0078);
+    Tag const SelectorUSValue(0x0072, 0x007a);
+    Tag const SelectorSLValue(0x0072, 0x007c);
+    Tag const SelectorSSValue(0x0072, 0x007e);
+    Tag const SelectorCodeSequenceValue(0x0072, 0x0080);
+    Tag const NumberOfScreens(0x0072, 0x0100);
+    Tag const NominalScreenDefinitionSequence(0x0072, 0x0102);
+    Tag const NumberOfVerticalPixels(0x0072, 0x0104);
+    Tag const NumberOfHorizontalPixels(0x0072, 0x0106);
+    Tag const DisplayEnvironmentSpatialPosition(0x0072, 0x0108);
+    Tag const ScreenMinimumGrayscaleBitDepth(0x0072, 0x010a);
+    Tag const ScreenMinimumColorBitDepth(0x0072, 0x010c);
+    Tag const ApplicationMaximumRepaintTime(0x0072, 0x010e);
+    Tag const DisplaySetsSequence(0x0072, 0x0200);
+    Tag const DisplaySetNumber(0x0072, 0x0202);
+    Tag const DisplaySetLabel(0x0072, 0x0203);
+    Tag const DisplaySetPresentationGroup(0x0072, 0x0204);
+    Tag const DisplaySetPresentationGroupDescription(0x0072, 0x0206);
+    Tag const PartialDataDisplayHandling(0x0072, 0x0208);
+    Tag const SynchronizedScrollingSequence(0x0072, 0x0210);
+    Tag const DisplaySetScrollingGroup(0x0072, 0x0212);
+    Tag const NavigationIndicatorSequence(0x0072, 0x0214);
+    Tag const NavigationDisplaySet(0x0072, 0x0216);
+    Tag const ReferenceDisplaySets(0x0072, 0x0218);
+    Tag const ImageBoxesSequence(0x0072, 0x0300);
+    Tag const ImageBoxNumber(0x0072, 0x0302);
+    Tag const ImageBoxLayoutType(0x0072, 0x0304);
+    Tag const ImageBoxTileHorizontalDimension(0x0072, 0x0306);
+    Tag const ImageBoxTileVerticalDimension(0x0072, 0x0308);
+    Tag const ImageBoxScrollDirection(0x0072, 0x0310);
+    Tag const ImageBoxSmallScrollType(0x0072, 0x0312);
+    Tag const ImageBoxSmallScrollAmount(0x0072, 0x0314);
+    Tag const ImageBoxLargeScrollType(0x0072, 0x0316);
+    Tag const ImageBoxLargeScrollAmount(0x0072, 0x0318);
+    Tag const ImageBoxOverlapPriority(0x0072, 0x0320);
+    Tag const CineRelativeToRealTime(0x0072, 0x0330);
+    Tag const FilterOperationsSequence(0x0072, 0x0400);
+    Tag const FilterByCategory(0x0072, 0x0402);
+    Tag const FilterByAttributePresence(0x0072, 0x0404);
+    Tag const FilterByOperator(0x0072, 0x0406);
+    Tag const StructuredDisplayBackgroundCIELabValue(0x0072, 0x0420);
+    Tag const EmptyImageBoxCIELabValue(0x0072, 0x0421);
+    Tag const StructuredDisplayImageBoxSequence(0x0072, 0x0422);
+    Tag const StructuredDisplayTextBoxSequence(0x0072, 0x0424);
+    Tag const ReferencedFirstFrameSequence(0x0072, 0x0427);
+    Tag const ImageBoxSynchronizationSequence(0x0072, 0x0430);
+    Tag const SynchronizedImageBoxList(0x0072, 0x0432);
+    Tag const TypeOfSynchronization(0x0072, 0x0434);
+    Tag const BlendingOperationType(0x0072, 0x0500);
+    Tag const ReformattingOperationType(0x0072, 0x0510);
+    Tag const ReformattingThickness(0x0072, 0x0512);
+    Tag const ReformattingInterval(0x0072, 0x0514);
+    Tag const ReformattingOperationInitialViewDirection(0x0072, 0x0516);
+    Tag const ThreeDRenderingType(0x0072, 0x0520);
+    Tag const SortingOperationsSequence(0x0072, 0x0600);
+    Tag const SortByCategory(0x0072, 0x0602);
+    Tag const SortingDirection(0x0072, 0x0604);
+    Tag const DisplaySetPatientOrientation(0x0072, 0x0700);
+    Tag const VOIType(0x0072, 0x0702);
+    Tag const PseudoColorType(0x0072, 0x0704);
+    Tag const PseudoColorPaletteInstanceReferenceSequence(0x0072, 0x0705);
+    Tag const ShowGrayscaleInverted(0x0072, 0x0706);
+    Tag const ShowImageTrueSizeFlag(0x0072, 0x0710);
+    Tag const ShowGraphicAnnotationFlag(0x0072, 0x0712);
+    Tag const ShowPatientDemographicsFlag(0x0072, 0x0714);
+    Tag const ShowAcquisitionTechniquesFlag(0x0072, 0x0716);
+    Tag const DisplaySetHorizontalJustification(0x0072, 0x0717);
+    Tag const DisplaySetVerticalJustification(0x0072, 0x0718);
+    Tag const ContinuationStartMeterset(0x0074, 0x0120);
+    Tag const ContinuationEndMeterset(0x0074, 0x0121);
+    Tag const ProcedureStepState(0x0074, 0x1000);
+    Tag const ProcedureStepProgressInformationSequence(0x0074, 0x1002);
+    Tag const ProcedureStepProgress(0x0074, 0x1004);
+    Tag const ProcedureStepProgressDescription(0x0074, 0x1006);
+    Tag const ProcedureStepCommunicationsURISequence(0x0074, 0x1008);
+    Tag const ContactURI(0x0074, 0x100a);
+    Tag const ContactDisplayName(0x0074, 0x100c);
+    Tag const ProcedureStepDiscontinuationReasonCodeSequence(0x0074, 0x100e);
+    Tag const BeamTaskSequence(0x0074, 0x1020);
+    Tag const BeamTaskType(0x0074, 0x1022);
+    Tag const BeamOrderIndexTrial(0x0074, 0x1024);
+    Tag const AutosequenceFlag(0x0074, 0x1025);
+    Tag const TableTopVerticalAdjustedPosition(0x0074, 0x1026);
+    Tag const TableTopLongitudinalAdjustedPosition(0x0074, 0x1027);
+    Tag const TableTopLateralAdjustedPosition(0x0074, 0x1028);
+    Tag const PatientSupportAdjustedAngle(0x0074, 0x102a);
+    Tag const TableTopEccentricAdjustedAngle(0x0074, 0x102b);
+    Tag const TableTopPitchAdjustedAngle(0x0074, 0x102c);
+    Tag const TableTopRollAdjustedAngle(0x0074, 0x102d);
+    Tag const DeliveryVerificationImageSequence(0x0074, 0x1030);
+    Tag const VerificationImageTiming(0x0074, 0x1032);
+    Tag const DoubleExposureFlag(0x0074, 0x1034);
+    Tag const DoubleExposureOrdering(0x0074, 0x1036);
+    Tag const DoubleExposureMetersetTrial(0x0074, 0x1038);
+    Tag const DoubleExposureFieldDeltaTrial(0x0074, 0x103a);
+    Tag const RelatedReferenceRTImageSequence(0x0074, 0x1040);
+    Tag const GeneralMachineVerificationSequence(0x0074, 0x1042);
+    Tag const ConventionalMachineVerificationSequence(0x0074, 0x1044);
+    Tag const IonMachineVerificationSequence(0x0074, 0x1046);
+    Tag const FailedAttributesSequence(0x0074, 0x1048);
+    Tag const OverriddenAttributesSequence(0x0074, 0x104a);
+    Tag const ConventionalControlPointVerificationSequence(0x0074, 0x104c);
+    Tag const IonControlPointVerificationSequence(0x0074, 0x104e);
+    Tag const AttributeOccurrenceSequence(0x0074, 0x1050);
+    Tag const AttributeOccurrencePointer(0x0074, 0x1052);
+    Tag const AttributeItemSelector(0x0074, 0x1054);
+    Tag const AttributeOccurrencePrivateCreator(0x0074, 0x1056);
+    Tag const SelectorSequencePointerItems(0x0074, 0x1057);
+    Tag const ScheduledProcedureStepPriority(0x0074, 0x1200);
+    Tag const WorklistLabel(0x0074, 0x1202);
+    Tag const ProcedureStepLabel(0x0074, 0x1204);
+    Tag const ScheduledProcessingParametersSequence(0x0074, 0x1210);
+    Tag const PerformedProcessingParametersSequence(0x0074, 0x1212);
+    Tag const UnifiedProcedureStepPerformedProcedureSequence(0x0074, 0x1216);
+    Tag const RelatedProcedureStepSequence(0x0074, 0x1220);
+    Tag const ProcedureStepRelationshipType(0x0074, 0x1222);
+    Tag const ReplacedProcedureStepSequence(0x0074, 0x1224);
+    Tag const DeletionLock(0x0074, 0x1230);
+    Tag const ReceivingAE(0x0074, 0x1234);
+    Tag const RequestingAE(0x0074, 0x1236);
+    Tag const ReasonForCancellation(0x0074, 0x1238);
+    Tag const SCPStatus(0x0074, 0x1242);
+    Tag const SubscriptionListStatus(0x0074, 0x1244);
+    Tag const UnifiedProcedureStepListStatus(0x0074, 0x1246);
+    Tag const BeamOrderIndex(0x0074, 0x1324);
+    Tag const DoubleExposureMeterset(0x0074, 0x1338);
+    Tag const DoubleExposureFieldDelta(0x0074, 0x133a);
+    Tag const ImplantAssemblyTemplateName(0x0076, 0x0001);
+    Tag const ImplantAssemblyTemplateIssuer(0x0076, 0x0003);
+    Tag const ImplantAssemblyTemplateVersion(0x0076, 0x0006);
+    Tag const ReplacedImplantAssemblyTemplateSequence(0x0076, 0x0008);
+    Tag const ImplantAssemblyTemplateType(0x0076, 0x000a);
+    Tag const OriginalImplantAssemblyTemplateSequence(0x0076, 0x000c);
+    Tag const DerivationImplantAssemblyTemplateSequence(0x0076, 0x000e);
+    Tag const ImplantAssemblyTemplateTargetAnatomySequence(0x0076, 0x0010);
+    Tag const ProcedureTypeCodeSequence(0x0076, 0x0020);
+    Tag const SurgicalTechnique(0x0076, 0x0030);
+    Tag const ComponentTypesSequence(0x0076, 0x0032);
+    Tag const ComponentTypeCodeSequence(0x0076, 0x0034);
+    Tag const ExclusiveComponentType(0x0076, 0x0036);
+    Tag const MandatoryComponentType(0x0076, 0x0038);
+    Tag const ComponentSequence(0x0076, 0x0040);
+    Tag const ComponentID(0x0076, 0x0055);
+    Tag const ComponentAssemblySequence(0x0076, 0x0060);
+    Tag const Component1ReferencedID(0x0076, 0x0070);
+    Tag const Component1ReferencedMatingFeatureSetID(0x0076, 0x0080);
+    Tag const Component1ReferencedMatingFeatureID(0x0076, 0x0090);
+    Tag const Component2ReferencedID(0x0076, 0x00a0);
+    Tag const Component2ReferencedMatingFeatureSetID(0x0076, 0x00b0);
+    Tag const Component2ReferencedMatingFeatureID(0x0076, 0x00c0);
+    Tag const ImplantTemplateGroupName(0x0078, 0x0001);
+    Tag const ImplantTemplateGroupDescription(0x0078, 0x0010);
+    Tag const ImplantTemplateGroupIssuer(0x0078, 0x0020);
+    Tag const ImplantTemplateGroupVersion(0x0078, 0x0024);
+    Tag const ReplacedImplantTemplateGroupSequence(0x0078, 0x0026);
+    Tag const ImplantTemplateGroupTargetAnatomySequence(0x0078, 0x0028);
+    Tag const ImplantTemplateGroupMembersSequence(0x0078, 0x002a);
+    Tag const ImplantTemplateGroupMemberID(0x0078, 0x002e);
+    Tag const ThreeDImplantTemplateGroupMemberMatchingPoint(0x0078, 0x0050);
+    Tag const ThreeDImplantTemplateGroupMemberMatchingAxes(0x0078, 0x0060);
+    Tag const ImplantTemplateGroupMemberMatching2DCoordinatesSequence(0x0078, 0x0070);
+    Tag const TwoDImplantTemplateGroupMemberMatchingPoint(0x0078, 0x0090);
+    Tag const TwoDImplantTemplateGroupMemberMatchingAxes(0x0078, 0x00a0);
+    Tag const ImplantTemplateGroupVariationDimensionSequence(0x0078, 0x00b0);
+    Tag const ImplantTemplateGroupVariationDimensionName(0x0078, 0x00b2);
+    Tag const ImplantTemplateGroupVariationDimensionRankSequence(0x0078, 0x00b4);
+    Tag const ReferencedImplantTemplateGroupMemberID(0x0078, 0x00b6);
+    Tag const ImplantTemplateGroupVariationDimensionRank(0x0078, 0x00b8);
+    Tag const SurfaceScanAcquisitionTypeCodeSequence(0x0080, 0x0001);
+    Tag const SurfaceScanModeCodeSequence(0x0080, 0x0002);
+    Tag const RegistrationMethodCodeSequence(0x0080, 0x0003);
+    Tag const ShotDurationTime(0x0080, 0x0004);
+    Tag const ShotOffsetTime(0x0080, 0x0005);
+    Tag const SurfacePointPresentationValueData(0x0080, 0x0006);
+    Tag const SurfacePointColorCIELabValueData(0x0080, 0x0007);
+    Tag const UVMappingSequence(0x0080, 0x0008);
+    Tag const TextureLabel(0x0080, 0x0009);
+    Tag const UValueData(0x0080, 0x0010);
+    Tag const VValueData(0x0080, 0x0011);
+    Tag const ReferencedTextureSequence(0x0080, 0x0012);
+    Tag const ReferencedSurfaceDataSequence(0x0080, 0x0013);
+    Tag const StorageMediaFileSetID(0x0088, 0x0130);
+    Tag const StorageMediaFileSetUID(0x0088, 0x0140);
+    Tag const IconImageSequence(0x0088, 0x0200);
+    Tag const TopicTitle(0x0088, 0x0904);
+    Tag const TopicSubject(0x0088, 0x0906);
+    Tag const TopicAuthor(0x0088, 0x0910);
+    Tag const TopicKeywords(0x0088, 0x0912);
+    Tag const SOPInstanceStatus(0x0100, 0x0410);
+    Tag const SOPAuthorizationDateTime(0x0100, 0x0420);
+    Tag const SOPAuthorizationComment(0x0100, 0x0424);
+    Tag const AuthorizationEquipmentCertificationNumber(0x0100, 0x0426);
+    Tag const MACIDNumber(0x0400, 0x0005);
+    Tag const MACCalculationTransferSyntaxUID(0x0400, 0x0010);
+    Tag const MACAlgorithm(0x0400, 0x0015);
+    Tag const DataElementsSigned(0x0400, 0x0020);
+    Tag const DigitalSignatureUID(0x0400, 0x0100);
+    Tag const DigitalSignatureDateTime(0x0400, 0x0105);
+    Tag const CertificateType(0x0400, 0x0110);
+    Tag const CertificateOfSigner(0x0400, 0x0115);
+    Tag const Signature(0x0400, 0x0120);
+    Tag const CertifiedTimestampType(0x0400, 0x0305);
+    Tag const CertifiedTimestamp(0x0400, 0x0310);
+    Tag const DigitalSignaturePurposeCodeSequence(0x0400, 0x0401);
+    Tag const ReferencedDigitalSignatureSequence(0x0400, 0x0402);
+    Tag const ReferencedSOPInstanceMACSequence(0x0400, 0x0403);
+    Tag const MAC(0x0400, 0x0404);
+    Tag const EncryptedAttributesSequence(0x0400, 0x0500);
+    Tag const EncryptedContentTransferSyntaxUID(0x0400, 0x0510);
+    Tag const EncryptedContent(0x0400, 0x0520);
+    Tag const ModifiedAttributesSequence(0x0400, 0x0550);
+    Tag const OriginalAttributesSequence(0x0400, 0x0561);
+    Tag const AttributeModificationDateTime(0x0400, 0x0562);
+    Tag const ModifyingSystem(0x0400, 0x0563);
+    Tag const SourceOfPreviousValues(0x0400, 0x0564);
+    Tag const ReasonForTheAttributeModification(0x0400, 0x0565);
+    Tag const NumberOfCopies(0x2000, 0x0010);
+    Tag const PrinterConfigurationSequence(0x2000, 0x001e);
+    Tag const PrintPriority(0x2000, 0x0020);
+    Tag const MediumType(0x2000, 0x0030);
+    Tag const FilmDestination(0x2000, 0x0040);
+    Tag const FilmSessionLabel(0x2000, 0x0050);
+    Tag const MemoryAllocation(0x2000, 0x0060);
+    Tag const MaximumMemoryAllocation(0x2000, 0x0061);
+    Tag const ColorImagePrintingFlag(0x2000, 0x0062);
+    Tag const CollationFlag(0x2000, 0x0063);
+    Tag const AnnotationFlag(0x2000, 0x0065);
+    Tag const ImageOverlayFlag(0x2000, 0x0067);
+    Tag const PresentationLUTFlag(0x2000, 0x0069);
+    Tag const ImageBoxPresentationLUTFlag(0x2000, 0x006a);
+    Tag const MemoryBitDepth(0x2000, 0x00a0);
+    Tag const PrintingBitDepth(0x2000, 0x00a1);
+    Tag const MediaInstalledSequence(0x2000, 0x00a2);
+    Tag const OtherMediaAvailableSequence(0x2000, 0x00a4);
+    Tag const SupportedImageDisplayFormatsSequence(0x2000, 0x00a8);
+    Tag const ReferencedFilmBoxSequence(0x2000, 0x0500);
+    Tag const ReferencedStoredPrintSequence(0x2000, 0x0510);
+    Tag const ImageDisplayFormat(0x2010, 0x0010);
+    Tag const AnnotationDisplayFormatID(0x2010, 0x0030);
+    Tag const FilmOrientation(0x2010, 0x0040);
+    Tag const FilmSizeID(0x2010, 0x0050);
+    Tag const PrinterResolutionID(0x2010, 0x0052);
+    Tag const DefaultPrinterResolutionID(0x2010, 0x0054);
+    Tag const MagnificationType(0x2010, 0x0060);
+    Tag const SmoothingType(0x2010, 0x0080);
+    Tag const DefaultMagnificationType(0x2010, 0x00a6);
+    Tag const OtherMagnificationTypesAvailable(0x2010, 0x00a7);
+    Tag const DefaultSmoothingType(0x2010, 0x00a8);
+    Tag const OtherSmoothingTypesAvailable(0x2010, 0x00a9);
+    Tag const BorderDensity(0x2010, 0x0100);
+    Tag const EmptyImageDensity(0x2010, 0x0110);
+    Tag const MinDensity(0x2010, 0x0120);
+    Tag const MaxDensity(0x2010, 0x0130);
+    Tag const Trim(0x2010, 0x0140);
+    Tag const ConfigurationInformation(0x2010, 0x0150);
+    Tag const ConfigurationInformationDescription(0x2010, 0x0152);
+    Tag const MaximumCollatedFilms(0x2010, 0x0154);
+    Tag const Illumination(0x2010, 0x015e);
+    Tag const ReflectedAmbientLight(0x2010, 0x0160);
+    Tag const PrinterPixelSpacing(0x2010, 0x0376);
+    Tag const ReferencedFilmSessionSequence(0x2010, 0x0500);
+    Tag const ReferencedImageBoxSequence(0x2010, 0x0510);
+    Tag const ReferencedBasicAnnotationBoxSequence(0x2010, 0x0520);
+    Tag const ImageBoxPosition(0x2020, 0x0010);
+    Tag const Polarity(0x2020, 0x0020);
+    Tag const RequestedImageSize(0x2020, 0x0030);
+    Tag const RequestedDecimateCropBehavior(0x2020, 0x0040);
+    Tag const RequestedResolutionID(0x2020, 0x0050);
+    Tag const RequestedImageSizeFlag(0x2020, 0x00a0);
+    Tag const DecimateCropResult(0x2020, 0x00a2);
+    Tag const BasicGrayscaleImageSequence(0x2020, 0x0110);
+    Tag const BasicColorImageSequence(0x2020, 0x0111);
+    Tag const ReferencedImageOverlayBoxSequence(0x2020, 0x0130);
+    Tag const ReferencedVOILUTBoxSequence(0x2020, 0x0140);
+    Tag const AnnotationPosition(0x2030, 0x0010);
+    Tag const TextString(0x2030, 0x0020);
+    Tag const ReferencedOverlayPlaneSequence(0x2040, 0x0010);
+    Tag const ReferencedOverlayPlaneGroups(0x2040, 0x0011);
+    Tag const OverlayPixelDataSequence(0x2040, 0x0020);
+    Tag const OverlayMagnificationType(0x2040, 0x0060);
+    Tag const OverlaySmoothingType(0x2040, 0x0070);
+    Tag const OverlayOrImageMagnification(0x2040, 0x0072);
+    Tag const MagnifyToNumberOfColumns(0x2040, 0x0074);
+    Tag const OverlayForegroundDensity(0x2040, 0x0080);
+    Tag const OverlayBackgroundDensity(0x2040, 0x0082);
+    Tag const OverlayMode(0x2040, 0x0090);
+    Tag const ThresholdDensity(0x2040, 0x0100);
+    Tag const ReferencedImageBoxSequenceRetired(0x2040, 0x0500);
+    Tag const PresentationLUTSequence(0x2050, 0x0010);
+    Tag const PresentationLUTShape(0x2050, 0x0020);
+    Tag const ReferencedPresentationLUTSequence(0x2050, 0x0500);
+    Tag const PrintJobID(0x2100, 0x0010);
+    Tag const ExecutionStatus(0x2100, 0x0020);
+    Tag const ExecutionStatusInfo(0x2100, 0x0030);
+    Tag const CreationDate(0x2100, 0x0040);
+    Tag const CreationTime(0x2100, 0x0050);
+    Tag const Originator(0x2100, 0x0070);
+    Tag const DestinationAE(0x2100, 0x0140);
+    Tag const OwnerID(0x2100, 0x0160);
+    Tag const NumberOfFilms(0x2100, 0x0170);
+    Tag const ReferencedPrintJobSequencePullStoredPrint(0x2100, 0x0500);
+    Tag const PrinterStatus(0x2110, 0x0010);
+    Tag const PrinterStatusInfo(0x2110, 0x0020);
+    Tag const PrinterName(0x2110, 0x0030);
+    Tag const PrintQueueID(0x2110, 0x0099);
+    Tag const QueueStatus(0x2120, 0x0010);
+    Tag const PrintJobDescriptionSequence(0x2120, 0x0050);
+    Tag const ReferencedPrintJobSequence(0x2120, 0x0070);
+    Tag const PrintManagementCapabilitiesSequence(0x2130, 0x0010);
+    Tag const PrinterCharacteristicsSequence(0x2130, 0x0015);
+    Tag const FilmBoxContentSequence(0x2130, 0x0030);
+    Tag const ImageBoxContentSequence(0x2130, 0x0040);
+    Tag const AnnotationContentSequence(0x2130, 0x0050);
+    Tag const ImageOverlayBoxContentSequence(0x2130, 0x0060);
+    Tag const PresentationLUTContentSequence(0x2130, 0x0080);
+    Tag const ProposedStudySequence(0x2130, 0x00a0);
+    Tag const OriginalImageSequence(0x2130, 0x00c0);
+    Tag const LabelUsingInformationExtractedFromInstances(0x2200, 0x0001);
+    Tag const LabelText(0x2200, 0x0002);
+    Tag const LabelStyleSelection(0x2200, 0x0003);
+    Tag const MediaDisposition(0x2200, 0x0004);
+    Tag const BarcodeValue(0x2200, 0x0005);
+    Tag const BarcodeSymbology(0x2200, 0x0006);
+    Tag const AllowMediaSplitting(0x2200, 0x0007);
+    Tag const IncludeNonDICOMObjects(0x2200, 0x0008);
+    Tag const IncludeDisplayApplication(0x2200, 0x0009);
+    Tag const PreserveCompositeInstancesAfterMediaCreation(0x2200, 0x000a);
+    Tag const TotalNumberOfPiecesOfMediaCreated(0x2200, 0x000b);
+    Tag const RequestedMediaApplicationProfile(0x2200, 0x000c);
+    Tag const ReferencedStorageMediaSequence(0x2200, 0x000d);
+    Tag const FailureAttributes(0x2200, 0x000e);
+    Tag const AllowLossyCompression(0x2200, 0x000f);
+    Tag const RequestPriority(0x2200, 0x0020);
+    Tag const RTImageLabel(0x3002, 0x0002);
+    Tag const RTImageName(0x3002, 0x0003);
+    Tag const RTImageDescription(0x3002, 0x0004);
+    Tag const ReportedValuesOrigin(0x3002, 0x000a);
+    Tag const RTImagePlane(0x3002, 0x000c);
+    Tag const XRayImageReceptorTranslation(0x3002, 0x000d);
+    Tag const XRayImageReceptorAngle(0x3002, 0x000e);
+    Tag const RTImageOrientation(0x3002, 0x0010);
+    Tag const ImagePlanePixelSpacing(0x3002, 0x0011);
+    Tag const RTImagePosition(0x3002, 0x0012);
+    Tag const RadiationMachineName(0x3002, 0x0020);
+    Tag const RadiationMachineSAD(0x3002, 0x0022);
+    Tag const RadiationMachineSSD(0x3002, 0x0024);
+    Tag const RTImageSID(0x3002, 0x0026);
+    Tag const SourceToReferenceObjectDistance(0x3002, 0x0028);
+    Tag const FractionNumber(0x3002, 0x0029);
+    Tag const ExposureSequence(0x3002, 0x0030);
+    Tag const MetersetExposure(0x3002, 0x0032);
+    Tag const DiaphragmPosition(0x3002, 0x0034);
+    Tag const FluenceMapSequence(0x3002, 0x0040);
+    Tag const FluenceDataSource(0x3002, 0x0041);
+    Tag const FluenceDataScale(0x3002, 0x0042);
+    Tag const PrimaryFluenceModeSequence(0x3002, 0x0050);
+    Tag const FluenceMode(0x3002, 0x0051);
+    Tag const FluenceModeID(0x3002, 0x0052);
+    Tag const DVHType(0x3004, 0x0001);
+    Tag const DoseUnits(0x3004, 0x0002);
+    Tag const DoseType(0x3004, 0x0004);
+    Tag const SpatialTransformOfDose(0x3004, 0x0005);
+    Tag const DoseComment(0x3004, 0x0006);
+    Tag const NormalizationPoint(0x3004, 0x0008);
+    Tag const DoseSummationType(0x3004, 0x000a);
+    Tag const GridFrameOffsetVector(0x3004, 0x000c);
+    Tag const DoseGridScaling(0x3004, 0x000e);
+    Tag const RTDoseROISequence(0x3004, 0x0010);
+    Tag const DoseValue(0x3004, 0x0012);
+    Tag const TissueHeterogeneityCorrection(0x3004, 0x0014);
+    Tag const DVHNormalizationPoint(0x3004, 0x0040);
+    Tag const DVHNormalizationDoseValue(0x3004, 0x0042);
+    Tag const DVHSequence(0x3004, 0x0050);
+    Tag const DVHDoseScaling(0x3004, 0x0052);
+    Tag const DVHVolumeUnits(0x3004, 0x0054);
+    Tag const DVHNumberOfBins(0x3004, 0x0056);
+    Tag const DVHData(0x3004, 0x0058);
+    Tag const DVHReferencedROISequence(0x3004, 0x0060);
+    Tag const DVHROIContributionType(0x3004, 0x0062);
+    Tag const DVHMinimumDose(0x3004, 0x0070);
+    Tag const DVHMaximumDose(0x3004, 0x0072);
+    Tag const DVHMeanDose(0x3004, 0x0074);
+    Tag const StructureSetLabel(0x3006, 0x0002);
+    Tag const StructureSetName(0x3006, 0x0004);
+    Tag const StructureSetDescription(0x3006, 0x0006);
+    Tag const StructureSetDate(0x3006, 0x0008);
+    Tag const StructureSetTime(0x3006, 0x0009);
+    Tag const ReferencedFrameOfReferenceSequence(0x3006, 0x0010);
+    Tag const RTReferencedStudySequence(0x3006, 0x0012);
+    Tag const RTReferencedSeriesSequence(0x3006, 0x0014);
+    Tag const ContourImageSequence(0x3006, 0x0016);
+    Tag const PredecessorStructureSetSequence(0x3006, 0x0018);
+    Tag const StructureSetROISequence(0x3006, 0x0020);
+    Tag const ROINumber(0x3006, 0x0022);
+    Tag const ReferencedFrameOfReferenceUID(0x3006, 0x0024);
+    Tag const ROIName(0x3006, 0x0026);
+    Tag const ROIDescription(0x3006, 0x0028);
+    Tag const ROIDisplayColor(0x3006, 0x002a);
+    Tag const ROIVolume(0x3006, 0x002c);
+    Tag const RTRelatedROISequence(0x3006, 0x0030);
+    Tag const RTROIRelationship(0x3006, 0x0033);
+    Tag const ROIGenerationAlgorithm(0x3006, 0x0036);
+    Tag const ROIGenerationDescription(0x3006, 0x0038);
+    Tag const ROIContourSequence(0x3006, 0x0039);
+    Tag const ContourSequence(0x3006, 0x0040);
+    Tag const ContourGeometricType(0x3006, 0x0042);
+    Tag const ContourSlabThickness(0x3006, 0x0044);
+    Tag const ContourOffsetVector(0x3006, 0x0045);
+    Tag const NumberOfContourPoints(0x3006, 0x0046);
+    Tag const ContourNumber(0x3006, 0x0048);
+    Tag const AttachedContours(0x3006, 0x0049);
+    Tag const ContourData(0x3006, 0x0050);
+    Tag const RTROIObservationsSequence(0x3006, 0x0080);
+    Tag const ObservationNumber(0x3006, 0x0082);
+    Tag const ReferencedROINumber(0x3006, 0x0084);
+    Tag const ROIObservationLabel(0x3006, 0x0085);
+    Tag const RTROIIdentificationCodeSequence(0x3006, 0x0086);
+    Tag const ROIObservationDescription(0x3006, 0x0088);
+    Tag const RelatedRTROIObservationsSequence(0x3006, 0x00a0);
+    Tag const RTROIInterpretedType(0x3006, 0x00a4);
+    Tag const ROIInterpreter(0x3006, 0x00a6);
+    Tag const ROIPhysicalPropertiesSequence(0x3006, 0x00b0);
+    Tag const ROIPhysicalProperty(0x3006, 0x00b2);
+    Tag const ROIPhysicalPropertyValue(0x3006, 0x00b4);
+    Tag const ROIElementalCompositionSequence(0x3006, 0x00b6);
+    Tag const ROIElementalCompositionAtomicNumber(0x3006, 0x00b7);
+    Tag const ROIElementalCompositionAtomicMassFraction(0x3006, 0x00b8);
+    Tag const AdditionalRTROIIdentificationCodeSequence(0x3006, 0x00b9);
+    Tag const FrameOfReferenceRelationshipSequence(0x3006, 0x00c0);
+    Tag const RelatedFrameOfReferenceUID(0x3006, 0x00c2);
+    Tag const FrameOfReferenceTransformationType(0x3006, 0x00c4);
+    Tag const FrameOfReferenceTransformationMatrix(0x3006, 0x00c6);
+    Tag const FrameOfReferenceTransformationComment(0x3006, 0x00c8);
+    Tag const MeasuredDoseReferenceSequence(0x3008, 0x0010);
+    Tag const MeasuredDoseDescription(0x3008, 0x0012);
+    Tag const MeasuredDoseType(0x3008, 0x0014);
+    Tag const MeasuredDoseValue(0x3008, 0x0016);
+    Tag const TreatmentSessionBeamSequence(0x3008, 0x0020);
+    Tag const TreatmentSessionIonBeamSequence(0x3008, 0x0021);
+    Tag const CurrentFractionNumber(0x3008, 0x0022);
+    Tag const TreatmentControlPointDate(0x3008, 0x0024);
+    Tag const TreatmentControlPointTime(0x3008, 0x0025);
+    Tag const TreatmentTerminationStatus(0x3008, 0x002a);
+    Tag const TreatmentTerminationCode(0x3008, 0x002b);
+    Tag const TreatmentVerificationStatus(0x3008, 0x002c);
+    Tag const ReferencedTreatmentRecordSequence(0x3008, 0x0030);
+    Tag const SpecifiedPrimaryMeterset(0x3008, 0x0032);
+    Tag const SpecifiedSecondaryMeterset(0x3008, 0x0033);
+    Tag const DeliveredPrimaryMeterset(0x3008, 0x0036);
+    Tag const DeliveredSecondaryMeterset(0x3008, 0x0037);
+    Tag const SpecifiedTreatmentTime(0x3008, 0x003a);
+    Tag const DeliveredTreatmentTime(0x3008, 0x003b);
+    Tag const ControlPointDeliverySequence(0x3008, 0x0040);
+    Tag const IonControlPointDeliverySequence(0x3008, 0x0041);
+    Tag const SpecifiedMeterset(0x3008, 0x0042);
+    Tag const DeliveredMeterset(0x3008, 0x0044);
+    Tag const MetersetRateSet(0x3008, 0x0045);
+    Tag const MetersetRateDelivered(0x3008, 0x0046);
+    Tag const ScanSpotMetersetsDelivered(0x3008, 0x0047);
+    Tag const DoseRateDelivered(0x3008, 0x0048);
+    Tag const TreatmentSummaryCalculatedDoseReferenceSequence(0x3008, 0x0050);
+    Tag const CumulativeDoseToDoseReference(0x3008, 0x0052);
+    Tag const FirstTreatmentDate(0x3008, 0x0054);
+    Tag const MostRecentTreatmentDate(0x3008, 0x0056);
+    Tag const NumberOfFractionsDelivered(0x3008, 0x005a);
+    Tag const OverrideSequence(0x3008, 0x0060);
+    Tag const ParameterSequencePointer(0x3008, 0x0061);
+    Tag const OverrideParameterPointer(0x3008, 0x0062);
+    Tag const ParameterItemIndex(0x3008, 0x0063);
+    Tag const MeasuredDoseReferenceNumber(0x3008, 0x0064);
+    Tag const ParameterPointer(0x3008, 0x0065);
+    Tag const OverrideReason(0x3008, 0x0066);
+    Tag const CorrectedParameterSequence(0x3008, 0x0068);
+    Tag const CorrectionValue(0x3008, 0x006a);
+    Tag const CalculatedDoseReferenceSequence(0x3008, 0x0070);
+    Tag const CalculatedDoseReferenceNumber(0x3008, 0x0072);
+    Tag const CalculatedDoseReferenceDescription(0x3008, 0x0074);
+    Tag const CalculatedDoseReferenceDoseValue(0x3008, 0x0076);
+    Tag const StartMeterset(0x3008, 0x0078);
+    Tag const EndMeterset(0x3008, 0x007a);
+    Tag const ReferencedMeasuredDoseReferenceSequence(0x3008, 0x0080);
+    Tag const ReferencedMeasuredDoseReferenceNumber(0x3008, 0x0082);
+    Tag const ReferencedCalculatedDoseReferenceSequence(0x3008, 0x0090);
+    Tag const ReferencedCalculatedDoseReferenceNumber(0x3008, 0x0092);
+    Tag const BeamLimitingDeviceLeafPairsSequence(0x3008, 0x00a0);
+    Tag const RecordedWedgeSequence(0x3008, 0x00b0);
+    Tag const RecordedCompensatorSequence(0x3008, 0x00c0);
+    Tag const RecordedBlockSequence(0x3008, 0x00d0);
+    Tag const TreatmentSummaryMeasuredDoseReferenceSequence(0x3008, 0x00e0);
+    Tag const RecordedSnoutSequence(0x3008, 0x00f0);
+    Tag const RecordedRangeShifterSequence(0x3008, 0x00f2);
+    Tag const RecordedLateralSpreadingDeviceSequence(0x3008, 0x00f4);
+    Tag const RecordedRangeModulatorSequence(0x3008, 0x00f6);
+    Tag const RecordedSourceSequence(0x3008, 0x0100);
+    Tag const SourceSerialNumber(0x3008, 0x0105);
+    Tag const TreatmentSessionApplicationSetupSequence(0x3008, 0x0110);
+    Tag const ApplicationSetupCheck(0x3008, 0x0116);
+    Tag const RecordedBrachyAccessoryDeviceSequence(0x3008, 0x0120);
+    Tag const ReferencedBrachyAccessoryDeviceNumber(0x3008, 0x0122);
+    Tag const RecordedChannelSequence(0x3008, 0x0130);
+    Tag const SpecifiedChannelTotalTime(0x3008, 0x0132);
+    Tag const DeliveredChannelTotalTime(0x3008, 0x0134);
+    Tag const SpecifiedNumberOfPulses(0x3008, 0x0136);
+    Tag const DeliveredNumberOfPulses(0x3008, 0x0138);
+    Tag const SpecifiedPulseRepetitionInterval(0x3008, 0x013a);
+    Tag const DeliveredPulseRepetitionInterval(0x3008, 0x013c);
+    Tag const RecordedSourceApplicatorSequence(0x3008, 0x0140);
+    Tag const ReferencedSourceApplicatorNumber(0x3008, 0x0142);
+    Tag const RecordedChannelShieldSequence(0x3008, 0x0150);
+    Tag const ReferencedChannelShieldNumber(0x3008, 0x0152);
+    Tag const BrachyControlPointDeliveredSequence(0x3008, 0x0160);
+    Tag const SafePositionExitDate(0x3008, 0x0162);
+    Tag const SafePositionExitTime(0x3008, 0x0164);
+    Tag const SafePositionReturnDate(0x3008, 0x0166);
+    Tag const SafePositionReturnTime(0x3008, 0x0168);
+    Tag const PulseSpecificBrachyControlPointDeliveredSequence(0x3008, 0x0171);
+    Tag const PulseNumber(0x3008, 0x0172);
+    Tag const BrachyPulseControlPointDeliveredSequence(0x3008, 0x0173);
+    Tag const CurrentTreatmentStatus(0x3008, 0x0200);
+    Tag const TreatmentStatusComment(0x3008, 0x0202);
+    Tag const FractionGroupSummarySequence(0x3008, 0x0220);
+    Tag const ReferencedFractionNumber(0x3008, 0x0223);
+    Tag const FractionGroupType(0x3008, 0x0224);
+    Tag const BeamStopperPosition(0x3008, 0x0230);
+    Tag const FractionStatusSummarySequence(0x3008, 0x0240);
+    Tag const TreatmentDate(0x3008, 0x0250);
+    Tag const TreatmentTime(0x3008, 0x0251);
+    Tag const RTPlanLabel(0x300a, 0x0002);
+    Tag const RTPlanName(0x300a, 0x0003);
+    Tag const RTPlanDescription(0x300a, 0x0004);
+    Tag const RTPlanDate(0x300a, 0x0006);
+    Tag const RTPlanTime(0x300a, 0x0007);
+    Tag const TreatmentProtocols(0x300a, 0x0009);
+    Tag const PlanIntent(0x300a, 0x000a);
+    Tag const TreatmentSites(0x300a, 0x000b);
+    Tag const RTPlanGeometry(0x300a, 0x000c);
+    Tag const PrescriptionDescription(0x300a, 0x000e);
+    Tag const DoseReferenceSequence(0x300a, 0x0010);
+    Tag const DoseReferenceNumber(0x300a, 0x0012);
+    Tag const DoseReferenceUID(0x300a, 0x0013);
+    Tag const DoseReferenceStructureType(0x300a, 0x0014);
+    Tag const NominalBeamEnergyUnit(0x300a, 0x0015);
+    Tag const DoseReferenceDescription(0x300a, 0x0016);
+    Tag const DoseReferencePointCoordinates(0x300a, 0x0018);
+    Tag const NominalPriorDose(0x300a, 0x001a);
+    Tag const DoseReferenceType(0x300a, 0x0020);
+    Tag const ConstraintWeight(0x300a, 0x0021);
+    Tag const DeliveryWarningDose(0x300a, 0x0022);
+    Tag const DeliveryMaximumDose(0x300a, 0x0023);
+    Tag const TargetMinimumDose(0x300a, 0x0025);
+    Tag const TargetPrescriptionDose(0x300a, 0x0026);
+    Tag const TargetMaximumDose(0x300a, 0x0027);
+    Tag const TargetUnderdoseVolumeFraction(0x300a, 0x0028);
+    Tag const OrganAtRiskFullVolumeDose(0x300a, 0x002a);
+    Tag const OrganAtRiskLimitDose(0x300a, 0x002b);
+    Tag const OrganAtRiskMaximumDose(0x300a, 0x002c);
+    Tag const OrganAtRiskOverdoseVolumeFraction(0x300a, 0x002d);
+    Tag const ToleranceTableSequence(0x300a, 0x0040);
+    Tag const ToleranceTableNumber(0x300a, 0x0042);
+    Tag const ToleranceTableLabel(0x300a, 0x0043);
+    Tag const GantryAngleTolerance(0x300a, 0x0044);
+    Tag const BeamLimitingDeviceAngleTolerance(0x300a, 0x0046);
+    Tag const BeamLimitingDeviceToleranceSequence(0x300a, 0x0048);
+    Tag const BeamLimitingDevicePositionTolerance(0x300a, 0x004a);
+    Tag const SnoutPositionTolerance(0x300a, 0x004b);
+    Tag const PatientSupportAngleTolerance(0x300a, 0x004c);
+    Tag const TableTopEccentricAngleTolerance(0x300a, 0x004e);
+    Tag const TableTopPitchAngleTolerance(0x300a, 0x004f);
+    Tag const TableTopRollAngleTolerance(0x300a, 0x0050);
+    Tag const TableTopVerticalPositionTolerance(0x300a, 0x0051);
+    Tag const TableTopLongitudinalPositionTolerance(0x300a, 0x0052);
+    Tag const TableTopLateralPositionTolerance(0x300a, 0x0053);
+    Tag const RTPlanRelationship(0x300a, 0x0055);
+    Tag const FractionGroupSequence(0x300a, 0x0070);
+    Tag const FractionGroupNumber(0x300a, 0x0071);
+    Tag const FractionGroupDescription(0x300a, 0x0072);
+    Tag const NumberOfFractionsPlanned(0x300a, 0x0078);
+    Tag const NumberOfFractionPatternDigitsPerDay(0x300a, 0x0079);
+    Tag const RepeatFractionCycleLength(0x300a, 0x007a);
+    Tag const FractionPattern(0x300a, 0x007b);
+    Tag const NumberOfBeams(0x300a, 0x0080);
+    Tag const BeamDoseSpecificationPoint(0x300a, 0x0082);
+    Tag const BeamDose(0x300a, 0x0084);
+    Tag const BeamMeterset(0x300a, 0x0086);
+    Tag const BeamDosePointDepth(0x300a, 0x0088);
+    Tag const BeamDosePointEquivalentDepth(0x300a, 0x0089);
+    Tag const BeamDosePointSSD(0x300a, 0x008a);
+    Tag const BeamDoseMeaning(0x300a, 0x008b);
+    Tag const BeamDoseVerificationControlPointSequence(0x300a, 0x008c);
+    Tag const AverageBeamDosePointDepth(0x300a, 0x008d);
+    Tag const AverageBeamDosePointEquivalentDepth(0x300a, 0x008e);
+    Tag const AverageBeamDosePointSSD(0x300a, 0x008f);
+    Tag const NumberOfBrachyApplicationSetups(0x300a, 0x00a0);
+    Tag const BrachyApplicationSetupDoseSpecificationPoint(0x300a, 0x00a2);
+    Tag const BrachyApplicationSetupDose(0x300a, 0x00a4);
+    Tag const BeamSequence(0x300a, 0x00b0);
+    Tag const TreatmentMachineName(0x300a, 0x00b2);
+    Tag const PrimaryDosimeterUnit(0x300a, 0x00b3);
+    Tag const SourceAxisDistance(0x300a, 0x00b4);
+    Tag const BeamLimitingDeviceSequence(0x300a, 0x00b6);
+    Tag const RTBeamLimitingDeviceType(0x300a, 0x00b8);
+    Tag const SourceToBeamLimitingDeviceDistance(0x300a, 0x00ba);
+    Tag const IsocenterToBeamLimitingDeviceDistance(0x300a, 0x00bb);
+    Tag const NumberOfLeafJawPairs(0x300a, 0x00bc);
+    Tag const LeafPositionBoundaries(0x300a, 0x00be);
+    Tag const BeamNumber(0x300a, 0x00c0);
+    Tag const BeamName(0x300a, 0x00c2);
+    Tag const BeamDescription(0x300a, 0x00c3);
+    Tag const BeamType(0x300a, 0x00c4);
+    Tag const BeamDeliveryDurationLimit(0x300a, 0x00c5);
+    Tag const RadiationType(0x300a, 0x00c6);
+    Tag const HighDoseTechniqueType(0x300a, 0x00c7);
+    Tag const ReferenceImageNumber(0x300a, 0x00c8);
+    Tag const PlannedVerificationImageSequence(0x300a, 0x00ca);
+    Tag const ImagingDeviceSpecificAcquisitionParameters(0x300a, 0x00cc);
+    Tag const TreatmentDeliveryType(0x300a, 0x00ce);
+    Tag const NumberOfWedges(0x300a, 0x00d0);
+    Tag const WedgeSequence(0x300a, 0x00d1);
+    Tag const WedgeNumber(0x300a, 0x00d2);
+    Tag const WedgeType(0x300a, 0x00d3);
+    Tag const WedgeID(0x300a, 0x00d4);
+    Tag const WedgeAngle(0x300a, 0x00d5);
+    Tag const WedgeFactor(0x300a, 0x00d6);
+    Tag const TotalWedgeTrayWaterEquivalentThickness(0x300a, 0x00d7);
+    Tag const WedgeOrientation(0x300a, 0x00d8);
+    Tag const IsocenterToWedgeTrayDistance(0x300a, 0x00d9);
+    Tag const SourceToWedgeTrayDistance(0x300a, 0x00da);
+    Tag const WedgeThinEdgePosition(0x300a, 0x00db);
+    Tag const BolusID(0x300a, 0x00dc);
+    Tag const BolusDescription(0x300a, 0x00dd);
+    Tag const EffectiveWedgeAngle(0x300a, 0x00de);
+    Tag const NumberOfCompensators(0x300a, 0x00e0);
+    Tag const MaterialID(0x300a, 0x00e1);
+    Tag const TotalCompensatorTrayFactor(0x300a, 0x00e2);
+    Tag const CompensatorSequence(0x300a, 0x00e3);
+    Tag const CompensatorNumber(0x300a, 0x00e4);
+    Tag const CompensatorID(0x300a, 0x00e5);
+    Tag const SourceToCompensatorTrayDistance(0x300a, 0x00e6);
+    Tag const CompensatorRows(0x300a, 0x00e7);
+    Tag const CompensatorColumns(0x300a, 0x00e8);
+    Tag const CompensatorPixelSpacing(0x300a, 0x00e9);
+    Tag const CompensatorPosition(0x300a, 0x00ea);
+    Tag const CompensatorTransmissionData(0x300a, 0x00eb);
+    Tag const CompensatorThicknessData(0x300a, 0x00ec);
+    Tag const NumberOfBoli(0x300a, 0x00ed);
+    Tag const CompensatorType(0x300a, 0x00ee);
+    Tag const CompensatorTrayID(0x300a, 0x00ef);
+    Tag const NumberOfBlocks(0x300a, 0x00f0);
+    Tag const TotalBlockTrayFactor(0x300a, 0x00f2);
+    Tag const TotalBlockTrayWaterEquivalentThickness(0x300a, 0x00f3);
+    Tag const BlockSequence(0x300a, 0x00f4);
+    Tag const BlockTrayID(0x300a, 0x00f5);
+    Tag const SourceToBlockTrayDistance(0x300a, 0x00f6);
+    Tag const IsocenterToBlockTrayDistance(0x300a, 0x00f7);
+    Tag const BlockType(0x300a, 0x00f8);
+    Tag const AccessoryCode(0x300a, 0x00f9);
+    Tag const BlockDivergence(0x300a, 0x00fa);
+    Tag const BlockMountingPosition(0x300a, 0x00fb);
+    Tag const BlockNumber(0x300a, 0x00fc);
+    Tag const BlockName(0x300a, 0x00fe);
+    Tag const BlockThickness(0x300a, 0x0100);
+    Tag const BlockTransmission(0x300a, 0x0102);
+    Tag const BlockNumberOfPoints(0x300a, 0x0104);
+    Tag const BlockData(0x300a, 0x0106);
+    Tag const ApplicatorSequence(0x300a, 0x0107);
+    Tag const ApplicatorID(0x300a, 0x0108);
+    Tag const ApplicatorType(0x300a, 0x0109);
+    Tag const ApplicatorDescription(0x300a, 0x010a);
+    Tag const CumulativeDoseReferenceCoefficient(0x300a, 0x010c);
+    Tag const FinalCumulativeMetersetWeight(0x300a, 0x010e);
+    Tag const NumberOfControlPoints(0x300a, 0x0110);
+    Tag const ControlPointSequence(0x300a, 0x0111);
+    Tag const ControlPointIndex(0x300a, 0x0112);
+    Tag const NominalBeamEnergy(0x300a, 0x0114);
+    Tag const DoseRateSet(0x300a, 0x0115);
+    Tag const WedgePositionSequence(0x300a, 0x0116);
+    Tag const WedgePosition(0x300a, 0x0118);
+    Tag const BeamLimitingDevicePositionSequence(0x300a, 0x011a);
+    Tag const LeafJawPositions(0x300a, 0x011c);
+    Tag const GantryAngle(0x300a, 0x011e);
+    Tag const GantryRotationDirection(0x300a, 0x011f);
+    Tag const BeamLimitingDeviceAngle(0x300a, 0x0120);
+    Tag const BeamLimitingDeviceRotationDirection(0x300a, 0x0121);
+    Tag const PatientSupportAngle(0x300a, 0x0122);
+    Tag const PatientSupportRotationDirection(0x300a, 0x0123);
+    Tag const TableTopEccentricAxisDistance(0x300a, 0x0124);
+    Tag const TableTopEccentricAngle(0x300a, 0x0125);
+    Tag const TableTopEccentricRotationDirection(0x300a, 0x0126);
+    Tag const TableTopVerticalPosition(0x300a, 0x0128);
+    Tag const TableTopLongitudinalPosition(0x300a, 0x0129);
+    Tag const TableTopLateralPosition(0x300a, 0x012a);
+    Tag const IsocenterPosition(0x300a, 0x012c);
+    Tag const SurfaceEntryPoint(0x300a, 0x012e);
+    Tag const SourceToSurfaceDistance(0x300a, 0x0130);
+    Tag const AverageBeamDosePointSourceToExternalContourSurfaceDistance(0x300a, 0x0131);
+    Tag const SourceToExternalContourDistance(0x300a, 0x0132);
+    Tag const ExternalContourEntryPoint(0x300a, 0x0133);
+    Tag const CumulativeMetersetWeight(0x300a, 0x0134);
+    Tag const TableTopPitchAngle(0x300a, 0x0140);
+    Tag const TableTopPitchRotationDirection(0x300a, 0x0142);
+    Tag const TableTopRollAngle(0x300a, 0x0144);
+    Tag const TableTopRollRotationDirection(0x300a, 0x0146);
+    Tag const HeadFixationAngle(0x300a, 0x0148);
+    Tag const GantryPitchAngle(0x300a, 0x014a);
+    Tag const GantryPitchRotationDirection(0x300a, 0x014c);
+    Tag const GantryPitchAngleTolerance(0x300a, 0x014e);
+    Tag const PatientSetupSequence(0x300a, 0x0180);
+    Tag const PatientSetupNumber(0x300a, 0x0182);
+    Tag const PatientSetupLabel(0x300a, 0x0183);
+    Tag const PatientAdditionalPosition(0x300a, 0x0184);
+    Tag const FixationDeviceSequence(0x300a, 0x0190);
+    Tag const FixationDeviceType(0x300a, 0x0192);
+    Tag const FixationDeviceLabel(0x300a, 0x0194);
+    Tag const FixationDeviceDescription(0x300a, 0x0196);
+    Tag const FixationDevicePosition(0x300a, 0x0198);
+    Tag const FixationDevicePitchAngle(0x300a, 0x0199);
+    Tag const FixationDeviceRollAngle(0x300a, 0x019a);
+    Tag const ShieldingDeviceSequence(0x300a, 0x01a0);
+    Tag const ShieldingDeviceType(0x300a, 0x01a2);
+    Tag const ShieldingDeviceLabel(0x300a, 0x01a4);
+    Tag const ShieldingDeviceDescription(0x300a, 0x01a6);
+    Tag const ShieldingDevicePosition(0x300a, 0x01a8);
+    Tag const SetupTechnique(0x300a, 0x01b0);
+    Tag const SetupTechniqueDescription(0x300a, 0x01b2);
+    Tag const SetupDeviceSequence(0x300a, 0x01b4);
+    Tag const SetupDeviceType(0x300a, 0x01b6);
+    Tag const SetupDeviceLabel(0x300a, 0x01b8);
+    Tag const SetupDeviceDescription(0x300a, 0x01ba);
+    Tag const SetupDeviceParameter(0x300a, 0x01bc);
+    Tag const SetupReferenceDescription(0x300a, 0x01d0);
+    Tag const TableTopVerticalSetupDisplacement(0x300a, 0x01d2);
+    Tag const TableTopLongitudinalSetupDisplacement(0x300a, 0x01d4);
+    Tag const TableTopLateralSetupDisplacement(0x300a, 0x01d6);
+    Tag const BrachyTreatmentTechnique(0x300a, 0x0200);
+    Tag const BrachyTreatmentType(0x300a, 0x0202);
+    Tag const TreatmentMachineSequence(0x300a, 0x0206);
+    Tag const SourceSequence(0x300a, 0x0210);
+    Tag const SourceNumber(0x300a, 0x0212);
+    Tag const SourceType(0x300a, 0x0214);
+    Tag const SourceManufacturer(0x300a, 0x0216);
+    Tag const ActiveSourceDiameter(0x300a, 0x0218);
+    Tag const ActiveSourceLength(0x300a, 0x021a);
+    Tag const SourceModelID(0x300a, 0x021b);
+    Tag const SourceDescription(0x300a, 0x021c);
+    Tag const SourceEncapsulationNominalThickness(0x300a, 0x0222);
+    Tag const SourceEncapsulationNominalTransmission(0x300a, 0x0224);
+    Tag const SourceIsotopeName(0x300a, 0x0226);
+    Tag const SourceIsotopeHalfLife(0x300a, 0x0228);
+    Tag const SourceStrengthUnits(0x300a, 0x0229);
+    Tag const ReferenceAirKermaRate(0x300a, 0x022a);
+    Tag const SourceStrength(0x300a, 0x022b);
+    Tag const SourceStrengthReferenceDate(0x300a, 0x022c);
+    Tag const SourceStrengthReferenceTime(0x300a, 0x022e);
+    Tag const ApplicationSetupSequence(0x300a, 0x0230);
+    Tag const ApplicationSetupType(0x300a, 0x0232);
+    Tag const ApplicationSetupNumber(0x300a, 0x0234);
+    Tag const ApplicationSetupName(0x300a, 0x0236);
+    Tag const ApplicationSetupManufacturer(0x300a, 0x0238);
+    Tag const TemplateNumber(0x300a, 0x0240);
+    Tag const TemplateType(0x300a, 0x0242);
+    Tag const TemplateName(0x300a, 0x0244);
+    Tag const TotalReferenceAirKerma(0x300a, 0x0250);
+    Tag const BrachyAccessoryDeviceSequence(0x300a, 0x0260);
+    Tag const BrachyAccessoryDeviceNumber(0x300a, 0x0262);
+    Tag const BrachyAccessoryDeviceID(0x300a, 0x0263);
+    Tag const BrachyAccessoryDeviceType(0x300a, 0x0264);
+    Tag const BrachyAccessoryDeviceName(0x300a, 0x0266);
+    Tag const BrachyAccessoryDeviceNominalThickness(0x300a, 0x026a);
+    Tag const BrachyAccessoryDeviceNominalTransmission(0x300a, 0x026c);
+    Tag const ChannelSequence(0x300a, 0x0280);
+    Tag const ChannelNumber(0x300a, 0x0282);
+    Tag const ChannelLength(0x300a, 0x0284);
+    Tag const ChannelTotalTime(0x300a, 0x0286);
+    Tag const SourceMovementType(0x300a, 0x0288);
+    Tag const NumberOfPulses(0x300a, 0x028a);
+    Tag const PulseRepetitionInterval(0x300a, 0x028c);
+    Tag const SourceApplicatorNumber(0x300a, 0x0290);
+    Tag const SourceApplicatorID(0x300a, 0x0291);
+    Tag const SourceApplicatorType(0x300a, 0x0292);
+    Tag const SourceApplicatorName(0x300a, 0x0294);
+    Tag const SourceApplicatorLength(0x300a, 0x0296);
+    Tag const SourceApplicatorManufacturer(0x300a, 0x0298);
+    Tag const SourceApplicatorWallNominalThickness(0x300a, 0x029c);
+    Tag const SourceApplicatorWallNominalTransmission(0x300a, 0x029e);
+    Tag const SourceApplicatorStepSize(0x300a, 0x02a0);
+    Tag const TransferTubeNumber(0x300a, 0x02a2);
+    Tag const TransferTubeLength(0x300a, 0x02a4);
+    Tag const ChannelShieldSequence(0x300a, 0x02b0);
+    Tag const ChannelShieldNumber(0x300a, 0x02b2);
+    Tag const ChannelShieldID(0x300a, 0x02b3);
+    Tag const ChannelShieldName(0x300a, 0x02b4);
+    Tag const ChannelShieldNominalThickness(0x300a, 0x02b8);
+    Tag const ChannelShieldNominalTransmission(0x300a, 0x02ba);
+    Tag const FinalCumulativeTimeWeight(0x300a, 0x02c8);
+    Tag const BrachyControlPointSequence(0x300a, 0x02d0);
+    Tag const ControlPointRelativePosition(0x300a, 0x02d2);
+    Tag const ControlPoint3DPosition(0x300a, 0x02d4);
+    Tag const CumulativeTimeWeight(0x300a, 0x02d6);
+    Tag const CompensatorDivergence(0x300a, 0x02e0);
+    Tag const CompensatorMountingPosition(0x300a, 0x02e1);
+    Tag const SourceToCompensatorDistance(0x300a, 0x02e2);
+    Tag const TotalCompensatorTrayWaterEquivalentThickness(0x300a, 0x02e3);
+    Tag const IsocenterToCompensatorTrayDistance(0x300a, 0x02e4);
+    Tag const CompensatorColumnOffset(0x300a, 0x02e5);
+    Tag const IsocenterToCompensatorDistances(0x300a, 0x02e6);
+    Tag const CompensatorRelativeStoppingPowerRatio(0x300a, 0x02e7);
+    Tag const CompensatorMillingToolDiameter(0x300a, 0x02e8);
+    Tag const IonRangeCompensatorSequence(0x300a, 0x02ea);
+    Tag const CompensatorDescription(0x300a, 0x02eb);
+    Tag const RadiationMassNumber(0x300a, 0x0302);
+    Tag const RadiationAtomicNumber(0x300a, 0x0304);
+    Tag const RadiationChargeState(0x300a, 0x0306);
+    Tag const ScanMode(0x300a, 0x0308);
+    Tag const VirtualSourceAxisDistances(0x300a, 0x030a);
+    Tag const SnoutSequence(0x300a, 0x030c);
+    Tag const SnoutPosition(0x300a, 0x030d);
+    Tag const SnoutID(0x300a, 0x030f);
+    Tag const NumberOfRangeShifters(0x300a, 0x0312);
+    Tag const RangeShifterSequence(0x300a, 0x0314);
+    Tag const RangeShifterNumber(0x300a, 0x0316);
+    Tag const RangeShifterID(0x300a, 0x0318);
+    Tag const RangeShifterType(0x300a, 0x0320);
+    Tag const RangeShifterDescription(0x300a, 0x0322);
+    Tag const NumberOfLateralSpreadingDevices(0x300a, 0x0330);
+    Tag const LateralSpreadingDeviceSequence(0x300a, 0x0332);
+    Tag const LateralSpreadingDeviceNumber(0x300a, 0x0334);
+    Tag const LateralSpreadingDeviceID(0x300a, 0x0336);
+    Tag const LateralSpreadingDeviceType(0x300a, 0x0338);
+    Tag const LateralSpreadingDeviceDescription(0x300a, 0x033a);
+    Tag const LateralSpreadingDeviceWaterEquivalentThickness(0x300a, 0x033c);
+    Tag const NumberOfRangeModulators(0x300a, 0x0340);
+    Tag const RangeModulatorSequence(0x300a, 0x0342);
+    Tag const RangeModulatorNumber(0x300a, 0x0344);
+    Tag const RangeModulatorID(0x300a, 0x0346);
+    Tag const RangeModulatorType(0x300a, 0x0348);
+    Tag const RangeModulatorDescription(0x300a, 0x034a);
+    Tag const BeamCurrentModulationID(0x300a, 0x034c);
+    Tag const PatientSupportType(0x300a, 0x0350);
+    Tag const PatientSupportID(0x300a, 0x0352);
+    Tag const PatientSupportAccessoryCode(0x300a, 0x0354);
+    Tag const FixationLightAzimuthalAngle(0x300a, 0x0356);
+    Tag const FixationLightPolarAngle(0x300a, 0x0358);
+    Tag const MetersetRate(0x300a, 0x035a);
+    Tag const RangeShifterSettingsSequence(0x300a, 0x0360);
+    Tag const RangeShifterSetting(0x300a, 0x0362);
+    Tag const IsocenterToRangeShifterDistance(0x300a, 0x0364);
+    Tag const RangeShifterWaterEquivalentThickness(0x300a, 0x0366);
+    Tag const LateralSpreadingDeviceSettingsSequence(0x300a, 0x0370);
+    Tag const LateralSpreadingDeviceSetting(0x300a, 0x0372);
+    Tag const IsocenterToLateralSpreadingDeviceDistance(0x300a, 0x0374);
+    Tag const RangeModulatorSettingsSequence(0x300a, 0x0380);
+    Tag const RangeModulatorGatingStartValue(0x300a, 0x0382);
+    Tag const RangeModulatorGatingStopValue(0x300a, 0x0384);
+    Tag const RangeModulatorGatingStartWaterEquivalentThickness(0x300a, 0x0386);
+    Tag const RangeModulatorGatingStopWaterEquivalentThickness(0x300a, 0x0388);
+    Tag const IsocenterToRangeModulatorDistance(0x300a, 0x038a);
+    Tag const ScanSpotTuneID(0x300a, 0x0390);
+    Tag const NumberOfScanSpotPositions(0x300a, 0x0392);
+    Tag const ScanSpotPositionMap(0x300a, 0x0394);
+    Tag const ScanSpotMetersetWeights(0x300a, 0x0396);
+    Tag const ScanningSpotSize(0x300a, 0x0398);
+    Tag const NumberOfPaintings(0x300a, 0x039a);
+    Tag const IonToleranceTableSequence(0x300a, 0x03a0);
+    Tag const IonBeamSequence(0x300a, 0x03a2);
+    Tag const IonBeamLimitingDeviceSequence(0x300a, 0x03a4);
+    Tag const IonBlockSequence(0x300a, 0x03a6);
+    Tag const IonControlPointSequence(0x300a, 0x03a8);
+    Tag const IonWedgeSequence(0x300a, 0x03aa);
+    Tag const IonWedgePositionSequence(0x300a, 0x03ac);
+    Tag const ReferencedSetupImageSequence(0x300a, 0x0401);
+    Tag const SetupImageComment(0x300a, 0x0402);
+    Tag const MotionSynchronizationSequence(0x300a, 0x0410);
+    Tag const ControlPointOrientation(0x300a, 0x0412);
+    Tag const GeneralAccessorySequence(0x300a, 0x0420);
+    Tag const GeneralAccessoryID(0x300a, 0x0421);
+    Tag const GeneralAccessoryDescription(0x300a, 0x0422);
+    Tag const GeneralAccessoryType(0x300a, 0x0423);
+    Tag const GeneralAccessoryNumber(0x300a, 0x0424);
+    Tag const SourceToGeneralAccessoryDistance(0x300a, 0x0425);
+    Tag const ApplicatorGeometrySequence(0x300a, 0x0431);
+    Tag const ApplicatorApertureShape(0x300a, 0x0432);
+    Tag const ApplicatorOpening(0x300a, 0x0433);
+    Tag const ApplicatorOpeningX(0x300a, 0x0434);
+    Tag const ApplicatorOpeningY(0x300a, 0x0435);
+    Tag const SourceToApplicatorMountingPositionDistance(0x300a, 0x0436);
+    Tag const NumberOfBlockSlabItems(0x300a, 0x0440);
+    Tag const BlockSlabSequence(0x300a, 0x0441);
+    Tag const BlockSlabThickness(0x300a, 0x0442);
+    Tag const BlockSlabNumber(0x300a, 0x0443);
+    Tag const DeviceMotionControlSequence(0x300a, 0x0450);
+    Tag const DeviceMotionExecutionMode(0x300a, 0x0451);
+    Tag const DeviceMotionObservationMode(0x300a, 0x0452);
+    Tag const DeviceMotionParameterCodeSequence(0x300a, 0x0453);
+    Tag const ReferencedRTPlanSequence(0x300c, 0x0002);
+    Tag const ReferencedBeamSequence(0x300c, 0x0004);
+    Tag const ReferencedBeamNumber(0x300c, 0x0006);
+    Tag const ReferencedReferenceImageNumber(0x300c, 0x0007);
+    Tag const StartCumulativeMetersetWeight(0x300c, 0x0008);
+    Tag const EndCumulativeMetersetWeight(0x300c, 0x0009);
+    Tag const ReferencedBrachyApplicationSetupSequence(0x300c, 0x000a);
+    Tag const ReferencedBrachyApplicationSetupNumber(0x300c, 0x000c);
+    Tag const ReferencedSourceNumber(0x300c, 0x000e);
+    Tag const ReferencedFractionGroupSequence(0x300c, 0x0020);
+    Tag const ReferencedFractionGroupNumber(0x300c, 0x0022);
+    Tag const ReferencedVerificationImageSequence(0x300c, 0x0040);
+    Tag const ReferencedReferenceImageSequence(0x300c, 0x0042);
+    Tag const ReferencedDoseReferenceSequence(0x300c, 0x0050);
+    Tag const ReferencedDoseReferenceNumber(0x300c, 0x0051);
+    Tag const BrachyReferencedDoseReferenceSequence(0x300c, 0x0055);
+    Tag const ReferencedStructureSetSequence(0x300c, 0x0060);
+    Tag const ReferencedPatientSetupNumber(0x300c, 0x006a);
+    Tag const ReferencedDoseSequence(0x300c, 0x0080);
+    Tag const ReferencedToleranceTableNumber(0x300c, 0x00a0);
+    Tag const ReferencedBolusSequence(0x300c, 0x00b0);
+    Tag const ReferencedWedgeNumber(0x300c, 0x00c0);
+    Tag const ReferencedCompensatorNumber(0x300c, 0x00d0);
+    Tag const ReferencedBlockNumber(0x300c, 0x00e0);
+    Tag const ReferencedControlPointIndex(0x300c, 0x00f0);
+    Tag const ReferencedControlPointSequence(0x300c, 0x00f2);
+    Tag const ReferencedStartControlPointIndex(0x300c, 0x00f4);
+    Tag const ReferencedStopControlPointIndex(0x300c, 0x00f6);
+    Tag const ReferencedRangeShifterNumber(0x300c, 0x0100);
+    Tag const ReferencedLateralSpreadingDeviceNumber(0x300c, 0x0102);
+    Tag const ReferencedRangeModulatorNumber(0x300c, 0x0104);
+    Tag const ApprovalStatus(0x300e, 0x0002);
+    Tag const ReviewDate(0x300e, 0x0004);
+    Tag const ReviewTime(0x300e, 0x0005);
+    Tag const ReviewerName(0x300e, 0x0008);
+    Tag const Arbitrary(0x4000, 0x0010);
+    Tag const TextComments(0x4000, 0x4000);
+    Tag const ResultsID(0x4008, 0x0040);
+    Tag const ResultsIDIssuer(0x4008, 0x0042);
+    Tag const ReferencedInterpretationSequence(0x4008, 0x0050);
+    Tag const ReportProductionStatusTrial(0x4008, 0x00ff);
+    Tag const InterpretationRecordedDate(0x4008, 0x0100);
+    Tag const InterpretationRecordedTime(0x4008, 0x0101);
+    Tag const InterpretationRecorder(0x4008, 0x0102);
+    Tag const ReferenceToRecordedSound(0x4008, 0x0103);
+    Tag const InterpretationTranscriptionDate(0x4008, 0x0108);
+    Tag const InterpretationTranscriptionTime(0x4008, 0x0109);
+    Tag const InterpretationTranscriber(0x4008, 0x010a);
+    Tag const InterpretationText(0x4008, 0x010b);
+    Tag const InterpretationAuthor(0x4008, 0x010c);
+    Tag const InterpretationApproverSequence(0x4008, 0x0111);
+    Tag const InterpretationApprovalDate(0x4008, 0x0112);
+    Tag const InterpretationApprovalTime(0x4008, 0x0113);
+    Tag const PhysicianApprovingInterpretation(0x4008, 0x0114);
+    Tag const InterpretationDiagnosisDescription(0x4008, 0x0115);
+    Tag const InterpretationDiagnosisCodeSequence(0x4008, 0x0117);
+    Tag const ResultsDistributionListSequence(0x4008, 0x0118);
+    Tag const DistributionName(0x4008, 0x0119);
+    Tag const DistributionAddress(0x4008, 0x011a);
+    Tag const InterpretationID(0x4008, 0x0200);
+    Tag const InterpretationIDIssuer(0x4008, 0x0202);
+    Tag const InterpretationTypeID(0x4008, 0x0210);
+    Tag const InterpretationStatusID(0x4008, 0x0212);
+    Tag const Impressions(0x4008, 0x0300);
+    Tag const ResultsComments(0x4008, 0x4000);
+    Tag const LowEnergyDetectors(0x4010, 0x0001);
+    Tag const HighEnergyDetectors(0x4010, 0x0002);
+    Tag const DetectorGeometrySequence(0x4010, 0x0004);
+    Tag const ThreatROIVoxelSequence(0x4010, 0x1001);
+    Tag const ThreatROIBase(0x4010, 0x1004);
+    Tag const ThreatROIExtents(0x4010, 0x1005);
+    Tag const ThreatROIBitmap(0x4010, 0x1006);
+    Tag const RouteSegmentID(0x4010, 0x1007);
+    Tag const GantryType(0x4010, 0x1008);
+    Tag const OOIOwnerType(0x4010, 0x1009);
+    Tag const RouteSegmentSequence(0x4010, 0x100a);
+    Tag const PotentialThreatObjectID(0x4010, 0x1010);
+    Tag const ThreatSequence(0x4010, 0x1011);
+    Tag const ThreatCategory(0x4010, 0x1012);
+    Tag const ThreatCategoryDescription(0x4010, 0x1013);
+    Tag const ATDAbilityAssessment(0x4010, 0x1014);
+    Tag const ATDAssessmentFlag(0x4010, 0x1015);
+    Tag const ATDAssessmentProbability(0x4010, 0x1016);
+    Tag const Mass(0x4010, 0x1017);
+    Tag const Density(0x4010, 0x1018);
+    Tag const ZEffective(0x4010, 0x1019);
+    Tag const BoardingPassID(0x4010, 0x101a);
+    Tag const CenterOfMass(0x4010, 0x101b);
+    Tag const CenterOfPTO(0x4010, 0x101c);
+    Tag const BoundingPolygon(0x4010, 0x101d);
+    Tag const RouteSegmentStartLocationID(0x4010, 0x101e);
+    Tag const RouteSegmentEndLocationID(0x4010, 0x101f);
+    Tag const RouteSegmentLocationIDType(0x4010, 0x1020);
+    Tag const AbortReason(0x4010, 0x1021);
+    Tag const VolumeOfPTO(0x4010, 0x1023);
+    Tag const AbortFlag(0x4010, 0x1024);
+    Tag const RouteSegmentStartTime(0x4010, 0x1025);
+    Tag const RouteSegmentEndTime(0x4010, 0x1026);
+    Tag const TDRType(0x4010, 0x1027);
+    Tag const InternationalRouteSegment(0x4010, 0x1028);
+    Tag const ThreatDetectionAlgorithmandVersion(0x4010, 0x1029);
+    Tag const AssignedLocation(0x4010, 0x102a);
+    Tag const AlarmDecisionTime(0x4010, 0x102b);
+    Tag const AlarmDecision(0x4010, 0x1031);
+    Tag const NumberOfTotalObjects(0x4010, 0x1033);
+    Tag const NumberOfAlarmObjects(0x4010, 0x1034);
+    Tag const PTORepresentationSequence(0x4010, 0x1037);
+    Tag const ATDAssessmentSequence(0x4010, 0x1038);
+    Tag const TIPType(0x4010, 0x1039);
+    Tag const DICOSVersion(0x4010, 0x103a);
+    Tag const OOIOwnerCreationTime(0x4010, 0x1041);
+    Tag const OOIType(0x4010, 0x1042);
+    Tag const OOISize(0x4010, 0x1043);
+    Tag const AcquisitionStatus(0x4010, 0x1044);
+    Tag const BasisMaterialsCodeSequence(0x4010, 0x1045);
+    Tag const PhantomType(0x4010, 0x1046);
+    Tag const OOIOwnerSequence(0x4010, 0x1047);
+    Tag const ScanType(0x4010, 0x1048);
+    Tag const ItineraryID(0x4010, 0x1051);
+    Tag const ItineraryIDType(0x4010, 0x1052);
+    Tag const ItineraryIDAssigningAuthority(0x4010, 0x1053);
+    Tag const RouteID(0x4010, 0x1054);
+    Tag const RouteIDAssigningAuthority(0x4010, 0x1055);
+    Tag const InboundArrivalType(0x4010, 0x1056);
+    Tag const CarrierID(0x4010, 0x1058);
+    Tag const CarrierIDAssigningAuthority(0x4010, 0x1059);
+    Tag const SourceOrientation(0x4010, 0x1060);
+    Tag const SourcePosition(0x4010, 0x1061);
+    Tag const BeltHeight(0x4010, 0x1062);
+    Tag const AlgorithmRoutingCodeSequence(0x4010, 0x1064);
+    Tag const TransportClassification(0x4010, 0x1067);
+    Tag const OOITypeDescriptor(0x4010, 0x1068);
+    Tag const TotalProcessingTime(0x4010, 0x1069);
+    Tag const DetectorCalibrationData(0x4010, 0x106c);
+    Tag const AdditionalScreeningPerformed(0x4010, 0x106d);
+    Tag const AdditionalInspectionSelectionCriteria(0x4010, 0x106e);
+    Tag const AdditionalInspectionMethodSequence(0x4010, 0x106f);
+    Tag const AITDeviceType(0x4010, 0x1070);
+    Tag const QRMeasurementsSequence(0x4010, 0x1071);
+    Tag const TargetMaterialSequence(0x4010, 0x1072);
+    Tag const SNRThreshold(0x4010, 0x1073);
+    Tag const ImageScaleRepresentation(0x4010, 0x1075);
+    Tag const ReferencedPTOSequence(0x4010, 0x1076);
+    Tag const ReferencedTDRInstanceSequence(0x4010, 0x1077);
+    Tag const PTOLocationDescription(0x4010, 0x1078);
+    Tag const AnomalyLocatorIndicatorSequence(0x4010, 0x1079);
+    Tag const AnomalyLocatorIndicator(0x4010, 0x107a);
+    Tag const PTORegionSequence(0x4010, 0x107b);
+    Tag const InspectionSelectionCriteria(0x4010, 0x107c);
+    Tag const SecondaryInspectionMethodSequence(0x4010, 0x107d);
+    Tag const PRCSToRCSOrientation(0x4010, 0x107e);
+    Tag const MACParametersSequence(0x4ffe, 0x0001);
+    Tag const SharedFunctionalGroupsSequence(0x5200, 0x9229);
+    Tag const PerFrameFunctionalGroupsSequence(0x5200, 0x9230);
+    Tag const WaveformSequence(0x5400, 0x0100);
+    Tag const ChannelMinimumValue(0x5400, 0x0110);
+    Tag const ChannelMaximumValue(0x5400, 0x0112);
+    Tag const WaveformBitsAllocated(0x5400, 0x1004);
+    Tag const WaveformSampleInterpretation(0x5400, 0x1006);
+    Tag const WaveformPaddingValue(0x5400, 0x100a);
+    Tag const WaveformData(0x5400, 0x1010);
+    Tag const FirstOrderPhaseCorrectionAngle(0x5600, 0x0010);
+    Tag const SpectroscopyData(0x5600, 0x0020);
+    Tag const FloatPixelData(0x7fe0, 0x0008);
+    Tag const DoubleFloatPixelData(0x7fe0, 0x0009);
+    Tag const PixelData(0x7fe0, 0x0010);
+    Tag const CoefficientsSDVN(0x7fe0, 0x0020);
+    Tag const CoefficientsSDHN(0x7fe0, 0x0030);
+    Tag const CoefficientsSDDN(0x7fe0, 0x0040);
+    Tag const DigitalSignaturesSequence(0xfffa, 0xfffa);
+    Tag const DataSetTrailingPadding(0xfffc, 0xfffc);
+    Tag const Item(0xfffe, 0xe000);
+    Tag const ItemDelimitationItem(0xfffe, 0xe00d);
+    Tag const SequenceDelimitationItem(0xfffe, 0xe0dd);
+}
+
+}
+
+#endif // _afc7b2d7_0869_4fea_9a9b_7fe6228baca9
diff --git a/src/dcmtkpp/unicode.cpp b/src/dcmtkpp/unicode.cpp
new file mode 100644
index 0000000..76246c7
--- /dev/null
+++ b/src/dcmtkpp/unicode.cpp
@@ -0,0 +1,332 @@
+/*************************************************************************
+ * dcmtkpp - 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 "dcmtkpp/unicode.h"
+
+#include <algorithm>
+#include <map>
+#include <set>
+#include <sstream>
+#include <string>
+
+#include <unicode/errorcode.h>
+#include <unicode/unistr.h>
+
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+std::map<std::string, std::string> const icu_encodings = {
+    { "", "" },
+    // Single-Byte Character Sets Without Code Extensions
+    { "ISO_IR 100", "iso-ir-100" },
+    { "ISO_IR 101", "iso-ir-101" },
+    { "ISO_IR 109", "iso-ir-109" },
+    { "ISO_IR 110", "iso-ir-110" },
+    { "ISO_IR 144", "iso-ir-144" },
+    { "ISO_IR 127", "iso-ir-127" },
+    { "ISO_IR 126", "iso-ir-126" },
+    { "ISO_IR 138", "iso-ir-138" },
+    { "ISO_IR 148", "iso-ir-148" },
+    { "ISO_IR 13", "Shift_JIS" }, // Since the 0x00 to 0x7f characters
+    // match ASCII (i.e. Romaji) and the 0xa1 to 0xdf map to half-width
+    // katakana of JIS X 0201. cf. https://en.wikipedia.org/wiki/Shift_JIS
+    { "ISO_IR 166", "TIS-620" },
+
+    // Single-Byte Character Sets with Code Extensions
+    { "ISO 2022 IR 6", "" },
+    { "ISO 2022 IR 100", "iso-ir-100" },
+    { "ISO 2022 IR 101", "iso-ir-101" },
+    { "ISO 2022 IR 109", "iso-ir-109" },
+    { "ISO 2022 IR 110", "iso-ir-110" },
+    { "ISO 2022 IR 144", "iso-ir-144" },
+    { "ISO 2022 IR 127", "iso-ir-127" },
+    { "ISO 2022 IR 126", "iso-ir-126" },
+    { "ISO 2022 IR 138", "iso-ir-138" },
+    { "ISO 2022 IR 148", "iso-ir-148" },
+    { "ISO 2022 IR 13", "Shift_JIS" },
+    { "ISO 2022 IR 166", "TIS-620" },
+
+    { "\x1B\x28\x42", "" },
+    { "\x1B\x2D\x41", "iso-ir-100" },
+    { "\x1B\x2D\x42", "iso-ir-101" },
+    { "\x1B\x2D\x43", "iso-ir-109" },
+    { "\x1B\x2D\x44", "iso-ir-110" },
+    { "\x1B\x2D\x4C", "iso-ir-144" },
+    { "\x1B\x2D\x47", "iso-ir-127" },
+    { "\x1B\x2D\x46", "iso-ir-126" },
+    { "\x1B\x2D\x48", "iso-ir-138" },
+    { "\x1B\x2D\x4D", "iso-ir-148" },
+    { "\x1B\x29\x49", "ISO-2022-JP" },
+    { "\x1B\x28\x4A", "ISO-2022-JP" },
+    { "\x1B\x2D\x54", "TIS-620" },
+
+    // Multi-Byte Character Sets with Code Extensions
+    { "ISO 2022 IR 87", "ISO-2022-JP" },
+    { "ISO 2022 IR 149", "EUC-KR" },
+    { "ISO 2022 IR 58", "ISO-2022-CN" },
+
+    { "\x1B\x24\x42", "ISO-2022-JP" },
+    { "\x1B\x24\x28\x44", "ISO-2022-JP" },
+    { "\x1B\x24\x29\x43", "iso-ir-149" },
+    { "\x1B\x24\x29\x41", "iso-ir-58" },
+
+    // Multi-Byte Character Sets Without Code Extensions
+    { "ISO_IR 192", "UTF-8" },
+    { "GB18030", "GB18030" },
+    // GBK
+};
+
+std::map<std::string, std::vector<std::string>> const escape_sequences = {
+    { "",   { "\x1B\x28\x42" } },
+    { "ISO 2022 IR 6",   { "\x1B\x28\x42" } },
+    { "ISO 2022 IR 100", { "\x1B\x2D\x41", "\x1B\x28\x42" } },
+    { "ISO 2022 IR 101", { "\x1B\x2D\x42", "\x1B\x28\x42" } },
+    { "ISO 2022 IR 109", { "\x1B\x2D\x43", "\x1B\x28\x42" } },
+    { "ISO 2022 IR 110", { "\x1B\x2D\x44", "\x1B\x28\x42" } },
+    { "ISO 2022 IR 144", { "\x1B\x2D\x4C", "\x1B\x28\x42" } },
+    { "ISO 2022 IR 127", { "\x1B\x2D\x47", "\x1B\x28\x42" } },
+    { "ISO 2022 IR 126", { "\x1B\x2D\x46", "\x1B\x28\x42" } },
+    { "ISO 2022 IR 138", { "\x1B\x2D\x48", "\x1B\x28\x42" } },
+    { "ISO 2022 IR 148", { "\x1B\x2D\x4D", "\x1B\x28\x42" } },
+    { "ISO 2022 IR 13",  { "\x1B\x29\x49", "\x1B\x28\x4A" } },
+    { "ISO 2022 IR 166", { "\x1B\x2D\x54", "\x1B\x28\x42" } },
+
+    { "ISO 2022 IR 87",  { "\x1B\x24\x42", "\x1B\x28\x42" } },
+    { "ISO 2022 IR 159", { "\x1B\x24\x28\x44" } },
+    { "ISO 2022 IR 149", { "\x1B\x24\x29\x43" } },
+    { "ISO 2022 IR 58",  { "\x1B\x24\x29\x41" } },
+};
+
+std::string find_encoder(std::string const & specific_character_set)
+{
+    std::string encoder;
+    auto const it = icu_encodings.find(specific_character_set);
+    if(it == icu_encodings.end())
+    {
+        throw Exception("Unknown encoding: "+specific_character_set);
+    }
+    encoder = it->second;
+
+    return encoder;
+}
+
+std::string as_utf8(
+    std::string::const_iterator const begin, std::string::const_iterator const end,
+    std::string const & encoding)
+{
+    icu::UnicodeString unicode(&(*begin), end-begin, encoding.c_str());
+    std::string result;
+    unicode.toUTF8String(result);
+
+    return result;
+}
+
+std::string as_utf8(
+    std::string::const_iterator const begin, std::string::const_iterator const end,
+    std::string const & initial_encoder,
+    std::vector<std::string> const & active_escape_sequences)
+{
+    std::string encoded;
+
+    auto encoder = initial_encoder;
+
+    auto item_begin = begin;
+    while(item_begin != end)
+    {
+        auto const item_end = std::find(item_begin+1, end, '\x1B');
+
+        if(*item_begin == '\x1B')
+        {
+            std::string escape_sequence(item_begin, item_begin+3);
+
+            // Find an encoder for the escape sequence
+            if(
+                std::find(
+                active_escape_sequences.begin(), active_escape_sequences.end(),
+                escape_sequence) != active_escape_sequences.end())
+            {
+                encoder = find_encoder(escape_sequence);
+            }
+            else
+            {
+                escape_sequence += *(item_begin+3);
+                if(
+                    std::find(
+                    active_escape_sequences.begin(), active_escape_sequences.end(),
+                    escape_sequence) != active_escape_sequences.end())
+                {
+                    encoder = find_encoder(escape_sequence);
+                }
+                else
+                {
+                    // Unknown escape sequence: do not update the encoder,
+                    // hope for the best.
+                }
+            }
+
+            if(encoder != "ISO-2022-JP")
+            {
+                // The ISO-2022-JP encoder of ICU must have the escape
+                // sequences
+                item_begin += escape_sequence.size();
+            }
+        }
+
+        encoded += as_utf8(item_begin, item_end, encoder);
+
+        item_begin = item_end;
+    }
+
+    return encoded;
+}
+
+enum class Group
+{
+    Alphabetic,
+    Ideographic,
+    Phonetic
+};
+
+std::vector<std::string> get_active_escape_sequences(
+    Value::Strings const & specific_character_set, Group const & group)
+{
+    std::vector<std::string> active_escape_sequences;
+
+    if(specific_character_set.size() >= 2)
+    {
+        auto const escape_sequences_it = escape_sequences.find(specific_character_set[1]);
+        if(escape_sequences_it == escape_sequences.end())
+        {
+            throw Exception("Unknown specific character set: "+specific_character_set[1]);
+        }
+        std::copy(
+            escape_sequences_it->second.begin(),
+            escape_sequences_it->second.end(),
+            std::back_inserter(active_escape_sequences));
+    }
+    if(group == Group::Phonetic)
+    {
+        auto const escape_sequences_it = escape_sequences.find(specific_character_set[0]);
+        if(escape_sequences_it != escape_sequences.end())
+        {
+            std::copy(
+                escape_sequences_it->second.begin(),
+                escape_sequences_it->second.end(),
+                std::back_inserter(active_escape_sequences));
+        }
+        if(specific_character_set.size() >= 3)
+        {
+            auto const escape_sequences_it = escape_sequences.find(specific_character_set[2]);
+            if(escape_sequences_it == escape_sequences.end())
+            {
+                throw Exception("Unknown specific character set: "+specific_character_set[2]);
+            }
+            std::copy(
+                escape_sequences_it->second.begin(),
+                escape_sequences_it->second.end(),
+                std::back_inserter(active_escape_sequences));
+        }
+    }
+
+    return active_escape_sequences;
+}
+
+std::string as_utf8(
+    std::string const & input, Value::Strings const & specific_character_set,
+    bool is_pn)
+{
+    // Control characters: line feed, carriage return, form feed and tabulation
+    // For Person Name, add the group splitters
+    std::string splitters = "\n\r\f\t";
+    if(is_pn)
+    {
+        if(
+            std::find(
+                specific_character_set.begin(), specific_character_set.end(),
+                "ISO 2022 IR 13") != specific_character_set.end() ||
+            std::find(
+                specific_character_set.begin(), specific_character_set.end(),
+                "ISO 2022 IR 87") != specific_character_set.end())
+        {
+            // The ISO-2022-JP encoder of ICU is stateful, whereas all other
+            // ISO 2022 encoders seem to be only codepages (i.e. stateless)
+            splitters.append("=");
+        }
+        else
+        {
+            splitters.append("^=");
+        }
+    }
+
+    std::string result;
+
+    Group group=Group::Alphabetic;
+
+    auto begin = input.begin();
+    while(begin != input.end())
+    {
+        // Active character set resets to default before any of the splitters
+        // cf. PS 3.5, 6.1.2.5.3
+        auto const end = std::find_first_of(
+            begin, input.end(), splitters.begin(), splitters.end());
+
+        std::string encoded;
+
+        if(specific_character_set.empty())
+        {
+            encoded = std::string(begin, end);
+        }
+        else if(is_pn && group != Group::Alphabetic)
+        {
+            auto const initial_encoder = find_encoder(specific_character_set[0]);
+            auto const active_escape_sequences =
+                get_active_escape_sequences(specific_character_set, group);
+            encoded = as_utf8(begin, end, initial_encoder, active_escape_sequences);
+        }
+        else
+        {
+            auto const encoder = find_encoder(specific_character_set[0]);
+            encoded = as_utf8(begin, end, encoder);
+        }
+
+        result.append(encoded);
+
+        // If present, add the splitter to the UTF-8 string.
+        if(end != input.end())
+        {
+            result.push_back(*end);
+            begin = end+1;
+            if(is_pn && *end == '=')
+            {
+                if(group == Group::Alphabetic)
+                {
+                    group = Group::Ideographic;
+                }
+                else if(group == Group::Ideographic)
+                {
+                    group = Group::Phonetic;
+                }
+                else
+                {
+                    throw Exception("Too many groups");
+                }
+            }
+        }
+        else
+        {
+            begin = end;
+        }
+    }
+
+    return result;
+}
+
+}
diff --git a/src/dcmtkpp/unicode.h b/src/dcmtkpp/unicode.h
new file mode 100644
index 0000000..4815d80
--- /dev/null
+++ b/src/dcmtkpp/unicode.h
@@ -0,0 +1,25 @@
+/*************************************************************************
+ * dcmtkpp - 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 _4a178325_e3d6_4f6f_9a18_ba6a983ee396
+#define _4a178325_e3d6_4f6f_9a18_ba6a983ee396
+
+#include <string>
+#include "dcmtkpp/Value.h"
+
+namespace dcmtkpp
+{
+
+/// @brief Convert a string to its UTF-8 representation
+std::string as_utf8(
+    std::string const & input, Value::Strings const & specific_character_set,
+    bool is_pn=false);
+
+}
+
+#endif // _4a178325_e3d6_4f6f_9a18_ba6a983ee396
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000..a8fe9a3
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,41 @@
+find_package(Boost COMPONENTS unit_test_framework REQUIRED)
+link_directories(${Boost_LIBRARY_DIRS})
+add_definitions(-DBOOST_TEST_DYN_LINK)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src)
+
+add_definitions("-D HAVE_CONFIG_H")
+
+file(GLOB_RECURSE tests *.cpp)
+foreach(test_file ${tests})
+    get_filename_component(test ${test_file} NAME_WE)
+    add_executable(${test} ${test_file})
+    target_link_libraries(${test} dcmtkpp ${Boost_LIBRARIES})
+    file(READ ${test_file} content)
+
+    set(pattern "BOOST_(AUTO|FIXTURE)_TEST_CASE\\(([^),]+)")
+
+    string(REGEX MATCHALL ${pattern} cases ${content})
+
+    foreach(case ${cases})
+        string(REGEX REPLACE ${pattern} "\\2" case ${case})
+        if(NOT ${case} MATCHES "##")
+            add_test("${test}_${case}" "${test}" "--run_test=${case}")
+        endif()
+    endforeach()
+
+    set(pattern "ElementTest\\([\n ]+([A-Z]+)")
+
+    string(REGEX MATCHALL ${pattern} matches ${content})
+
+    foreach(match ${matches})
+        string(REGEX REPLACE ${pattern} "\\1" vr ${match})
+
+        set(case "${vr}FromDcmtkpp")
+        add_test("${test}_${case}" "${test}" "--run_test=${case}")
+
+        set(case "${vr}ToDcmtkpp")
+        add_test("${test}_${case}" "${test}" "--run_test=${case}")
+    endforeach()
+
+endforeach()
diff --git a/tests/MessageFixtureBase.h b/tests/MessageFixtureBase.h
new file mode 100644
index 0000000..55abb73
--- /dev/null
+++ b/tests/MessageFixtureBase.h
@@ -0,0 +1,54 @@
+#ifndef _779c46d6_b6ea_443a_9642_f1ec5b87d4b3
+#define _779c46d6_b6ea_443a_9642_f1ec5b87d4b3
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/Message.h"
+
+/// @brief Base class for fixtures of Message-derived classes.
+template<typename TMessage>
+struct MessageFixtureBase
+{
+    /// @brief Check that a specific message can be constructed from a generic Message.
+    void check_message_constructor(
+        dcmtkpp::DataSet const & command_set)
+    {
+        dcmtkpp::Message const generic_message(command_set);
+        TMessage const message(generic_message);
+        this->check(message);
+    }
+
+    /// @brief Check that a specific message can be constructed from a generic Message.
+    void check_message_constructor(
+        dcmtkpp::DataSet const & command_set, dcmtkpp::DataSet const & data_set)
+    {
+        dcmtkpp::Message const generic_message(command_set, data_set);
+        TMessage const message(generic_message);
+        this->check(message);
+    }
+
+    /// @brief Check that a specific message cannot be constructed from a generic Message.
+    void check_message_constructor_throw(
+        dcmtkpp::DataSet const & command_set)
+    {
+        dcmtkpp::Message const generic_message(command_set);
+        BOOST_CHECK_THROW(
+            TMessage const message(generic_message),
+            dcmtkpp::Exception);
+    }
+
+    /// @brief Check that a specific message cannot be constructed from a generic Message.
+    void check_message_constructor_throw(
+        dcmtkpp::DataSet const & command_set, dcmtkpp::DataSet const & data_set)
+    {
+        dcmtkpp::Message const generic_message(command_set, data_set);
+        BOOST_CHECK_THROW(
+            TMessage const message(generic_message),
+            dcmtkpp::Exception);
+    }
+
+    /// @brief Check that the specific message attributes are set correctly
+    virtual void check(TMessage const & message) =0;
+};
+
+#endif // _779c46d6_b6ea_443a_9642_f1ec5b87d4b3
diff --git a/tests/PeerFixtureBase.h b/tests/PeerFixtureBase.h
new file mode 100644
index 0000000..532501c
--- /dev/null
+++ b/tests/PeerFixtureBase.h
@@ -0,0 +1,86 @@
+#ifndef _b21e8d37_0125_4d64_84aa_f91d9d96612b
+#define _b21e8d37_0125_4d64_84aa_f91d9d96612b
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <boost/lexical_cast.hpp>
+
+#include "dcmtkpp/Association.h"
+#include "dcmtkpp/Network.h"
+
+/// @brief Base class for fixtures of requiring a working association.
+class PeerFixtureBase
+{
+public:
+    dcmtkpp::Network network;
+    dcmtkpp::Association association;
+
+    struct PresentationContext
+    {
+        std::string abstract_syntax;
+        std::vector<std::string> transfer_syntaxes;
+        T_ASC_SC_ROLE role;
+
+        PresentationContext(std::string const & abstract_syntax, std::vector<std::string> const & transfer_syntaxes, T_ASC_SC_ROLE role=ASC_SC_ROLE_DEFAULT)
+        : abstract_syntax(abstract_syntax),
+          transfer_syntaxes(transfer_syntaxes), role(role)
+        {
+            // Nothing else
+        }
+    };
+
+    PeerFixtureBase(T_ASC_NetworkRole role, int port, int timeout,
+        std::vector<PresentationContext> const & presentation_contexts)
+    : network(role, port, timeout), association()
+    {
+        this->network.initialize();
+
+        this->association.set_own_ae_title(
+            this->_get_environment_variable("DCMTKPP_OWN_AET"));
+        this->association.set_peer_host_name(
+            this->_get_environment_variable("DCMTKPP_PEER_HOST_NAME"));
+        this->association.set_peer_port(
+            this->_get_environment_variable<uint16_t>("DCMTKPP_PEER_PORT"));
+        this->association.set_peer_ae_title(
+            this->_get_environment_variable("DCMTKPP_PEER_AET"));
+        for(auto const & presentation_context: presentation_contexts)
+        {
+            this->association.add_presentation_context(
+                presentation_context.abstract_syntax,
+                presentation_context.transfer_syntaxes,
+                presentation_context.role);
+        }
+
+        this->association.associate(this->network);
+    }
+
+    ~PeerFixtureBase()
+    {
+        this->association.release();
+        this->network.drop();
+    }
+
+private:
+
+    std::string _get_environment_variable(std::string const & name) const
+    {
+        char* value = getenv(name.c_str());
+        if(value == NULL)
+        {
+            BOOST_FAIL(name + " is not defined");
+        }
+        return value;
+    }
+
+    template<typename T>
+    T _get_environment_variable(std::string const & name) const
+    {
+        return boost::lexical_cast<T>(this->_get_environment_variable(name));
+    }
+};
+
+#endif // _b21e8d37_0125_4d64_84aa_f91d9d96612b
diff --git a/tests/code/Association.cpp b/tests/code/Association.cpp
new file mode 100644
index 0000000..a300c2f
--- /dev/null
+++ b/tests/code/Association.cpp
@@ -0,0 +1,251 @@
+#define BOOST_TEST_MODULE Association
+#include <boost/test/unit_test.hpp>
+
+#include <ostream>
+
+#include "dcmtkpp/Association.h"
+#include "dcmtkpp/Exception.h"
+
+#include "../PeerFixtureBase.h"
+
+namespace dcmtkpp
+{
+
+std::ostream & operator<<(std::ostream & stream, UserIdentityType const & type)
+{
+    stream << int(type);
+    return stream;
+}
+
+}
+
+BOOST_AUTO_TEST_CASE(DefaultConstructor)
+{
+    dcmtkpp::Association association;
+    BOOST_CHECK_EQUAL(association.get_own_ae_title(), "");
+
+    BOOST_CHECK_EQUAL(association.get_peer_host_name(), "");
+    BOOST_CHECK_EQUAL(association.get_peer_port(), 104);
+    BOOST_CHECK_EQUAL(association.get_peer_ae_title(), "");
+
+    BOOST_CHECK_EQUAL(
+        association.get_user_identity_type(), dcmtkpp::UserIdentityType::None);
+    BOOST_CHECK_EQUAL(association.get_user_identity_primary_field(), "");
+    BOOST_CHECK_EQUAL(association.get_user_identity_secondary_field(), "");
+
+    BOOST_CHECK(!association.is_associated());
+    BOOST_CHECK_EQUAL(
+        association.get_association(), static_cast<T_ASC_Association*>(NULL));
+}
+
+BOOST_AUTO_TEST_CASE(CopyConstructor)
+{
+    dcmtkpp::Association association;
+    association.set_own_ae_title("local");
+
+    association.set_peer_host_name("pacs.example.com");
+    association.set_peer_port(11112);
+    association.set_peer_ae_title("remote");
+
+    association.set_user_identity_to_username_and_password("foo", "bar");
+
+    dcmtkpp::Association const other(association);
+
+    BOOST_CHECK_EQUAL(other.get_own_ae_title(), association.get_own_ae_title());
+
+    BOOST_CHECK_EQUAL(
+        other.get_peer_host_name(), association.get_peer_host_name());
+    BOOST_CHECK_EQUAL(other.get_peer_port(), association.get_peer_port());
+    BOOST_CHECK_EQUAL(
+        other.get_peer_ae_title(), association.get_peer_ae_title());
+
+    BOOST_CHECK_EQUAL(
+        other.get_user_identity_type(), association.get_user_identity_type());
+    BOOST_CHECK_EQUAL(
+        other.get_user_identity_primary_field(),
+        association.get_user_identity_primary_field());
+    BOOST_CHECK_EQUAL(
+        other.get_user_identity_secondary_field(),
+        association.get_user_identity_secondary_field());
+}
+
+BOOST_AUTO_TEST_CASE(Assignment)
+{
+    dcmtkpp::Association association;
+    association.set_own_ae_title("local");
+
+    association.set_peer_host_name("pacs.example.com");
+    association.set_peer_port(11112);
+    association.set_peer_ae_title("remote");
+
+    association.set_user_identity_to_username_and_password("foo", "bar");
+
+    dcmtkpp::Association other;
+    other = association;
+
+    BOOST_CHECK_EQUAL(other.get_own_ae_title(), association.get_own_ae_title());
+
+    BOOST_CHECK_EQUAL(
+        other.get_peer_host_name(), association.get_peer_host_name());
+    BOOST_CHECK_EQUAL(other.get_peer_port(), association.get_peer_port());
+    BOOST_CHECK_EQUAL(
+        other.get_peer_ae_title(), association.get_peer_ae_title());
+
+    BOOST_CHECK_EQUAL(
+        other.get_user_identity_type(), association.get_user_identity_type());
+    BOOST_CHECK_EQUAL(
+        other.get_user_identity_primary_field(),
+        association.get_user_identity_primary_field());
+    BOOST_CHECK_EQUAL(
+        other.get_user_identity_secondary_field(),
+        association.get_user_identity_secondary_field());
+}
+
+BOOST_AUTO_TEST_CASE(OwnAETitle)
+{
+    dcmtkpp::Association association;
+    association.set_own_ae_title("myself");
+    BOOST_CHECK_EQUAL(association.get_own_ae_title(), "myself");
+}
+
+BOOST_AUTO_TEST_CASE(PeerHostName)
+{
+    dcmtkpp::Association association;
+    association.set_peer_host_name("pacs.example.com");
+    BOOST_CHECK_EQUAL(association.get_peer_host_name(), "pacs.example.com");
+}
+
+BOOST_AUTO_TEST_CASE(PeerPort)
+{
+    dcmtkpp::Association association;
+    association.set_peer_port(11112);
+    BOOST_CHECK_EQUAL(association.get_peer_port(), 11112);
+}
+
+BOOST_AUTO_TEST_CASE(PeerAETitle)
+{
+    dcmtkpp::Association association;
+    association.set_peer_ae_title("remote");
+    BOOST_CHECK_EQUAL(association.get_peer_ae_title(), "remote");
+}
+
+BOOST_AUTO_TEST_CASE(UserIdentityType)
+{
+    dcmtkpp::Association association;
+    association.set_user_identity_type(dcmtkpp::UserIdentityType::Username);
+    BOOST_CHECK_EQUAL(
+        association.get_user_identity_type(),
+        dcmtkpp::UserIdentityType::Username);
+}
+
+BOOST_AUTO_TEST_CASE(UserIdentityPrimaryField)
+{
+    dcmtkpp::Association association;
+    association.set_user_identity_primary_field("user");
+    BOOST_CHECK_EQUAL(association.get_user_identity_primary_field(), "user");
+}
+
+BOOST_AUTO_TEST_CASE(UserIdentitySecondaryField)
+{
+    dcmtkpp::Association association;
+    association.set_user_identity_secondary_field("password");
+    BOOST_CHECK_EQUAL(
+        association.get_user_identity_secondary_field(), "password");
+}
+
+BOOST_AUTO_TEST_CASE(UserIdentityNone)
+{
+    dcmtkpp::Association association;
+    association.set_user_identity_to_none();
+    BOOST_CHECK_EQUAL(association.get_user_identity_primary_field(), "");
+    BOOST_CHECK_EQUAL(association.get_user_identity_secondary_field(), "");
+}
+
+BOOST_AUTO_TEST_CASE(UserIdentityUsername)
+{
+    dcmtkpp::Association association;
+    association.set_user_identity_to_username("user");
+    BOOST_CHECK_EQUAL(
+        association.get_user_identity_type(),
+        dcmtkpp::UserIdentityType::Username);
+    BOOST_CHECK_EQUAL(association.get_user_identity_primary_field(), "user");
+    BOOST_CHECK_EQUAL(association.get_user_identity_secondary_field(), "");
+}
+
+BOOST_AUTO_TEST_CASE(UserIdentityUsernameAndPassword)
+{
+    dcmtkpp::Association association;
+    association.set_user_identity_to_username_and_password("user", "password");
+    BOOST_CHECK_EQUAL(
+        association.get_user_identity_type(),
+        dcmtkpp::UserIdentityType::UsernameAndPassword);
+    BOOST_CHECK_EQUAL(association.get_user_identity_primary_field(), "user");
+    BOOST_CHECK_EQUAL(
+        association.get_user_identity_secondary_field(), "password");
+}
+
+BOOST_AUTO_TEST_CASE(UserIdentityKerberos)
+{
+    dcmtkpp::Association association;
+    association.set_user_identity_to_kerberos("ticket");
+    BOOST_CHECK_EQUAL(
+        association.get_user_identity_type(),
+        dcmtkpp::UserIdentityType::Kerberos);
+    BOOST_CHECK_EQUAL(association.get_user_identity_primary_field(), "ticket");
+    BOOST_CHECK_EQUAL(association.get_user_identity_secondary_field(), "");
+}
+
+BOOST_AUTO_TEST_CASE(UserIdentitySAML)
+{
+    dcmtkpp::Association association;
+    association.set_user_identity_to_saml("assertion");
+    BOOST_CHECK_EQUAL(
+        association.get_user_identity_type(), dcmtkpp::UserIdentityType::SAML);
+    BOOST_CHECK_EQUAL(
+        association.get_user_identity_primary_field(), "assertion");
+    BOOST_CHECK_EQUAL(association.get_user_identity_secondary_field(), "");
+}
+
+BOOST_AUTO_TEST_CASE(Associate)
+{
+    PeerFixtureBase fixture(NET_REQUESTOR, 0, 10, 
+        {
+            { UID_VerificationSOPClass,
+                {UID_LittleEndianImplicitTransferSyntax}
+            }
+        });
+    BOOST_CHECK_THROW(
+        fixture.association.set_own_ae_title("foo"), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(
+        fixture.association.set_peer_host_name("foo"), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(
+        fixture.association.set_peer_port(1234), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(
+        fixture.association.set_peer_ae_title("foo"), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(
+        fixture.association.add_presentation_context(
+                UID_GETPatientRootQueryRetrieveInformationModel,
+                { UID_LittleEndianImplicitTransferSyntax }),
+        dcmtkpp::Exception);
+    BOOST_CHECK_THROW(
+        fixture.association.set_user_identity_type(dcmtkpp::UserIdentityType::SAML), 
+        dcmtkpp::Exception);
+    BOOST_CHECK_THROW(
+        fixture.association.set_user_identity_primary_field("foo"), 
+        dcmtkpp::Exception);
+    BOOST_CHECK_THROW(
+        fixture.association.set_user_identity_secondary_field("foo"), 
+        dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(Release)
+{
+    dcmtkpp::Association association;
+    BOOST_CHECK_THROW(association.release(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(Abort)
+{
+    dcmtkpp::Association association;
+    BOOST_CHECK_THROW(association.abort(), dcmtkpp::Exception);
+}
diff --git a/tests/code/CEchoRequest.cpp b/tests/code/CEchoRequest.cpp
new file mode 100644
index 0000000..934a900
--- /dev/null
+++ b/tests/code/CEchoRequest.cpp
@@ -0,0 +1,56 @@
+#define BOOST_TEST_MODULE CEchoRequest
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcuid.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CEchoRequest.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+
+#include "../MessageFixtureBase.h"
+
+struct Fixture: public MessageFixtureBase<dcmtkpp::CEchoRequest>
+{
+    dcmtkpp::DataSet command_set;
+
+    Fixture()
+    {
+        this->command_set.add("CommandField", {dcmtkpp::Message::Command::C_ECHO_RQ});
+        this->command_set.add("MessageID", {1234});
+        this->command_set.add("AffectedSOPClassUID", {UID_VerificationSOPClass});
+    }
+
+    void check(dcmtkpp::CEchoRequest const & message)
+    {
+        BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_ECHO_RQ);
+        BOOST_CHECK_EQUAL(message.get_message_id(), 1234);
+        BOOST_CHECK_EQUAL(
+            message.get_affected_sop_class_uid(), UID_VerificationSOPClass);
+        BOOST_CHECK(!message.has_data_set());
+    }
+};
+
+BOOST_FIXTURE_TEST_CASE(Constructor, Fixture)
+{
+    dcmtkpp::CEchoRequest const message(1234, UID_VerificationSOPClass);
+    this->check(message);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructor, Fixture)
+{
+    this->check_message_constructor(this->command_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorWrongCommandField, Fixture)
+{
+    this->command_set.as_int("CommandField") = {dcmtkpp::Message::Command::C_ECHO_RSP};
+    this->check_message_constructor_throw(this->command_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorMissingAffectSOPClass, Fixture)
+{
+    this->command_set.remove("AffectedSOPClassUID");
+    this->check_message_constructor_throw(this->command_set);
+}
diff --git a/tests/code/CEchoResponse.cpp b/tests/code/CEchoResponse.cpp
new file mode 100644
index 0000000..01195c4
--- /dev/null
+++ b/tests/code/CEchoResponse.cpp
@@ -0,0 +1,58 @@
+#define BOOST_TEST_MODULE CEchoResponse
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcuid.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CEchoResponse.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+
+#include "../MessageFixtureBase.h"
+
+struct Fixture: public MessageFixtureBase<dcmtkpp::CEchoResponse>
+{
+    dcmtkpp::DataSet command_set;
+
+    Fixture()
+    {
+        this->command_set.add("CommandField", {dcmtkpp::Message::Command::C_ECHO_RSP});
+        this->command_set.add("MessageIDBeingRespondedTo", {1234});
+        this->command_set.add("Status", {STATUS_Success});
+        this->command_set.add("AffectedSOPClassUID", {UID_VerificationSOPClass});
+    }
+
+    void check(dcmtkpp::CEchoResponse const & message)
+    {
+        BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_ECHO_RSP);
+        BOOST_CHECK_EQUAL(message.get_message_id_being_responded_to(), 1234);
+        BOOST_CHECK_EQUAL(message.get_status(), STATUS_Success);
+        BOOST_CHECK_EQUAL(message.get_affected_sop_class_uid(), UID_VerificationSOPClass);
+        BOOST_CHECK(!message.has_data_set());
+    }
+};
+
+BOOST_FIXTURE_TEST_CASE(Constructor, Fixture)
+{
+    dcmtkpp::CEchoResponse const message(
+        1234, STATUS_Success, UID_VerificationSOPClass);
+    this->check(message);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructor, Fixture)
+{
+    this->check_message_constructor(this->command_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorWrongCommandField, Fixture)
+{
+    this->command_set.as_int("CommandField") = {dcmtkpp::Message::Command::C_ECHO_RQ};
+    this->check_message_constructor_throw(this->command_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorMissingAffectSOPClass, Fixture)
+{
+    this->command_set.remove("AffectedSOPClassUID");
+    this->check_message_constructor_throw(this->command_set);
+}
diff --git a/tests/code/CFindRequest.cpp b/tests/code/CFindRequest.cpp
new file mode 100644
index 0000000..f06ad39
--- /dev/null
+++ b/tests/code/CFindRequest.cpp
@@ -0,0 +1,83 @@
+#define BOOST_TEST_MODULE CFindRequest
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcuid.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CFindRequest.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+
+#include "../MessageFixtureBase.h"
+
+struct Fixture: public MessageFixtureBase<dcmtkpp::CFindRequest>
+{
+    dcmtkpp::DataSet command_set;
+    dcmtkpp::DataSet query;
+
+    Fixture()
+    {
+        this->command_set.add("CommandField", {dcmtkpp::Message::Command::C_FIND_RQ});
+        this->command_set.add("MessageID", {1234});
+        this->command_set.add("AffectedSOPClassUID",
+            {UID_FINDPatientRootQueryRetrieveInformationModel});
+        this->command_set.add("Priority", {DIMSE_PRIORITY_MEDIUM});
+
+        this->query.add("PatientName", {"Doe^John"});
+        this->query.add("StudyDescription", {"Brain"});
+        this->query.add("QueryRetrieveLevel", {"STUDY"});
+    }
+
+    virtual void check(dcmtkpp::CFindRequest const & message)
+    {
+        BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_FIND_RQ);
+        BOOST_CHECK_EQUAL(message.get_message_id(), 1234);
+        BOOST_CHECK_EQUAL(
+            message.get_affected_sop_class_uid(),
+            UID_FINDPatientRootQueryRetrieveInformationModel);
+        BOOST_CHECK(message.get_data_set() == this->query);
+    }
+};
+
+BOOST_FIXTURE_TEST_CASE(Constructor, Fixture)
+{
+    dcmtkpp::CFindRequest const message(
+        1234, UID_FINDPatientRootQueryRetrieveInformationModel,
+        DIMSE_PRIORITY_MEDIUM, this->query);
+    this->check(message);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructor, Fixture)
+{
+    this->check_message_constructor(this->command_set, this->query);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorWrongCommandField, Fixture)
+{
+    this->command_set.as_int("CommandField") = {dcmtkpp::Message::Command::C_ECHO_RQ};
+    this->check_message_constructor_throw(this->command_set, this->query);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorMissingAffectSOPClass, Fixture)
+{
+    this->command_set.remove("AffectedSOPClassUID");
+    this->check_message_constructor_throw(this->command_set, this->query);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorMissingPriority, Fixture)
+{
+    this->command_set.remove("Priority");
+    this->check_message_constructor_throw(this->command_set, this->query);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorMissingQuery, Fixture)
+{
+    this->check_message_constructor_throw(this->command_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorEmptyQuery, Fixture)
+{
+    dcmtkpp::DataSet empty;
+    this->check_message_constructor_throw(this->command_set, empty);
+}
diff --git a/tests/code/CFindResponse.cpp b/tests/code/CFindResponse.cpp
new file mode 100644
index 0000000..55a17e9
--- /dev/null
+++ b/tests/code/CFindResponse.cpp
@@ -0,0 +1,72 @@
+#define BOOST_TEST_MODULE CFindResponse
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcuid.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CFindResponse.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+
+#include "../MessageFixtureBase.h"
+
+struct Fixture: public MessageFixtureBase<dcmtkpp::CFindResponse>
+{
+    dcmtkpp::DataSet command_set;
+    dcmtkpp::DataSet data_set;
+
+    Fixture()
+    {
+        command_set.add("CommandField", {dcmtkpp::Message::Command::C_FIND_RSP});
+        command_set.add("MessageIDBeingRespondedTo", {1234});
+        command_set.add("Status", {STATUS_Success});
+
+        command_set.add("MessageID", {5678});
+        command_set.add("AffectedSOPClassUID",
+            {UID_FINDStudyRootQueryRetrieveInformationModel});
+
+        data_set.add("PatientName", {"Doe^John"});
+        data_set.add("PatientID", {"DJ123"});
+        data_set.add("StudyDescription", {"Brain"});
+        data_set.add("StudyInstanceUID", {"1.2.3"});
+    }
+
+    virtual void check(dcmtkpp::CFindResponse const & message)
+    {
+        BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_FIND_RSP);
+        BOOST_CHECK_EQUAL(message.get_message_id_being_responded_to(), 1234);
+        BOOST_CHECK_EQUAL(message.get_status(), STATUS_Success);
+
+        BOOST_CHECK(message.has_message_id());
+        BOOST_CHECK_EQUAL(message.get_message_id(), 5678);
+
+        BOOST_CHECK(message.has_affected_sop_class_uid());
+        BOOST_CHECK_EQUAL(
+            message.get_affected_sop_class_uid(),
+            UID_FINDStudyRootQueryRetrieveInformationModel);
+
+        BOOST_CHECK(message.has_data_set());
+        BOOST_CHECK(message.get_data_set() == this->data_set);
+    }
+};
+
+BOOST_FIXTURE_TEST_CASE(Constructor, Fixture)
+{
+    dcmtkpp::CFindResponse message(1234, STATUS_Success, this->data_set);
+    message.set_message_id(5678);
+    message.set_affected_sop_class_uid(
+        UID_FINDStudyRootQueryRetrieveInformationModel);
+    this->check(message);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructor, Fixture)
+{
+    this->check_message_constructor(this->command_set, this->data_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorWrongCommandField, Fixture)
+{
+    this->command_set.as_int("CommandField") = {dcmtkpp::Message::Command::C_ECHO_RQ};
+    this->check_message_constructor_throw(this->command_set, this->data_set);
+}
diff --git a/tests/code/CGetRequest.cpp b/tests/code/CGetRequest.cpp
new file mode 100644
index 0000000..7a83ace
--- /dev/null
+++ b/tests/code/CGetRequest.cpp
@@ -0,0 +1,80 @@
+#define BOOST_TEST_MODULE CGetRequest
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CGetRequest.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/registry.h"
+
+#include "../MessageFixtureBase.h"
+
+struct Fixture: public MessageFixtureBase<dcmtkpp::CGetRequest>
+{
+    dcmtkpp::DataSet command_set;
+    dcmtkpp::DataSet query;
+
+    Fixture()
+    {
+        this->command_set.add("CommandField", {dcmtkpp::Message::Command::C_GET_RQ});
+        this->command_set.add("MessageID", {1234});
+        this->command_set.add("AffectedSOPClassUID",
+            {UID_GETPatientRootQueryRetrieveInformationModel});
+        this->command_set.add("Priority", {DIMSE_PRIORITY_MEDIUM});
+
+        this->query.add("PatientName", {"Doe^John"});
+        this->query.add("StudyDescription", {"Brain"});
+        this->query.add("QueryRetrieveLevel", {"STUDY"});
+    }
+
+    virtual void check(dcmtkpp::CGetRequest const & message)
+    {
+        BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_GET_RQ);
+        BOOST_CHECK_EQUAL(message.get_message_id(), 1234);
+        BOOST_CHECK_EQUAL(
+            message.get_affected_sop_class_uid(),
+            UID_GETPatientRootQueryRetrieveInformationModel);
+        BOOST_CHECK(message.has_data_set());
+        BOOST_CHECK(message.get_data_set() == this->query);
+    }
+};
+
+BOOST_FIXTURE_TEST_CASE(Constructor, Fixture)
+{
+    dcmtkpp::CGetRequest const message(
+        1234, UID_GETPatientRootQueryRetrieveInformationModel,
+        DIMSE_PRIORITY_MEDIUM, this->query);
+    this->check(message);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructor, Fixture)
+{
+    this->check_message_constructor(this->command_set, this->query);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorWrongCommandField, Fixture)
+{
+    this->command_set.as_int("CommandField") = {dcmtkpp::Message::Command::C_ECHO_RQ};
+    this->check_message_constructor_throw(this->command_set, this->query);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorMissingAffectSOPClass, Fixture)
+{
+    this->command_set.remove("AffectedSOPClassUID");
+    this->check_message_constructor_throw(this->command_set, this->query);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorMissingPriority, Fixture)
+{
+    this->command_set.remove("Priority");
+    this->check_message_constructor_throw(this->command_set, this->query);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorEmptyQuery, Fixture)
+{
+    dcmtkpp::DataSet empty;
+    this->check_message_constructor_throw(this->command_set, empty);
+}
diff --git a/tests/code/CGetResponse.cpp b/tests/code/CGetResponse.cpp
new file mode 100644
index 0000000..c207421
--- /dev/null
+++ b/tests/code/CGetResponse.cpp
@@ -0,0 +1,94 @@
+#define BOOST_TEST_MODULE CGetResponse
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcuid.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CGetResponse.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/registry.h"
+
+#include "../MessageFixtureBase.h"
+
+struct Fixture: public MessageFixtureBase<dcmtkpp::CGetResponse>
+{
+    dcmtkpp::DataSet command_set;
+    dcmtkpp::DataSet data_set;
+
+    Fixture()
+    {
+        this->command_set.add("CommandField", {dcmtkpp::Message::Command::C_GET_RSP});
+        this->command_set.add("MessageIDBeingRespondedTo", {1234});
+        this->command_set.add("Status", {STATUS_Success});
+
+        this->command_set.add("MessageID", {5678});
+        this->command_set.add("AffectedSOPClassUID",
+            {UID_GETStudyRootQueryRetrieveInformationModel});
+        this->command_set.add(dcmtkpp::registry::NumberOfRemainingSuboperations, {1});
+        this->command_set.add(dcmtkpp::registry::NumberOfCompletedSuboperations, {2});
+        this->command_set.add(dcmtkpp::registry::NumberOfFailedSuboperations, {3});
+        this->command_set.add(dcmtkpp::registry::NumberOfWarningSuboperations, {4});
+
+        this->data_set.add("PatientName", {"Doe^John"});
+        this->data_set.add("PatientID", {"DJ123"});
+        this->data_set.add("StudyDescription", {"Brain"});
+        this->data_set.add("StudyInstanceUID", {"1.2.3"});
+    }
+
+    virtual void check(dcmtkpp::CGetResponse const & message)
+    {
+        BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_GET_RSP);
+        BOOST_CHECK_EQUAL(message.get_message_id_being_responded_to(), 1234);
+        BOOST_CHECK_EQUAL(message.get_status(), STATUS_Success);
+
+        BOOST_CHECK(message.has_message_id());
+        BOOST_CHECK_EQUAL(message.get_message_id(), 5678);
+
+        BOOST_CHECK(message.has_affected_sop_class_uid());
+        BOOST_CHECK_EQUAL(
+            message.get_affected_sop_class_uid(),
+            UID_GETStudyRootQueryRetrieveInformationModel);
+
+        BOOST_CHECK(message.has_number_of_remaining_sub_operations());
+        BOOST_CHECK_EQUAL(message.get_number_of_remaining_sub_operations(), 1);
+
+        BOOST_CHECK(message.has_number_of_completed_sub_operations());
+        BOOST_CHECK_EQUAL(message.get_number_of_completed_sub_operations(), 2);
+
+        BOOST_CHECK(message.has_number_of_failed_sub_operations());
+        BOOST_CHECK_EQUAL(message.get_number_of_failed_sub_operations(), 3);
+
+        BOOST_CHECK(message.has_number_of_warning_sub_operations());
+        BOOST_CHECK_EQUAL(message.get_number_of_warning_sub_operations(), 4);
+
+        BOOST_CHECK(message.has_data_set());
+        BOOST_CHECK(message.get_data_set() == this->data_set);
+    }
+};
+
+BOOST_FIXTURE_TEST_CASE(Constructor, Fixture)
+{
+    dcmtkpp::CGetResponse message(1234, STATUS_Success, this->data_set);
+    message.set_message_id(5678);
+    message.set_affected_sop_class_uid(
+        UID_GETStudyRootQueryRetrieveInformationModel);
+    message.set_number_of_remaining_sub_operations(1);
+    message.set_number_of_completed_sub_operations(2);
+    message.set_number_of_failed_sub_operations(3);
+    message.set_number_of_warning_sub_operations(4);
+
+    this->check(message);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructor, Fixture)
+{
+    this->check_message_constructor(this->command_set, this->data_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorWrongCommandField, Fixture)
+{
+    this->command_set.as_int(dcmtkpp::registry::CommandField) = { dcmtkpp::Message::Command::C_ECHO_RQ };
+    this->check_message_constructor_throw(this->command_set, this->data_set);
+}
diff --git a/tests/code/CMoveRequest.cpp b/tests/code/CMoveRequest.cpp
new file mode 100644
index 0000000..41a490a
--- /dev/null
+++ b/tests/code/CMoveRequest.cpp
@@ -0,0 +1,81 @@
+#define BOOST_TEST_MODULE CMoveRequest
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcuid.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CMoveRequest.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+
+#include "../MessageFixtureBase.h"
+
+struct Fixture: public MessageFixtureBase<dcmtkpp::CMoveRequest>
+{
+    dcmtkpp::DataSet command_set;
+    dcmtkpp::DataSet query;
+
+    Fixture()
+    {
+        this->command_set.add("CommandField", {dcmtkpp::Message::Command::C_MOVE_RQ});
+        this->command_set.add("MessageID", {1234});
+        this->command_set.add("AffectedSOPClassUID",
+            {UID_MOVEPatientRootQueryRetrieveInformationModel});
+        this->command_set.add("Priority", {DIMSE_PRIORITY_MEDIUM});
+        this->command_set.add("MoveDestination", {"destination"});
+
+        this->query.add("PatientName", {"Doe^John"});
+        this->query.add("StudyDescription", {"Brain"});
+        this->query.add("QueryRetrieveLevel", {"STUDY"});
+    }
+
+    virtual void check(dcmtkpp::CMoveRequest const & message)
+    {
+        BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_MOVE_RQ);
+        BOOST_CHECK_EQUAL(message.get_message_id(), 1234);
+        BOOST_CHECK_EQUAL(
+            message.get_affected_sop_class_uid(),
+            UID_MOVEPatientRootQueryRetrieveInformationModel);
+        BOOST_CHECK_EQUAL(message.get_move_destination(), "destination");
+        BOOST_CHECK(message.has_data_set());
+        BOOST_CHECK(message.get_data_set() == this->query);
+    }
+};
+
+BOOST_FIXTURE_TEST_CASE(Constructor, Fixture)
+{
+    dcmtkpp::CMoveRequest const message(
+        1234, UID_MOVEPatientRootQueryRetrieveInformationModel,
+        DIMSE_PRIORITY_MEDIUM, "destination", this->query);
+    this->check(message);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructor, Fixture)
+{
+    this->check_message_constructor(this->command_set, this->query);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorWrongCommandField, Fixture)
+{
+    this->command_set.as_int("CommandField") = {dcmtkpp::Message::Command::C_ECHO_RQ};
+    this->check_message_constructor_throw(this->command_set, this->query);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorMissingAffectSOPClass, Fixture)
+{
+    this->command_set.remove("AffectedSOPClassUID");
+    this->check_message_constructor_throw(this->command_set, this->query);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorMissingPriority, Fixture)
+{
+    this->command_set.remove("Priority");
+    this->check_message_constructor_throw(this->command_set, this->query);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorEmptyQuery, Fixture)
+{
+    dcmtkpp::DataSet empty;
+    this->check_message_constructor_throw(this->command_set, empty);
+}
diff --git a/tests/code/CMoveResponse.cpp b/tests/code/CMoveResponse.cpp
new file mode 100644
index 0000000..ceb7b5b
--- /dev/null
+++ b/tests/code/CMoveResponse.cpp
@@ -0,0 +1,93 @@
+#define BOOST_TEST_MODULE CMoveResponse
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcuid.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CMoveResponse.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+
+#include "../MessageFixtureBase.h"
+
+struct Fixture: public MessageFixtureBase<dcmtkpp::CMoveResponse>
+{
+    dcmtkpp::DataSet command_set;
+    dcmtkpp::DataSet data_set;
+
+    Fixture()
+    {
+        this->command_set.add("CommandField", {dcmtkpp::Message::Command::C_MOVE_RSP});
+        this->command_set.add("MessageIDBeingRespondedTo", {1234});
+        this->command_set.add("Status", {STATUS_Success});
+
+        this->command_set.add("MessageID", {5678});
+        this->command_set.add("AffectedSOPClassUID",
+            {UID_MOVEStudyRootQueryRetrieveInformationModel});
+        this->command_set.add(dcmtkpp::registry::NumberOfRemainingSuboperations, {1});
+        this->command_set.add(dcmtkpp::registry::NumberOfCompletedSuboperations, {2});
+        this->command_set.add(dcmtkpp::registry::NumberOfFailedSuboperations, {3});
+        this->command_set.add(dcmtkpp::registry::NumberOfWarningSuboperations, {4});
+
+        this->data_set.add("PatientName", {"Doe^John"});
+        this->data_set.add("PatientID", {"DJ123"});
+        this->data_set.add("StudyDescription", {"Brain"});
+        this->data_set.add("StudyInstanceUID", {"1.2.3"});
+    }
+
+    virtual void check(dcmtkpp::CMoveResponse const & message)
+    {
+        BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_MOVE_RSP);
+        BOOST_CHECK_EQUAL(message.get_message_id_being_responded_to(), 1234);
+        BOOST_CHECK_EQUAL(message.get_status(), STATUS_Success);
+
+        BOOST_CHECK(message.has_message_id());
+        BOOST_CHECK_EQUAL(message.get_message_id(), 5678);
+
+        BOOST_CHECK(message.has_affected_sop_class_uid());
+        BOOST_CHECK_EQUAL(
+            message.get_affected_sop_class_uid(),
+            UID_MOVEStudyRootQueryRetrieveInformationModel);
+
+        BOOST_CHECK(message.has_number_of_remaining_sub_operations());
+        BOOST_CHECK_EQUAL(message.get_number_of_remaining_sub_operations(), 1);
+
+        BOOST_CHECK(message.has_number_of_completed_sub_operations());
+        BOOST_CHECK_EQUAL(message.get_number_of_completed_sub_operations(), 2);
+
+        BOOST_CHECK(message.has_number_of_failed_sub_operations());
+        BOOST_CHECK_EQUAL(message.get_number_of_failed_sub_operations(), 3);
+
+        BOOST_CHECK(message.has_number_of_warning_sub_operations());
+        BOOST_CHECK_EQUAL(message.get_number_of_warning_sub_operations(), 4);
+
+        BOOST_CHECK(message.has_data_set());
+        BOOST_CHECK(message.get_data_set() == this->data_set);
+    }
+};
+
+BOOST_FIXTURE_TEST_CASE(Constructor, Fixture)
+{
+    dcmtkpp::CMoveResponse message(1234, STATUS_Success, this->data_set);
+    message.set_message_id(5678);
+    message.set_affected_sop_class_uid(
+        UID_MOVEStudyRootQueryRetrieveInformationModel);
+    message.set_number_of_remaining_sub_operations(1);
+    message.set_number_of_completed_sub_operations(2);
+    message.set_number_of_failed_sub_operations(3);
+    message.set_number_of_warning_sub_operations(4);
+
+    this->check(message);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructor, Fixture)
+{
+    this->check_message_constructor(this->command_set, this->data_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorWrongCommandField, Fixture)
+{
+    this->command_set.as_int("CommandField") = {dcmtkpp::Message::Command::C_ECHO_RQ};
+    this->check_message_constructor_throw(this->command_set, this->data_set);
+}
diff --git a/tests/code/CStoreRequest.cpp b/tests/code/CStoreRequest.cpp
new file mode 100644
index 0000000..9c9f625
--- /dev/null
+++ b/tests/code/CStoreRequest.cpp
@@ -0,0 +1,88 @@
+#define BOOST_TEST_MODULE CStoreRequest
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcuid.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CStoreRequest.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+
+#include "../MessageFixtureBase.h"
+
+struct Fixture: public MessageFixtureBase<dcmtkpp::CStoreRequest>
+{
+    dcmtkpp::DataSet command_set;
+    dcmtkpp::DataSet data_set;
+
+    Fixture()
+    {
+        this->command_set.add("CommandField", {dcmtkpp::Message::Command::C_STORE_RQ});
+        this->command_set.add("MessageID", {1234});
+        this->command_set.add("AffectedSOPClassUID", {UID_MRImageStorage});
+        this->command_set.add("AffectedSOPInstanceUID", {"1.2.3.4"});
+        this->command_set.add("Priority", {DIMSE_PRIORITY_MEDIUM});
+
+        this->command_set.add("MoveOriginatorApplicationEntityTitle", {"origin"});
+        this->command_set.add("MoveOriginatorMessageID", {5678});
+
+        this->data_set.add("PatientName", {"Doe^John"});
+        this->data_set.add("PatientID", {"DJ123"});
+        this->data_set.add("StudyDescription", {"Brain"});
+        this->data_set.add("StudyInstanceUID", {"1.2.3"});
+    }
+
+    void check(dcmtkpp::CStoreRequest const & message)
+    {
+        BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_STORE_RQ);
+        BOOST_CHECK_EQUAL(message.get_message_id(), 1234);
+        BOOST_CHECK_EQUAL(
+            message.get_affected_sop_class_uid(), UID_MRImageStorage);
+        BOOST_CHECK_EQUAL(
+            message.get_affected_sop_instance_uid(), "1.2.3.4");
+
+        BOOST_CHECK(message.has_move_originator_ae_title());
+        BOOST_CHECK_EQUAL(message.get_move_originator_ae_title(), "origin");
+
+        BOOST_CHECK(message.has_move_originator_message_id());
+        BOOST_CHECK_EQUAL(message.get_move_originator_message_id(), 5678);
+
+        BOOST_CHECK(message.has_data_set());
+        BOOST_CHECK(message.get_data_set() == this->data_set);
+    }
+};
+
+BOOST_FIXTURE_TEST_CASE(Constructor, Fixture)
+{
+    dcmtkpp::CStoreRequest message(
+        1234, UID_MRImageStorage, "1.2.3.4", DIMSE_PRIORITY_MEDIUM,
+        this->data_set);
+    message.set_move_originator_ae_title("origin");
+    message.set_move_originator_message_id(5678);
+
+    this->check(message);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructor, Fixture)
+{
+    this->check_message_constructor(this->command_set, this->data_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorWrongCommandField, Fixture)
+{
+    this->command_set.as_int("CommandField") = {dcmtkpp::Message::Command::C_ECHO_RSP};
+    this->check_message_constructor_throw(this->command_set, this->data_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorMissingAffectSOPClass, Fixture)
+{
+    this->command_set.remove("AffectedSOPClassUID");
+    this->check_message_constructor_throw(this->command_set, this->data_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorMissingAffectSOPInstance, Fixture)
+{
+    this->command_set.remove("AffectedSOPInstanceUID");
+    this->check_message_constructor_throw(this->command_set, this->data_set);
+}
diff --git a/tests/code/CStoreResponse.cpp b/tests/code/CStoreResponse.cpp
new file mode 100644
index 0000000..77ca267
--- /dev/null
+++ b/tests/code/CStoreResponse.cpp
@@ -0,0 +1,68 @@
+#define BOOST_TEST_MODULE CStoreResponse
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcuid.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/CStoreResponse.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+
+#include "../MessageFixtureBase.h"
+
+struct Fixture: public MessageFixtureBase<dcmtkpp::CStoreResponse>
+{
+    dcmtkpp::DataSet command_set;
+
+    Fixture()
+    {
+        this->command_set.add("CommandField", {dcmtkpp::Message::Command::C_STORE_RSP});
+        this->command_set.add("MessageIDBeingRespondedTo", {1234});
+        this->command_set.add("Status", {STATUS_Success});
+
+        this->command_set.add("MessageID", {5678});
+        this->command_set.add("AffectedSOPClassUID", {UID_MRImageStorage});
+        this->command_set.add("AffectedSOPInstanceUID", {"1.2.3.4"});
+    }
+
+    void check(dcmtkpp::CStoreResponse const & message)
+    {
+        BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_STORE_RSP);
+        BOOST_CHECK_EQUAL(message.get_message_id_being_responded_to(), 1234);
+        BOOST_CHECK_EQUAL(message.get_status(), STATUS_Success);
+        BOOST_CHECK(!message.has_data_set());
+
+        BOOST_CHECK(message.has_message_id());
+        BOOST_CHECK_EQUAL(message.get_message_id(), 5678);
+
+        BOOST_CHECK(message.has_affected_sop_class_uid());
+        BOOST_CHECK_EQUAL(
+            message.get_affected_sop_class_uid(), UID_MRImageStorage);
+
+        BOOST_CHECK(message.has_affected_sop_instance_uid());
+        BOOST_CHECK_EQUAL(message.get_affected_sop_instance_uid(), "1.2.3.4");
+    }
+};
+
+BOOST_FIXTURE_TEST_CASE(Constructor, Fixture)
+{
+    dcmtkpp::CStoreResponse message(1234, STATUS_Success);
+    message.set_message_id(5678);
+    message.set_affected_sop_class_uid(UID_MRImageStorage);
+    message.set_affected_sop_instance_uid("1.2.3.4");
+
+    this->check(message);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructor, Fixture)
+{
+    this->check_message_constructor(this->command_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorWrongCommandField, Fixture)
+{
+    this->command_set.add("CommandField", {dcmtkpp::Message::Command::C_ECHO_RQ});
+    this->check_message_constructor_throw(this->command_set);
+}
+
diff --git a/tests/code/Cancellation.cpp b/tests/code/Cancellation.cpp
new file mode 100644
index 0000000..5f2954f
--- /dev/null
+++ b/tests/code/Cancellation.cpp
@@ -0,0 +1,40 @@
+#define BOOST_TEST_MODULE Cancellation
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Cancellation.h"
+
+#include "../MessageFixtureBase.h"
+
+struct Fixture: public MessageFixtureBase<dcmtkpp::Cancellation>
+{
+    dcmtkpp::DataSet command_set;
+    Fixture()
+    {
+        this->command_set.add("CommandField", {dcmtkpp::Message::Command::C_CANCEL_RQ});
+        this->command_set.add("MessageIDBeingRespondedTo", {1234});
+    }
+
+    void check(dcmtkpp::Cancellation const & message)
+    {
+        BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_CANCEL_RQ);
+        BOOST_CHECK_EQUAL(message.get_message_id_being_responded_to(), 1234);
+    }
+};
+
+BOOST_FIXTURE_TEST_CASE(Constructor, Fixture)
+{
+    dcmtkpp::Cancellation const message(1234);
+    this->check(message);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructor, Fixture)
+{
+    this->check_message_constructor(this->command_set);
+}
+
+BOOST_FIXTURE_TEST_CASE(MessageConstructorWrongCommandField, Fixture)
+{
+    this->command_set.as_int("CommandField") = {dcmtkpp::Message::Command::C_ECHO_RQ};
+    this->check_message_constructor_throw(this->command_set);
+}
diff --git a/tests/code/DataSet.cpp b/tests/code/DataSet.cpp
new file mode 100644
index 0000000..f28aa3c
--- /dev/null
+++ b/tests/code/DataSet.cpp
@@ -0,0 +1,273 @@
+#define BOOST_TEST_MODULE DataSet
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/Tag.h"
+#include "dcmtkpp/VR.h"
+
+BOOST_AUTO_TEST_CASE(Empty)
+{
+    dcmtkpp::DataSet dataset;
+    BOOST_CHECK(dataset.empty());
+    BOOST_CHECK_EQUAL(dataset.size(), 0);
+    BOOST_CHECK(!dataset.has(dcmtkpp::Tag("PatientName")));
+}
+
+BOOST_AUTO_TEST_CASE(AddExplicitVR)
+{
+    dcmtkpp::Tag const tag("PatientName");
+
+    dcmtkpp::DataSet dataset;
+    dataset.add(tag, dcmtkpp::VR::PN);
+
+    BOOST_CHECK(!dataset.empty());
+    BOOST_CHECK_EQUAL(dataset.size(), 1);
+    BOOST_CHECK(dataset.has(tag));
+    BOOST_CHECK(dataset.get_vr(tag) == dcmtkpp::VR::PN);
+}
+
+BOOST_AUTO_TEST_CASE(AddImplicitVR)
+{
+    dcmtkpp::Tag const tag("PatientName");
+
+    dcmtkpp::DataSet dataset;
+    dataset.add(tag);
+
+    BOOST_CHECK(!dataset.empty());
+    BOOST_CHECK_EQUAL(dataset.size(), 1);
+    BOOST_CHECK(dataset.has(tag));
+    BOOST_CHECK(dataset.get_vr(tag) == dcmtkpp::VR::PN);
+}
+
+BOOST_AUTO_TEST_CASE(AddValueExplicitVR)
+{
+    dcmtkpp::Tag const tag("PatientName");
+
+    dcmtkpp::DataSet dataset;
+    dataset.add(tag, { "Doe^John"}, dcmtkpp::VR::PN);
+
+    BOOST_CHECK(!dataset.empty());
+    BOOST_CHECK_EQUAL(dataset.size(), 1);
+    BOOST_CHECK(dataset.has(tag));
+    BOOST_CHECK(dataset.get_vr(tag) == dcmtkpp::VR::PN);
+    BOOST_CHECK(dataset.as_string(tag) == dcmtkpp::Value::Strings({ "Doe^John" }));
+}
+
+BOOST_AUTO_TEST_CASE(AddValueImplicitVR)
+{
+    dcmtkpp::Tag const tag("PatientName");
+
+    dcmtkpp::DataSet dataset;
+    dataset.add(tag, { "Doe^John"});
+
+    BOOST_CHECK(!dataset.empty());
+    BOOST_CHECK_EQUAL(dataset.size(), 1);
+    BOOST_CHECK(dataset.has(tag));
+    BOOST_CHECK(dataset.get_vr(tag) == dcmtkpp::VR::PN);
+    BOOST_CHECK(dataset.as_string(tag) == dcmtkpp::Value::Strings({ "Doe^John" }));
+}
+
+BOOST_AUTO_TEST_CASE(AddInvalidTag)
+{
+    dcmtkpp::Tag const tag(0xdead, 0xbeef);
+    dcmtkpp::DataSet dataset;
+
+    BOOST_CHECK_THROW(dataset.add(tag), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(AddInt)
+{
+    dcmtkpp::Tag const tag("Rows");
+
+    dcmtkpp::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());
+}
+
+BOOST_AUTO_TEST_CASE(AddDouble)
+{
+    dcmtkpp::Tag const tag("SpacingBetweenSlices");
+
+    dcmtkpp::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());
+}
+
+BOOST_AUTO_TEST_CASE(AddString)
+{
+    dcmtkpp::Tag const tag("PatientID");
+
+    dcmtkpp::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());
+}
+
+BOOST_AUTO_TEST_CASE(AddDataSet)
+{
+    dcmtkpp::Tag const tag("ReferencedStudySequence");
+
+    dcmtkpp::DataSet dataset;
+    dataset.add(tag);
+
+    BOOST_CHECK(dataset.is_data_set(tag));
+    BOOST_CHECK(dataset.empty(tag));
+    BOOST_CHECK_EQUAL(dataset.size(tag), 0);
+
+    dcmtkpp::Value::DataSets const & value = dataset.as_data_set(tag);
+    BOOST_CHECK(value.empty());
+}
+
+BOOST_AUTO_TEST_CASE(ModifyInt)
+{
+    dcmtkpp::Tag const tag("Rows");
+
+    dcmtkpp::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)
+{
+    dcmtkpp::Tag const tag("SpacingBetweenSlices");
+
+    dcmtkpp::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)
+{
+    dcmtkpp::Tag const tag("PatientID");
+
+    dcmtkpp::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)
+{
+    dcmtkpp::Tag const tag("ReferencedStudySequence");
+
+    dcmtkpp::DataSet dataset;
+    dataset.add(tag);
+
+    dcmtkpp::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);
+
+    dcmtkpp::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") == dcmtkpp::Value::Strings({"DJ1234"}));
+}
+
+BOOST_AUTO_TEST_CASE(GetVRMissing)
+{
+    dcmtkpp::Tag const tag("PatientID");
+    dcmtkpp::DataSet dataset;
+    BOOST_CHECK_THROW(dataset.get_vr(tag), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(TestEmptyMissing)
+{
+    dcmtkpp::Tag const tag("PatientID");
+    dcmtkpp::DataSet dataset;
+    BOOST_CHECK_THROW(dataset.empty(tag), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(SizeMissing)
+{
+    dcmtkpp::Tag const tag("PatientID");
+    dcmtkpp::DataSet dataset;
+    BOOST_CHECK_THROW(dataset.size(tag), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(Remove)
+{
+    dcmtkpp::Tag const tag("PatientID");
+    dcmtkpp::DataSet dataset;
+    dataset.add(tag);
+
+    dataset.remove(tag);
+    BOOST_CHECK(!dataset.has(tag));
+}
+
+BOOST_AUTO_TEST_CASE(RemoveMissing)
+{
+    dcmtkpp::Tag const tag("PatientID");
+    dcmtkpp::DataSet dataset;
+    dataset.add(tag);
+
+    dcmtkpp::Tag const other("PatientName");
+
+    BOOST_CHECK_THROW(
+        dataset.remove(other),
+        dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(Equality)
+{
+    dcmtkpp::DataSet dataset1;
+    dataset1.add("PatientID", {"DJ1234"});
+
+    dcmtkpp::DataSet dataset2;
+    dataset2.add("PatientID", {"DJ1234"});
+
+    dcmtkpp::DataSet dataset3;
+    dataset3.add("PatientAge", {"042Y"});
+
+    BOOST_CHECK(dataset1 == dataset2);
+    BOOST_CHECK(! (dataset1 == dataset3));
+}
+
+BOOST_AUTO_TEST_CASE(Difference)
+{
+    dcmtkpp::DataSet dataset1;
+    dataset1.add("PatientID", {"DJ1234"});
+
+    dcmtkpp::DataSet dataset2;
+    dataset2.add("PatientID", {"DJ1234"});
+
+    dcmtkpp::DataSet dataset3;
+    dataset3.add("PatientAge", {"042Y"});
+
+    BOOST_CHECK(! (dataset1 != dataset2));
+    BOOST_CHECK(dataset1 != dataset3);
+}
diff --git a/tests/code/Element.cpp b/tests/code/Element.cpp
new file mode 100644
index 0000000..23c82e7
--- /dev/null
+++ b/tests/code/Element.cpp
@@ -0,0 +1,160 @@
+#define BOOST_TEST_MODULE Element
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Element.h"
+#include "dcmtkpp/Exception.h"
+
+BOOST_AUTO_TEST_CASE(Empty)
+{
+    dcmtkpp::Element element;
+    BOOST_CHECK(element.empty());
+    BOOST_CHECK_EQUAL(element.size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(Int)
+{
+    dcmtkpp::Element const element((dcmtkpp::Value::Integers()));
+    BOOST_CHECK(element.is_int());
+
+    std::vector<int64_t> const & value = element.as_int();
+    BOOST_CHECK(value.empty());
+}
+
+BOOST_AUTO_TEST_CASE(ModifyInt)
+{
+    dcmtkpp::Element element({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 == dcmtkpp::Value::Integers({0, 1}));
+}
+
+BOOST_AUTO_TEST_CASE(IntWrong)
+{
+    dcmtkpp::Element element((dcmtkpp::Value::Integers()));
+    BOOST_CHECK_THROW(element.as_real(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(element.as_string(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(Double)
+{
+    dcmtkpp::Element const element((dcmtkpp::Value::Reals()));
+    BOOST_CHECK(element.is_real());
+
+    std::vector<double> const & value = element.as_real();
+    BOOST_CHECK(value.empty());
+}
+
+BOOST_AUTO_TEST_CASE(ModifyDouble)
+{
+    dcmtkpp::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 == dcmtkpp::Value::Reals({0., 1.5}));
+}
+
+BOOST_AUTO_TEST_CASE(DoubleWrong)
+{
+    dcmtkpp::Element element((dcmtkpp::Value::Reals()));
+    BOOST_CHECK_THROW(element.as_int(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(element.as_string(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(element.as_data_set(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(String)
+{
+    dcmtkpp::Element const element((dcmtkpp::Value::Strings()));
+    BOOST_CHECK(element.is_string());
+
+    std::vector<std::string> const & value = element.as_string();
+    BOOST_CHECK(value.empty());
+}
+
+BOOST_AUTO_TEST_CASE(ModifyString)
+{
+    dcmtkpp::Element element({""});
+    element.as_string().push_back("foo");
+
+    BOOST_CHECK(!element.empty());
+    BOOST_CHECK_EQUAL(element.size(), 2);
+
+    std::vector<std::string> const & value = element.as_string();
+    BOOST_CHECK(value == dcmtkpp::Value::Strings({"", "foo"}));
+}
+
+BOOST_AUTO_TEST_CASE(StringWrong)
+{
+    dcmtkpp::Element element((dcmtkpp::Value::Strings()));
+    BOOST_CHECK_THROW(element.as_int(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(element.as_real(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(element.as_data_set(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(DataSet)
+{
+    dcmtkpp::Element const element((dcmtkpp::Value::DataSets()));
+    BOOST_CHECK(element.is_data_set());
+
+    dcmtkpp::Value::DataSets const & value = element.as_data_set();
+    BOOST_CHECK(value.empty());
+}
+
+BOOST_AUTO_TEST_CASE(ModifyDataSet)
+{
+    dcmtkpp::Element element((dcmtkpp::Value::DataSets()));
+
+    dcmtkpp::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);
+
+    dcmtkpp::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") == dcmtkpp::Value::Strings({"DJ1234"}));
+}
+
+BOOST_AUTO_TEST_CASE(DataSetWrong)
+{
+    dcmtkpp::Element element((dcmtkpp::Value::DataSets()));
+    BOOST_CHECK_THROW(element.as_int(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(element.as_real(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(element.as_string(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(Equality)
+{
+    dcmtkpp::Element const element1({12,34}, dcmtkpp::VR::US);
+    dcmtkpp::Element const element2({12,34}, dcmtkpp::VR::US);
+    dcmtkpp::Element const element3({12.,34.}, dcmtkpp::VR::FL);
+    dcmtkpp::Element const element4({12,34}, dcmtkpp::VR::UL);
+
+    BOOST_CHECK(element1 == element2);
+    BOOST_CHECK(! (element1 == element3));
+    BOOST_CHECK(! (element1 == element4));
+}
+
+BOOST_AUTO_TEST_CASE(Difference)
+{
+    dcmtkpp::Element const element1({12,34}, dcmtkpp::VR::US);
+    dcmtkpp::Element const element2({12,34}, dcmtkpp::VR::US);
+    dcmtkpp::Element const element3({12.,34.}, dcmtkpp::VR::FL);
+    dcmtkpp::Element const element4({12,34}, dcmtkpp::VR::UL);
+
+    BOOST_CHECK(! (element1 != element2));
+    BOOST_CHECK(element1 != element3);
+    BOOST_CHECK(element1 != element4);
+}
diff --git a/tests/code/ElementAccessor.cpp b/tests/code/ElementAccessor.cpp
new file mode 100644
index 0000000..4e8ac3e
--- /dev/null
+++ b/tests/code/ElementAccessor.cpp
@@ -0,0 +1,125 @@
+#define BOOST_TEST_MODULE ElementAccessor
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dcdatset.h>
+#include <dcmtk/dcmdata/dcdeftag.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/ElementAccessor.h"
+#include "dcmtkpp/VRTraits.h"
+
+struct Fixture
+{
+    DcmDataset dataset;
+
+    Fixture()
+    {
+        OFCondition condition;
+        condition = dataset.putAndInsertOFStringArray(DCM_PatientID, "DJ123");
+        if(condition.bad())
+        {
+            throw dcmtkpp::Exception(condition);
+        }
+
+        condition = dataset.putAndInsertUint16(DCM_MessageID, 1234);
+        if(condition.bad())
+        {
+            throw dcmtkpp::Exception(condition);
+        }
+    }
+};
+
+BOOST_FIXTURE_TEST_CASE(GetCorrectTypeString, Fixture)
+{
+    BOOST_CHECK_EQUAL(
+        dcmtkpp::ElementAccessor<std::string>::get(this->dataset, DCM_PatientID),
+        "DJ123");
+}
+
+BOOST_FIXTURE_TEST_CASE(GetCorrectVRString, Fixture)
+{
+    BOOST_CHECK_EQUAL(
+        dcmtkpp::ElementAccessor<
+            typename dcmtkpp::VRTraits<EVR_LO>::ValueType
+        >::get(this->dataset, DCM_PatientID),
+        "DJ123");
+}
+
+BOOST_FIXTURE_TEST_CASE(GetCorrectTypeNonString, Fixture)
+{
+    BOOST_CHECK_EQUAL(
+        dcmtkpp::ElementAccessor<Uint16>::get(this->dataset, DCM_MessageID),
+        1234);
+}
+
+BOOST_FIXTURE_TEST_CASE(GetCorrectVRNonString, Fixture)
+{
+    BOOST_CHECK_EQUAL(
+        dcmtkpp::ElementAccessor<
+            typename dcmtkpp::VRTraits<EVR_US>::ValueType
+        >::get(this->dataset, DCM_MessageID),
+        1234);
+}
+
+BOOST_FIXTURE_TEST_CASE(GetWrongTypeString, Fixture)
+{
+    BOOST_CHECK_THROW(
+        dcmtkpp::ElementAccessor<Float32>::get(this->dataset, DCM_PatientID),
+        dcmtkpp::Exception);
+}
+
+BOOST_FIXTURE_TEST_CASE(GetWrongTypeNonString, Fixture)
+{
+    BOOST_CHECK_THROW(
+        dcmtkpp::ElementAccessor<Float32>::get(this->dataset, DCM_MessageID),
+        dcmtkpp::Exception);
+}
+
+BOOST_FIXTURE_TEST_CASE(SetEmpty, Fixture)
+{
+    dcmtkpp::ElementAccessor<std::string>::set(this->dataset, DCM_PatientName, "FOO");
+    OFString value;
+    OFCondition const condition =
+        this->dataset.findAndGetOFString(DCM_PatientName, value);
+    BOOST_REQUIRE(condition.good());
+    BOOST_CHECK_EQUAL(std::string(value.c_str()), "FOO");
+}
+
+BOOST_FIXTURE_TEST_CASE(SetWrongTypeString, Fixture)
+{
+    BOOST_CHECK_THROW(
+        dcmtkpp::ElementAccessor<Float32>::set(
+            this->dataset, DCM_PatientName, 1.234),
+        dcmtkpp::Exception);
+}
+
+BOOST_FIXTURE_TEST_CASE(SetWrongTypeNonString, Fixture)
+{
+    BOOST_CHECK_THROW(
+        dcmtkpp::ElementAccessor<Float64>::set(
+            this->dataset, DCM_Status, STATUS_Success),
+        dcmtkpp::Exception);
+}
+
+BOOST_FIXTURE_TEST_CASE(SetExisting, Fixture)
+{
+    dcmtkpp::ElementAccessor<std::string>::set(this->dataset, DCM_PatientID, "FOO");
+    OFString value;
+    OFCondition const condition =
+        this->dataset.findAndGetOFString(DCM_PatientID, value);
+    BOOST_REQUIRE(condition.good());
+    BOOST_CHECK_EQUAL(std::string(value.c_str()), "FOO");
+}
+
+BOOST_FIXTURE_TEST_CASE(Has, Fixture)
+{
+    BOOST_CHECK(
+        dcmtkpp::ElementAccessor<std::string>::has(this->dataset, DCM_PatientID));
+}
+
+BOOST_FIXTURE_TEST_CASE(HasNot, Fixture)
+{
+    BOOST_CHECK(
+        !dcmtkpp::ElementAccessor<std::string>::has(this->dataset, DCM_PatientName));
+}
diff --git a/tests/code/Exception.cpp b/tests/code/Exception.cpp
new file mode 100644
index 0000000..c0939d5
--- /dev/null
+++ b/tests/code/Exception.cpp
@@ -0,0 +1,36 @@
+#define BOOST_TEST_MODULE Message
+#include <boost/test/unit_test.hpp>
+
+#include <ostream>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/ofstd/ofcond.h>
+
+#include "dcmtkpp/Exception.h"
+
+namespace dcmtkpp
+{
+
+std::ostream & operator<<(std::ostream & stream, Exception::Source const & type)
+{
+    stream << int(type);
+    return stream;
+}
+
+}
+
+BOOST_AUTO_TEST_CASE(StringConstructor)
+{
+    dcmtkpp::Exception const exception("foo");
+    BOOST_CHECK_EQUAL(exception.get_source(), dcmtkpp::Exception::Source::Message);
+    BOOST_CHECK_EQUAL(exception.what(), "foo");
+    BOOST_CHECK_THROW(exception.get_condition(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(ConditionConstructor)
+{
+    dcmtkpp::Exception const exception(EC_IllegalParameter);
+    BOOST_CHECK_EQUAL(exception.get_source(), dcmtkpp::Exception::Source::Condition);
+    BOOST_CHECK_EQUAL(exception.what(), EC_IllegalParameter.text());
+    BOOST_CHECK(exception.get_condition() == EC_IllegalParameter);
+}
diff --git a/tests/code/FindSCU.cpp b/tests/code/FindSCU.cpp
new file mode 100644
index 0000000..a7758df
--- /dev/null
+++ b/tests/code/FindSCU.cpp
@@ -0,0 +1,65 @@
+#define BOOST_TEST_MODULE FindSCU
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/FindSCU.h"
+
+#include "../PeerFixtureBase.h"
+
+struct Fixture: public PeerFixtureBase
+{
+    static bool called;
+
+    dcmtkpp::DataSet query;
+
+    Fixture()
+    : PeerFixtureBase(NET_REQUESTOR, 104, 10,
+        {
+            {
+                UID_FINDPatientRootQueryRetrieveInformationModel,
+                { UID_LittleEndianImplicitTransferSyntax }
+            }
+        })
+    {
+        Fixture::called = false;
+
+        this->query.add("QueryRetrieveLevel", {"PATIENT"});
+        this->query.add("PatientName", {"Doe^John"});
+        this->query.add("PatientID");
+    }
+
+
+    static void callback(dcmtkpp::DataSet const &)
+    {
+        Fixture::called = true;
+    }
+};
+
+bool Fixture::called = false;
+
+BOOST_FIXTURE_TEST_CASE(Find, Fixture)
+{
+    dcmtkpp::FindSCU scu;
+    scu.set_network(&this->network);
+    scu.set_association(&this->association);
+
+    scu.set_affected_sop_class(UID_FINDPatientRootQueryRetrieveInformationModel);
+    auto const results = scu.find(this->query);
+
+    BOOST_REQUIRE_EQUAL(results.size(), 1);
+    BOOST_CHECK(
+        results[0].as_string("PatientID") ==
+            dcmtkpp::Value::Strings({"DJ001"}));
+}
+
+BOOST_FIXTURE_TEST_CASE(FindCallback, Fixture)
+{
+    dcmtkpp::FindSCU scu;
+    scu.set_network(&this->network);
+    scu.set_association(&this->association);
+
+    scu.set_affected_sop_class(UID_FINDPatientRootQueryRetrieveInformationModel);
+    scu.find(this->query, Fixture::callback);
+
+    BOOST_CHECK(Fixture::called);
+}
diff --git a/tests/code/GetSCU.cpp b/tests/code/GetSCU.cpp
new file mode 100644
index 0000000..d588760
--- /dev/null
+++ b/tests/code/GetSCU.cpp
@@ -0,0 +1,69 @@
+#define BOOST_TEST_MODULE GetSCU
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/GetSCU.h"
+
+#include "../PeerFixtureBase.h"
+
+struct Fixture: public PeerFixtureBase
+{
+    static bool called;
+
+    dcmtkpp::DataSet query;
+
+    Fixture()
+    : PeerFixtureBase(NET_REQUESTOR, 104, 10,
+        {
+            {
+                UID_GETPatientRootQueryRetrieveInformationModel,
+                { UID_LittleEndianImplicitTransferSyntax }
+            },
+            {
+                UID_RawDataStorage, { UID_LittleEndianImplicitTransferSyntax },
+                ASC_SC_ROLE_SCP
+            }
+        })
+    {
+        Fixture::called = false;
+
+        this->query.add("QueryRetrieveLevel", {"PATIENT"});
+        this->query.add("PatientName", {"Doe^John"});
+    }
+
+
+    static void callback(dcmtkpp::DataSet const &)
+    {
+        Fixture::called = true;
+    }
+};
+
+bool Fixture::called = false;
+
+BOOST_FIXTURE_TEST_CASE(Get, Fixture)
+{
+    dcmtkpp::GetSCU scu;
+    scu.set_network(&this->network);
+    scu.set_association(&this->association);
+
+    scu.set_affected_sop_class(UID_GETPatientRootQueryRetrieveInformationModel);
+    auto const results = scu.get(this->query);
+
+    BOOST_REQUIRE_EQUAL(results.size(), 1);
+    BOOST_CHECK(
+        results[0].as_string("SOPInstanceUID") ==
+            dcmtkpp::Value::Strings({"2.25.95090344942250266709587559073467305647"}));
+}
+
+BOOST_FIXTURE_TEST_CASE(GetCallback, Fixture)
+{
+    dcmtkpp::GetSCU scu;
+    scu.set_network(&this->network);
+    scu.set_association(&this->association);
+
+    scu.set_affected_sop_class(UID_GETPatientRootQueryRetrieveInformationModel);
+    scu.get(this->query, Fixture::callback);
+
+    BOOST_CHECK(Fixture::called);
+}
+
diff --git a/tests/code/Message.cpp b/tests/code/Message.cpp
new file mode 100644
index 0000000..0b8e836
--- /dev/null
+++ b/tests/code/Message.cpp
@@ -0,0 +1,57 @@
+#define BOOST_TEST_MODULE Message
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+
+BOOST_AUTO_TEST_CASE(DefaultConstructor)
+{
+    dcmtkpp::Message const message;
+
+    // Command Set might not be empty (Command Group Length, Data Set Type)
+    BOOST_CHECK(!message.has_data_set());
+}
+
+BOOST_AUTO_TEST_CASE(Constructor)
+{
+    dcmtkpp::DataSet command_set;
+    command_set.add("CommandField", {dcmtkpp::Message::Command::C_ECHO_RQ});
+
+    dcmtkpp::DataSet data_set;
+
+    dcmtkpp::Message const message(command_set, data_set);
+
+    BOOST_CHECK_EQUAL(
+        message.get_command_set().as_int("CommandField", 0),
+        dcmtkpp::Message::Command::C_ECHO_RQ);
+
+    BOOST_CHECK(message.has_data_set());
+    BOOST_CHECK(message.get_data_set().empty());
+
+    BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_ECHO_RQ);
+}
+
+BOOST_AUTO_TEST_CASE(CommandField)
+{
+    dcmtkpp::Message message;
+    message.set_command_field(dcmtkpp::Message::Command::C_FIND_RSP);
+
+    BOOST_CHECK(
+        message.get_command_set().as_int("CommandField") ==
+            dcmtkpp::Value::Integers({dcmtkpp::Message::Command::C_FIND_RSP}));
+    BOOST_CHECK_EQUAL(message.get_command_field(), dcmtkpp::Message::Command::C_FIND_RSP);
+}
+
+BOOST_AUTO_TEST_CASE(DeleteDataSet)
+{
+    dcmtkpp::DataSet command_set;
+    dcmtkpp::DataSet data_set;
+
+    dcmtkpp::Message message(command_set, data_set);
+
+    BOOST_CHECK(message.has_data_set());
+
+    message.delete_data_set();
+
+    BOOST_CHECK(!message.has_data_set());
+}
diff --git a/tests/code/MoveSCU.cpp b/tests/code/MoveSCU.cpp
new file mode 100644
index 0000000..11bf2c9
--- /dev/null
+++ b/tests/code/MoveSCU.cpp
@@ -0,0 +1,82 @@
+#define BOOST_TEST_MODULE MoveSCU
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/MoveSCU.h"
+
+#include "../PeerFixtureBase.h"
+
+struct Fixture: public PeerFixtureBase
+{
+    static bool called;
+
+    dcmtkpp::DataSet query;
+
+    Fixture()
+    : PeerFixtureBase(NET_ACCEPTORREQUESTOR, 11113, 10,
+        {
+            {
+                UID_MOVEPatientRootQueryRetrieveInformationModel,
+                { UID_LittleEndianImplicitTransferSyntax }
+            },
+            {
+                UID_RawDataStorage, { UID_LittleEndianImplicitTransferSyntax },
+                ASC_SC_ROLE_SCP
+            }
+        })
+    {
+        Fixture::called = false;
+
+        this->query.add("QueryRetrieveLevel", {"PATIENT"});
+        this->query.add("PatientName", {"Doe^John"});
+    }
+
+    static void callback(dcmtkpp::DataSet const &)
+    {
+        Fixture::called = true;
+    }
+};
+
+bool Fixture::called = false;
+
+BOOST_AUTO_TEST_CASE(DefaultConstructor)
+{
+    dcmtkpp::MoveSCU const scu;
+    BOOST_CHECK_EQUAL(scu.get_move_destination(), "");
+}
+
+BOOST_AUTO_TEST_CASE(MoveDestination)
+{
+    dcmtkpp::MoveSCU scu;
+    scu.set_move_destination("remote");
+    BOOST_CHECK_EQUAL(scu.get_move_destination(), "remote");
+}
+
+BOOST_FIXTURE_TEST_CASE(Move, Fixture)
+{
+    dcmtkpp::MoveSCU scu;
+    scu.set_network(&this->network);
+    scu.set_association(&this->association);
+    scu.set_move_destination("LOCAL");
+
+    scu.set_affected_sop_class(UID_MOVEPatientRootQueryRetrieveInformationModel);
+    auto const results = scu.move(this->query);
+
+    BOOST_REQUIRE_EQUAL(results.size(), 1);
+    BOOST_CHECK(
+        results[0].as_string("SOPInstanceUID") ==
+            dcmtkpp::Value::Strings{"2.25.95090344942250266709587559073467305647"});
+}
+
+BOOST_FIXTURE_TEST_CASE(MoveCallback, Fixture)
+{
+    dcmtkpp::MoveSCU scu;
+    scu.set_network(&this->network);
+    scu.set_association(&this->association);
+    scu.set_move_destination("LOCAL");
+
+    scu.set_affected_sop_class(UID_MOVEPatientRootQueryRetrieveInformationModel);
+    scu.move(this->query, Fixture::callback);
+
+    BOOST_CHECK(Fixture::called);
+}
diff --git a/tests/code/Network.cpp b/tests/code/Network.cpp
new file mode 100644
index 0000000..f2594f9
--- /dev/null
+++ b/tests/code/Network.cpp
@@ -0,0 +1,156 @@
+#define BOOST_TEST_MODULE Network
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmnet/assoc.h>
+
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/Network.h"
+
+BOOST_AUTO_TEST_CASE(DefaultConstructor)
+{
+    dcmtkpp::Network network;
+
+    BOOST_CHECK_EQUAL(network.get_role(), NET_REQUESTOR);
+    BOOST_CHECK_EQUAL(network.get_port(), 0);
+    BOOST_CHECK_EQUAL(network.get_timeout(), 30);
+    BOOST_CHECK_EQUAL(network.get_options(), 0);
+
+    BOOST_CHECK(!network.is_initialized());
+    BOOST_CHECK_EQUAL(network.get_network(), static_cast<T_ASC_Network*>(NULL));
+}
+
+BOOST_AUTO_TEST_CASE(Constructor)
+{
+    dcmtkpp::Network network(NET_ACCEPTOR, 11112, 10, 1);
+
+    BOOST_CHECK_EQUAL(network.get_role(), NET_ACCEPTOR);
+    BOOST_CHECK_EQUAL(network.get_port(), 11112);
+    BOOST_CHECK_EQUAL(network.get_timeout(), 10);
+    BOOST_CHECK_EQUAL(network.get_options(), 1);
+
+    BOOST_CHECK(!network.is_initialized());
+    BOOST_CHECK_EQUAL(network.get_network(), static_cast<T_ASC_Network*>(NULL));
+}
+
+BOOST_AUTO_TEST_CASE(CopyConstructor)
+{
+    dcmtkpp::Network network(NET_ACCEPTOR, 11112, 10, 1);
+    dcmtkpp::Network other(network);
+
+    BOOST_CHECK_EQUAL(other.get_role(), network.get_role());
+    BOOST_CHECK_EQUAL(other.get_port(), network.get_port());
+    BOOST_CHECK_EQUAL(other.get_timeout(), network.get_timeout());
+    BOOST_CHECK_EQUAL(other.get_options(), network.get_options());
+    BOOST_CHECK_EQUAL(other.is_initialized(), network.is_initialized());
+    BOOST_CHECK_EQUAL(other.get_network(), network.get_network());
+}
+
+BOOST_AUTO_TEST_CASE(Assignment)
+{
+    dcmtkpp::Network network(NET_ACCEPTOR, 11112, 10, 1);
+    dcmtkpp::Network other(NET_REQUESTOR, 112, 30, 0);
+    other = network;
+
+    BOOST_CHECK_EQUAL(other.get_role(), network.get_role());
+    BOOST_CHECK_EQUAL(other.get_port(), network.get_port());
+    BOOST_CHECK_EQUAL(other.get_timeout(), network.get_timeout());
+    BOOST_CHECK_EQUAL(other.get_options(), network.get_options());
+    BOOST_CHECK_EQUAL(other.is_initialized(), network.is_initialized());
+    BOOST_CHECK_EQUAL(other.get_network(), network.get_network());
+}
+
+BOOST_AUTO_TEST_CASE(Role)
+{
+    dcmtkpp::Network network;
+    network.set_role(NET_ACCEPTOR);
+
+    BOOST_CHECK_EQUAL(network.get_role(), NET_ACCEPTOR);
+}
+
+BOOST_AUTO_TEST_CASE(RoleAssociated)
+{
+    dcmtkpp::Network network;
+    network.initialize();
+
+    BOOST_CHECK_THROW(network.set_role(NET_ACCEPTOR), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(Port)
+{
+    dcmtkpp::Network network;
+    network.set_port(1234);
+
+    BOOST_CHECK_EQUAL(network.get_port(), 1234);
+}
+
+BOOST_AUTO_TEST_CASE(PortAssociated)
+{
+    dcmtkpp::Network network;
+    network.initialize();
+
+    BOOST_CHECK_THROW(network.set_port(1234), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(Timeout)
+{
+    dcmtkpp::Network network;
+    network.set_timeout(10);
+
+    BOOST_CHECK_EQUAL(network.get_timeout(), 10);
+}
+
+BOOST_AUTO_TEST_CASE(TimeoutAssociated)
+{
+    dcmtkpp::Network network;
+    network.initialize();
+
+    BOOST_CHECK_THROW(network.set_timeout(10), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(Options)
+{
+    dcmtkpp::Network network;
+    network.set_options(1);
+
+    BOOST_CHECK_EQUAL(network.get_options(), 1);
+}
+
+BOOST_AUTO_TEST_CASE(OptionsAssociated)
+{
+    dcmtkpp::Network network;
+    network.initialize();
+
+    BOOST_CHECK_THROW(network.set_options(1), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(Initialize)
+{
+    dcmtkpp::Network network(NET_REQUESTOR, 11112, 1, 0);
+    network.initialize();
+
+    BOOST_CHECK(network.is_initialized());
+    BOOST_CHECK_NE(network.get_network(),  static_cast<T_ASC_Network*>(NULL));
+}
+
+BOOST_AUTO_TEST_CASE(Drop)
+{
+    dcmtkpp::Network network(NET_REQUESTOR, 11112, 1, 0);
+    network.initialize();
+    network.drop();
+    BOOST_CHECK(!network.is_initialized());
+    BOOST_CHECK_EQUAL(network.get_network(),  static_cast<T_ASC_Network*>(NULL));
+}
+
+BOOST_AUTO_TEST_CASE(InitializeTwice)
+{
+    dcmtkpp::Network network(NET_REQUESTOR, 11112, 1, 0);
+    network.initialize();
+    BOOST_REQUIRE_THROW(network.initialize(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(DropNotInitialized)
+{
+    dcmtkpp::Network network;
+    BOOST_REQUIRE_THROW(network.drop(), dcmtkpp::Exception);
+}
diff --git a/tests/code/Request.cpp b/tests/code/Request.cpp
new file mode 100644
index 0000000..c040689
--- /dev/null
+++ b/tests/code/Request.cpp
@@ -0,0 +1,27 @@
+#define BOOST_TEST_MODULE Request
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/Request.h"
+
+BOOST_AUTO_TEST_CASE(Constructor)
+{
+    dcmtkpp::Request const message(1234);
+
+    BOOST_CHECK_EQUAL(message.get_message_id(), 1234);
+}
+
+BOOST_AUTO_TEST_CASE(MessageConstructor)
+{
+    dcmtkpp::DataSet command_set;
+    command_set.add("MessageID", {1234});
+    dcmtkpp::Message const generic_message(command_set);
+
+    dcmtkpp::Request const message(generic_message);
+
+    BOOST_CHECK_EQUAL(message.get_message_id(), 1234);
+    BOOST_CHECK(!message.has_data_set());
+}
diff --git a/tests/code/Response.cpp b/tests/code/Response.cpp
new file mode 100644
index 0000000..85070a2
--- /dev/null
+++ b/tests/code/Response.cpp
@@ -0,0 +1,31 @@
+#define BOOST_TEST_MODULE Response
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmnet/dimse.h>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Message.h"
+#include "dcmtkpp/Response.h"
+
+BOOST_AUTO_TEST_CASE(Constructor)
+{
+    dcmtkpp::Response const message(1234, STATUS_Pending);
+
+    BOOST_CHECK_EQUAL(message.get_message_id_being_responded_to(), 1234);
+    BOOST_CHECK_EQUAL(message.get_status(), STATUS_Pending);
+}
+
+BOOST_AUTO_TEST_CASE(MessageConstructor)
+{
+    dcmtkpp::DataSet command_set;
+    command_set.add("MessageIDBeingRespondedTo", {1234});
+    command_set.add("Status", {STATUS_Pending});
+    dcmtkpp::Message const generic_message(command_set);
+
+    dcmtkpp::Response const message(generic_message);
+
+    BOOST_CHECK_EQUAL(message.get_message_id_being_responded_to(), 1234);
+    BOOST_CHECK_EQUAL(message.get_status(), STATUS_Pending);
+    BOOST_CHECK(!message.has_data_set());
+}
diff --git a/tests/code/SCU.cpp b/tests/code/SCU.cpp
new file mode 100644
index 0000000..58a1951
--- /dev/null
+++ b/tests/code/SCU.cpp
@@ -0,0 +1,41 @@
+#define BOOST_TEST_MODULE SCU
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/SCU.h"
+
+#include "../PeerFixtureBase.h"
+
+struct Fixture: public PeerFixtureBase
+{
+    Fixture()
+    : PeerFixtureBase(NET_REQUESTOR, 104, 10,
+        {
+            { UID_VerificationSOPClass,
+                {UID_LittleEndianImplicitTransferSyntax}
+            }
+        })
+    {
+        // Nothing else
+    }
+};
+
+BOOST_AUTO_TEST_CASE(DefaultConstructor)
+{
+    dcmtkpp::SCU const scu;
+    BOOST_CHECK_EQUAL(scu.get_affected_sop_class(), "");
+}
+
+BOOST_AUTO_TEST_CASE(AffectedSOPClassUID)
+{
+    dcmtkpp::SCU scu;
+    scu.set_affected_sop_class("1.2.3");
+    BOOST_CHECK_EQUAL(scu.get_affected_sop_class(), "1.2.3");
+}
+
+BOOST_FIXTURE_TEST_CASE(Echo, Fixture)
+{
+    dcmtkpp::SCU scu;
+    scu.set_network(&this->network);
+    scu.set_association(&this->association);
+    scu.echo();
+}
diff --git a/tests/code/ServiceRole.cpp b/tests/code/ServiceRole.cpp
new file mode 100644
index 0000000..609e244
--- /dev/null
+++ b/tests/code/ServiceRole.cpp
@@ -0,0 +1,62 @@
+#define BOOST_TEST_MODULE ServiceRole
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/Association.h"
+#include "dcmtkpp/Network.h"
+#include "dcmtkpp/ServiceRole.h"
+
+BOOST_AUTO_TEST_CASE(DefaultConstructor)
+{
+    dcmtkpp::ServiceRole const role;
+    BOOST_CHECK_EQUAL(
+        role.get_network(), static_cast<dcmtkpp::Network *>(NULL));
+    BOOST_CHECK_EQUAL(
+        role.get_association(), static_cast<dcmtkpp::Association *>(NULL));
+}
+
+BOOST_AUTO_TEST_CASE(Network)
+{
+    dcmtkpp::ServiceRole role;
+
+    dcmtkpp::Network network;
+    role.set_network(&network);
+
+    BOOST_CHECK_EQUAL(role.get_network(), &network);
+}
+
+BOOST_AUTO_TEST_CASE(Association)
+{
+    dcmtkpp::ServiceRole role;
+
+    dcmtkpp::Association association;
+    role.set_association(&association);
+
+    BOOST_CHECK_EQUAL(role.get_association(), &association);
+}
+
+BOOST_AUTO_TEST_CASE(CopyConstructor)
+{
+    dcmtkpp::Network network;
+    dcmtkpp::Association association;
+    dcmtkpp::ServiceRole role;
+    role.set_network(&network);
+    role.set_association(&association);
+
+    dcmtkpp::ServiceRole const other(role);
+    BOOST_CHECK_EQUAL(other.get_network(), role.get_network());
+    BOOST_CHECK_EQUAL(other.get_association(), role.get_association());
+}
+
+BOOST_AUTO_TEST_CASE(Assignement)
+{
+    dcmtkpp::Network network;
+    dcmtkpp::Association association;
+    dcmtkpp::ServiceRole role;
+    role.set_network(&network);
+    role.set_association(&association);
+
+    dcmtkpp::ServiceRole other;
+    other = role;
+    BOOST_CHECK_EQUAL(other.get_network(), role.get_network());
+    BOOST_CHECK_EQUAL(other.get_association(), role.get_association());
+}
diff --git a/tests/code/StoreSCU.cpp b/tests/code/StoreSCU.cpp
new file mode 100644
index 0000000..d1de26a
--- /dev/null
+++ b/tests/code/StoreSCU.cpp
@@ -0,0 +1,79 @@
+#define BOOST_TEST_MODULE StoreSCU
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/StoreSCU.h"
+
+#include "../PeerFixtureBase.h"
+
+struct Fixture: public PeerFixtureBase
+{
+    static bool called;
+
+    dcmtkpp::DataSet dataset;
+
+    Fixture()
+    : PeerFixtureBase(NET_REQUESTOR, 104, 10,
+        {
+            { UID_RawDataStorage,
+                {UID_LittleEndianImplicitTransferSyntax}
+            }
+        })
+    {
+        Fixture::called = false;
+
+        this->dataset.add("ImageType", {"ORIGINAL", "PRIMARY", "OTHER"});
+        this->dataset.add("PatientID", {"1234"});
+        this->dataset.add("StudyInstanceUID", {"2.25.386726390606491051215227596277040710"});
+        this->dataset.add("SeriesInstanceUID", {"2.25.235367796740370588607388995952651763168"});
+        this->dataset.add("SOPClassUID", {UID_RawDataStorage});
+        this->dataset.add("SOPInstanceUID", {"2.25.294312554735929033890522327215919068328"});
+    }
+
+
+    static void callback(void*, unsigned long)
+    {
+        Fixture::called = true;
+    }
+};
+
+bool Fixture::called = false;
+
+BOOST_AUTO_TEST_CASE(AffectedSOPClassUID)
+{
+    dcmtkpp::DataSet dataset;
+    dataset.add("SOPClassUID", {UID_RawDataStorage});
+
+    dcmtkpp::StoreSCU scu;
+    scu.set_affected_sop_class(dataset);
+    BOOST_CHECK_EQUAL(scu.get_affected_sop_class(), UID_RawDataStorage);
+}
+
+BOOST_AUTO_TEST_CASE(AffectedSOPClassUIDNoSOPClassUID)
+{
+    dcmtkpp::DataSet dataset;
+
+    dcmtkpp::StoreSCU scu;
+    BOOST_CHECK_THROW(scu.set_affected_sop_class(dataset), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(AffectedSOPClassUIDUnknownSOPClassUID)
+{
+    dcmtkpp::DataSet dataset;
+    dataset.add("SOPClassUID", {"invalid"});
+
+    dcmtkpp::StoreSCU scu;
+    BOOST_CHECK_THROW(scu.set_affected_sop_class(dataset), dcmtkpp::Exception);
+}
+
+BOOST_FIXTURE_TEST_CASE(Store, Fixture)
+{
+    dcmtkpp::StoreSCU scu;
+    scu.set_network(&this->network);
+    scu.set_association(&this->association);
+
+    scu.set_affected_sop_class(this->dataset);
+    scu.store(this->dataset, Fixture::callback);
+    BOOST_CHECK(this->called);
+}
diff --git a/tests/code/Tag.cpp b/tests/code/Tag.cpp
new file mode 100644
index 0000000..6c4e4a7
--- /dev/null
+++ b/tests/code/Tag.cpp
@@ -0,0 +1,187 @@
+#define BOOST_TEST_MODULE Tag
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/Tag.h"
+
+BOOST_AUTO_TEST_CASE(TwoArgumentsConstructor)
+{
+    dcmtkpp::Tag const tag(0xdead, 0xbeef);
+    BOOST_CHECK_EQUAL(tag.group, 0xdead);
+    BOOST_CHECK_EQUAL(tag.element, 0xbeef);
+}
+
+BOOST_AUTO_TEST_CASE(OneArgumentConstructor)
+{
+    dcmtkpp::Tag const tag(0xdeadbeef);
+    BOOST_CHECK_EQUAL(tag.group, 0xdead);
+    BOOST_CHECK_EQUAL(tag.element, 0xbeef);
+}
+
+BOOST_AUTO_TEST_CASE(StringConstructor)
+{
+    dcmtkpp::Tag const tag(std::string("PixelData"));
+    BOOST_CHECK_EQUAL(tag.group, 0x7fe0);
+    BOOST_CHECK_EQUAL(tag.element, 0x0010);
+}
+
+BOOST_AUTO_TEST_CASE(CharConstructor)
+{
+    dcmtkpp::Tag const tag("PixelData");
+    BOOST_CHECK_EQUAL(tag.group, 0x7fe0);
+    BOOST_CHECK_EQUAL(tag.element, 0x0010);
+}
+
+BOOST_AUTO_TEST_CASE(StringConstructorNumeric)
+{
+    dcmtkpp::Tag const tag(std::string("7fe00010"));
+    BOOST_CHECK_EQUAL(tag.group, 0x7fe0);
+    BOOST_CHECK_EQUAL(tag.element, 0x0010);
+}
+
+BOOST_AUTO_TEST_CASE(CharConstructorNumeric)
+{
+    dcmtkpp::Tag const tag("7fe00010");
+    BOOST_CHECK_EQUAL(tag.group, 0x7fe0);
+    BOOST_CHECK_EQUAL(tag.element, 0x0010);
+}
+
+BOOST_AUTO_TEST_CASE(StringConstructorWrong)
+{
+    BOOST_CHECK_THROW(dcmtkpp::Tag(std::string("Foobar")), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(CharConstructorWrong)
+{
+    BOOST_CHECK_THROW(dcmtkpp::Tag("Foobar"), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(StringConstructorNumericWrong)
+{
+    BOOST_CHECK_THROW(dcmtkpp::Tag(std::string("XXXXYYYY")), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(CharConstructorNumericWrong)
+{
+    BOOST_CHECK_THROW(dcmtkpp::Tag("XXXXYYYY"), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(CopyConstructor)
+{
+    dcmtkpp::Tag const tag(0xdead, 0xbeef);
+    dcmtkpp::Tag const other(tag);
+    BOOST_CHECK_EQUAL(other.group, 0xdead);
+    BOOST_CHECK_EQUAL(other.element, 0xbeef);
+}
+
+BOOST_AUTO_TEST_CASE(IsPrivate)
+{
+    dcmtkpp::Tag const tag1(0xdead, 0xbeef);
+    dcmtkpp::Tag const tag2(0x7fe0, 0x0010);
+
+    BOOST_CHECK(tag1.is_private());
+    BOOST_CHECK(!tag2.is_private());
+}
+
+BOOST_AUTO_TEST_CASE(Name)
+{
+    dcmtkpp::Tag const tag(0x7fe0, 0x0010);
+    std::string const name = tag.get_name();
+    BOOST_CHECK_EQUAL(name, "PixelData");
+}
+
+BOOST_AUTO_TEST_CASE(NameWrong)
+{
+    dcmtkpp::Tag const tag(0xEEEE, 0xEEEE);
+    BOOST_CHECK_THROW(tag.get_name(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(Equality)
+{
+    dcmtkpp::Tag const tag1(0xdead, 0xbeef);
+    dcmtkpp::Tag const tag2(0xdead, 0xbeef);
+    dcmtkpp::Tag const tag3(0xbeef, 0xf00d);
+
+    BOOST_CHECK(tag1 == tag2);
+    BOOST_CHECK( ! (tag1 == tag3) );
+}
+
+BOOST_AUTO_TEST_CASE(Difference)
+{
+    dcmtkpp::Tag const tag1(0xdead, 0xbeef);
+    dcmtkpp::Tag const tag2(0xdead, 0xbeef);
+    dcmtkpp::Tag const tag3(0xbeef, 0xf00d);
+
+    BOOST_CHECK( ! (tag1 != tag2) );
+    BOOST_CHECK(tag1 != tag3);
+}
+
+BOOST_AUTO_TEST_CASE(Inferior)
+{
+    dcmtkpp::Tag const tag1(0xdead, 0xbeef);
+    dcmtkpp::Tag const tag2(0xdead, 0xf00d);
+    dcmtkpp::Tag const tag3(0xbeef, 0xf00d);
+
+    BOOST_CHECK(tag1 < tag2);
+    BOOST_CHECK(tag3 < tag1);
+
+    BOOST_CHECK( ! (tag2 < tag1) );
+    BOOST_CHECK( ! (tag1 < tag3) );
+}
+
+BOOST_AUTO_TEST_CASE(Superior)
+{
+    dcmtkpp::Tag const tag1(0xdead, 0xbeef);
+    dcmtkpp::Tag const tag2(0xdead, 0xf00d);
+    dcmtkpp::Tag const tag3(0xbeef, 0xf00d);
+
+    BOOST_CHECK(tag2 > tag1);
+    BOOST_CHECK(tag1 > tag3);
+
+    BOOST_CHECK( ! (tag1 > tag2) );
+    BOOST_CHECK( ! (tag3 > tag1) );
+}
+
+BOOST_AUTO_TEST_CASE(InferiorOrEqual)
+{
+    dcmtkpp::Tag const tag1(0xdead, 0xbeef);
+    dcmtkpp::Tag const tag2(0xdead, 0xf00d);
+    dcmtkpp::Tag const tag3(0xbeef, 0xf00d);
+    dcmtkpp::Tag const tag4(0xdead, 0xbeef);
+
+    BOOST_CHECK(tag1 <= tag2);
+    BOOST_CHECK(tag3 <= tag1);
+    BOOST_CHECK(tag1 <= tag4);
+
+    BOOST_CHECK( ! (tag2 <= tag1) );
+    BOOST_CHECK( ! (tag1 <= tag3) );
+}
+
+BOOST_AUTO_TEST_CASE(SuperiorOrEqual)
+{
+    dcmtkpp::Tag const tag1(0xdead, 0xbeef);
+    dcmtkpp::Tag const tag2(0xdead, 0xf00d);
+    dcmtkpp::Tag const tag3(0xbeef, 0xf00d);
+    dcmtkpp::Tag const tag4(0xdead, 0xbeef);
+
+    BOOST_CHECK(tag2 >= tag1);
+    BOOST_CHECK(tag1 >= tag3);
+    BOOST_CHECK(tag1 >= tag4);
+
+    BOOST_CHECK( ! (tag1 >= tag2) );
+    BOOST_CHECK( ! (tag3 >= tag1) );
+}
+
+BOOST_AUTO_TEST_CASE(StreamInsertion)
+{
+    dcmtkpp::Tag const tag(0xdead, 0xbeef);
+    std::ostringstream stream;
+    stream << tag;
+    BOOST_CHECK_EQUAL(stream.str(), "deadbeef");
+}
+
+BOOST_AUTO_TEST_CASE(StringConversion)
+{
+    dcmtkpp::Tag const tag(0xdead, 0xbeef);
+    BOOST_CHECK_EQUAL(std::string(tag), "deadbeef");
+}
diff --git a/tests/code/VR.cpp b/tests/code/VR.cpp
new file mode 100644
index 0000000..f231879
--- /dev/null
+++ b/tests/code/VR.cpp
@@ -0,0 +1,31 @@
+#define BOOST_TEST_MODULE VR
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/Exception.h"
+#include "dcmtkpp/VR.h"
+
+BOOST_AUTO_TEST_CASE(as_string)
+{
+    dcmtkpp::VR const vr(dcmtkpp::VR::AT);
+    std::string const string = dcmtkpp::as_string(vr);
+    BOOST_CHECK_EQUAL(string, "AT");
+}
+
+BOOST_AUTO_TEST_CASE(as_string_invalid)
+{
+    dcmtkpp::VR const vr(dcmtkpp::VR::INVALID);
+    BOOST_CHECK_THROW(dcmtkpp::as_string(vr), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(as_vr)
+{
+    std::string const string("AT");
+    dcmtkpp::VR const vr = dcmtkpp::as_vr(string);
+    BOOST_CHECK(vr == dcmtkpp::VR::AT);
+}
+
+BOOST_AUTO_TEST_CASE(as_vr_wrong)
+{
+    std::string const string("XX");
+    BOOST_CHECK_THROW(dcmtkpp::as_vr(string), dcmtkpp::Exception);
+}
diff --git a/tests/code/Value.cpp b/tests/code/Value.cpp
new file mode 100644
index 0000000..d62017a
--- /dev/null
+++ b/tests/code/Value.cpp
@@ -0,0 +1,250 @@
+#define BOOST_TEST_MODULE Value
+#include <boost/test/unit_test.hpp>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Element.h"
+#include "dcmtkpp/Exception.h"
+
+BOOST_AUTO_TEST_CASE(Empty)
+{
+    dcmtkpp::Value const value;
+
+    BOOST_CHECK(value.get_type() == dcmtkpp::Value::Type::Empty);
+    BOOST_CHECK_THROW(value.as_integers(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(value.as_reals(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(value.as_strings(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(value.as_data_sets(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(Integers)
+{
+    dcmtkpp::Value const value({1234});
+
+    BOOST_CHECK(value.get_type() == dcmtkpp::Value::Type::Integers);
+    BOOST_CHECK(value.as_integers() == dcmtkpp::Value::Integers({1234}));
+
+    BOOST_CHECK_THROW(value.as_reals(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(value.as_strings(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(value.as_data_sets(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(ModifyIntegers)
+{
+    dcmtkpp::Value value({1234});
+    value.as_integers().push_back(5678);
+    BOOST_CHECK(value.as_integers() == dcmtkpp::Value::Integers({1234, 5678}));
+}
+
+BOOST_AUTO_TEST_CASE(Reals)
+{
+    dcmtkpp::Value const value({12.34});
+
+    BOOST_CHECK(value.get_type() == dcmtkpp::Value::Type::Reals);
+    BOOST_CHECK(value.as_reals() == dcmtkpp::Value::Reals({12.34}));
+
+    BOOST_CHECK_THROW(value.as_integers(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(value.as_strings(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(value.as_data_sets(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(ModifyReals)
+{
+    dcmtkpp::Value value({12.34});
+    value.as_reals().push_back(56.78);
+    BOOST_CHECK(value.as_reals() == dcmtkpp::Value::Reals({12.34, 56.78}));
+}
+
+BOOST_AUTO_TEST_CASE(Strings)
+{
+    dcmtkpp::Value const value({"foo"});
+
+    BOOST_CHECK(value.get_type() == dcmtkpp::Value::Type::Strings);
+    BOOST_CHECK(value.as_strings() == dcmtkpp::Value::Strings({"foo"}));
+
+    BOOST_CHECK_THROW(value.as_integers(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(value.as_reals(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(value.as_data_sets(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(ModifyStrings)
+{
+    dcmtkpp::Value value({"foo"});
+    value.as_strings().push_back("bar");
+    BOOST_CHECK(value.as_strings() == dcmtkpp::Value::Strings({"foo", "bar"}));
+}
+
+BOOST_AUTO_TEST_CASE(DataSets)
+{
+    dcmtkpp::DataSet data_set;
+    data_set.add("PatientID", {"DJ1234"});
+    dcmtkpp::Value const value({data_set});
+
+    BOOST_CHECK(value.get_type() == dcmtkpp::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") ==
+            dcmtkpp::Value::Strings({"DJ1234"}));
+
+    BOOST_CHECK_THROW(value.as_integers(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(value.as_strings(), dcmtkpp::Exception);
+    BOOST_CHECK_THROW(value.as_reals(), dcmtkpp::Exception);
+}
+
+BOOST_AUTO_TEST_CASE(ModifyDataSets)
+{
+    dcmtkpp::DataSet data_set;
+    data_set.add("PatientID");
+    data_set.as_string("PatientID").push_back("DJ1234");
+    dcmtkpp::Value value({data_set});
+
+    value.as_data_sets()[0].as_string("PatientID")[0] = "XXX";
+
+    BOOST_CHECK(value.get_type() == dcmtkpp::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") ==
+            dcmtkpp::Value::Strings({"XXX"}));
+}
+
+BOOST_AUTO_TEST_CASE(EqualityEmpty)
+{
+    dcmtkpp::Value const value1;
+    dcmtkpp::Value const value2;
+    dcmtkpp::Value const value3((dcmtkpp::Value::Integers()));
+    BOOST_CHECK(value1 == value2);
+    BOOST_CHECK( ! (value1 == value3));
+}
+
+BOOST_AUTO_TEST_CASE(EqualityIntegers)
+{
+    dcmtkpp::Value const value1({1,2});
+    dcmtkpp::Value const value2({1,2});
+    dcmtkpp::Value const value3({3,4});
+    dcmtkpp::Value const value4({3,4});
+    BOOST_CHECK(value1 == value2);
+    BOOST_CHECK( ! (value1 == value3));
+    BOOST_CHECK( ! (value1 == value4));
+}
+
+BOOST_AUTO_TEST_CASE(EqualityReals)
+{
+    dcmtkpp::Value const value1({1,2});
+    dcmtkpp::Value const value2({1,2});
+    dcmtkpp::Value const value3({3,4});
+    dcmtkpp::Value const value4({3,4});
+    BOOST_CHECK(value1 == value2);
+    BOOST_CHECK( ! (value1 == value3));
+    BOOST_CHECK( ! (value1 == value4));
+}
+
+BOOST_AUTO_TEST_CASE(EqualityStrings)
+{
+    dcmtkpp::Value const value1({"1","2"});
+    dcmtkpp::Value const value2({"1","2"});
+    dcmtkpp::Value const value3({"3","4"});
+    dcmtkpp::Value const value4({3,4});
+    BOOST_CHECK(value1 == value2);
+    BOOST_CHECK( ! (value1 == value3));
+    BOOST_CHECK( ! (value1 == value4));
+}
+
+BOOST_AUTO_TEST_CASE(EqualityDataSets)
+{
+    dcmtkpp::DataSet dataset1;
+    dataset1.add("PatientID", {"DJ1234"});
+    dataset1.add("PixelSpacing", {1.5, 2.5});
+
+    dcmtkpp::DataSet dataset2;
+    dataset1.add("PatientName", {"Doe^John"});
+    dataset1.add("PatientAge", {"042Y"});
+
+    dcmtkpp::Value const value1({dataset1});
+    dcmtkpp::Value const value2({dataset1});
+    dcmtkpp::Value const value3({dataset2});
+    dcmtkpp::Value const value4({3,4});
+    BOOST_CHECK(value1 == value2);
+    BOOST_CHECK( ! (value1 == value3));
+    BOOST_CHECK( ! (value1 == value4));
+}
+
+BOOST_AUTO_TEST_CASE(DifferenceEmpty)
+{
+    dcmtkpp::Value const value1;
+    dcmtkpp::Value const value2;
+    dcmtkpp::Value const value3((dcmtkpp::Value::Integers()));
+    BOOST_CHECK(! (value1 != value2));
+    BOOST_CHECK(value1 != value3);
+}
+
+BOOST_AUTO_TEST_CASE(DifferenceIntegers)
+{
+    dcmtkpp::Value const value1({1,2});
+    dcmtkpp::Value const value2({1,2});
+    dcmtkpp::Value const value3({3,4});
+    dcmtkpp::Value const value4({3,4});
+    BOOST_CHECK(! (value1 != value2));
+    BOOST_CHECK(value1 != value3);
+    BOOST_CHECK(value1 != value4);
+}
+
+BOOST_AUTO_TEST_CASE(DifferenceReals)
+{
+    dcmtkpp::Value const value1({1.,2.});
+    dcmtkpp::Value const value2({1.,2.});
+    dcmtkpp::Value const value3({3.,4.});
+    dcmtkpp::Value const value4({3,4});
+    BOOST_CHECK(! (value1 != value2));
+    BOOST_CHECK(value1 != value3);
+    BOOST_CHECK(value1 != value4);
+}
+
+BOOST_AUTO_TEST_CASE(DifferenceStrings)
+{
+    dcmtkpp::Value const value1({"1","2"});
+    dcmtkpp::Value const value2({"1","2"});
+    dcmtkpp::Value const value3({"3","4"});
+    dcmtkpp::Value const value4({3,4});
+    BOOST_CHECK(! (value1 != value2));
+    BOOST_CHECK(value1 != value3);
+    BOOST_CHECK(value1 != value4);
+}
+
+BOOST_AUTO_TEST_CASE(DifferenceDataSets)
+{
+    dcmtkpp::DataSet dataset1;
+    dataset1.add("PatientID", {"DJ1234"});
+    dataset1.add("PixelSpacing", {1.5, 2.5});
+
+    dcmtkpp::DataSet dataset2;
+    dataset1.add("PatientName", {"Doe^John"});
+    dataset1.add("PatientAge", {"042Y"});
+
+    dcmtkpp::Value const value1({dataset1});
+    dcmtkpp::Value const value2({dataset1});
+    dcmtkpp::Value const value3({dataset2});
+    dcmtkpp::Value const value4({3,4});
+    BOOST_CHECK(! (value1 != value2));
+    BOOST_CHECK(value1 != value3);
+    BOOST_CHECK(value1 != value4);
+}
+
+struct Visitor
+{
+    typedef bool result_type;
+
+    template<typename T>
+    bool operator()(T const & container) const
+    {
+        return true;
+    }
+};
+
+BOOST_AUTO_TEST_CASE(VisitorEmpty)
+{
+    dcmtkpp::Value const value;
+    BOOST_CHECK_THROW(
+        dcmtkpp::apply_visitor(Visitor(), value),
+        dcmtkpp::Exception);
+}
diff --git a/tests/code/conversion.cpp b/tests/code/conversion.cpp
new file mode 100644
index 0000000..ce4c671
--- /dev/null
+++ b/tests/code/conversion.cpp
@@ -0,0 +1,424 @@
+#define BOOST_TEST_MODULE conversion
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dctk.h>
+
+#include "dcmtkpp/conversion.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/ElementAccessor.h"
+#include "dcmtkpp/Tag.h"
+#include "dcmtkpp/Value.h"
+#include "dcmtkpp/VR.h"
+#include "dcmtkpp/VRTraits.h"
+
+BOOST_AUTO_TEST_CASE(TagFromDcmtkpp)
+{
+    dcmtkpp::Tag const source(0xdead, 0xbeef);
+    DcmTagKey const destination = dcmtkpp::convert(source);
+
+    BOOST_CHECK_EQUAL(destination.getGroup(), 0xdead);
+    BOOST_CHECK_EQUAL(destination.getElement(), 0xbeef);
+}
+
+BOOST_AUTO_TEST_CASE(TagFromDcmtk)
+{
+    DcmTagKey const source(0xdead, 0xbeef);
+    dcmtkpp::Tag const destination = dcmtkpp::convert(source);
+
+    BOOST_CHECK_EQUAL(destination.group, 0xdead);
+    BOOST_CHECK_EQUAL(destination.element, 0xbeef);
+}
+
+template<typename TValueType>
+void compare(TValueType const & t1, TValueType const & t2)
+{
+    BOOST_CHECK_EQUAL(t1, t2);
+}
+
+template<>
+void compare<dcmtkpp::Value::Reals::value_type>(
+    dcmtkpp::Value::Reals::value_type const & t1,
+    dcmtkpp::Value::Reals::value_type const & t2)
+{
+    BOOST_CHECK_CLOSE(t1, t2, 1e-6);
+}
+
+template<dcmtkpp::VR VVR, DcmEVR VEVR, typename TInputType, typename TOutputType>
+void test_element_from_dcmtkpp(
+    TInputType const & source_value,
+    TInputType const & (dcmtkpp::Element::*getter)() const)
+{
+    dcmtkpp::Tag const source_tag(0xdead, 0xbeef);
+    DcmTagKey const destination_tag = dcmtkpp::convert(source_tag);
+
+    dcmtkpp::Element const source(source_value, VVR);
+
+    DcmElement * destination = dcmtkpp::convert(source_tag, source);
+    BOOST_CHECK_NE(destination, (DcmElement const *)(NULL));
+
+    BOOST_CHECK_EQUAL(destination->getVR(), VEVR);
+    BOOST_CHECK_NE(
+        dynamic_cast<TOutputType *>(destination), (TOutputType *)(NULL));
+
+    BOOST_CHECK_EQUAL(destination->getVM(), source.size());
+    for(std::size_t i=0; i<source.size(); ++i)
+    {
+        typedef typename dcmtkpp::VRTraits<VEVR>::ValueType ValueType;
+        if(typeid(TInputType) == typeid(dcmtkpp::Value::Reals))
+        {
+            compare<ValueType>(
+                dcmtkpp::ElementAccessor<ValueType>::element_get(*destination, i),
+                (source.*getter)()[i]);
+        }
+        else
+        {
+            BOOST_CHECK_EQUAL(
+                dcmtkpp::ElementAccessor<ValueType>::element_get(*destination, i),
+                (source.*getter)()[i]);
+        }
+    }
+}
+
+template<dcmtkpp::VR VVR, DcmEVR VEVR, typename TInputType, typename TElementType>
+void test_element_to_dcmtkpp(
+    TInputType const & source_value,
+    TInputType const & (dcmtkpp::Element::*getter)() const)
+{
+    DcmTag const source_tag(0xdead, 0xbeef, VEVR);
+    TElementType source(source_tag);
+    if(typeid(TInputType) == typeid(dcmtkpp::Value::Strings) ||
+        VEVR == EVR_IS || VEVR == EVR_DS)
+    {
+        OFString value;
+
+        if(!source_value.empty())
+        {
+            auto const last_it = --source_value.end();
+            auto it = source_value.begin();
+            while(it != last_it)
+            {
+                std::ostringstream stream;
+                stream << *it;
+                value += stream.str().c_str();
+                value += "\\";
+                ++it;
+            }
+
+            std::ostringstream stream;
+            stream << *last_it;
+            value += stream.str().c_str();
+        }
+
+        source.putOFStringArray(value);
+    }
+    else
+    {
+        for(unsigned int i=0; i<source_value.size(); ++i)
+        {
+            auto const & item = source_value[i];
+            dcmtkpp::ElementAccessor<typename dcmtkpp::VRTraits<VEVR>::ValueType>::element_set(
+                source, item, i);
+        }
+    }
+
+    dcmtkpp::Element const destination = dcmtkpp::convert(&source);
+
+    BOOST_CHECK(VVR == destination.vr);
+    BOOST_CHECK_EQUAL(source.getVM(), destination.size());
+    for(std::size_t i=0; i<destination.size(); ++i)
+    {
+        typedef typename dcmtkpp::VRTraits<VEVR>::ValueType ValueType;
+        if(typeid(TInputType) == typeid(dcmtkpp::Value::Reals))
+        {
+            compare<ValueType>(
+                dcmtkpp::ElementAccessor<ValueType>::element_get(source, i),
+                (destination.*getter)()[i]);
+        }
+        else
+        {
+            BOOST_CHECK_EQUAL(
+                dcmtkpp::ElementAccessor<ValueType>::element_get(source, i),
+                (destination.*getter)()[i]);
+        }
+    }
+}
+
+#define ElementTest(vr, InputType, ElementType, value, getter) \
+BOOST_AUTO_TEST_CASE(vr##FromDcmtkpp) \
+{ \
+    test_element_from_dcmtkpp< \
+        dcmtkpp::VR::vr, EVR_##vr, InputType, ElementType>(value, getter); \
+} \
+BOOST_AUTO_TEST_CASE(vr##ToDcmtkpp) \
+{ \
+    test_element_to_dcmtkpp< \
+        dcmtkpp::VR::vr, EVR_##vr, InputType, ElementType>(value, getter); \
+}
+
+ElementTest(
+    AE, dcmtkpp::Value::Strings, DcmApplicationEntity,
+    dcmtkpp::Value::Strings({"foo", "bar"}), &dcmtkpp::Element::as_string);
+
+ElementTest(
+    AS, dcmtkpp::Value::Strings, DcmAgeString,
+    dcmtkpp::Value::Strings({"012Y", "345D"}), &dcmtkpp::Element::as_string);
+
+ElementTest(
+    CS, dcmtkpp::Value::Strings, DcmCodeString,
+    dcmtkpp::Value::Strings({"foo", "bar"}), &dcmtkpp::Element::as_string);
+
+ElementTest(
+    DA, dcmtkpp::Value::Strings, DcmDate,
+    dcmtkpp::Value::Strings({"19000101", "20131215"}),
+    &dcmtkpp::Element::as_string);
+
+ElementTest(
+    DS, dcmtkpp::Value::Reals, DcmDecimalString,
+    dcmtkpp::Value::Reals({12.34, 56.78}), &dcmtkpp::Element::as_real);
+
+ElementTest(
+    DT, dcmtkpp::Value::Strings, DcmDateTime,
+    dcmtkpp::Value::Strings({"19000101123456", "201312150123"}),
+    &dcmtkpp::Element::as_string);
+
+ElementTest(
+    FL, dcmtkpp::Value::Reals, DcmFloatingPointSingle,
+    dcmtkpp::Value::Reals({12.34, 56.78}), &dcmtkpp::Element::as_real);
+
+ElementTest(
+    FD, dcmtkpp::Value::Reals, DcmFloatingPointDouble,
+    dcmtkpp::Value::Reals({12.34, 56.78}), &dcmtkpp::Element::as_real);
+
+ElementTest(
+    IS, dcmtkpp::Value::Integers, DcmIntegerString,
+    dcmtkpp::Value::Integers({34567, -67890}), &dcmtkpp::Element::as_int);
+
+ElementTest(
+    LO, dcmtkpp::Value::Strings, DcmLongString,
+    dcmtkpp::Value::Strings({"foo bar", "something else"}),
+    &dcmtkpp::Element::as_string);
+
+ElementTest(
+    LT, dcmtkpp::Value::Strings, DcmLongText,
+    dcmtkpp::Value::Strings({"foo\nbar\\something else"}),
+    &dcmtkpp::Element::as_string);
+
+// OB
+// OF
+// OW
+
+ElementTest(
+    PN, dcmtkpp::Value::Strings, DcmPersonName,
+    dcmtkpp::Value::Strings({"Doe^John", "^Bob^Dr."}),
+    &dcmtkpp::Element::as_string);
+
+ElementTest(
+    SH, dcmtkpp::Value::Strings, DcmShortString,
+    dcmtkpp::Value::Strings({"foo", "bar"}), &dcmtkpp::Element::as_string);
+
+ElementTest(
+    SL, dcmtkpp::Value::Integers, DcmSignedLong,
+    dcmtkpp::Value::Integers({34567, -56789}), &dcmtkpp::Element::as_int);
+
+ElementTest(
+    SS, dcmtkpp::Value::Integers, DcmSignedShort,
+    dcmtkpp::Value::Integers({1234, -5678}), &dcmtkpp::Element::as_int);
+
+ElementTest(
+    ST, dcmtkpp::Value::Strings, DcmShortText,
+    dcmtkpp::Value::Strings({"foo\nbar\\something else"}),
+    &dcmtkpp::Element::as_string);
+
+ElementTest(
+    TM, dcmtkpp::Value::Strings, DcmTime,
+    dcmtkpp::Value::Strings({"123456", "0123"}),
+    &dcmtkpp::Element::as_string);
+
+ElementTest(
+    UI, dcmtkpp::Value::Strings, DcmUniqueIdentifier,
+    dcmtkpp::Value::Strings(
+        {"1.2.840.10008.5.1.4.1.1.4", "1.2.840.10008.5.1.4.1.1.4.1"}),
+        &dcmtkpp::Element::as_string);
+
+ElementTest(
+    UL, dcmtkpp::Value::Integers, DcmUnsignedLong,
+    dcmtkpp::Value::Integers({123456, 789012}), &dcmtkpp::Element::as_int);
+
+// UN
+
+ElementTest(
+    US, dcmtkpp::Value::Integers, DcmUnsignedShort,
+    dcmtkpp::Value::Integers({12345, 6789}), &dcmtkpp::Element::as_int);
+
+ElementTest(
+    UT, dcmtkpp::Value::Strings, DcmUnlimitedText,
+    dcmtkpp::Value::Strings({"foo\nbar\\something else"}),
+    &dcmtkpp::Element::as_string);
+
+BOOST_AUTO_TEST_CASE(ATFromDcmtkpp)
+{
+    dcmtkpp::Element const source(
+        dcmtkpp::Value::Strings({"deadbeef", "beeff00d"}), dcmtkpp::VR::AT);
+
+    DcmElement * destination = dcmtkpp::convert(
+        dcmtkpp::Tag(0x1234, 0x5678), source);
+
+    BOOST_CHECK_NE(destination, (DcmElement const *)(NULL));
+
+    BOOST_CHECK_EQUAL(destination->getVR(), dcmtkpp::convert(source.vr));
+    BOOST_CHECK_NE(
+        dynamic_cast<DcmAttributeTag *>(destination),
+        (DcmAttributeTag *)(NULL));
+
+    BOOST_CHECK_EQUAL(destination->getVM(), source.size());
+    for(std::size_t i=0; i<source.size(); ++i)
+    {
+        dcmtkpp::Tag const & source_tag = source.as_string()[i];
+
+        DcmTagKey destination_tag;
+        OFCondition const condition = destination->getTagVal(destination_tag, i);
+        BOOST_CHECK(condition.good());
+
+        BOOST_CHECK(source_tag == dcmtkpp::convert(destination_tag));
+    }
+}
+
+BOOST_AUTO_TEST_CASE(ATToDcmtkpp)
+{
+    DcmAttributeTag source(DcmTag(0x1234, 0x5678, EVR_AT));
+    source.putTagVal(DcmTagKey(0xdead, 0xbeef), 0);
+    source.putTagVal(DcmTagKey(0xbeef, 0xf00d), 1);
+
+    dcmtkpp::Element const destination = dcmtkpp::convert(&source);
+
+    BOOST_CHECK(destination.vr == dcmtkpp::convert(source.getVR()));
+    BOOST_CHECK_EQUAL(source.getVM(), destination.size());
+    for(std::size_t i=0; i<destination.size(); ++i)
+    {
+        DcmTagKey source_tag;
+        source.getTagVal(source_tag, i);
+
+        dcmtkpp::Tag const & destination_tag = destination.as_string()[i];
+        BOOST_CHECK(dcmtkpp::convert(source_tag) == destination_tag);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(SQFromDcmtkpp)
+{
+    dcmtkpp::DataSet item;
+    item.add("PatientID");
+    item.as_string("PatientID").push_back("DJ1234");
+
+    dcmtkpp::Element const source(
+        dcmtkpp::Value::DataSets({item}), dcmtkpp::VR::SQ);
+
+    dcmtkpp::Tag const source_tag(0xdead, 0xbeef);
+
+    DcmElement * destination = dcmtkpp::convert(source_tag, source);
+
+    BOOST_CHECK_NE(destination, (DcmElement const *)(NULL));
+
+    BOOST_CHECK_EQUAL(destination->getVR(), dcmtkpp::convert(source.vr));
+    BOOST_CHECK_NE(
+        dynamic_cast<DcmSequenceOfItems *>(destination),
+        (DcmSequenceOfItems *)(NULL));
+
+    BOOST_CHECK_EQUAL(destination->getVM(), source.size());
+    for(std::size_t i=0; i<source.size(); ++i)
+    {
+        dcmtkpp::DataSet const & source_item = source.as_data_set()[i];
+        DcmItem * item = dynamic_cast<DcmSequenceOfItems *>(destination)->getItem(i);
+        DcmDataset * destination_item = dynamic_cast<DcmDataset *>(item);
+        BOOST_CHECK(source_item == dcmtkpp::convert(destination_item));
+    }
+}
+
+BOOST_AUTO_TEST_CASE(SQToDcmtkpp)
+{
+    DcmDataset * item = new DcmDataset;
+    item->putAndInsertOFStringArray(DCM_PatientID, "DJ1234");
+
+    DcmSequenceOfItems source(DcmTag(0xdead, 0xbeef, EVR_SQ));
+    source.append(item);
+
+    dcmtkpp::Element const destination = dcmtkpp::convert(&source);
+
+    BOOST_CHECK(destination.vr == dcmtkpp::convert(source.getVR()));
+    BOOST_CHECK_EQUAL(source.getVM(), destination.size());
+    for(std::size_t i=0; i<destination.size(); ++i)
+    {
+        DcmItem * item = source.getItem(i);
+        DcmDataset * source_item = dynamic_cast<DcmDataset *>(item);
+        BOOST_REQUIRE(source_item != NULL);
+
+        dcmtkpp::DataSet const & destination_item = destination.as_data_set()[i];
+        BOOST_CHECK(dcmtkpp::convert(source_item) == destination_item);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(EmptyDataSetFromDcmtkpp)
+{
+    dcmtkpp::DataSet empty;
+    DcmItem * result = dcmtkpp::convert(empty);
+    BOOST_CHECK_EQUAL(result->card(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(EmptyDataSetFromDcmtk)
+{
+    DcmDataset empty;
+    dcmtkpp::DataSet const result = dcmtkpp::convert(&empty);
+    BOOST_CHECK(result.empty());
+}
+
+BOOST_AUTO_TEST_CASE(DataSetFromDcmtkpp)
+{
+    dcmtkpp::Element const patient_id_source(
+        dcmtkpp::Value::Strings({"DJ1234"}), dcmtkpp::VR::CS);
+    dcmtkpp::Element const pixel_spacing_source(
+        dcmtkpp::Value::Reals({1.23, 4.56}), dcmtkpp::VR::DS);
+
+    dcmtkpp::DataSet source;
+    source.add(dcmtkpp::Tag("PatientID"), patient_id_source);
+    source.add(dcmtkpp::Tag("PixelSpacing"), pixel_spacing_source);
+
+    DcmItem * result = dcmtkpp::convert(source);
+    BOOST_CHECK_EQUAL(result->card(), 2);
+
+    DcmElement * patient_id;
+    OFCondition const patient_id_ok =
+        result->findAndGetElement(DCM_PatientID, patient_id);
+    BOOST_CHECK(patient_id_ok.good());
+    BOOST_CHECK(
+        dcmtkpp::convert(patient_id).as_string() ==
+            patient_id_source.as_string());
+
+    DcmElement * pixel_spacing;
+    OFCondition const pixel_spacing_ok =
+        result->findAndGetElement(DCM_PixelSpacing, pixel_spacing);
+    BOOST_CHECK(pixel_spacing_ok.good());
+    BOOST_CHECK(
+        dcmtkpp::convert(pixel_spacing).as_real() ==
+            pixel_spacing_source.as_real());
+}
+
+BOOST_AUTO_TEST_CASE(DataSetFromDcmtk)
+{
+    dcmtkpp::Element const patient_id_source(
+        dcmtkpp::Value::Strings({"DJ1234"}), dcmtkpp::VR::CS);
+    dcmtkpp::Element const pixel_spacing_source(
+        dcmtkpp::Value::Reals({1.23, 4.56}), dcmtkpp::VR::DS);
+
+    DcmDataset source;
+    source.insert(dcmtkpp::convert(dcmtkpp::Tag("PatientID"), patient_id_source));
+    source.insert(dcmtkpp::convert(dcmtkpp::Tag("PixelSpacing"), pixel_spacing_source));
+
+    dcmtkpp::DataSet const result = dcmtkpp::convert(&source);
+    BOOST_CHECK_EQUAL(result.size(), 2);
+    BOOST_CHECK(
+        result.as_string(dcmtkpp::Tag("PatientID")) ==
+            patient_id_source.as_string());
+    BOOST_CHECK(
+        result.as_real(dcmtkpp::Tag("PixelSpacing")) ==
+            pixel_spacing_source.as_real());
+}
diff --git a/tests/code/json_converter.cpp b/tests/code/json_converter.cpp
new file mode 100644
index 0000000..8e1200a
--- /dev/null
+++ b/tests/code/json_converter.cpp
@@ -0,0 +1,269 @@
+#define BOOST_TEST_MODULE json_converter
+#include <boost/test/unit_test.hpp>
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include <jsoncpp/json/json.h>
+
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/Element.h"
+#include "dcmtkpp/json_converter.h"
+#include "dcmtkpp/Value.h"
+#include "dcmtkpp/VR.h"
+
+BOOST_AUTO_TEST_CASE(AsJSONEmpty)
+{
+    dcmtkpp::DataSet data_set;
+    auto const json = dcmtkpp::as_json(data_set);
+    BOOST_REQUIRE(json.empty());
+}
+
+template<typename TChecker, typename TGetter, typename TValue>
+void check_json_array(
+    Json::Value const & object, TChecker checker, TGetter getter,
+    TValue const & expected)
+{
+    BOOST_REQUIRE(object.isArray());
+    BOOST_REQUIRE_EQUAL(object.size(), expected.size());
+    for(Json::ArrayIndex i=0; i<object.size(); ++i)
+    {
+        BOOST_REQUIRE((object[i].*checker)());
+        BOOST_REQUIRE_EQUAL((object[i].*getter)(), expected[i]);
+    }
+}
+
+void check_json_object(Json::Value const & object,
+    std::set<std::string> const & expected_members)
+{
+    BOOST_REQUIRE(object.isObject());
+    auto const members = object.getMemberNames();
+    BOOST_REQUIRE(
+        std::set<std::string>(members.begin(), members.end()) == expected_members);
+}
+
+void check_json_string(Json::Value const & object, std::string const & expected_value)
+{
+    BOOST_REQUIRE(object.isString());
+    BOOST_REQUIRE_EQUAL(object.asString(), expected_value);
+}
+
+BOOST_AUTO_TEST_CASE(AsJSONIntegers)
+{
+    dcmtkpp::DataSet data_set;
+    data_set.add(0xdeadbeef,
+        dcmtkpp::Element(dcmtkpp::Value::Integers({1, 2}), dcmtkpp::VR::SS));
+    auto const json = dcmtkpp::as_json(data_set);
+    check_json_object(json, {"deadbeef"});
+    check_json_object(json["deadbeef"], {"vr", "Value"});
+    check_json_string(json["deadbeef"]["vr"], "SS");
+    check_json_array(json["deadbeef"]["Value"],
+        &Json::Value::isInt, &Json::Value::asInt, data_set.as_int(0xdeadbeef));
+}
+
+BOOST_AUTO_TEST_CASE(AsJSONReals)
+{
+    dcmtkpp::DataSet data_set;
+    data_set.add(0xdeadbeef,
+        dcmtkpp::Element(dcmtkpp::Value::Reals({1.2, 3.4}), dcmtkpp::VR::FL));
+    auto const json = dcmtkpp::as_json(data_set);
+    check_json_object(json, {"deadbeef"});
+    check_json_object(json["deadbeef"], {"vr", "Value"});
+    check_json_string(json["deadbeef"]["vr"], "FL");
+    check_json_array(json["deadbeef"]["Value"],
+        &Json::Value::isDouble, &Json::Value::asDouble, data_set.as_real(0xdeadbeef));
+}
+
+BOOST_AUTO_TEST_CASE(AsJSONStrings)
+{
+    dcmtkpp::DataSet data_set;
+    data_set.add(0xdeadbeef,
+        dcmtkpp::Element(
+            dcmtkpp::Value::Strings({"FOO", "BAR"}),
+            dcmtkpp::VR::CS));
+    auto const json = dcmtkpp::as_json(data_set);
+    check_json_object(json, {"deadbeef"});
+    check_json_object(json["deadbeef"], {"vr", "Value"});
+    check_json_string(json["deadbeef"]["vr"], "CS");
+    check_json_array(json["deadbeef"]["Value"],
+        &Json::Value::isString, &Json::Value::asString, data_set.as_string(0xdeadbeef));
+}
+
+BOOST_AUTO_TEST_CASE(AsJSONPersonName)
+{
+    dcmtkpp::DataSet data_set;
+    data_set.add(0xdeadbeef,
+        dcmtkpp::Element(
+            dcmtkpp::Value::Strings({"Alpha^Betic=Ideo^Graphic=Pho^Netic"}),
+            dcmtkpp::VR::PN));
+    auto const json = dcmtkpp::as_json(data_set);
+    check_json_object(json, {"deadbeef"});
+    check_json_object(json["deadbeef"], {"vr", "Value"});
+    check_json_string(json["deadbeef"]["vr"], "PN");
+
+    BOOST_REQUIRE(json["deadbeef"]["Value"].isArray());
+    BOOST_REQUIRE_EQUAL(json["deadbeef"]["Value"].size(), 1);
+    check_json_object(
+        json["deadbeef"]["Value"][0], {"Alphabetic", "Ideographic", "Phonetic"});
+    check_json_string(json["deadbeef"]["Value"][0]["Alphabetic"], {"Alpha^Betic"});
+    check_json_string(json["deadbeef"]["Value"][0]["Ideographic"], {"Ideo^Graphic"});
+    check_json_string(json["deadbeef"]["Value"][0]["Phonetic"], {"Pho^Netic"});
+}
+
+BOOST_AUTO_TEST_CASE(AsJSONDataSets)
+{
+    dcmtkpp::DataSet item;
+    item.add(0xbeeff00d,
+        dcmtkpp::Element(dcmtkpp::Value::Integers({1,2}), dcmtkpp::VR::SS));
+    dcmtkpp::DataSet data_set;
+    data_set.add(0xdeadbeef,
+        dcmtkpp::Element(
+            dcmtkpp::Value::DataSets({item}),
+            dcmtkpp::VR::SQ));
+
+    auto const json = dcmtkpp::as_json(data_set);
+
+    check_json_object(json, {"deadbeef"});
+    check_json_object(json["deadbeef"], {"vr", "Value"});
+    check_json_string(json["deadbeef"]["vr"], "SQ");
+
+    BOOST_REQUIRE(json["deadbeef"]["Value"].isArray());
+    BOOST_REQUIRE_EQUAL(json["deadbeef"]["Value"].size(), 1);
+    check_json_object(json["deadbeef"]["Value"][0], {"beeff00d"});
+
+    check_json_object(json["deadbeef"]["Value"][0]["beeff00d"], {"vr", "Value"});
+    check_json_string(json["deadbeef"]["Value"][0]["beeff00d"]["vr"], "SS");
+    check_json_array(json["deadbeef"]["Value"][0]["beeff00d"]["Value"],
+        &Json::Value::isInt, &Json::Value::asInt, item.as_int(0xbeeff00d));
+}
+
+BOOST_AUTO_TEST_CASE(AsJSONBinary)
+{
+    dcmtkpp::DataSet data_set;
+    data_set.add(0xdeadbeef,
+        dcmtkpp::Element(
+            dcmtkpp::Value::Binary({0x1, 0x2, 0x3, 0x4, 0x5}),
+            dcmtkpp::VR::OB));
+
+    auto const json = dcmtkpp::as_json(data_set);
+
+    check_json_object(json, {"deadbeef"});
+    check_json_object(json["deadbeef"], {"vr", "InlineBinary"});
+    check_json_string(json["deadbeef"]["vr"], "OB");
+    check_json_string(json["deadbeef"]["InlineBinary"], "AQIDBAU=");
+}
+
+BOOST_AUTO_TEST_CASE(AsDataSetEmpty)
+{
+    std::stringstream data;
+    data << "{ }";
+    Json::Value json;
+    data >> json;
+
+    dcmtkpp::DataSet const data_set = dcmtkpp::as_dataset(json);
+    BOOST_REQUIRE(data_set.empty());
+}
+
+BOOST_AUTO_TEST_CASE(AsDataSetIntegers)
+{
+    std::stringstream data;
+    data << "{ \"deadbeef\": { \"vr\": \"SS\", \"Value\": [1, 2] } }";
+    Json::Value json;
+    data >> json;
+
+    dcmtkpp::DataSet const data_set = dcmtkpp::as_dataset(json);
+    BOOST_REQUIRE_EQUAL(data_set.size(), 1);
+    BOOST_REQUIRE(data_set.has("deadbeef"));
+    BOOST_REQUIRE(data_set.get_vr("deadbeef") == dcmtkpp::VR::SS);
+    BOOST_REQUIRE(data_set.is_int("deadbeef"));
+    BOOST_REQUIRE(data_set.as_int("deadbeef") == dcmtkpp::Value::Integers({1, 2}));
+}
+
+BOOST_AUTO_TEST_CASE(AsDataSetReals)
+{
+    std::stringstream data;
+    data << "{ \"deadbeef\": { \"vr\": \"FL\", \"Value\": [1.2, 3.4] } }";
+    Json::Value json;
+    data >> json;
+
+    dcmtkpp::DataSet const data_set = dcmtkpp::as_dataset(json);
+    BOOST_REQUIRE_EQUAL(data_set.size(), 1);
+    BOOST_REQUIRE(data_set.has("deadbeef"));
+    BOOST_REQUIRE(data_set.get_vr("deadbeef") == dcmtkpp::VR::FL);
+    BOOST_REQUIRE(data_set.is_real("deadbeef"));
+    BOOST_REQUIRE(data_set.as_real("deadbeef") == dcmtkpp::Value::Reals({1.2, 3.4}));
+}
+
+BOOST_AUTO_TEST_CASE(AsDataSetStrings)
+{
+    std::stringstream data;
+    data << "{ \"deadbeef\": { \"vr\": \"CS\", \"Value\": [\"FOO\", \"BAR\"] } }";
+    Json::Value json;
+    data >> json;
+
+    dcmtkpp::DataSet const data_set = dcmtkpp::as_dataset(json);
+    BOOST_REQUIRE_EQUAL(data_set.size(), 1);
+    BOOST_REQUIRE(data_set.has("deadbeef"));
+    BOOST_REQUIRE(data_set.get_vr("deadbeef") == dcmtkpp::VR::CS);
+    BOOST_REQUIRE(data_set.is_string("deadbeef"));
+    BOOST_REQUIRE(data_set.as_string("deadbeef") == dcmtkpp::Value::Strings({"FOO", "BAR"}));
+}
+
+BOOST_AUTO_TEST_CASE(AsDataSetPersonName)
+{
+    std::stringstream data;
+    data << "{ \"deadbeef\": { \"vr\": \"PN\", \"Value\": [ ";
+    data << "{ \"Alphabetic\": \"Alpha^Betic\" , ";
+    data << "\"Ideographic\": \"Ideo^Graphic\" , ";
+    data << "\"Phonetic\": \"Pho^Netic\" } ";
+    data << " ] } }";
+    Json::Value json;
+    data >> json;
+
+    dcmtkpp::DataSet const data_set = dcmtkpp::as_dataset(json);
+    BOOST_REQUIRE_EQUAL(data_set.size(), 1);
+    BOOST_REQUIRE(data_set.has("deadbeef"));
+    BOOST_REQUIRE(data_set.get_vr("deadbeef") == dcmtkpp::VR::PN);
+    BOOST_REQUIRE(data_set.is_string("deadbeef"));
+    BOOST_REQUIRE(data_set.as_string("deadbeef") == dcmtkpp::Value::Strings(
+        {"Alpha^Betic=Ideo^Graphic=Pho^Netic"}));
+}
+
+BOOST_AUTO_TEST_CASE(AsDataSetDataSets)
+{
+    std::stringstream data;
+    data << "{ \"deadbeef\": { \"vr\": \"SQ\", \"Value\": [ ";
+    data << "{ \"beeff00d\": { \"vr\": \"SS\", \"Value\": [1, 2] } }";
+    data << " ] } }";
+    Json::Value json;
+    data >> json;
+
+    dcmtkpp::DataSet const data_set = dcmtkpp::as_dataset(json);
+    BOOST_REQUIRE_EQUAL(data_set.size(), 1);
+    BOOST_REQUIRE(data_set.has("deadbeef"));
+    BOOST_REQUIRE(data_set.get_vr("deadbeef") == dcmtkpp::VR::SQ);
+    BOOST_REQUIRE(data_set.is_data_set("deadbeef"));
+
+    dcmtkpp::DataSet item;
+    item.add(0xbeeff00d,
+        dcmtkpp::Element(dcmtkpp::Value::Integers({1,2}), dcmtkpp::VR::SS));
+    BOOST_REQUIRE(data_set.as_data_set("deadbeef") == dcmtkpp::Value::DataSets({item}));
+}
+
+
+BOOST_AUTO_TEST_CASE(AsDataSetBinary)
+{
+    std::stringstream data;
+    data << "{ \"deadbeef\": { \"vr\": \"OB\", \"InlineBinary\": \"AQIDBAU=\" } }";
+    Json::Value json;
+    data >> json;
+
+    dcmtkpp::DataSet const data_set = dcmtkpp::as_dataset(json);
+    BOOST_REQUIRE_EQUAL(data_set.size(), 1);
+    BOOST_REQUIRE(data_set.has("deadbeef"));
+    BOOST_REQUIRE(data_set.get_vr("deadbeef") == dcmtkpp::VR::OB);
+    BOOST_REQUIRE(data_set.is_binary("deadbeef"));
+    BOOST_REQUIRE(data_set.as_binary("deadbeef") == dcmtkpp::Value::Binary(
+        {0x1, 0x2, 0x3, 0x4, 0x5}));
+}
diff --git a/tests/code/unicode.cpp b/tests/code/unicode.cpp
new file mode 100644
index 0000000..5d23016
--- /dev/null
+++ b/tests/code/unicode.cpp
@@ -0,0 +1,258 @@
+#define BOOST_TEST_MODULE unicode
+#include <boost/test/unit_test.hpp>
+
+#include <dcmtk/config/osconfig.h>
+#include <dcmtk/dcmdata/dctk.h>
+
+#include "dcmtkpp/conversion.h"
+#include "dcmtkpp/DataSet.h"
+#include "dcmtkpp/unicode.h"
+
+BOOST_AUTO_TEST_CASE(SCSARAB)
+{
+    dcmtkpp::Value::Strings const specific_character_set = { "ISO_IR 127" };
+    std::string const source =
+        "\xe2\xc8\xc7\xe6\xea" "^" "\xe4\xe6\xd2\xc7\xd1";
+    std::string const expected =
+        "\xd9\x82\xd8\xa8\xd8\xa7\xd9\x86\xd9\x8a"
+        "^"
+        "\xd9\x84\xd9\x86\xd8\xb2\xd8\xa7\xd8\xb1";
+
+    std::string const utf8 = dcmtkpp::as_utf8(
+        source, specific_character_set, true);
+    BOOST_REQUIRE_EQUAL(utf8, expected);
+}
+
+BOOST_AUTO_TEST_CASE(SCSFREN)
+{
+    dcmtkpp::Value::Strings const specific_character_set = { "ISO_IR 100" };
+    std::string const source = "Buc" "^" "J\xe9r\xf4me";
+    std::string const expected =
+        "Buc" "^" "J\xc3\xa9r\xc3\xb4me";
+
+    std::string const utf8 = dcmtkpp::as_utf8(
+        source, specific_character_set, true);
+    BOOST_REQUIRE_EQUAL(utf8, expected);
+}
+
+BOOST_AUTO_TEST_CASE(SCSGERM)
+{
+    dcmtkpp::Value::Strings const specific_character_set = { "ISO_IR 100" };
+    std::string const source =
+        "\xc4neas" "^" "R\xfc" "diger";
+    std::string const expected =
+        "\xc3\x84neas" "^" "R\xc3\xbc" "diger";
+
+    std::string const utf8 = dcmtkpp::as_utf8(
+        source, specific_character_set, true);
+    BOOST_REQUIRE_EQUAL(utf8, expected);
+}
+
+BOOST_AUTO_TEST_CASE(SCSGREEK)
+{
+    dcmtkpp::Value::Strings const specific_character_set = { "ISO_IR 126" };
+    std::string const source = "\xc4\xe9\xef\xed\xf5\xf3\xe9\xef\xf2";
+    std::string const expected =
+        "\xce\x94\xce\xb9\xce\xbf\xce\xbd\xcf\x85\xcf\x83\xce\xb9\xce\xbf\xcf\x82";
+
+    std::string const utf8 = dcmtkpp::as_utf8(
+        source, specific_character_set, true);
+    BOOST_REQUIRE_EQUAL(utf8, expected);
+}
+
+BOOST_AUTO_TEST_CASE(SCSH31)
+{
+    dcmtkpp::Value::Strings const specific_character_set =
+        { "", "ISO 2022 IR 87" };
+    std::string const source =
+        "Yamada" "^" "Tarou"
+        "="
+        "\x1b\x24\x42\x3b\x33\x45\x44\x1b\x28\x42"
+            "^" "\x1b\x24\x42\x42\x40\x4f\x3a\x1b\x28\x42"
+        "="
+        "\x1b\x24\x42\x24\x64\x24\x5e\x24\x40\x1b\x28\x42"
+            "^" "\x1b\x24\x42\x24\x3f\x24\x6d\x24\x26\x1b\x28\x42";
+    std::string const expected =
+        "Yamada" "^" "Tarou"
+        "="
+        "\xe5\xb1\xb1\xe7\x94\xb0" "^" "\xe5\xa4\xaa\xe9\x83\x8e"
+        "="
+        "\xe3\x82\x84\xe3\x81\xbe\xe3\x81\xa0"
+            "^" "\xe3\x81\x9f\xe3\x82\x8d\xe3\x81\x86";
+
+    std::string const utf8 = dcmtkpp::as_utf8(
+        source, specific_character_set, true);
+    BOOST_REQUIRE_EQUAL(utf8, expected);
+}
+
+BOOST_AUTO_TEST_CASE(SCSH32)
+{
+    dcmtkpp::Value::Strings const specific_character_set =
+        { "ISO 2022 IR 13", "ISO 2022 IR 87" };
+    std::string const source =
+        "\xd4\xcf\xc0\xde" "^" "\xc0\xdb\xb3"
+        "="
+        "\x1b\x24\x42\x3b\x33\x45\x44\x1b\x28\x4a"
+            "^" "\x1b\x24\x42\x42\x40\x4f\x3a\x1b\x28\x4a"
+        "="
+        "\x1b\x24\x42\x24\x64\x24\x5e\x24\x40\x1b\x28\x4a"
+            "\x5e\x1b\x24\x42\x24\x3f\x24\x6d\x24\x26\x1b\x28\x4a";
+    std::string const expected =
+        "\xef\xbe\x94\xef\xbe\x8f\xef\xbe\x80\xef\xbe\x9e"
+            "^" "\xef\xbe\x80\xef\xbe\x9b\xef\xbd\xb3"
+        "="
+        "\xe5\xb1\xb1\xe7\x94\xb0"
+            "^" "\xe5\xa4\xaa\xe9\x83\x8e"
+        "="
+        "\xe3\x82\x84\xe3\x81\xbe\xe3\x81\xa0"
+            "^" "\xe3\x81\x9f\xe3\x82\x8d\xe3\x81\x86";
+
+    std::string const utf8 = dcmtkpp::as_utf8(
+        source, specific_character_set, true);
+    BOOST_REQUIRE_EQUAL(utf8, expected);
+}
+
+BOOST_AUTO_TEST_CASE(SCSHBRW)
+{
+    dcmtkpp::Value::Strings const specific_character_set = { "ISO_IR 138" };
+    std::string const source = "\xf9\xf8\xe5\xef" "^" "\xe3\xe1\xe5\xf8\xe4";
+    std::string const expected =
+        "\xd7\xa9\xd7\xa8\xd7\x95\xd7\x9f"
+            "^" "\xd7\x93\xd7\x91\xd7\x95\xd7\xa8\xd7\x94";
+
+    std::string const utf8 = dcmtkpp::as_utf8(
+        source, specific_character_set, true);
+    BOOST_REQUIRE_EQUAL(utf8, expected);
+}
+
+BOOST_AUTO_TEST_CASE(SCSI2)
+{
+    dcmtkpp::Value::Strings const specific_character_set =
+        { "", "ISO 2022 IR 149" };
+
+    std::string const source =
+        "\x48\x6f\x6e\x67" "^" "\x47\x69\x6c\x64\x6f\x6e\x67"
+        "="
+        "\x1b\x24\x29\x43\xfb\xf3" "^" "\x1b\x24\x29\x43\xd1\xce\xd4\xd7"
+        "="
+        "\x1b\x24\x29\x43\xc8\xab" "^" "\x1b\x24\x29\x43\xb1\xe6\xb5\xbf";
+    std::string const expected =
+        "\x48\x6f\x6e\x67" "^" "\x47\x69\x6c\x64\x6f\x6e\x67"
+        "="
+        "\xe6\xb4\xaa" "^" "\xe5\x90\x89\xe6\xb4\x9e"
+        "="
+        "\xed\x99\x8d" "^" "\xea\xb8\xb8\xeb\x8f\x99";
+
+    std::string const utf8 = dcmtkpp::as_utf8(
+        source, specific_character_set, true);
+    BOOST_REQUIRE_EQUAL(utf8, expected);
+}
+
+BOOST_AUTO_TEST_CASE(SCSRUSS)
+{
+    dcmtkpp::Value::Strings const specific_character_set = { "ISO_IR 144" };
+    std::string const source = "\xbb\xee\xda\x63\x65\xdc\xd1\x79\x70\xd3";
+    std::string const expected =
+        "\xd0\x9b\xd1\x8e\xd0\xba\x63\x65\xd0\xbc\xd0\xb1\x79\x70\xd0\xb3";
+
+    std::string const utf8 = dcmtkpp::as_utf8(
+        source, specific_character_set, true);
+    BOOST_REQUIRE_EQUAL(utf8, expected);
+}
+
+BOOST_AUTO_TEST_CASE(SCSX1)
+{
+    dcmtkpp::Value::Strings const specific_character_set = { "ISO_IR 192" };
+    std::string const source =
+        "Wang" "^" "XiaoDong"
+        "="
+        "\xe7\x8e\x8b" "^" "\xe5\xb0\x8f\xe6\x9d\xb1"
+        "=";
+    std::string const expected =
+        "Wang" "^" "XiaoDong"
+        "\x3d\xe7\x8e\x8b" "^" "\xe5\xb0\x8f\xe6\x9d\xb1"
+        "=";
+
+    std::string const utf8 = dcmtkpp::as_utf8(
+        source, specific_character_set, true);
+    BOOST_REQUIRE_EQUAL(utf8, expected);
+}
+
+BOOST_AUTO_TEST_CASE(SCSX2)
+{
+    dcmtkpp::Value::Strings const specific_character_set = { "GB18030" };
+    std::string const source =
+        "Wang" "^" "XiaoDong"
+        "=" ""
+        "\xcd\xf5" "^" "\xd0\xa1\xb6\xab"
+        "=";
+    std::string const expected =
+        "Wang" "^" "XiaoDong"
+        "="
+        "\xe7\x8e\x8b" "^" "\xe5\xb0\x8f\xe4\xb8\x9c"
+        "=";
+
+    std::string const utf8 = dcmtkpp::as_utf8(
+        source, specific_character_set, true);
+    BOOST_REQUIRE_EQUAL(utf8, expected);
+}
+
+/*
+dcmtkpp::DataSet read(std::string const & filename)
+{
+    DcmFileFormat format;
+
+    OFCondition const condition = format.loadFile(filename.c_str());
+    if(condition.bad())
+    {
+        throw dcmtkpp::Exception(condition);
+    }
+
+    dcmtkpp::DataSet const result = dcmtkpp::convert(format.getDataset());
+
+    return result;
+}
+
+
+int main(int argc, char ** argv)
+{
+    for(char** argument=argv+1; argument != argv+argc; ++argument)
+    {
+        std::cout << "Reading " << *argument << std::endl;
+
+        dcmtkpp::DataSet data_set;
+        try
+        {
+            data_set = read(*argument);
+        }
+        catch(dcmtkpp::Exception const & e)
+        {
+            std::cerr << "Could not read " << *argument << ": " << e.what() << "\n";
+            continue;
+        }
+
+        std::string patient_name;
+        try
+        {
+            patient_name = dcmtkpp::as_utf8(
+                data_set.as_string("PatientName")[0],
+                data_set.as_string("SpecificCharacterSet"), true);
+        }
+        catch(dcmtkpp::Exception const & e)
+        {
+            std::cerr << "Could not convert PatientName to UTF-8: " << e.what() << "\n";
+            continue;
+        }
+
+        std::cout << "    dcmtkpp::Value::Strings const specific_character_set = {\n";
+        for(auto const & c: data_set.as_string("SpecificCharacterSet"))
+        {
+            std::cout << "        " << "\"" << c << "\",\n";
+        }
+        std::cout << "    };\n";
+        std::cout << "Patient Name: \"" << patient_name << "\"\n";
+    }
+
+    return 0;
+}
+*/
diff --git a/tests/run.sh b/tests/run.sh
new file mode 100755
index 0000000..fa8a490
--- /dev/null
+++ b/tests/run.sh
@@ -0,0 +1,57 @@
+#! /bin/sh
+
+set -e
+set -u
+
+configure() {
+    cat > ${directory}/config  << EOF
+HostTable BEGIN
+remote = (REMOTE, localhost, 11112)
+local = (LOCAL, localhost, 11113)
+HostTable END
+
+AETable BEGIN
+REMOTE ${directory} RW (10, 1024mb) local
+AETable END
+EOF
+}
+
+add_data() {
+dump2dcm --write-xfer-little /dev/stdin ${directory}/data.dcm <<EOF
+(0008,0016) UI =RawDataStorage
+(0008,0018) UI [2.25.95090344942250266709587559073467305647]
+(0010,0010) PN [Doe^John]
+(0010,0020) LO [DJ001]
+EOF
+storescu -aet LOCAL -aec REMOTE localhost 11112 ${directory}/data.dcm
+}
+
+start_scp() {
+    dcmqrscp -c ${directory}/config 11112 &
+    PID=$!
+    sleep 1
+}
+
+stop_scp() {
+    kill ${PID}
+}
+
+clean() {
+    rm -rf ${directory}
+}
+
+directory=$(mktemp -d dcmtkpp.XXX)
+configure
+start_scp
+add_data
+
+export DCMTKPP_OWN_AET=LOCAL
+export DCMTKPP_PEER_HOST_NAME=localhost
+export DCMTKPP_PEER_PORT=11112
+export DCMTKPP_PEER_AET=REMOTE
+
+ctest --no-compress-output -T Test || true
+
+stop_scp
+clean
+

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/dcmtkpp.git



More information about the debian-med-commit mailing list