diff --git a/.gitattributes b/.gitattributes index 049993f..56ff96d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,9 @@ appveyor.yml merge=ours * -whitespace -/Source/DataDictionary/gdcmDefaultDicts.cxx hooks.MaxObjectKiB=2048 -/Source/InformationObjectDefinition/Part3.xml hooks.MaxObjectKiB=4096 +/Source/DataDictionary/gdcmDefaultDicts.cxx hooks-max-size=1500000 +/Source/DataDictionary/gdcmPrivateDefaultDicts.cxx hooks-max-size=1500000 +/Source/DataDictionary/gdcmTagToType.h hooks-max-size=1500000 +/Source/InformationObjectDefinition/Part3.xml hooks-max-size=3000000 +/Source/DataDictionary/privatedicts.xml hooks-max-size=1500000 +/Utilities/gdcmopenjpeg/src/lib/openjp2/j2k.c hooks-max-size=750000 diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml new file mode 100644 index 0000000..a8260a5 --- /dev/null +++ b/.github/workflows/c-cpp.yml @@ -0,0 +1,26 @@ +name: C/C++ CI + +on: + push: + branches: [ "release" ] + pull_request: + branches: [ "release" ] + +jobs: + example_matrix: + strategy: + matrix: + os: [windows-latest, ubuntu-latest] + runs-on: ${{ matrix.os }} + steps: + - name: checkout source + uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 2 + - name: configure + run: cmake -DGDCM_BUILD_SHARED_LIBS=ON -DGDCM_BUILD_DOCBOOK_MANPAGES:BOOL=OFF -DCMAKE_BUILD_TYPE:STRING=None -B build + - name: make + run: cmake --build build + - name: make check + run: ctest --test-dir build --parallel 2 --output-on-failure || true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9a104c --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# back-up +*~ +*.bak + +# files when there are conflicts +*.orig + +# qtcreator files +CMakeLists.txt.user* + +# kdevelop files +*.kdev* diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8170523 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Testing/Data"] + path = Testing/Data + url = git://git.code.sf.net/p/gdcm/gdcmdata diff --git a/.travis.yml b/.travis.yml index ff3bf85..9cd2e44 100644 --- a/.travis.yml +++ b/.travis.yml @@ -73,9 +73,9 @@ before_install: #- if [ "$TRAVIS_OS_NAME" == "osx" ]; then virtualenv env -p python3 ; fi #- if [ "$TRAVIS_OS_NAME" == "osx" ]; then source env/bin/activate ; fi # kakadu setup for linux/system: - - if [ "$B_NAME" == "system" ]; then wget http://kakadusoftware.com/wp-content/uploads/2014/06/KDU77_Demo_Apps_for_Linux-x86-64_150710.zip; fi - - if [ "$B_NAME" == "system" ]; then unzip KDU77_Demo_Apps_for_Linux-x86-64_150710.zip; fi - - if [ "$B_NAME" == "system" ]; then export PATH=$PATH:$PWD/KDU77_Demo_Apps_for_Linux-x86-64_150710; fi + - if [ "$B_NAME" == "system" ]; then wget http://kakadusoftware.com/wp-content/uploads/KDU805_Demo_Apps_for_Linux-x86-64_200602.zip; fi + - if [ "$B_NAME" == "system" ]; then unzip KDU805_Demo_Apps_for_Linux-x86-64_200602.zip; fi + - if [ "$B_NAME" == "system" ]; then export PATH=$PATH:$PWD/KDU805_Demo_Apps_for_Linux-x86-64_200602; fi install: true before_script: - cmake -Wno-dev -G "Unix Makefiles" -DCMAKE_BUILD_TYPE:STRING=None -DGDCM_BUILD_TESTING:BOOL=ON -DGDCM_BUILD_APPLICATIONS:BOOL=ON -DGDCM_BUILD_SHARED_LIBS:BOOL=ON -DBUILDNAME:STRING=${TRAVIS_OS_NAME}-${TRAVIS_BRANCH}-${B_NAME} ${CMAKE_EXTRA} . diff --git a/AUTHORS b/AUTHORS index e37e40b..b7a24c6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -21,7 +21,7 @@ GDCM 2.x: Joel Spaltenstein : Developer (Mac OS X) -GDCM 1.x (Developpers and contributors, alphabetical order) +GDCM 1.x (Developers and contributors, alphabetical order) -------- Aris Basic Fabrice Bellet diff --git a/Applications/Cxx/CMakeLists.txt b/Applications/Cxx/CMakeLists.txt index 6bd8eca..e18ec85 100644 --- a/Applications/Cxx/CMakeLists.txt +++ b/Applications/Cxx/CMakeLists.txt @@ -6,7 +6,7 @@ # gdcmanon -if(WIN32 AND NOT CYGWIN) +if(WIN32 AND NOT CYGWIN AND NOT MINGW) include_directories( "${GDCM_SOURCE_DIR}/Utilities/getopt" ) @@ -46,6 +46,7 @@ set(GDCM_EXECUTABLE_NAME gdcmraw gdcmscanner gdcmanon + gdcmclean gdcmgendir #gdcmoverlay gdcmimg @@ -72,13 +73,12 @@ if(GDCM_USE_SYSTEM_POPPLER) if(LIBPOPPLER_GLOBALPARAMS_CSTOR_HAS_PARAM) list(APPEND libpoppler_flags -DLIBPOPPLER_GLOBALPARAMS_CSTOR_HAS_PARAM) endif() - if(NOT LIBPOPPLER_GLOBALPARAMS_CSTOR_HAS_PARAM) - CHECK_CXX_SOURCE_COMPILES( - "\#include \nint main() { globalParams = new GlobalParams(); return 0;}" - LIBPOPPLER_GLOBALPARAMS_IS_NOT_UNIQUE_PTR) - if(NOT LIBPOPPLER_GLOBALPARAMS_IS_NOT_UNIQUE_PTR) - list(APPEND libpoppler_flags -DLIBPOPPLER_GLOBALPARAMS_IS_UNIQUE_PTR) - endif() + CHECK_CXX_SOURCE_COMPILES( + "\#include \nint main() { globalParams.reset( new GlobalParams()); return 0;}" + LIBPOPPLER_GLOBALPARAMS_HAS_RESET) + set(libpoppler_flags) + if(LIBPOPPLER_GLOBALPARAMS_HAS_RESET) + list(APPEND libpoppler_flags -DLIBPOPPLER_GLOBALPARAMS_HAS_RESET) endif() CHECK_CXX_SOURCE_COMPILES( "\#include \nint main() { PDFDoc d((GooString*)NULL,(GooString*)NULL,(GooString*)NULL); d.getPDFVersion(); return 0;}" @@ -110,6 +110,18 @@ if(GDCM_USE_SYSTEM_POPPLER) if(LIBPOPPLER_GOOSTRING_HAS_GETCSTRING) list(APPEND libpoppler_flags -DLIBPOPPLER_GOOSTRING_HAS_GETCSTRING) endif() + CHECK_CXX_SOURCE_COMPILES( + "\#include \nint main() { Unicode u; char buf[8]; const UnicodeMap *uMap; uMap->mapUnicode(u, buf, sizeof(buf)); return 0; }" + LIBPOPPLER_UNICODEMAP_HAS_CONSTMAPUNICODE) + if(LIBPOPPLER_UNICODEMAP_HAS_CONSTMAPUNICODE) + list(APPEND libpoppler_flags -DLIBPOPPLER_UNICODEMAP_HAS_CONSTMAPUNICODE) + endif() + CHECK_CXX_SOURCE_COMPILES( + "\#include \nint main() { std::optional ownerPW, userPW; PDFDoc d((BaseStream*)nullptr,ownerPW,userPW); return 0;}" + LIBPOPPLER_PDFDOC_HAS_OPTIONAL) + if(LIBPOPPLER_PDFDOC_HAS_OPTIONAL) + list(APPEND libpoppler_flags -DLIBPOPPLER_PDFDOC_HAS_OPTIONAL) + endif() if(libpoppler_flags) string(REPLACE ";" " " libpoppler_flags_string "${libpoppler_flags}") set_source_files_properties( @@ -151,6 +163,12 @@ if(GDCM_USE_SYSTEM_PAPYRUS3) ) endif() +if(NOT GDCM_USE_SYSTEM_ZLIB) + include_directories( + "${GDCM_BINARY_DIR}/Utilities/gdcmzlib" + ) +endif() + foreach(exename ${GDCM_EXECUTABLE_NAME}) if(${exename} STREQUAL "gdcminfo") add_executable(${exename} ${exename}.cxx puff.c) @@ -170,6 +188,8 @@ foreach(exename ${GDCM_EXECUTABLE_NAME}) endif() elseif(${exename} STREQUAL "gdcmstream") target_link_libraries(${exename} ${GDCM_OPENJPEG_LIBRARIES}) + elseif(${exename} STREQUAL "gdcmdump") + target_link_libraries(${exename} ${GDCM_ZLIB_LIBRARIES}) elseif(${exename} STREQUAL "gdcminfo") if(GDCM_USE_SYSTEM_POPPLER) target_link_libraries(${exename} ${POPPLER_LIBRARIES}) @@ -178,7 +198,7 @@ foreach(exename ${GDCM_EXECUTABLE_NAME}) if(GDCM_EXECUTABLE_PROPERTIES) set_target_properties(${exename} PROPERTIES ${GDCM_EXECUTABLE_PROPERTIES}) endif() - if(WIN32 AND NOT CYGWIN) + if(WIN32 AND NOT CYGWIN AND NOT MINGW) target_link_libraries(${exename} gdcmgetopt) endif() if(NOT GDCM_INSTALL_NO_RUNTIME) diff --git a/Applications/Cxx/gdcmanon.cxx b/Applications/Cxx/gdcmanon.cxx index 2d2e3d2..cfa29ca 100644 --- a/Applications/Cxx/gdcmanon.cxx +++ b/Applications/Cxx/gdcmanon.cxx @@ -45,7 +45,9 @@ static void PrintVersion() static bool AnonymizeOneFileDumb(gdcm::Anonymizer &anon, const char *filename, const char *outfilename, - std::vector const &empty_tags, std::vector const &remove_tags, std::vector< std::pair > const & replace_tags, bool continuemode = false) + std::vector const &empty_tags, std::vector const &clear_tags, std::vector const &remove_tags, std::vector< std::pair > const & replace_tags, + std::vector const &empty_privatetags, std::vector const &clear_privatetags, std::vector const &remove_privatetags, std::vector< std::pair > const & replace_privatetags, + bool continuemode = false) { gdcm::Reader reader; reader.SetFileName( filename ); @@ -67,29 +69,66 @@ static bool AnonymizeOneFileDumb(gdcm::Anonymizer &anon, const char *filename, c anon.SetFile( file ); - if( empty_tags.empty() && replace_tags.empty() && remove_tags.empty() ) + if( empty_tags.empty() && clear_tags.empty() && replace_tags.empty() && remove_tags.empty() + && empty_privatetags.empty() && clear_privatetags.empty() && replace_privatetags.empty() && remove_privatetags.empty() ) { - std::cerr << "No operation to be done." << std::endl; + std::cerr << "No operation(s) to be done." << std::endl; return false; } - std::vector::const_iterator it = empty_tags.begin(); bool success = true; + // Private Creator(s) must be done first: +{ + std::vector< std::pair >::const_iterator it2 = replace_tags.begin(); + for(; it2 != replace_tags.end(); ++it2) + { + success = success && anon.Replace( it2->first, it2->second.c_str() ); + } +} + + // Regular Private: +{ + std::vector::const_iterator it = empty_privatetags.begin(); + for(; it != empty_privatetags.end(); ++it) + { + success = success && anon.Empty( *it ); + } + it = clear_privatetags.begin(); + for(; it != clear_privatetags.end(); ++it) + { + success = success && anon.Clear( *it ); + } + it = remove_privatetags.begin(); + for(; it != remove_privatetags.end(); ++it) + { + success = success && anon.Remove( *it ); + } + + std::vector< std::pair >::const_iterator it2 = replace_privatetags.begin(); + for(; it2 != replace_privatetags.end(); ++it2) + { + success = success && anon.Replace( it2->first, it2->second.c_str() ); + } +} + + // Public Remove or Empty may impact Private Creator, so do them last. +{ + std::vector::const_iterator it = empty_tags.begin(); for(; it != empty_tags.end(); ++it) { success = success && anon.Empty( *it ); } + it = clear_tags.begin(); + for(; it != clear_tags.end(); ++it) + { + success = success && anon.Clear( *it ); + } it = remove_tags.begin(); for(; it != remove_tags.end(); ++it) { success = success && anon.Remove( *it ); } - - std::vector< std::pair >::const_iterator it2 = replace_tags.begin(); - for(; it2 != replace_tags.end(); ++it2) - { - success = success && anon.Replace( it2->first, it2->second.c_str() ); - } +} gdcm::Writer writer; writer.SetFileName( outfilename ); @@ -237,8 +276,13 @@ static void PrintHelp() std::cout << " --aes256 AES 256 (default)." << std::endl; std::cout << "Dumb mode options:" << std::endl; std::cout << " --empty %d,%d DICOM tag(s) to empty" << std::endl; + std::cout << " %d,%d,%s DICOM private tag(s) to empty" << std::endl; + std::cout << " --clear %d,%d DICOM tag(s) to clear" << std::endl; + std::cout << " %d,%d,%s DICOM private tag(s) to clear" << std::endl; std::cout << " --remove %d,%d DICOM tag(s) to remove" << std::endl; + std::cout << " %d,%d,%s DICOM private tag(s) to remove" << std::endl; std::cout << " --replace %d,%d=%s DICOM tag(s) to replace" << std::endl; + std::cout << " %d,%d,%s=%s DICOM private tag(s) to replace" << std::endl; std::cout << "General Options:" << std::endl; std::cout << " -V --verbose more verbose (warning+error)." << std::endl; std::cout << " -W --warning print warning info." << std::endl; @@ -308,13 +352,20 @@ int main(int argc, char *argv[]) int recursive = 0; int continuemode = 0; int empty_tag = 0; + int clear_tag = 0; int remove_tag = 0; int replace_tag = 0; int crypto_api = 0; std::vector empty_tags; + std::vector clear_tags; std::vector remove_tags; std::vector< std::pair > replace_tags_value; + std::vector empty_privatetags; + std::vector clear_privatetags; + std::vector remove_privatetags; + std::vector< std::pair > replace_privatetags_value; gdcm::Tag tag; + gdcm::PrivateTag privatetag; gdcm::CryptoFactory::CryptoLib crypto_lib; crypto_lib = gdcm::CryptoFactory::DEFAULT; @@ -340,10 +391,11 @@ int main(int argc, char *argv[]) {"recursive", no_argument, nullptr, 'r'}, {"dumb", no_argument, &dumb_mode, 1}, {"empty", required_argument, &empty_tag, 1}, // 15 + {"clear", required_argument, &clear_tag, 1}, // 16 {"remove", required_argument, &remove_tag, 1}, {"replace", required_argument, &replace_tag, 1}, {"continue", no_argument, &continuemode, 1}, - {"crypto", required_argument, &crypto_api, 1}, //19 + {"crypto", required_argument, &crypto_api, 1}, //20 {"verbose", no_argument, nullptr, 'V'}, {"warning", no_argument, nullptr, 'W'}, @@ -409,49 +461,75 @@ int main(int argc, char *argv[]) else if( option_index == 15 ) /* empty */ { assert( strcmp(s, "empty") == 0 ); - if( !tag.ReadFromCommaSeparatedString(optarg) ) + if( privatetag.ReadFromCommaSeparatedString(optarg) ) + empty_privatetags.push_back( privatetag ); + else if( tag.ReadFromCommaSeparatedString(optarg) ) + empty_tags.push_back( tag ); + else { - std::cerr << "Could not read Tag: " << optarg << std::endl; + std::cerr << "Could not read Tag/PrivateTag: " << optarg << std::endl; return 1; } - empty_tags.push_back( tag ); } - else if( option_index == 16 ) /* remove */ + else if( option_index == 16 ) /* clear */ + { + assert( strcmp(s, "clear") == 0 ); + if( privatetag.ReadFromCommaSeparatedString(optarg) ) + clear_privatetags.push_back( privatetag ); + else if( tag.ReadFromCommaSeparatedString(optarg) ) + clear_tags.push_back( tag ); + else + { + std::cerr << "Could not read Tag/PrivateTag: " << optarg << std::endl; + return 1; + } + } + else if( option_index == 17 ) /* remove */ { assert( strcmp(s, "remove") == 0 ); - if( !tag.ReadFromCommaSeparatedString(optarg) ) + if( privatetag.ReadFromCommaSeparatedString(optarg) ) + remove_privatetags.push_back( privatetag ); + else if( tag.ReadFromCommaSeparatedString(optarg) ) + remove_tags.push_back( tag ); + else { - std::cerr << "Could not read Tag: " << optarg << std::endl; + std::cerr << "Could not read Tag/PrivateTag: " << optarg << std::endl; return 1; } - remove_tags.push_back( tag ); } - else if( option_index == 17 ) /* replace */ + else if( option_index == 18 ) /* replace */ { assert( strcmp(s, "replace") == 0 ); - if( !tag.ReadFromCommaSeparatedString(optarg) ) + if( privatetag.ReadFromCommaSeparatedString(optarg) ) { - std::cerr << "Could not read Tag: " << optarg << std::endl; return 1; } - std::stringstream ss; - ss.str( optarg ); - uint16_t dummy; - char cdummy; // comma - ss >> std::hex >> dummy; - assert( tag.GetGroup() == dummy ); - ss >> cdummy; - assert( cdummy == ',' ); - ss >> std::hex >> dummy; - assert( tag.GetElement() == dummy ); - ss >> cdummy; - assert( cdummy == ',' || cdummy == '=' ); - std::string str; - //ss >> str; - std::getline(ss, str); // do not skip whitespace - replace_tags_value.emplace_back(tag, str ); + else if( tag.ReadFromCommaSeparatedString(optarg) ) + { + std::stringstream ss; + ss.str( optarg ); + uint16_t dummy; + char cdummy; // comma + ss >> std::hex >> dummy; + assert( tag.GetGroup() == dummy ); + ss >> cdummy; + assert( cdummy == ',' ); + ss >> std::hex >> dummy; + assert( tag.GetElement() == dummy ); + ss >> cdummy; + assert( cdummy == ',' || cdummy == '=' ); + std::string str; + //ss >> str; + std::getline(ss, str); // do not skip whitespace + replace_tags_value.emplace_back(tag, str ); + } + else + { + std::cerr << "Could not read Tag/PrivateTag: " << optarg << std::endl; + return 1; + } } - else if( option_index == 19 ) /* crypto */ + else if( option_index == 20 ) /* crypto */ { assert( strcmp(s, "crypto") == 0 ); if (strcmp(optarg, "openssl") == 0) @@ -674,6 +752,11 @@ int main(int argc, char *argv[]) std::cerr << "Input directory should be different from output directory" << std::endl; return 1; } +#ifdef _MSC_VER + if (outfilename.back() == '\\') + outfilename = outfilename.substr(0, outfilename.size() - 1); +#endif + if( outfilename.back() != '/' ) outfilename += '/'; nfiles = dir.Load(filename, (recursive > 0 ? true : false)); filenames = dir.GetFilenames(); gdcm::Directory::FilenamesType::const_iterator it = filenames.begin(); @@ -810,7 +893,8 @@ int main(int argc, char *argv[]) { const char *in = filenames[i].c_str(); const char *out = outfilenames[i].c_str(); - if( !AnonymizeOneFileDumb(anon, in, out, empty_tags, remove_tags, replace_tags_value, (continuemode > 0 ? true: false)) ) + if( !AnonymizeOneFileDumb(anon, in, out, empty_tags, clear_tags, remove_tags, replace_tags_value, + empty_privatetags, clear_privatetags, remove_privatetags, replace_privatetags_value, (continuemode > 0 ? true: false)) ) { //std::cerr << "Could not anonymize: " << in << std::endl; delete cms_ptr; diff --git a/Applications/Cxx/gdcmclean.cxx b/Applications/Cxx/gdcmclean.cxx new file mode 100644 index 0000000..26eb3ee --- /dev/null +++ b/Applications/Cxx/gdcmclean.cxx @@ -0,0 +1,544 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + */ +#include "gdcmCSAHeader.h" +#include "gdcmCleaner.h" +#include "gdcmDPath.h" +#include "gdcmDefs.h" +#include "gdcmDict.h" +#include "gdcmDicts.h" +#include "gdcmDirectory.h" +#include "gdcmGlobal.h" +#include "gdcmReader.h" +#include "gdcmSystem.h" +#include "gdcmVR.h" +#include "gdcmVersion.h" +#include "gdcmWriter.h" + +#include +#include + +static void PrintVersion() { + std::cout << "gdcmclean: gdcm " << gdcm::Version::GetVersion() << " "; + const char date[] = "$Date$"; + std::cout << date << std::endl; +} + +static bool CleanOneFile(gdcm::Cleaner &cleaner, const char *filename, + const char *outfilename, bool skipmeta, + bool continuemode = false) { + gdcm::Reader reader; + reader.SetFileName(filename); + if (!reader.Read()) { + std::cerr << "Could not read : " << filename << std::endl; + if (continuemode) { + std::cerr << "Skipping from cleaning process (continue mode)." + << std::endl; + return true; + } else { + std::cerr << "Check [--continue] option for skipping files." << std::endl; + return false; + } + } + gdcm::File &file = reader.GetFile(); + cleaner.SetFile(file); + if (!cleaner.Clean()) { + std::cerr << "Could not clean: " << filename << std::endl; + if (continuemode) { + std::cerr << "Skipping from cleaning process (continue mode)." + << std::endl; + return true; + } else { + std::cerr << "Check [--continue] option for skipping files." << std::endl; + return false; + } + } + + gdcm::Writer writer; + writer.SetFileName(outfilename); + writer.SetCheckFileMetaInformation(!skipmeta); + writer.SetFile(file); + if (!writer.Write()) { + std::cerr << "Could not Write : " << outfilename << std::endl; + if (strcmp(filename, outfilename) != 0) { + gdcm::System::RemoveFile(outfilename); + } else { + std::cerr << "gdcmclean just corrupted: " << filename + << " for you (data lost)." << std::endl; + } + return false; + } + return true; +} + +static inline bool isValidPublicKeyword(const char *keyword, gdcm::Tag &tag) { + static const gdcm::Global &g = gdcm::Global::GetInstance(); + static const gdcm::Dicts &dicts = g.GetDicts(); + static const gdcm::Dict &pubdict = dicts.GetPublicDict(); + + pubdict.GetDictEntryByKeyword(keyword, tag); + if (tag != gdcm::Tag(0xffff, 0xffff)) return true; + return false; +} + +static void PrintHelp() { + PrintVersion(); + std::cout << "Usage: gdcmclean [OPTION]... FILE..." << std::endl; + std::cout << "Options:" << std::endl; + std::cout << " -i --input DICOM filename / directory" + << std::endl; + std::cout << " -o --output DICOM filename / directory" + << std::endl; + std::cout + << " -r --recursive recursively process (sub-)directories." + << std::endl; + std::cout << " --continue Do not stop when file found is " + "not DICOM." + << std::endl; + std::cout << "Edition options:" << std::endl; + std::cout << " --empty %d,%d DICOM tag(s) to empty" + << std::endl; + std::cout << " %d,%d,%s DICOM private tag(s) to empty" + << std::endl; + std::cout << " %s DICOM keyword/path(s) to empty" + << std::endl; + std::cout << " --remove %d,%d DICOM tag(s) to remove" + << std::endl; + std::cout << " %d,%d,%s DICOM private tag(s) to remove" + << std::endl; + std::cout << " %s DICOM keyword/path(s) to remove" + << std::endl; + std::cout << " --scrub %d,%d DICOM tag(s) to scrub" + << std::endl; + std::cout << " %d,%d,%s DICOM private tag(s) to scrub" + << std::endl; + std::cout << " %s DICOM keyword/path(s) to scrub" + << std::endl; + std::cout << " --preserve %s DICOM path(s) to preserve" + << std::endl; + std::cout << " --preserve-missing-private-creator Whether or " + "not preserve private attributes with missing private creator." + << std::endl; + std::cout << " --preserve-group-length Whether or " + "not preserve deprecated group length attributes (will not be " + "re-computed)." + << std::endl; + std::cout << " --preserve-illegal Whether or " + "not preserve illegal attributes (eg. group 0003...)." + << std::endl; + std::cout << "General Options:" << std::endl; + std::cout << " -V --verbose more verbose (warning+error)." + << std::endl; + std::cout << " -W --warning print warning info." << std::endl; + std::cout << " -D --debug print debug info." << std::endl; + std::cout << " -E --error print error info." << std::endl; + std::cout << " -h --help print help." << std::endl; + std::cout << " -v --version print version." << std::endl; +} + +int main(int argc, char *argv[]) { + int c; + + std::string filename; + gdcm::Directory::FilenamesType filenames; + std::string outfilename; + gdcm::Directory::FilenamesType outfilenames; + int skipmeta = 0; + int continuemode = 0; + int verbose = 0; + int warning = 0; + int debug = 0; + int error = 0; + int help = 0; + int version = 0; + int recursive = 0; + int empty_tag = 0; + int remove_tag = 0; + int scrub_tag = 0; + int preserve_tag = 0; + int preserveAllMissingPrivateCreator = 0; + int preserveAllGroupLength = 0; + int preserveAllIllegal = 0; + std::vector empty_dpaths; + std::vector remove_dpaths; + std::vector scrub_dpaths; + std::vector preserve_dpaths; + std::vector empty_vrs; + std::vector empty_tags; + std::vector empty_privatetags; + std::vector remove_vrs; + std::vector remove_tags; + std::vector remove_privatetags; + std::vector scrub_tags; // clean-digital-trash + std::vector scrub_privatetags; // clean-digital-trash + gdcm::Tag tag; + gdcm::PrivateTag privatetag; + gdcm::DPath dpath; + + while (1) { + // int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = { + {"input", required_argument, NULL, 'i'}, // i + {"output", required_argument, NULL, 'o'}, // o + {"recursive", no_argument, NULL, 'r'}, + {"empty", required_argument, &empty_tag, 1}, // 3 + {"remove", required_argument, &remove_tag, 1}, // 4 + {"scrub", required_argument, &scrub_tag, 1}, // 5 + {"preserve", required_argument, &preserve_tag, 1}, // 5 + {"continue", no_argument, NULL, 'c'}, + {"skip-meta", 0, &skipmeta, 1}, // should I document this one ? + {"preserve-missing-private-creator", 0, + &preserveAllMissingPrivateCreator, 1}, // + {"preserve-group-length", 0, &preserveAllGroupLength, 1}, // + {"preserve-illegal", 0, &preserveAllIllegal, 1}, // + + {"verbose", no_argument, NULL, 'V'}, + {"warning", no_argument, NULL, 'W'}, + {"debug", no_argument, NULL, 'D'}, + {"error", no_argument, NULL, 'E'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + + {0, 0, 0, 0}}; + + c = getopt_long(argc, argv, "i:o:rcVWDEhv", long_options, &option_index); + if (c == -1) { + break; + } + + switch (c) { + case 0: { + const char *s = long_options[option_index].name; + (void)s; + if (optarg) { + if (option_index == 3) /* empty */ + { + assert(strcmp(s, "empty") == 0); + if (gdcm::VR::IsValid(optarg)) + empty_vrs.push_back(gdcm::VR::GetVRTypeFromFile(optarg)); + else if (privatetag.ReadFromCommaSeparatedString(optarg)) + empty_privatetags.push_back(privatetag); + else if (tag.ReadFromCommaSeparatedString(optarg)) + empty_tags.push_back(tag); + else if (isValidPublicKeyword(optarg, tag)) + empty_tags.push_back(tag); + else if (dpath.ConstructFromString(optarg)) + empty_dpaths.push_back(dpath); + else { + std::cerr << "Could not read Tag/PrivateTag/DPath: " << optarg + << std::endl; + return 1; + } + + } else if (option_index == 4) /* remove */ + { + if (gdcm::VR::IsValid(optarg)) + remove_vrs.push_back(gdcm::VR::GetVRTypeFromFile(optarg)); + if (privatetag.ReadFromCommaSeparatedString(optarg)) + remove_privatetags.push_back(privatetag); + else if (tag.ReadFromCommaSeparatedString(optarg)) + remove_tags.push_back(tag); + else if (isValidPublicKeyword(optarg, tag)) + remove_tags.push_back(tag); + else if (dpath.ConstructFromString(optarg)) + remove_dpaths.push_back(dpath); + else { + std::cerr << "Could not read Tag/PrivateTag/DPath: " << optarg + << std::endl; + return 1; + } + + } else if (option_index == 5) /* scrub */ + { + if (privatetag.ReadFromCommaSeparatedString(optarg)) + scrub_privatetags.push_back(privatetag); + else if (tag.ReadFromCommaSeparatedString(optarg)) + scrub_tags.push_back(tag); + else if (isValidPublicKeyword(optarg, tag)) + scrub_tags.push_back(tag); + else { + std::cerr << "Could not read Tag/PrivateTag/DPath: " << optarg + << std::endl; + return 1; + } + } else if (option_index == 6) /* preserve */ + { + if (dpath.ConstructFromString(optarg)) + preserve_dpaths.push_back(dpath); + else { + std::cerr << "Could not read DPath: " << optarg << std::endl; + return 1; + } + } else { + assert(0); + } + } + } break; + + case 'i': + assert(filename.empty()); + filename = optarg; + break; + + case 'o': + assert(outfilename.empty()); + outfilename = optarg; + break; + + case 'c': + continuemode = 1; + break; + + case 'r': + recursive = 1; + break; + + case 'V': + verbose = 1; + break; + + case 'W': + warning = 1; + break; + + case 'D': + debug = 1; + break; + + case 'E': + error = 1; + break; + + case 'h': + help = 1; + break; + + case 'v': + version = 1; + break; + + case '?': + break; + + default: + printf("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) { + std::vector files; + while (optind < argc) { + files.push_back(argv[optind++]); + } + if (files.size() == 2 && filename.empty() && outfilename.empty()) { + filename = files[0]; + outfilename = files[1]; + } else { + PrintHelp(); + return 1; + } + } + + if (version) { + PrintVersion(); + return 0; + } + + if (help) { + PrintHelp(); + return 0; + } + + if (filename.empty()) { + PrintHelp(); + return 1; + } + + if (!gdcm::System::FileExists(filename.c_str())) { + std::cerr << "Could not find file: " << filename << std::endl; + return 1; + } + + // Are we in single file or directory mode: + unsigned int nfiles = 1; + gdcm::Directory dir; + if (gdcm::System::FileIsDirectory(filename.c_str())) { + if (!gdcm::System::FileIsDirectory(outfilename.c_str())) { + if (gdcm::System::FileExists(outfilename.c_str())) { + std::cerr << "Could not create directory since " << outfilename + << " is already a file" << std::endl; + return 1; + } + } + // For now avoid user mistake + if (filename == outfilename) { + std::cerr << "Input directory should be different from output directory" + << std::endl; + return 1; + } + if (*outfilename.rbegin() != '/') outfilename += '/'; + nfiles = dir.Load(filename, (recursive > 0 ? true : false)); + filenames = dir.GetFilenames(); + gdcm::Directory::FilenamesType::const_iterator it = filenames.begin(); + // Prepare outfilenames + for (; it != filenames.end(); ++it) { + std::string dup = *it; // make a copy + std::string &out = dup.replace(0, filename.size(), outfilename); + outfilenames.push_back(out); + } + // Prepare outdirectory + gdcm::Directory::FilenamesType const &dirs = dir.GetDirectories(); + gdcm::Directory::FilenamesType::const_iterator itdir = dirs.begin(); + for (; itdir != dirs.end(); ++itdir) { + std::string dirdup = *itdir; // make a copy + std::string &dirout = dirdup.replace(0, filename.size(), outfilename); + if (!gdcm::System::MakeDirectory(dirout.c_str())) { + std::cerr << "Could not create directory: " << dirout << std::endl; + return 1; + } + } + } else { + filenames.push_back(filename); + outfilenames.push_back(outfilename); + } + + if (filenames.size() != outfilenames.size()) { + std::cerr << "Something went really wrong" << std::endl; + return 1; + } + + // Debug is a little too verbose + gdcm::Trace::SetDebug((debug > 0 ? true : false)); + gdcm::Trace::SetWarning((warning > 0 ? true : false)); + gdcm::Trace::SetError((error > 0 ? true : false)); + // when verbose is true, make sure warning+error are turned on: + if (verbose) { + gdcm::Trace::SetWarning((verbose > 0 ? true : false)); + gdcm::Trace::SetError((verbose > 0 ? true : false)); + } + + gdcm::FileMetaInformation::SetSourceApplicationEntityTitle("gdcmclean"); + + // Setup gdcm::Cleaner + gdcm::Cleaner cleaner; + cleaner.RemoveAllMissingPrivateCreator(!preserveAllMissingPrivateCreator); + cleaner.RemoveAllGroupLength(!preserveAllGroupLength); + cleaner.RemoveAllIllegal(!preserveAllIllegal); + // Preserve + for (std::vector::const_iterator it = preserve_dpaths.begin(); + it != preserve_dpaths.end(); ++it) { + if (!cleaner.Preserve(*it)) { + std::cerr << "Impossible to Preserve: " << *it << std::endl; + return 1; + } + } + // VR + for (std::vector::const_iterator it = empty_vrs.begin(); + it != empty_vrs.end(); ++it) { + if (!cleaner.Empty(*it)) { + std::cerr << "Impossible to Empty: " << *it << std::endl; + return 1; + } + } + for (std::vector::const_iterator it = remove_vrs.begin(); + it != remove_vrs.end(); ++it) { + if (!cleaner.Remove(*it)) { + std::cerr << "Impossible to Remove: " << *it << std::endl; + return 1; + } + } + // Empty + for (std::vector::const_iterator it = empty_tags.begin(); + it != empty_tags.end(); ++it) { + if (!cleaner.Empty(*it)) { + std::cerr << "Impossible to Empty: " << *it << std::endl; + return 1; + } + } + for (std::vector::const_iterator it = + empty_privatetags.begin(); + it != empty_privatetags.end(); ++it) { + if (!cleaner.Empty(*it)) { + std::cerr << "Impossible to Empty: " << *it << std::endl; + return 1; + } + } + for (std::vector::const_iterator it = empty_dpaths.begin(); + it != empty_dpaths.end(); ++it) { + if (!cleaner.Empty(*it)) { + std::cerr << "Impossible to Empty: " << *it << std::endl; + return 1; + } + } + // Remove + for (std::vector::const_iterator it = remove_tags.begin(); + it != remove_tags.end(); ++it) { + if (!cleaner.Remove(*it)) { + std::cerr << "Impossible to Remove: " << *it << std::endl; + return 1; + } + } + for (std::vector::const_iterator it = + remove_privatetags.begin(); + it != remove_privatetags.end(); ++it) { + if (!cleaner.Remove(*it)) { + std::cerr << "Impossible to Remove: " << *it << std::endl; + return 1; + } + } + for (std::vector::const_iterator it = remove_dpaths.begin(); + it != remove_dpaths.end(); ++it) { + if (!cleaner.Remove(*it)) { + std::cerr << "Impossible to Remove: " << *it << std::endl; + return 1; + } + } + // Scrub + for (std::vector::const_iterator it = scrub_tags.begin(); + it != scrub_tags.end(); ++it) { + if (!cleaner.Scrub(*it)) { + std::cerr << "Impossible to Scrub: " << *it << std::endl; + return 1; + } + } + for (std::vector::const_iterator it = + scrub_privatetags.begin(); + it != scrub_privatetags.end(); ++it) { + if (!cleaner.Scrub(*it)) { + std::cerr << "Impossible to Scrub: " << *it << std::endl; + return 1; + } + } + for (std::vector::const_iterator it = scrub_dpaths.begin(); + it != scrub_dpaths.end(); ++it) { + if (!cleaner.Scrub(*it)) { + std::cerr << "Impossible to Scrub: " << *it << std::endl; + return 1; + } + } + { + for (unsigned int i = 0; i < nfiles; ++i) { + const char *in = filenames[i].c_str(); + const char *out = outfilenames[i].c_str(); + if (!CleanOneFile(cleaner, in, out, skipmeta > 0 ? true : false, + continuemode > 0 ? true : false)) { + return 1; + } + } + } + + return 0; +} diff --git a/Applications/Cxx/gdcmconv.cxx b/Applications/Cxx/gdcmconv.cxx index 59df7ad..aa924d9 100644 --- a/Applications/Cxx/gdcmconv.cxx +++ b/Applications/Cxx/gdcmconv.cxx @@ -13,10 +13,10 @@ =========================================================================*/ /* * HISTORY: - * In GDCM 1.X the prefered terms was 'ReWrite', however one author of GDCM dislike + * In GDCM 1.X the preferred term was 'ReWrite', however one author of GDCM dislike * the term ReWrite since it is associated with the highly associated with the Rewrite * notion in software programming where using reinvent the wheel and rewrite from scratch code - * the term convert was prefered + * the term convert was preferred * * Tools to conv. Goals being to 'purify' a DICOM file. * For now it will do the minimum: @@ -25,7 +25,7 @@ * simply discarded (not written). * - Elements are written in alphabetical order * - 32bits VR have the residue bytes sets to 0x0,0x0 - * - Same goes from Item Length end delimitor, sets to 0x0,0x0 + * - Same goes from Item Length end delimiter, sets to 0x0,0x0 * - All buggy files (wrong length: GE, 13 and Siemens Leonardo) are fixed * - All size are even (no odd length from gdcm 1.x) * @@ -44,7 +44,7 @@ * - Any broken JPEG file (wrong bits) should be fixed * - DicomObject bug should be fixed * - Meta and Dataset should have a matching UID (more generally File Meta - * should be correct (Explicit!) and consistant with DataSet) + * should be correct (Explicit!) and consistent with DataSet) * - User should be able to specify he wants Group Length (or remove them) * - Media SOP should be correct (deduct from something else or set to * SOP Secondary if all else fail). @@ -153,7 +153,7 @@ static void PrintHelp() std::cout << " -F --force Force decompression/merging before recompression/splitting." << std::endl; std::cout << " --generate-icon Generate icon." << std::endl; std::cout << " --icon-minmax %d,%d Min/Max value for icon." << std::endl; - std::cout << " --icon-auto-minmax Automatically commpute best Min/Max values for icon." << std::endl; + std::cout << " --icon-auto-minmax Automatically compute best Min/Max values for icon." << std::endl; std::cout << " --compress-icon Decide whether icon follows main TransferSyntax or remains uncompressed." << std::endl; std::cout << " --planar-configuration [01] Change planar configuration." << std::endl; std::cout << " -Y --lossy Use the lossy (if possible) compressor." << std::endl; @@ -926,7 +926,7 @@ int main (int argc, char *argv[]) } // Handle here the general file (not required to be image) - if ( explicitts || implicit || deflated ) + if ( !raw && (explicitts || implicit || deflated) ) { if( explicitts && implicit ) return 1; // guard if( explicitts && deflated ) return 1; // guard @@ -1178,7 +1178,11 @@ int main (int argc, char *argv[]) { if( lossy ) { - change.SetTransferSyntax( gdcm::TransferSyntax::JPEGBaselineProcess1 ); + const gdcm::PixelFormat &pf = image.GetPixelFormat(); + if( pf.GetBitsAllocated() > 8 ) + change.SetTransferSyntax(gdcm::TransferSyntax::JPEGExtendedProcess2_4); + else + change.SetTransferSyntax( gdcm::TransferSyntax::JPEGBaselineProcess1 ); jpegcodec.SetLossless( false ); if( quality ) { @@ -1261,11 +1265,15 @@ int main (int argc, char *argv[]) if( ts.IsExplicit() ) { change.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + if( implicit ) + change.SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); } else { assert( ts.IsImplicit() ); change.SetTransferSyntax( gdcm::TransferSyntax::ImplicitVRLittleEndian ); + if( explicitts ) + change.SetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); } #endif } diff --git a/Applications/Cxx/gdcmdictdump.cxx b/Applications/Cxx/gdcmdictdump.cxx index 5923e37..6926419 100644 --- a/Applications/Cxx/gdcmdictdump.cxx +++ b/Applications/Cxx/gdcmdictdump.cxx @@ -1,4 +1,4 @@ /* -* TODO: Is this really usefull ? -* Dump the dict from a DICOM file. Usefull for the private dict +* TODO: Is this really useful ? +* Dump the dict from a DICOM file. Useful for the private dict */ diff --git a/Applications/Cxx/gdcmdiff.cxx b/Applications/Cxx/gdcmdiff.cxx index 649b98e..94ead5c 100644 --- a/Applications/Cxx/gdcmdiff.cxx +++ b/Applications/Cxx/gdcmdiff.cxx @@ -232,8 +232,8 @@ static void difference_of_sequences(const gdcm::DataElement& sqde1, { gdcm::SmartPointer sqi1 = sqde1.GetValueAsSQ(); gdcm::SmartPointer sqi2 = sqde2.GetValueAsSQ(); - size_t n1 = sqi1->GetNumberOfItems(); - size_t n2 = sqi2->GetNumberOfItems(); + size_t n1 = sqi1 ? sqi1->GetNumberOfItems() : 0; + size_t n2 = sqi2 ? sqi2->GetNumberOfItems() : 0; size_t n = (n1 < n2) ? n1 : n2 ; std::stringstream sq_note; if (n1 != n2) diff --git a/Applications/Cxx/gdcmdump.cxx b/Applications/Cxx/gdcmdump.cxx index 51f82c0..db9299a 100644 --- a/Applications/Cxx/gdcmdump.cxx +++ b/Applications/Cxx/gdcmdump.cxx @@ -19,7 +19,7 @@ * - dcmInfo (SIEMENS) * - PrintFile (GDCM 1.x) * - * For now all layout are harcoded (see --color/--xml-dict for instance) + * For now all layout are hardcoded (see --color/--xml-dict for instance) * * gdcmdump has some feature not described in the DICOM standard: * --csa : to print CSA information (dcmInfo.exe compatible) @@ -49,10 +49,16 @@ #include "gdcmASN1.h" #include "gdcmAttribute.h" #include "gdcmBase64.h" +#include "gdcmMEC_MR3.h" #include "gdcmTagKeywords.h" +#include "gdcmDeflateStream.h" #include #include +#ifdef GDCM_HAVE_CODECVT +#include +#endif +#include #include /* for printf */ #include /* for exit */ @@ -190,7 +196,7 @@ static void ProcessSDSDataString( std::istream & is ) static void ProcessSDSData( std::istream & is ) { - // havent been able to figure out what was the begin meant for + // haven't been able to figure out what was the begin meant for is.seekg( 0x20 - 8 ); uint32_t version = 0; assert( sizeof(uint32_t) == 4 ); @@ -355,6 +361,7 @@ static bool DumpToshibaDTI( const char * input, size_t len ) ds.Read( is ); gdcm::Printer p; + //gdcm::DictPrinter p; p.SetFile( file ); p.SetColor( color != 0 ); p.Print( std::cout ); @@ -363,13 +370,12 @@ static bool DumpToshibaDTI( const char * input, size_t len ) } -static int DumpTOSHIBA_PMTF_INFORMATION_DATA(const gdcm::DataSet & ds) +static int DumpTOSHIBA_Reverse(const gdcm::DataSet & ds, const gdcm::PrivateTag &tpmtf, const gdcm::PrivateTag &tseq) { // (0029,0010) ?? (LO) [PMTF INFORMATION DATA ] # 22,1 Private Creator // (0029,1001) ?? (SQ) (Sequence with undefined length) # u/l,1 ? - const gdcm::PrivateTag tpmtf(0x0029,0x1,"PMTF INFORMATION DATA"); - if( !ds.FindDataElement( tpmtf) ) return 1; + if( !ds.FindDataElement( tpmtf) ) return 0; // this is not an error at this point const gdcm::DataElement& pmtf = ds.GetDataElement( tpmtf ); if ( pmtf.IsEmpty() ) return 1; gdcm::SmartPointer seq = pmtf.GetValueAsSQ(); @@ -383,7 +389,6 @@ static int DumpTOSHIBA_PMTF_INFORMATION_DATA(const gdcm::DataSet & ds) gdcm::DataSet &subds = item.GetNestedDataSet(); // (0029,0010) ?? (LO) [PMTF INFORMATION DATA ] # 22,1 Private Creator // (0029,1090) ?? (OB) 00\05\00\13\00\12\00\22\ # 202,1 ? - const gdcm::PrivateTag tseq(0x0029,0x90,"PMTF INFORMATION DATA"); if( subds.FindDataElement( tseq ) ) { @@ -491,7 +496,7 @@ struct Data2 os << " UserAdress4: " << std::string(UserAdress4,32) << "\n"; os << " UserAdress5: " << std::string(UserAdress5,32) << "\n"; os << " RecDate: " << std::string(RecDate,8) << "\n"; - os << " RecTime: " << std::string(RecTime,64) << "\n"; + os << " RecTime: " << std::string(RecTime,6) << "\n"; os << " RecPlace: " << std::string(RecPlace,64) << "\n"; os << " RecSource: " << std::string(RecSource,64) << "\n"; os << " DF1: " << std::string(DF1,64) << "\n"; @@ -698,6 +703,26 @@ static int DumpEl2_new(const gdcm::DataSet & ds) const gdcm::ByteValue * bv = de01f7_26.GetByteValue(); const char *begin = bv->GetPointer(); + const size_t buf_len= bv->GetLength(); + + bool isgzip = false; + if( buf_len > (0x15f + 3) ) { + const unsigned char *sig = (const unsigned char*)begin + 0x15f; + isgzip = sig[0] == 0x1f && sig[1] == 0x8b && sig[2] == 0x08 /* DEFLATE */; + } + + if( isgzip ) { + size_t offset = 0x15f; + size_t len = buf_len - 0x15f; + std::string str( begin + offset, begin + len ); + std::istringstream is( str ); + + zlib_stream::zip_istream gzis( is ); + std::string out; + while( std::getline(gzis, out) ) { + std::cout << out << std::endl; + } + } else { uint32_t val0[3]; memcpy( &val0, begin, sizeof( val0 ) ); assert( val0[0] == 0xF22D ); @@ -717,6 +742,7 @@ static int DumpEl2_new(const gdcm::DataSet & ds) std::cout << std::endl; begin += o; } + } return 0; } @@ -851,6 +877,38 @@ static int PrintCT3(const std::string & filename, bool verbose) return ret; } +static int PrintMEC_MR3(const std::string & filename, bool verbose) +{ + (void)verbose; + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + // Original Data + const gdcm::PrivateTag tmecmr3(0x700d,0x08,"TOSHIBA_MEC_MR3"); + if( !ds.FindDataElement( tmecmr3) ) return 1; + const gdcm::DataElement& mecmr3 = ds.GetDataElement( tmecmr3 ); + if ( mecmr3.IsEmpty() ) return 1; + const gdcm::ByteValue * bv = mecmr3.GetByteValue(); + + const char *inbuffer = bv->GetPointer(); + const size_t buf_len= bv->GetLength(); + + int ret = 0; + if (!gdcm::MEC_MR3::Print(inbuffer, buf_len)) + { + ret = 1; + } + + return ret; +} + static int PrintPMTF(const std::string & filename, bool verbose) { (void)verbose; @@ -863,11 +921,91 @@ static int PrintPMTF(const std::string & filename, bool verbose) } const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); - int ret = cleanup::DumpTOSHIBA_PMTF_INFORMATION_DATA( ds ); + int ret = 0; + { + const gdcm::PrivateTag tpmtf(0x0029,0x1,"PMTF INFORMATION DATA"); + static const gdcm::PrivateTag &tseq = gdcm::MEC_MR3::GetPMTFInformationDataTag(); + ret += cleanup::DumpTOSHIBA_Reverse( ds, tpmtf, tseq ); + } + + { + const gdcm::PrivateTag tpmtf(0x0029,0x1,"CANON_MEC_MR3"); + static const gdcm::PrivateTag &tseq = gdcm::MEC_MR3::GetCanonMECMR3Tag(); + ret += cleanup::DumpTOSHIBA_Reverse( ds, tpmtf, tseq ); + + // PAS Reproduct Information + const gdcm::PrivateTag tpasri(0x700d,0x19,"CANON_MEC_MR3^10"); + if( ds.FindDataElement( tpasri) ) { + const gdcm::DataElement& pasri = ds.GetDataElement( tpasri ); + if (! pasri.IsEmpty() ) { + const gdcm::ByteValue * bv = pasri.GetByteValue(); + std::string s(bv->GetPointer(), bv->GetLength() ); + std::cout << std::endl; + std::cout << "PAS Reproduct Information (XML)" << std::endl; + // header states: + // + // so simply dump without further cleanup: + std::cout << s.c_str() << std::endl; + } + } + } + + { + const gdcm::PrivateTag tpmtf(0x0029,0x1,"TOSHIBA_MEC_MR3"); + static const gdcm::PrivateTag &tseq = gdcm::MEC_MR3::GetToshibaMECMR3Tag(); + ret += cleanup::DumpTOSHIBA_Reverse( ds, tpmtf, tseq ); + + const gdcm::PrivateTag tpmtf2(0x0029,0x2,"TOSHIBA_MEC_MR3"); + ret += cleanup::DumpTOSHIBA_Reverse( ds, tpmtf2, tseq ); + } return ret; } +static void print_utf8(std::string const& s) +{ + const char delim = 0; + auto start = 0U; + auto end = s.find(delim); + while (end != std::string::npos) + { + std::cout << s.substr(start, end - start) << std::endl; + start = end + 1; + end = s.find(delim, start); + } +} + +static int PrintMedComHistory(const std::string & filename, bool verbose) +{ + (void)verbose; + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + const gdcm::PrivateTag tmedcom(0x0029,0x20,"SIEMENS MEDCOM HEADER"); + if( !ds.FindDataElement( tmedcom) ) return 1; + const gdcm::DataElement& medcom = ds.GetDataElement( tmedcom); + if ( medcom.IsEmpty() ) return 1; + const gdcm::ByteValue * bv = medcom.GetByteValue(); + + const size_t size = bv->GetLength(); + std::u16string u16((size / 2) + 0, '\0'); + bv->GetBuffer( (char*)&u16[0], size ); + +#ifdef GDCM_HAVE_CODECVT + std::string utf8 = std::wstring_convert< + std::codecvt_utf8_utf16, char16_t>{}.to_bytes(u16); + print_utf8(utf8); +#else + std::cerr << "Missing GDCM_HAVE_CODECVT support" << std::endl; +#endif + return 0; +} static int PrintPDB(const std::string & filename, bool verbose) { @@ -902,26 +1040,14 @@ static int PrintPDB(const std::string & filename, bool verbose) return ret; } -static int PrintCSABase64(const std::string & filename, const char * name) +static int PrintCSABase64Impl(gdcm::CSAHeader &csa, std::string const & csaname ) { - gdcm::Reader reader; - reader.SetFileName( filename.c_str() ); - if( !reader.Read() ) - { - std::cerr << "Failed to read: " << filename << std::endl; - return 1; - } - const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); - - gdcm::CSAHeader csa; - const gdcm::PrivateTag &t1 = csa.GetCSAImageHeaderInfoTag(); - if( !ds.FindDataElement( t1 ) ) return 1; - csa.LoadFromDataElement( ds.GetDataElement( t1 ) ); - + const char *name = csaname.c_str(); if( csa.FindCSAElementByName(name) ) { const gdcm::CSAElement & el = csa.GetCSAElementByName(name); - if( el.IsEmpty() ) return 1; + // this is not error if empty: + if( el.IsEmpty() ) return 0; const gdcm::ByteValue* bv = el.GetByteValue(); std::string str( bv->GetPointer(), bv->GetLength() ); str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); @@ -948,12 +1074,48 @@ static int PrintCSABase64(const std::string & filename, const char * name) return 1; } gdcm::Printer p; + //gdcm::DictPrinter p; p.SetFile( file ); + //p.SetColor( 1 ); + std::cout << "--" << csaname << "--" << std::endl; p.Print(std::cout); } return 0; } +static int PrintCSABase64(const std::string & filename, std::vector const & csanames ) +{ + gdcm::Reader reader; + reader.SetFileName( filename.c_str() ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + int ret = 0; + + gdcm::CSAHeader csa; + const gdcm::PrivateTag &t1 = csa.GetCSAImageHeaderInfoTag(); + if( !ds.FindDataElement( t1 ) ) return 1; + csa.LoadFromDataElement( ds.GetDataElement( t1 ) ); + for( std::vector::const_iterator it = csanames.begin(); + it != csanames.end(); ++it ) { + ret += PrintCSABase64Impl(csa, *it ); + } + + const gdcm::PrivateTag &t2 = csa.GetCSASeriesHeaderInfoTag(); + if( !ds.FindDataElement( t2 ) ) return 1; + csa.LoadFromDataElement( ds.GetDataElement( t2 ) ); + for( std::vector::const_iterator it = csanames.begin(); + it != csanames.end(); ++it ) { + ret += PrintCSABase64Impl(csa, *it ); + } + + return ret; +} + static int PrintCSA(const std::string & filename) { gdcm::Reader reader; @@ -1133,7 +1295,9 @@ static void PrintHelp() std::cout << " -C --csa print SIEMENS CSA Header (0029,[12]0,SIEMENS CSA HEADER)." << std::endl; std::cout << " --csa-asl print decoded SIEMENS CSA MR_ASL (base64)." << std::endl; std::cout << " --csa-diffusion print decoded SIEMENS CSA MRDiffusion (base64)." << std::endl; + std::cout << " --csa64 print decoded SIEMENS CSA FMRI/MR_ASL/MRDiffusion... (base64)." << std::endl; std::cout << " --mrprotocol print SIEMENS CSA MrProtocol only (within ASCCONV BEGIN/END)." << std::endl; + std::cout << " or Phoenix Meta Protocol (0021,19,SIEMENS MR SDS 01)." << std::endl; std::cout << " -P --pdb print GEMS Protocol Data Block (0025,1b,GEMS_SERS_01)." << std::endl; std::cout << " --elscint print ELSCINT Protocol Information (01f7,26,ELSCINT1)." << std::endl; std::cout << " --vepro print VEPRO Protocol Information (0055,20,VEPRO VIF 3.0 DATA)." << std::endl; @@ -1141,6 +1305,10 @@ static void PrintHelp() std::cout << " --sds print Philips MR Series Data Storage (1.3.46.670589.11.0.0.12.2) Information (2005,32,Philips MR Imaging DD 002)." << std::endl; std::cout << " --ct3 print CT Private Data 2 (7005,10,TOSHIBA_MEC_CT3)." << std::endl; std::cout << " --pmtf print PMTF INFORMATION DATA sub-sequences (0029,01,PMTF INFORMATION DATA)." << std::endl; + std::cout << " or TOSHIBA_MEC_MR3 sub-sequences (0029,01,TOSHIBA_MEC_MR3)." << std::endl; + std::cout << " or CANON_MEC_MR3 sub-sequences (0029,01,CANON_MEC_MR3)." << std::endl; + std::cout << " --medcom print MedCom History Information as UTF-8 (0029,20,SIEMENS MEDCOM HEADER)." << std::endl; + std::cout << " --mr3 print Original Data as UTF-8 (700d,08,TOSHIBA_MEC_MR3)." << std::endl; std::cout << " -A --asn1 print encapsulated ASN1 structure >(0400,0520)." << std::endl; std::cout << " --map-uid-names map UID to names." << std::endl; std::cout << "General Options:" << std::endl; @@ -1166,14 +1334,17 @@ int main (int argc, char *argv[]) int printcsa = 0; int printmrprotocol = 0; int printcsabase64 = 0; + int printmedcom = 0; // MedCom History Information int printcsaasl = 0; int printcsadiffusion = 0; + int printcsa64 = 0; int printpdb = 0; int printelscint = 0; int printvepro = 0; int printsds = 0; // MR Series Data Storage int printct3 = 0; // TOSHIBA_MEC_CT3 - int printpmtf = 0; // TOSHIBA / PMTF INFORMATION DATA + int printmecmr3 = 0; // TOSHIBA_MEC_MR3 + int printpmtf = 0; // TOSHIBA / PMTF INFORMATION DATA & TOSHIBA / TOSHIBA_MEC_MR3 & CANON_MEC_MR3 int verbose = 0; int warning = 0; int debug = 0; @@ -1218,8 +1389,12 @@ int main (int argc, char *argv[]) {"ct3", 0, &printct3, 1}, {"csa-asl", 0, &printcsaasl, 1}, {"csa-diffusion", 0, &printcsadiffusion, 1}, + {"csa64", 0, &printcsa64, 1}, {"mrprotocol", 0, &printmrprotocol, 1}, {"pmtf", 0, &printpmtf, 1}, + {"mecmr3", 0, &printpmtf, 1}, + {"medcom", 0, &printmedcom, 1}, + {"mr3", 0, &printmecmr3, 1}, {nullptr, 0, nullptr, 0} // required }; static const char short_options[] = "i:xrpdcCPAVWDEhvI"; @@ -1391,16 +1566,26 @@ int main (int argc, char *argv[]) std::cerr << "Not handled for now" << std::endl; } - const char * csaname = nullptr; + std::vector csanames; if( printcsaasl ) { printcsabase64 = 1; - csaname = "MR_ASL"; + csanames.push_back( "MR_ASL" ); } else if( printcsadiffusion ) { printcsabase64 = 1; - csaname = "MRDiffusion"; + csanames.push_back( "MRDiffusion" ); + } + else if( printcsa64 ) + { + printcsabase64 = 1; + // keep me sorted + csanames.push_back( "FmriAcquisitionDescriptionSequence" ); + csanames.push_back( "FmriConditionsDataSequence" ); + csanames.push_back( "FmriResultSequence" ); + csanames.push_back( "MR_ASL" ); + csanames.push_back( "MRDiffusion" ); } // else @@ -1441,6 +1626,14 @@ int main (int argc, char *argv[]) { res += PrintPMTF(*it, verbose!= 0); } + else if( printmecmr3 ) + { + res += PrintMEC_MR3(*it, verbose!=0); + } + else if( printmedcom ) + { + res += PrintMedComHistory(*it, verbose!=0); + } else if( printelscint ) { res += PrintELSCINT(*it, verbose!= 0); @@ -1459,7 +1652,7 @@ int main (int argc, char *argv[]) } else if( printcsabase64 ) { - res += PrintCSABase64(*it, csaname); + res += PrintCSABase64(*it, csanames); } else if( dump ) { @@ -1500,6 +1693,14 @@ int main (int argc, char *argv[]) { res += PrintPMTF(filename, verbose!= 0); } + else if( printmecmr3 ) + { + res += PrintMEC_MR3(filename, verbose!= 0); + } + else if( printmedcom ) + { + res += PrintMedComHistory(filename, verbose!= 0); + } else if( printelscint ) { res += PrintELSCINT(filename, verbose!= 0); @@ -1518,7 +1719,7 @@ int main (int argc, char *argv[]) } else if( printcsabase64 ) { - res += PrintCSABase64(filename, csaname); + res += PrintCSABase64(filename, csanames); } else if( dump ) { diff --git a/Applications/Cxx/gdcmimg.cxx b/Applications/Cxx/gdcmimg.cxx index d2bcfa4..566dca2 100644 --- a/Applications/Cxx/gdcmimg.cxx +++ b/Applications/Cxx/gdcmimg.cxx @@ -346,6 +346,7 @@ static bool PopulateSingeFile( gdcm::PixmapWriter & writer, static bool Populate( gdcm::PixmapWriter & writer, gdcm::ImageCodec & jpeg, gdcm::Directory::FilenamesType const & filenames, unsigned int ndim = 2, std::streampos const & pos = 0 ) { + assert( !filenames.empty() ); std::vector::const_iterator it = filenames.begin(); bool b = true; gdcm::Pixmap &image = writer.GetPixmap(); @@ -511,6 +512,7 @@ int main (int argc, char *argv[]) assert( strcmp(s, "input") == 0 ); assert( filename.IsEmpty() ); filename = optarg; + filenames.emplace_back(filename); } else if( option_index == 2 ) /* depth */ { @@ -606,6 +608,7 @@ int main (int argc, char *argv[]) //printf ("option i with value '%s'\n", optarg); assert( filename.IsEmpty() ); filename = optarg; + filenames.emplace_back(filename); break; case 'o': @@ -1180,9 +1183,9 @@ int main (int argc, char *argv[]) if ( region[0] > region[1] || region[2] > region[3] || region[4] > region[5] - || region[1] > dims[0] - || region[3] > dims[1] - || (imageori.GetNumberOfDimensions() > 2 && region[5] > dims[2]) ) + || region[1] >= dims[0] + || region[3] >= dims[1] + || (imageori.GetNumberOfDimensions() > 2 && region[5] >= dims[2]) ) { if( imageori.GetNumberOfDimensions() == 2 ) { diff --git a/Applications/Cxx/gdcminfo.cxx b/Applications/Cxx/gdcminfo.cxx index ff6f151..ff95085 100644 --- a/Applications/Cxx/gdcminfo.cxx +++ b/Applications/Cxx/gdcminfo.cxx @@ -196,12 +196,15 @@ static std::string getInfoDate(Dict *infoDict, const char *key) std::string out; #ifdef LIBPOPPLER_NEW_OBJECT_API - if ((obj = infoDict->lookup((char*)key)).isString()) + if ((obj = infoDict->lookup(const_cast(key))).isString()) #else if (infoDict->lookup((char*)key, &obj)->isString()) #endif { - const GooString* gs = obj.getString(); +#ifndef LIBPOPPLER_GOOSTRING_HAS_GETCSTRING + const +#endif + GooString* gs = obj.getString(); #ifdef LIBPOPPLER_GOOSTRING_HAS_GETCSTRING s = gs->getCString(); #else @@ -216,11 +219,11 @@ static std::string getInfoDate(Dict *infoDict, const char *key) { switch (n) { - case 1: mon = 1; - case 2: day = 1; - case 3: hour = 0; - case 4: min = 0; - case 5: sec = 0; + case 1: mon = 1; /* fall through */ + case 2: day = 1; /* fall through */ + case 3: hour = 0; /* fall through */ + case 4: min = 0; /* fall through */ + case 5: sec = 0; /* fall through */ } tmStruct.tm_year = year - 1900; tmStruct.tm_mon = mon - 1; @@ -258,7 +261,11 @@ static std::string getInfoDate(Dict *infoDict, const char *key) return out; } +#ifdef LIBPOPPLER_UNICODEMAP_HAS_CONSTMAPUNICODE static std::string getInfoString(Dict *infoDict, const char *key, const UnicodeMap *uMap) +#else +static std::string getInfoString(Dict *infoDict, const char *key, UnicodeMap *uMap) +#endif { Object obj; #ifdef LIBPOPPLER_GOOSTRING_HAS_CONSTGETCHAR @@ -273,7 +280,7 @@ static std::string getInfoString(Dict *infoDict, const char *key, const UnicodeM std::string out; #ifdef LIBPOPPLER_NEW_OBJECT_API - if ((obj = infoDict->lookup((char*)key)).isString()) + if ((obj = infoDict->lookup(const_cast(key))).isString()) #else if (infoDict->lookup((char*)key, &obj)->isString()) #endif @@ -487,15 +494,19 @@ static int ProcessOneFile( std::string const & filename, gdcm::Defs const & defs MemStream *appearStream; - appearStream = new MemStream((char*)bv->GetPointer(), 0, + appearStream = new MemStream(const_cast(bv->GetPointer()), 0, #ifdef LIBPOPPLER_NEW_OBJECT_API bv->GetLength(), std::move(appearDict)); #else bv->GetLength(), &appearDict); #endif +#ifdef LIBPOPPLER_PDFDOC_HAS_OPTIONAL + std::optional ownerPW, userPW; +#else GooString *ownerPW, *userPW; ownerPW = NULL; userPW = NULL; +#endif PDFDoc *doc; doc = new PDFDoc(appearStream, ownerPW, userPW); @@ -509,12 +520,16 @@ static int ProcessOneFile( std::string const & filename, gdcm::Defs const & defs std::string creationdate; std::string moddate; +#ifdef LIBPOPPLER_UNICODEMAP_HAS_CONSTMAPUNICODE const UnicodeMap *uMap; -#ifdef LIBPOPPLER_GLOBALPARAMS_IS_UNIQUE_PTR - globalParams = std::make_unique(); #else + UnicodeMap *uMap; +#endif #ifdef LIBPOPPLER_GLOBALPARAMS_CSTOR_HAS_PARAM globalParams = new GlobalParams(0); +#else +#ifdef LIBPOPPLER_GLOBALPARAMS_HAS_RESET + globalParams.reset(new GlobalParams()); #else globalParams = new GlobalParams(); #endif diff --git a/Applications/Cxx/gdcmpap3.cxx b/Applications/Cxx/gdcmpap3.cxx index 6b9a7cf..b918b0d 100644 --- a/Applications/Cxx/gdcmpap3.cxx +++ b/Applications/Cxx/gdcmpap3.cxx @@ -110,7 +110,7 @@ static bool DecompressPapyrus3( int pap3handle, int itemnum, gdcm::TransferSynta gdcm::DataSet & nested = file.GetDataSet(); - /* position the file pointer to the begining of the data set */ + /* position the file pointer to the beginning of the data set */ PapyShort err = Papy3GotoNumber (fileNb, (PapyShort)imageNb, DataSetID); gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) ); diff --git a/Applications/Cxx/gdcmpdf.cxx b/Applications/Cxx/gdcmpdf.cxx index 8e5e88f..5a98d28 100644 --- a/Applications/Cxx/gdcmpdf.cxx +++ b/Applications/Cxx/gdcmpdf.cxx @@ -25,6 +25,9 @@ #include #include #include +#ifdef LIBPOPPLER_PDFDOC_HAS_OPTIONAL +#include +#endif #endif #include @@ -44,12 +47,15 @@ static std::string getInfoDate(Dict *infoDict, const char *key) std::string out; #ifdef LIBPOPPLER_NEW_OBJECT_API - if ((obj = infoDict->lookup((char*)key)).isString()) + if ((obj = infoDict->lookup(const_cast(key))).isString()) #else if (infoDict->lookup((char*)key, &obj)->isString()) #endif { - const GooString* gs = obj.getString(); +#ifndef LIBPOPPLER_GOOSTRING_HAS_GETCSTRING + const +#endif + GooString* gs = obj.getString(); #ifdef LIBPOPPLER_GOOSTRING_HAS_GETCSTRING s = gs->getCString(); #else @@ -64,11 +70,11 @@ static std::string getInfoDate(Dict *infoDict, const char *key) { switch (n) { - case 1: mon = 1; - case 2: day = 1; - case 3: hour = 0; - case 4: min = 0; - case 5: sec = 0; + case 1: mon = 1; /* fall through */ + case 2: day = 1; /* fall through */ + case 3: hour = 0; /* fall through */ + case 4: min = 0; /* fall through */ + case 5: sec = 0; /* fall through */ } tmStruct.tm_year = year - 1900; tmStruct.tm_mon = mon - 1; @@ -106,7 +112,11 @@ static std::string getInfoDate(Dict *infoDict, const char *key) return out; } +#ifdef LIBPOPPLER_UNICODEMAP_HAS_CONSTMAPUNICODE static std::string getInfoString(Dict *infoDict, const char *key, const UnicodeMap *uMap, bool & unicode) +#else +static std::string getInfoString(Dict *infoDict, const char *key, UnicodeMap *uMap, bool & unicode) +#endif { Object obj; #ifdef LIBPOPPLER_GOOSTRING_HAS_CONSTGETCHAR @@ -121,7 +131,7 @@ static std::string getInfoString(Dict *infoDict, const char *key, const UnicodeM std::string out; #ifdef LIBPOPPLER_NEW_OBJECT_API - if ((obj = infoDict->lookup((char*)key)).isString()) + if ((obj = infoDict->lookup(const_cast(key))).isString()) #else if (infoDict->lookup((char*)key, &obj)->isString()) #endif @@ -329,18 +339,32 @@ int main (int argc, char *argv[]) return 0; } +#ifdef LIBPOPPLER_PDFDOC_HAS_OPTIONAL + std::optional ownerPW, userPW; +#else GooString *ownerPW, *userPW; +#endif GooString *fileName; +#ifdef LIBPOPPLER_PDFDOC_HAS_OPTIONAL + std::unique_ptr doc; +#else PDFDoc *doc; +#endif Object info; +#ifdef LIBPOPPLER_UNICODEMAP_HAS_CONSTMAPUNICODE const UnicodeMap *uMap; +#else + UnicodeMap *uMap; +#endif +#ifndef LIBPOPPLER_PDFDOC_HAS_OPTIONAL ownerPW = NULL; userPW = NULL; -#ifdef LIBPOPPLER_GLOBALPARAMS_IS_UNIQUE_PTR - globalParams = std::make_unique(); -#else +#endif #ifdef LIBPOPPLER_GLOBALPARAMS_CSTOR_HAS_PARAM globalParams = new GlobalParams(0); +#else +#ifdef LIBPOPPLER_GLOBALPARAMS_HAS_RESET + globalParams.reset(new GlobalParams()); #else globalParams = new GlobalParams(); #endif @@ -368,7 +392,11 @@ int main (int argc, char *argv[]) #ifndef LIBPOPPLER_NEW_OBJECT_API obj.initNull(); #endif +#ifdef LIBPOPPLER_PDFDOC_HAS_OPTIONAL + doc = PDFDocFactory().createPDFDoc(*fileName, ownerPW, userPW); +#else doc = new PDFDoc(fileName, ownerPW, userPW); +#endif if (doc->isEncrypted()) { @@ -397,8 +425,13 @@ return ch; http://msdn.microsoft.com/en-us/library/078sfkak(VS.80).aspx } */ +#ifdef LIBPOPPLER_PDFDOC_HAS_OPTIONAL + ownerPW = GooString( password.c_str() ); + doc = PDFDocFactory().createPDFDoc(*fileName, ownerPW, userPW); +#else ownerPW = new GooString( password.c_str() ); doc = new PDFDoc(fileName, ownerPW, userPW); +#endif } std::string title; @@ -462,7 +495,7 @@ http://msdn.microsoft.com/en-us/library/078sfkak(VS.80).aspx char date[22]; const size_t datelen = 8; int res = gdcm::System::GetCurrentDateTime(date); - if( !res ) return false; + if( !res ) return 1; { gdcm::DataElement de( gdcm::Tag(0x0008,0x0020) ); // Do not copy the whole cstring: @@ -687,6 +720,17 @@ http://msdn.microsoft.com/en-us/library/078sfkak(VS.80).aspx at.SetValue( "application/pdf" ); ds.Insert( at.GetAsDataElement() ); } +{ +// gdcm::Attribute<0x0042, 0x0015> at; +// at.SetValue( length ); +// ds.Insert( at.GetAsDataElement() ); + gdcm::Element el; + el.SetValue( length ); + gdcm::DataElement de = el.GetAsDataElement(); + de.SetTag( gdcm::Tag(0x0042, 0x0015) ); + ds.Insert( de ); +} + writer.SetFileName( outfilename.c_str() ); diff --git a/Applications/Cxx/gdcmscanner.cxx b/Applications/Cxx/gdcmscanner.cxx index 9df9828..bf037fc 100644 --- a/Applications/Cxx/gdcmscanner.cxx +++ b/Applications/Cxx/gdcmscanner.cxx @@ -27,8 +27,8 @@ * --bench... */ -#include "gdcmScanner.h" -#include "gdcmStrictScanner.h" +#include "gdcmScanner2.h" +#include "gdcmStrictScanner2.h" #include "gdcmTrace.h" #include "gdcmVersion.h" #include "gdcmSimpleSubjectWatcher.h" @@ -84,18 +84,26 @@ static int DoIt( gdcm::Directory const & d, bool const & print , int table, VectorTags const & tags, - VectorPrivateTags const & privatetags) + VectorPrivateTags const & privatetags, bool header) { gdcm::SmartPointer ps = new TScanner; TScanner &s = *ps; //gdcm::SimpleSubjectWatcher watcher(ps, "Scanner"); for( VectorTags::const_iterator it = tags.begin(); it != tags.end(); ++it) { - s.AddTag( *it ); + if(!s.AddPublicTag( *it )) + { + std::cerr << "Failure to add public tag: " << *it << std::endl; + return 1; + } } for( VectorPrivateTags::const_iterator it = privatetags.begin(); it != privatetags.end(); ++it) { - s.AddPrivateTag( *it ); + if(!s.AddPrivateTag( *it )) + { + std::cerr << "Failure to add private tag: " << *it << std::endl; + return 1; + } } bool b = s.Scan( d.GetFilenames() ); if( !b ) @@ -106,7 +114,7 @@ static int DoIt( if (print) { if(table) - s.PrintTable( std::cout ); + s.PrintTable( std::cout, header ); else s.Print( std::cout ); } @@ -133,6 +141,7 @@ int main(int argc, char *argv[]) int strict = 0; int table = 0; + int header = 0; int verbose = 0; int warning = 0; int debug = 0; @@ -152,6 +161,7 @@ int main(int argc, char *argv[]) {"keyword", required_argument, nullptr, 'k'}, {"strict", no_argument, &strict, 1}, {"table", no_argument, &table, 1}, + {"header", no_argument, &header, 1}, // General options ! {"verbose", no_argument, nullptr, 'V'}, @@ -325,6 +335,6 @@ int main(int argc, char *argv[]) std::cout << "done retrieving file list " << nfiles << " files found." << std::endl; if( strict ) - return DoIt(d,print,table,tags,privatetags); - return DoIt(d,print,table,tags,privatetags); + return DoIt(d,print,table,tags,privatetags,header>0); + return DoIt(d,print,table,tags,privatetags,header > 0); } diff --git a/Applications/Cxx/gdcmtar.cxx b/Applications/Cxx/gdcmtar.cxx index a52fef4..a0d39ea 100644 --- a/Applications/Cxx/gdcmtar.cxx +++ b/Applications/Cxx/gdcmtar.cxx @@ -813,15 +813,15 @@ static int MakeImageEnhanced( std::string const & filename, std::string const &o namespace gdcm { -static const DataElement &GetNestedDataElement( const DataSet &ds, const Tag & t1, const Tag & t2 ) +static inline void ReplaceIf(DataSet &rootds, const DataSet &ds, const Tag & t1, const Tag & t2 ) { - assert( ds.FindDataElement( t1 ) ); + if( !ds.FindDataElement( t1 ) ) return ; SmartPointer sqi1 = ds.GetDataElement( t1 ).GetValueAsSQ(); - assert( sqi1 ); + if( !sqi1 || sqi1->IsEmpty() ) return ; const Item &item1 = sqi1->GetItem(1); const DataSet & ds1 = item1.GetNestedDataSet(); - assert( ds1.FindDataElement( t2 ) ); - return ds1.GetDataElement( t2 ); + if( !ds1.FindDataElement( t2 ) ) return ; + rootds.Replace(ds1.GetDataElement( t2 )); } static bool RemapSharedIntoOld( gdcm::DataSet & ds, @@ -837,53 +837,53 @@ static bool RemapSharedIntoOld( gdcm::DataSet & ds, const DataSet & sfgs_ds = item1.GetNestedDataSet(); #if 1 // Repetition Time - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x0080) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x0080) ); // Echo Train Length - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x0091) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x0091) ); // Flip Angle - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x1314) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x1314) ); // Number of Averages - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9119), Tag(0x0018,0x0083) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9119), Tag(0x0018,0x0083) ); // Percent Sampling - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9125), Tag(0x0018,0x0093) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9125), Tag(0x0018,0x0093) ); // Percent Phase Field of View - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9125), Tag(0x0018,0x0094) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9125), Tag(0x0018,0x0094) ); // Receive Coil Name - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9042), Tag(0x0018,0x1250) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9042), Tag(0x0018,0x1250) ); // Transmit Coil Name - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9049), Tag(0x0018,0x1251) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9049), Tag(0x0018,0x1251) ); // InPlanePhaseEncodingDirection - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9125), Tag(0x0018,0x1312) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9125), Tag(0x0018,0x1312) ); // TransmitterFrequency - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9006), Tag(0x0018,0x9098) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9006), Tag(0x0018,0x9098) ); // InversionRecovery - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9115), Tag(0x0018,0x9009) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9115), Tag(0x0018,0x9009) ); // FlowCompensation - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9115), Tag(0x0018,0x9010) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9115), Tag(0x0018,0x9010) ); // ReceiveCoilType - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9042), Tag(0x0018,0x9043) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9042), Tag(0x0018,0x9043) ); // QuadratureReceiveCoil - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9042), Tag(0x0018,0x9044) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9042), Tag(0x0018,0x9044) ); // SlabThickness - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9107), Tag(0x0018,0x9104) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9107), Tag(0x0018,0x9104) ); // MultiCoilDefinitionSequence - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9042), Tag(0x0018,0x9045) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9042), Tag(0x0018,0x9045) ); // SlabOrientation - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9107), Tag(0x0018,0x9105) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9107), Tag(0x0018,0x9105) ); // MidSlabPosition - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9107), Tag(0x0018,0x9106) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9107), Tag(0x0018,0x9106) ); // OperatingModeSequence - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x9176) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x9176) ); // MRAcquisitionPhaseEncodingStepsOutOf - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9125), Tag(0x0018,0x9232) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9125), Tag(0x0018,0x9232) ); // SpecificAbsorptionRateSequence - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x9239) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0018,0x9112), Tag(0x0018,0x9239) ); // AnatomicRegionSequence - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0020,0x9071), Tag(0x0008,0x2218) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0020,0x9071), Tag(0x0008,0x2218) ); // Purpose of Reference Code Sequence // FIXME what if there is multiple purpose of rcs ? - ds.Replace( GetNestedDataElement(sfgs_ds, Tag(0x0008,0x1140), Tag(0x0040,0xa170) ) ); + ReplaceIf(ds, sfgs_ds, Tag(0x0008,0x1140), Tag(0x0040,0xa170) ); #else for( DataSet::ConstIterator it = sfgs_ds.Begin(); @@ -898,44 +898,44 @@ static bool RemapSharedIntoOld( gdcm::DataSet & ds, #if 1 // Effective Echo Time - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0018,0x9114), Tag(0x0018,0x9082) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0018,0x9114), Tag(0x0018,0x9082) ); // -> should also be Echo Time // Nominal Cardiac Trigger Delay Time - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0018,0x9118), Tag(0x0020,0x9153) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0018,0x9118), Tag(0x0020,0x9153) ); // Metabolite Map Description - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0018,0x9152), Tag(0x0018,0x9080) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0018,0x9152), Tag(0x0018,0x9080) ); // IPP - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9113), Tag(0x0020,0x0032) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0020,0x9113), Tag(0x0020,0x0032) ); // IOP - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9116), Tag(0x0020,0x0037) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0020,0x9116), Tag(0x0020,0x0037) ); // Slice Thickness - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9110), Tag(0x0018,0x0050) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0028,0x9110), Tag(0x0018,0x0050) ); // Pixel Spacing - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9110), Tag(0x0028,0x0030) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0028,0x9110), Tag(0x0028,0x0030) ); // window level - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9132), Tag(0x0028,0x1050) ) ); - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9132), Tag(0x0028,0x1051) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0028,0x9132), Tag(0x0028,0x1050) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0028,0x9132), Tag(0x0028,0x1051) ); // rescale slope/intercept - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9145), Tag(0x0028,0x1052) ) ); - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9145), Tag(0x0028,0x1053) ) ); - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0028,0x9145), Tag(0x0028,0x1054) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0028,0x9145), Tag(0x0028,0x1052) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0028,0x9145), Tag(0x0028,0x1053) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0028,0x9145), Tag(0x0028,0x1054) ); // FrameReferenceDateTime - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9111), Tag(0x0018,0x9151) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0020,0x9111), Tag(0x0018,0x9151) ); // FrameAcquisitionDuration - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9111), Tag(0x0018,0x9220) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0020,0x9111), Tag(0x0018,0x9220) ); // TemporalPositionIndex - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9111), Tag(0x0020,0x9128) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0020,0x9111), Tag(0x0020,0x9128) ); // InStackPositionNumber - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9111), Tag(0x0020,0x9057) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0020,0x9111), Tag(0x0020,0x9057) ); // FrameType - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0018,0x9226), Tag(0x0008,0x9007) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0018,0x9226), Tag(0x0008,0x9007) ); // DimensionIndexValues - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9111), Tag(0x0020,0x9157) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0020,0x9111), Tag(0x0020,0x9157) ); // FrameAcquisitionDateTime - ds.Replace( GetNestedDataElement(pffgs_ds, Tag(0x0020,0x9111), Tag(0x0018,0x9074) ) ); + ReplaceIf(ds, pffgs_ds, Tag(0x0020,0x9111), Tag(0x0018,0x9074) ); // Nominal Cardiac Trigger Delay Time -> Trigger Time //const DataElement &NominalCardiacTriggerDelayTime = // GetNestedDataElement(pffgs_ds, Tag(0x0018,0x9226), Tag(0x0008,0x9007) ); @@ -1392,7 +1392,7 @@ int main (int argc, char *argv[]) gdcm::UIDs uid; uid.SetFromUID( ms.GetString() ); - if( uid != gdcm::UIDs::EnhancedMRImageStorage ) + if( uid != gdcm::UIDs::uid_1_2_840_10008_5_1_4_1_1_4_1 ) //NOTE: uid_1_2_840_10008_5_1_4_1_1_4_1 = 121, // Enhanced MR Image Storage { std::cerr << "MediaStorage is not handled " << ms << " [" << uid.GetName() << "]" << std::endl; return 1; @@ -1416,6 +1416,11 @@ int main (int argc, char *argv[]) const gdcm::DataElement &pixeldata = image.GetDataElement(); //const gdcm::ByteValue *bv = pixeldata.GetByteValue(); gdcm::SmartPointer bv = const_cast(pixeldata.GetByteValue()); + if( !bv ) + { + std::cerr << "decompress first" << std::endl; + return 1; + } unsigned long slice_len = image.GetBufferLength() / dims[2]; assert( slice_len * dims[2] == image.GetBufferLength() ); //assert( image.GetBufferLength() == bv->GetLength() ); @@ -1466,7 +1471,7 @@ int main (int argc, char *argv[]) char date[22]; const size_t datelen = 8; - //int res = gdcm::System::GetCurrentDateTime(date); + gdcm::System::GetCurrentDateTime(date); gdcm::Attribute<0x8,0x12> instcreationdate; instcreationdate.SetValue( gdcm::DTComp( date, datelen ) ); ds.Replace( instcreationdate.GetAsDataElement() ); @@ -1514,6 +1519,7 @@ int main (int argc, char *argv[]) // gdcm::DataElement &pd = slice.GetDataElement(); const char *sliceptr = bv->GetPointer() + i * slice_len; gdcm::DataElement newpixeldata( gdcm::Tag(0x7fe0,0x0010) ); + newpixeldata.SetVR( pixeldata.GetVR() ); newpixeldata.SetByteValue( sliceptr, (uint32_t)slice_len); // slow ! ds.Replace( newpixeldata ); diff --git a/Applications/Cxx/gdcmxml.cxx b/Applications/Cxx/gdcmxml.cxx index 3a96831..15e125b 100644 --- a/Applications/Cxx/gdcmxml.cxx +++ b/Applications/Cxx/gdcmxml.cxx @@ -355,7 +355,7 @@ static void PopulateDataSet(xmlTextReaderPtr reader,DataSet &DS, int depth, bool READ_NEXT \ char *value_char = (char*)xmlTextReaderConstValue(reader); \ int nvalue = sscanf(value_char,"%d",&(values[count++])); \ - assert( nvalue == 1 ); \ + assert( nvalue == 1 ); (void)nvalue; \ READ_NEXT /*Value ending tag*/ \ name = (const char*)xmlTextReaderConstName(reader); \ READ_NEXT \ diff --git a/Applications/Cxx/puff.c b/Applications/Cxx/puff.c index df8470c..1433785 100644 --- a/Applications/Cxx/puff.c +++ b/Applications/Cxx/puff.c @@ -43,7 +43,7 @@ * - Use pointers instead of long to specify source and * destination sizes to avoid arbitrary 4 GB limits * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!), - * but leave simple version for readabilty + * but leave simple version for readability * - Make sure invalid distances detected if pointers * are 16 bits * - Fix fixed codes table error diff --git a/CMake/ExportConfiguration/GDCMConfig.cmake.in b/CMake/ExportConfiguration/GDCMConfig.cmake.in index 3f553f6..f8e9d0b 100644 --- a/CMake/ExportConfiguration/GDCMConfig.cmake.in +++ b/CMake/ExportConfiguration/GDCMConfig.cmake.in @@ -37,9 +37,9 @@ get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) if(EXISTS ${SELF_DIR}/GDCMTargets.cmake) # This is an install tree include(${SELF_DIR}/GDCMTargets.cmake) - get_filename_component(GDCM_INCLUDE_ROOT "${SELF_DIR}/../../../@GDCM_INSTALL_INCLUDE_DIR@" ABSOLUTE) + get_filename_component(GDCM_INCLUDE_ROOT "${SELF_DIR}/../../@GDCM_INSTALL_INCLUDE_DIR@" ABSOLUTE) set(GDCM_INCLUDE_DIRS ${GDCM_INCLUDE_ROOT}) - get_filename_component(GDCM_LIB_ROOT "${SELF_DIR}/../../../@GDCM_INSTALL_LIB_DIR@" ABSOLUTE) + get_filename_component(GDCM_LIB_ROOT "${SELF_DIR}/../../@GDCM_INSTALL_LIB_DIR@" ABSOLUTE) set(GDCM_LIBRARY_DIRS ${GDCM_LIB_ROOT}) else() if(EXISTS ${SELF_DIR}/GDCMExports.cmake) diff --git a/CMake/FindJavaProperties.cmake b/CMake/FindJavaProperties.cmake index 85ceafc..f5f440d 100644 --- a/CMake/FindJavaProperties.cmake +++ b/CMake/FindJavaProperties.cmake @@ -20,7 +20,7 @@ get_filename_component(current_list_path ${CMAKE_CURRENT_LIST_FILE} PATH) find_package(Java 1.5 REQUIRED) -# need to re-run everytime the setting for Java has changed: +# need to re-run every time the setting for Java has changed: # There is technically one caveat still, when one only modify # Java_JAVA_EXECUTABLE from cmake-gui, everything is re-run properly except the # FIND_PATH for jar and javac diff --git a/CMake/FindMd5sum.cmake b/CMake/FindMd5sum.cmake index 5070930..10aaca4 100644 --- a/CMake/FindMd5sum.cmake +++ b/CMake/FindMd5sum.cmake @@ -20,7 +20,7 @@ endif () macro(COMPUTE_MD5SUMS DIRECTORY OUTPUT_FILE) # Super ugly and barely readable but you need that in order to -# work around a deficiency in EXECUTE_PROCESS which does not have dependencie scanning +# work around a deficiency in EXECUTE_PROCESS which does not have dependencies scanning file(WRITE ${CMAKE_BINARY_DIR}/md5sum.cmake " diff --git a/CMake/FindOpenSSL.cmake b/CMake/FindOpenSSL.cmake index ee71d82..f27b3b0 100644 --- a/CMake/FindOpenSSL.cmake +++ b/CMake/FindOpenSSL.cmake @@ -58,7 +58,7 @@ if(WIN32 AND NOT CYGWIN) # * MTd for static-debug # Implementation details: - # We are using the libraries located in the VC subdir instead of the parent directory eventhough : + # We are using the libraries located in the VC subdir instead of the parent directory even though : # libeay32MD.lib is identical to ../libeay32.lib, and # ssleay32MD.lib is identical to ../ssleay32.lib find_library(LIB_EAY_DEBUG NAMES libeay32MDd libeay32 diff --git a/CMake/UseCSharpTest.cmake b/CMake/UseCSharpTest.cmake index 30b59e2..9a95921 100644 --- a/CMake/UseCSharpTest.cmake +++ b/CMake/UseCSharpTest.cmake @@ -3,7 +3,7 @@ # set(ENV{PYTHONPATH} ${LIBRARY_OUTPUT_PATH}) # set(my_test "from test_mymodule import *\;test_mymodule()") # add_test(PYTHON-TEST-MYMODULE python -c ${my_test}) -# Since cmake is only transmitting the ADD_TEST line to ctest thus you are loosing +# Since cmake is only transmitting the ADD_TEST line to ctest thus you are losing # the env var. The only way to store the env var is to physically write in the cmake script # whatever PYTHONPATH you want and then add the test as 'cmake -P python_test.cmake' # diff --git a/CMake/UsePythonTest.cmake b/CMake/UsePythonTest.cmake index 78f5314..93c9def 100644 --- a/CMake/UsePythonTest.cmake +++ b/CMake/UsePythonTest.cmake @@ -3,7 +3,7 @@ # set(ENV{PYTHONPATH} ${LIBRARY_OUTPUT_PATH}) # set(my_test "from test_mymodule import *\;test_mymodule()") # add_test(PYTHON-TEST-MYMODULE python -c ${my_test}) -# Since cmake is only transmitting the ADD_TEST line to ctest thus you are loosing +# Since cmake is only transmitting the ADD_TEST line to ctest thus you are losing # the env var. The only way to store the env var is to physically write in the cmake script # whatever PYTHONPATH you want and then add the test as 'cmake -P python_test.cmake' # diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a11eb9..7ce6a24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ endif() #---------------------------------------------------------------------------- project(GDCM - VERSION 3.0.5 + VERSION 3.0.21 LANGUAGES CXX C ) ## NOTE: the "DESCRIPTION" feature of project() was introduced in cmake 3.10.0 @@ -28,6 +28,7 @@ set(GDCM_MAJOR_VERSION ${GDCM_VERSION_MAJOR}) set(GDCM_MINOR_VERSION ${GDCM_VERSION_MINOR}) set(GDCM_BUILD_VERSION ${GDCM_VERSION_PATCH}) set(GDCM_VERSION "${GDCM_VERSION_MAJOR}.${GDCM_VERSION_MINOR}.${GDCM_VERSION_PATCH}") # ${GDCM_VERSION_TWEAK} +set(GDCM_SHORT_VERSION "${GDCM_VERSION_MAJOR}.${GDCM_VERSION_MINOR}") mark_as_advanced(CMAKE_BACKWARDS_COMPATIBILITY CMAKE_BUILD_TYPE CMAKE_INSTALL_PREFIX) set(GDCM_CMAKE_DIR "${GDCM_SOURCE_DIR}/CMake" CACHE INTERNAL "") @@ -133,6 +134,12 @@ if(NOT LIBRARY_OUTPUT_PATH) mark_as_advanced(LIBRARY_OUTPUT_PATH) endif() +# TODO: The following should be used for CMake 3 and beyond, +# EXECUTABLE_OUTPUT_PATH and LIBRARY_OUTPUT_PATH are deprecated +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}) + #----------------------------------------------------------------------------- # Adding GDCM_DATA_ROOT if(GDCM_STANDALONE) @@ -180,23 +187,12 @@ macro(CHECK_INCLUDE_FILE_CONCAT FILE VARIABLE) endif() endmacro() -CHECK_INCLUDE_FILE("stdint.h" GDCM_HAVE_STDINT_H) -if(UNIX) #Avoid polluting Win32 cmakecache - CHECK_INCLUDE_FILE("inttypes.h" GDCM_HAVE_INTTYPES_H) -endif() - #include(${GDCM_SOURCE_DIR}/CMake/gdcmPlatformCxxTests.cmake) # #GDCM_PLATFORM_CXX_TEST(GDCM_CXX_HAS_FUNCTION # "Checking whether compiler has __FUNCTION__" DIRECT) -#----------------------------------------------------------------------------- -# Build the main lib... -if(NOT GDCM_HAVE_STDINT_H) - message(FATAL_ERROR "You system does not have stdint.h") -endif() - # -------------------------------------------------------------------------- # Configure the export configuration @@ -508,11 +504,14 @@ endif() #----------------------------------------------------------------------------- # Wrapping if(GDCM_STANDALONE) - option(GDCM_WRAP_PYTHON "build python wrapping" OFF) + option(GDCM_WRAP_PYTHON "build gdcm/python wrapping" OFF) + option(VTKGDCM_WRAP_PYTHON "build vtkgdcm/python wrapping" OFF) option(GDCM_WRAP_PERL "build perl wrapping (experimental !)" OFF) option(GDCM_WRAP_PHP "build php wrapping" OFF) - option(GDCM_WRAP_JAVA "build java wrapping" OFF) - option(GDCM_WRAP_CSHARP "build csharp wrapping" OFF) + option(GDCM_WRAP_JAVA "build gdcm/java wrapping" OFF) + option(VTKGDCM_WRAP_JAVA "build vtkgdcm/java wrapping" OFF) + option(GDCM_WRAP_CSHARP "build gdcm/csharp wrapping" OFF) + option(VTKGDCM_WRAP_CSHARP "build vtkgdcm/csharp wrapping" OFF) mark_as_advanced(GDCM_WRAP_PHP) mark_as_advanced(GDCM_WRAP_PERL) mark_as_advanced(GDCM_USE_ACTIVIZ) @@ -661,7 +660,96 @@ if(GDCM_STANDALONE) mark_as_advanced(VTK_DIR) set(GDCM_VTK_DIR ${VTK_DIR}) mark_as_advanced(GDCM_USE_PARAVIEW) - add_subdirectory(Utilities/VTK) + + set(VTKGDCM_NAME vtkgdcm CACHE STRING "vtk-gdcm lib name") + mark_as_advanced(VTKGDCM_NAME) + + if(VTK_VERSION VERSION_LESS 8.90) + add_subdirectory(Utilities/VTK) + else() + message(STATUS "Building Utilities/VTK as a VTK 9 Module") + # TODO: use VTKGDCM_NAME instead of vtkgdcm + + option(VTKGDCM_VERSIONED_INSTALL "Install with versioned names." ON) + mark_as_advanced(VTKGDCM_VERSIONED_INSTALL) + if(VTKGDCM_VERSIONED_INSTALL) + set(vtk_version_suffix "-${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}") + set(vtkgdcm_library_suffix "${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}") + else() + set(vtk_version_suffix "") + set(vtkgdcm_library_suffix "") + endif() + if(DEFINED GDCM_CUSTOM_LIBRARY_SUFFIX) + set(vtkgdcm_library_suffix "${GDCM_CUSTOM_LIBRARY_SUFFIX}") + endif() + + vtk_module_scan( + MODULE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/Utilities/VTK/vtkgdcm.module" + REQUEST_MODULES "GDCM::vtkgdcm" + PROVIDES_MODULES vtkgdcm_modules + ENABLE_TESTS "${GDCM_BUILD_TESTING}" + ) + + # documented at https://vtk.org/doc/nightly/html/group__module.html + vtk_module_build( + MODULES ${vtkgdcm_modules} + INSTALL_EXPORT GDCM + ARCHIVE_DESTINATION "${GDCM_INSTALL_LIB_DIR}" + HEADERS_DESTINATION "${GDCM_INSTALL_INCLUDE_DIR}/vtk${vtk_version_suffix}" + CMAKE_DESTINATION "${GDCM_INSTALL_PACKAGE_DIR}" + LICENSE_DESTINATION "${GDCM_INSTALL_DATA_DIR}/vtkgdcm-${GDCM_SHORT_VERSION}" + HIERARCHY_DESTINATION "${GDCM_INSTALL_LIB_DIR}/vtk${vtk_version_suffix}/hierarchy/vtkgdcm" + LIBRARY_NAME_SUFFIX "${vtkgdcm_library_suffix}" + VERSION "${GDCM_VERSION}" + SOVERSION "1" + # TODO: these are probably not set as they should be + #USE_EXTERNAL "${GDCM_USE_EXTERNAL}" + #TEST_DATA_TARGET vtkgdcmData + #TEST_INPUT_DATA_DIRECTORY "${vtkgdcm_test_data_directory_input}" + #TEST_OUTPUT_DATA_DIRECTORY "${vtkgdcm_test_data_directory_output}" + ) + + if(VTKGDCM_WRAP_PYTHON) + find_package(PythonInterp ${VTK_PYTHON_VERSION} QUIET) + + vtk_module_wrap_python( + MODULES ${vtkgdcm_modules} + TARGET GDCM::vtkgdcmpython + INSTALL_EXPORT vtkgdcmPython + PYTHON_PACKAGE "vtkgdcm" + CMAKE_DESTINATION "${GDCM_INSTALL_PACKAGE_DIR}" + LIBRARY_DESTINATION "${GDCM_INSTALL_LIB_DIR}" + MODULE_DESTINATION "${GDCM_VTK_INSTALL_PYTHONMODULE_DIR}" + SOABI "${Python${VTK_PYTHON_VERSION}_SOABI}" + BUILD_STATIC OFF + ) + + file(GENERATE + OUTPUT "${CMAKE_BINARY_DIR}/${GDCM_VTK_INSTALL_PYTHONMODULE_DIR}/vtkgdcm/__init__.py" + CONTENT "from .vtkgdcm import *\n\n__all__ = ['vtkgdcm']\n__version__ = \"${GDCM_VERSION}\"\n") + install( + FILES "${CMAKE_BINARY_DIR}/${GDCM_VTK_INSTALL_PYTHONMODULE_DIR}/vtkgdcm/__init__.py" + DESTINATION "${GDCM_VTK_INSTALL_PYTHONMODULE_DIR}/vtkgdcm/") + + export( + EXPORT vtkgdcmPython + NAMESPACE GDCM:: + FILE "${GDCM_INSTALL_PACKAGE_DIR}/vtkgdcmPython-targets.cmake") + install( + EXPORT vtkgdcmPython + NAMESPACE GDCM:: + FILE vtkgdcmPython-targets.cmake + DESTINATION "${GDCM_INSTALL_PACKAGE_DIR}") + endif() + + if(VTKGDCM_WRAP_JAVA) + # TODO: this is broken, incomplete, needs lots of work + vtk_module_wrap_java( + MODULES ${vtkgdcm_modules} + WRAPPED_MODULES vtkgdcm_java_wrapped_modules + JAVA_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles") + endif() + endif() endif() endif() @@ -800,7 +888,7 @@ if(GDCM_STANDALONE) # disabled for ITK distribution of gdcm set(CPACK_NUGET_PACKAGE_DESCRIPTION "Grassroots DiCoM is a C++ library for DICOM medical files. It is accessible from Python, C#, Java and PHP. It supports RAW, JPEG, JPEG 2000, JPEG-LS, RLE and deflated transfer syntax. It comes with a super fast scanner implementation to quickly scan hundreds of DICOM files. It supports SCU network operations (C-ECHO, C-FIND, C-STORE, C-MOVE). PS 3.3 & 3.6 are distributed as XML files. - It also provides PS 3.15 certificates and password based mecanism to anonymize and de-identify DICOM datasets.") + It also provides PS 3.15 certificates and password based mechanism to anonymize and de-identify DICOM datasets.") set(CPACK_NUGET_PACKAGE_LICENSEURL "http://gdcm.sourceforge.net/Copyright.html") set(CPACK_NUGET_PACKAGE_HOMEPAGE_URL "http://gdcm.sourceforge.net") set(CPACK_NUGET_PACKAGE_TAGS "dicom" "medical") @@ -816,11 +904,11 @@ if(GDCM_STANDALONE) # disabled for ITK distribution of gdcm if(GDCM_USE_VTK) foreach(comp ${components}) if( "${comp}" STREQUAL "PythonModule" ) - if(VTK_WRAP_PYTHON) + if(VTK_WRAP_PYTHON AND VTKGDCM_WRAP_PYTHON) list(APPEND components VTK${comp}) endif() elseif( "${comp}" STREQUAL "JavaModule" ) - if(VTK_WRAP_JAVA) + if(VTK_WRAP_JAVA AND VTKGDCM_WRAP_JAVA) list(APPEND components VTK${comp}) endif() else() diff --git a/Examples/Csharp/CMakeLists.txt b/Examples/Csharp/CMakeLists.txt index 54a0f53..0818c42 100644 --- a/Examples/Csharp/CMakeLists.txt +++ b/Examples/Csharp/CMakeLists.txt @@ -32,6 +32,7 @@ set(CSHARP_EXAMPLES if(BUILD_TESTING) list(APPEND CSHARP_EXAMPLES BasicAnonymizer + Cleaner ClinicalTrialIdentificationWorkflow ) endif() diff --git a/Examples/Csharp/Cleaner.cs b/Examples/Csharp/Cleaner.cs new file mode 100644 index 0000000..d78fe8b --- /dev/null +++ b/Examples/Csharp/Cleaner.cs @@ -0,0 +1,124 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/** + */ +/* + * Usage: + * $ export LD_LIBRARY_PATH=$HOME/Projects/gdcm/debug-gcc/bin + * $ mono bin/Cleaner.exe gdcmData/012345.002.050.dcm out.dcm + */ +using System; +using gdcm; + +public class MyWatcher : SimpleSubjectWatcher +{ + public MyWatcher(Subject s):base(s,"Override String"){} + protected override void StartFilter() { + System.Console.WriteLine( "This is my start" ); + } + protected override void EndFilter(){ + System.Console.WriteLine( "This is my end" ); + } + protected override void ShowProgress(Subject caller, Event evt){ + ProgressEvent pe = ProgressEvent.Cast(evt); + System.Console.WriteLine( "This is my progress: " + pe.GetProgress() ); + } + protected override void ShowIteration(){ + System.Console.WriteLine( "This is my iteration" ); + } + protected override void ShowAnonymization(Subject caller, Event evt){ +/* + * A couple of explanation are necessary here to understand how SWIG work + * http://www.swig.org/Doc1.3/Java.html#adding_downcasts + * + * System.Console.WriteLine( "This is my Anonymization. Type: " + evt.GetEventName() ); + * System.Type type = evt.GetType(); + * System.Console.WriteLine( "This is my Anonymization. System.Type: " + type.ToString() ); + * System.Console.WriteLine( "This is my Anonymization. CheckEvent: " + ae.CheckEvent( evt ) ); + * System.Console.WriteLine( "This is my Anonymization. Processing Tag #" + ae.GetTag().toString() ); + */ + AnonymizeEvent ae = AnonymizeEvent.Cast(evt); + if( ae != null ) + { + Tag t = ae.GetTag(); + System.Console.WriteLine( "This is my Anonymization. Processing Tag #" + t.toString() ); + } + else + { + System.Console.WriteLine( "This is my Anonymization. Unhandled Event type: " + evt.GetEventName() ); + } + } + protected override void ShowAbort(){ + System.Console.WriteLine( "This is my abort" ); + } +} + +public class Cleaner +{ + public static int Main(string[] args) + { + gdcm.Global global = gdcm.Global.GetInstance(); + if( !global.LoadResourcesFiles() ) + { + System.Console.WriteLine( "Could not LoadResourcesFiles" ); + return 1; + } + + string file1 = args[0]; + string file2 = args[1]; + Reader reader = new Reader(); + reader.SetFileName( file1 ); + bool ret = reader.Read(); + if( !ret ) + { + return 1; + } + + SmartPtrCleaner scleaner = gdcm.Cleaner.New(); + gdcm.Cleaner cleaner = scleaner.__ref__(); + + //SimpleSubjectWatcher watcher = new SimpleSubjectWatcher(cleaner, "Anonymizer"); + MyWatcher watcher = new MyWatcher(cleaner); + + cleaner.SetFile( reader.GetFile() ); + cleaner.Empty( new gdcm.VR(gdcm.VR.VRType.PN) ); + gdcm.DPath dpath = new gdcm.DPath(); + dpath.ConstructFromString( "/0010,0010" ); + cleaner.Preserve( dpath ); + gdcm.Tag t1 = new gdcm.Tag(0x10, 0x30); + cleaner.Empty( t1 ); + gdcm.PrivateTag pt0 = new gdcm.PrivateTag( new gdcm.Tag(0x29,0x60), "SIEMENS MEDCOM HEADER2" ); + cleaner.Remove( pt0 ); + gdcm.PrivateTag pt1 = new gdcm.PrivateTag( new gdcm.Tag(0x29,0x10), "SIEMENS CSA HEADER" ); + gdcm.PrivateTag pt2 = new gdcm.PrivateTag( new gdcm.Tag(0x29,0x20), "SIEMENS CSA HEADER" ); + cleaner.Scrub( pt1 ); + cleaner.Scrub( pt2 ); + if( !cleaner.Clean() ) + { + return 1; + } + + Writer writer = new Writer(); + writer.SetFileName( file2 ); + writer.SetFile( cleaner.GetFile() ); + ret = writer.Write(); + if( !ret ) + { + return 1; + } + + return 0; + } +} diff --git a/Examples/Cxx/CMakeLists.txt b/Examples/Cxx/CMakeLists.txt index 6fafcb3..ff40f5b 100644 --- a/Examples/Cxx/CMakeLists.txt +++ b/Examples/Cxx/CMakeLists.txt @@ -48,6 +48,7 @@ set(EXAMPLES_SRCS CreateJPIPDataSet DumpADAC DumpToshibaDTI + DumpToshibaDTI2 DumpImageHeaderInfo ReadMultiTimesException pmsct_rgb1 diff --git a/Examples/Cxx/CompressImage.cxx b/Examples/Cxx/CompressImage.cxx index 7b8c604..a5e66de 100644 --- a/Examples/Cxx/CompressImage.cxx +++ b/Examples/Cxx/CompressImage.cxx @@ -49,7 +49,9 @@ int main(int argc, char *argv[]) // the dataset is the the set of element we are interested in: //gdcm::DataSet &ds = file.GetDataSet(); - const gdcm::Image &image = reader.GetImage(); + gdcm::Image &image = reader.GetImage(); + // image.SetSpacing(0, 0.1); + // image.SetSpacing(1, 0.2); image.Print( std::cout ); gdcm::ImageChangeTransferSyntax change; diff --git a/Examples/Cxx/DumpExamCard.cxx b/Examples/Cxx/DumpExamCard.cxx index 9e33251..d6d8a5b 100644 --- a/Examples/Cxx/DumpExamCard.cxx +++ b/Examples/Cxx/DumpExamCard.cxx @@ -194,7 +194,7 @@ struct param assert( bla < sizeof(name0) ); is.read( name0, bla); size_t l = strlen(name0); - assert( l == bla ); + assert( l == bla ); (void)l; char * ptr = strdup( name0 ); v4.ptr = ptr; type = param_string; @@ -209,7 +209,7 @@ struct param assert( bla < sizeof(name0) ); is.read( name0, bla); size_t l = strlen(name0); - assert( l == bla ); + assert( l == bla ); (void)l; memcpy( this->name, name0, bla ); is.read( (char*)&bla, sizeof(bla) ); assert( bla == 0x1 ); diff --git a/Examples/Cxx/DumpToshibaDTI2.cxx b/Examples/Cxx/DumpToshibaDTI2.cxx new file mode 100644 index 0000000..d24d9ab --- /dev/null +++ b/Examples/Cxx/DumpToshibaDTI2.cxx @@ -0,0 +1,122 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * https://gazelle.ihe.net/EVSClient/dicomResult.seam;jsessionid=x+Rf9Zs+ip49P+jC3L8SLZb8?&oid=1.3.6.1.4.1.12559.11.1.2.1.4.1622284 + */ +#include "gdcmReader.h" +#include "gdcmPrivateTag.h" +#include "gdcmPrinter.h" +#include "gdcmDictPrinter.h" + +#include +#include +#include + +#include + +static bool DumpToshibaDTI2( const char * input, size_t len ) +{ + static int i = 0; + ++i; + if( len % 2 ) return false; + + std::vector copy( input, input + len ); + std::reverse( copy.begin(), copy.end() ); + +#if 0 + std::ostringstream f; + f << "debug" << i; + std::ofstream of( f.str().c_str(), std::ios::binary ); + of.write( ©[0], copy.size() ); + of.close(); +#else + + std::istringstream is; + std::string dup( ©[0], copy.size() ); + is.str( dup ); + + gdcm::File file; + gdcm::FileMetaInformation & fmi = file.GetHeader(); + fmi.SetDataSetTransferSyntax( gdcm::TransferSyntax::ExplicitVRLittleEndian ); + gdcm::DataSet & ds = file.GetDataSet(); + ds.Read( is ); + + //gdcm::DictPrinter p; + gdcm::Printer p; + p.SetFile( file ); + p.SetColor( true ); + p.Print( std::cout ); +#endif + + return true; +} + +int main(int argc, char *argv[]) +{ + if( argc < 2 ) return 1; + const char *filename = argv[1]; + gdcm::Reader reader; + reader.SetFileName( filename ); + if( !reader.Read() ) + { + std::cerr << "Failed to read: " << filename << std::endl; + return 1; + } + const gdcm::DataSet& ds = reader.GetFile().GetDataSet(); + + /* + (0029,1001) SQ (Sequence with explicit length #=6) # 18746, 1 Unknown Tag & Data + (fffe,e000) na (Item with explicit length #=2) # 206, 1 Item + (0029,0010) LO [TOSHIBA_MEC_MR3] # 16, 1 PrivateCreator + (0029,1090) OB 00\07\00\06\00\05\00\04\00\03\00\02\00\0c\00\01\00\00\00\00\00\12... # 170, 1 Unknown Tag & Data + (fffe,e00d) na (ItemDelimitationItem for re-encoding) # 0, 0 ItemDelimitationItem + (fffe,e000) na (Item with explicit length #=2) # 866, 1 Item + (0029,0010) LO [TOSHIBA_MEC_MR3] # 16, 1 PrivateCreator + (0029,1090) OB 45\4e\49\50\53\4c\20\52\41\5c\45\4e\49\50\53\4c\54\5c\52\45\53\55... # 830, 1 Unknown Tag & Data + [...] + (0029,1002) SQ (Sequence with explicit length #=1) # 120, 1 Unknown Tag & Data + (fffe,e000) na (Item with explicit length #=2) # 112, 1 Item + (0029,0010) LO [TOSHIBA_MEC_MR3] # 16, 1 PrivateCreator + (0029,1090) OB 00\10\00\02\53\55\10\80\70\0d\30\31\5e\33\52\4d\5f\43\45\4d\5f\41... # 76, 1 Unknown Tag & Data + (fffe,e00d) na (ItemDelimitationItem for re-encoding) # 0, 0 ItemDelimitationItem + */ + + const gdcm::PrivateTag tmecmr3(0x0029,0x1,"TOSHIBA_MEC_MR3"); + if( !ds.FindDataElement( tmecmr3) ) return 1; + const gdcm::DataElement& mecmr3 = ds.GetDataElement( tmecmr3 ); + if ( mecmr3.IsEmpty() ) return 1; + gdcm::SmartPointer seq = mecmr3.GetValueAsSQ(); + if ( !seq || !seq->GetNumberOfItems() ) return 1; + + size_t n = seq->GetNumberOfItems(); + for( size_t i = 1; i <= n; ++i ) + { + gdcm::Item &item = seq->GetItem(i); + gdcm::DataSet &subds = item.GetNestedDataSet(); + const gdcm::PrivateTag tseq(0x0029,0x90,"TOSHIBA_MEC_MR3"); + + if( subds.FindDataElement( tseq ) ) + { + const gdcm::DataElement & de = subds.GetDataElement( tseq ); + const gdcm::ByteValue * bv = de.GetByteValue(); + if( !bv ) return 1; + + bool b = DumpToshibaDTI2( bv->GetPointer(), bv->GetLength() ); + if( !b ) return 1; + } + + } + + return 0; +} diff --git a/Examples/Cxx/ReadMultiTimesException.cxx b/Examples/Cxx/ReadMultiTimesException.cxx index 87fb0d7..866879a 100644 --- a/Examples/Cxx/ReadMultiTimesException.cxx +++ b/Examples/Cxx/ReadMultiTimesException.cxx @@ -43,8 +43,9 @@ int main(int argc, char* argv[]) char *buffer = new char[ len ]; img.GetBuffer( buffer ); // do NOT de-allocate buffer ! } - catch (std::bad_alloc) + catch (std::bad_alloc &ba) { + (void)ba; std::cerr << "BAD ALLOC Exception caught!" << std::endl; } catch (...) diff --git a/Examples/Java/CMakeLists.txt b/Examples/Java/CMakeLists.txt index 1acd963..337e53e 100644 --- a/Examples/Java/CMakeLists.txt +++ b/Examples/Java/CMakeLists.txt @@ -15,6 +15,7 @@ set(examples DecompressImage ScanDirectory ReadFiles + SimplePrint FileAnonymize ) foreach(example ${examples}) diff --git a/Examples/Java/SimplePrint.java b/Examples/Java/SimplePrint.java new file mode 100644 index 0000000..e32e9b9 --- /dev/null +++ b/Examples/Java/SimplePrint.java @@ -0,0 +1,72 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/* + * Compilation: + * $ CLASSPATH=gdcm.jar javac ../../gdcm/Examples/Java/SimplePrint.java -d . + * + * Usage: + * $ LD_LIBRARY_PATH=. CLASSPATH=gdcm.jar:. java SimplePrint gdcmData/012345.002.050.dcm + */ +import gdcm.*; + +public class SimplePrint +{ + public static void RecurseDataSet(File f, DataSet ds, String indent) + { + JavaDataSet cds = new JavaDataSet(ds); + while(!cds.IsAtEnd()) + { + DataElement de = cds.GetCurrent(); + // Compute VR from the toplevel file, and the currently processed dataset: + VR vr = DataSetHelper.ComputeVR(f, ds, de.GetTag() ); + + if( vr.Compatible( new VR(VR.VRType.SQ) ) ) + { + long uvl = de.GetVL().GetValueLength(); // Test cast is ok + System.out.println( indent + de.GetTag().toString() + ":" + uvl ); // why not ? + //SequenceOfItems sq = de.GetSequenceOfItems(); + // GetValueAsSQ handle more cases than GetSequenceOfItems + SmartPtrSQ sq = de.GetValueAsSQ(); + long n = sq.GetNumberOfItems(); + for( long i = 1; i <= n; i++) // item starts at 1, not 0 + { + Item item = sq.GetItem( i ); + DataSet nested = item.GetNestedDataSet(); + RecurseDataSet( f, nested, indent + " " ); + } + } + else + { + System.out.println( indent + de.toString() ); + } + cds.Next(); + } + } + + public static void main(String[] args) throws Exception + { + String filename = args[0]; + Reader reader = new Reader(); + reader.SetFileName( filename ); + boolean ret = reader.Read(); + if( !ret ) + { + throw new Exception("Could not read: " + filename ); + } + File f = reader.GetFile(); + DataSet ds = f.GetDataSet(); + + RecurseDataSet( f, ds, "" ); + } +} diff --git a/Source/Common/CMakeLists.txt b/Source/Common/CMakeLists.txt index 484e3c4..5a33bbf 100644 --- a/Source/Common/CMakeLists.txt +++ b/Source/Common/CMakeLists.txt @@ -8,6 +8,7 @@ option(GDCM_SUPPORT_BROKEN_IMPLEMENTATION "Handle broken DICOM" ON) mark_as_advanced( GDCM_ALWAYS_TRACE_MACRO GDCM_SUPPORT_BROKEN_IMPLEMENTATION + GDCM_AUTOLOAD_GDCMJNI ) #if(WIN32) @@ -63,6 +64,9 @@ CHECK_CXX_SOURCE_COMPILES( CHECK_CXX_SOURCE_COMPILES( "\#include \nint main() { const wchar_t fn[10] = {}; std::ifstream is( fn ); return 0;}" GDCM_HAVE_WCHAR_IFSTREAM) +CHECK_CXX_SOURCE_COMPILES( + "\#include \n#include \n#include \nint main() { std::u16string u16; std::string utf8 = std::wstring_convert, char16_t>{}.to_bytes(u16); }" + GDCM_HAVE_CODECVT) if(GDCM_USE_SYSTEM_OPENSSL) set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES} @@ -73,6 +77,9 @@ CHECK_CXX_SOURCE_COMPILES( #HAVE_CMS_RECIPIENT_KEY) "\#include \nint main() { CMS_add0_recipient_password(0,0,0,0,0,0,0); return 0;}" GDCM_HAVE_CMS_RECIPIENT_PASSWORD) +CHECK_CXX_SOURCE_COMPILES( + "\#include \nint main() { const void*mem; int len; BIO_new_mem_buf(mem, len); }" + OPENSSL_HAS_CONST_VOID_BIO_NEW_MEM_BUF) endif() #----------------------------------------------------------------------------- @@ -163,6 +170,11 @@ set(Common_SRCS ${Common_SRCS} gdcmOpenSSLP7CryptoFactory.cxx gdcmOpenSSLP7CryptographicMessageSyntax.cxx ) +if(OPENSSL_HAS_CONST_VOID_BIO_NEW_MEM_BUF) +set_source_files_properties( + gdcmOpenSSLP7CryptographicMessageSyntax.cxx + PROPERTIES COMPILE_FLAGS "-DOPENSSL_HAS_CONST_VOID_BIO_NEW_MEM_BUF") +endif() endif() if(GDCM_USE_SYSTEM_OPENSSL AND GDCM_HAVE_CMS_RECIPIENT_PASSWORD) @@ -170,6 +182,11 @@ set(Common_SRCS ${Common_SRCS} gdcmOpenSSLCryptoFactory.cxx gdcmOpenSSLCryptographicMessageSyntax.cxx ) +if(OPENSSL_HAS_CONST_VOID_BIO_NEW_MEM_BUF) +set_source_files_properties( + gdcmOpenSSLCryptographicMessageSyntax.cxx + PROPERTIES COMPILE_FLAGS "-DOPENSSL_HAS_CONST_VOID_BIO_NEW_MEM_BUF") +endif() endif() if(GDCM_BUILD_TESTING) diff --git a/Source/Common/gdcmBase64.cxx b/Source/Common/gdcmBase64.cxx index 228813f..fbe2290 100644 --- a/Source/Common/gdcmBase64.cxx +++ b/Source/Common/gdcmBase64.cxx @@ -59,7 +59,6 @@ static std::string base64_encode(unsigned char const* bytes_to_encode, size_t in { std::string ret; size_t i = 0; - size_t j = 0; unsigned char char_array_3[3]; unsigned char char_array_4[4]; @@ -79,7 +78,7 @@ static std::string base64_encode(unsigned char const* bytes_to_encode, size_t in if (i) { - for(j = i; j < 3; j++) + for(size_t j = i; j < 3; j++) char_array_3[j] = '\0'; char_array_4[0] = (unsigned char)((char_array_3[0] & 0xfc) >> 2); @@ -87,7 +86,7 @@ static std::string base64_encode(unsigned char const* bytes_to_encode, size_t in char_array_4[2] = (unsigned char)(((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6)); char_array_4[3] = (unsigned char)(char_array_3[2] & 0x3f); - for (j = 0; j < i + 1; j++) + for (size_t j = 0; j < i + 1; j++) ret += base64_chars[char_array_4[j]]; while((i++ < 3)) @@ -102,7 +101,6 @@ static std::string base64_decode(std::string const& encoded_string) { size_t in_len = encoded_string.size(); size_t i = 0; - size_t j = 0; size_t in_ = 0; unsigned char char_array_4[4], char_array_3[3]; std::string ret; @@ -124,17 +122,18 @@ static std::string base64_decode(std::string const& encoded_string) } if (i) { - for (j = i; j <4; j++) + for (size_t j = i; j <4; j++) char_array_4[j] = 0; - for (j = 0; j <4; j++) + for (size_t j = 0; j <4; j++) char_array_4[j] = (unsigned char)base64_chars.find(char_array_4[j]); char_array_3[0] = (unsigned char)((char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4)); char_array_3[1] = (unsigned char)(((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2)); char_array_3[2] = (unsigned char)(((char_array_4[2] & 0x3) << 6) + char_array_4[3]); - for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + for (size_t j = 0; (j < i - 1); j++) + ret += char_array_3[j]; } return ret; diff --git a/Source/Common/gdcmByteSwap.h b/Source/Common/gdcmByteSwap.h index 3b6b34f..fdf4d29 100644 --- a/Source/Common/gdcmByteSwap.h +++ b/Source/Common/gdcmByteSwap.h @@ -22,7 +22,7 @@ namespace gdcm /** * \brief ByteSwap - * \details Perform machine dependent byte swaping (Little Endian, + * \details Perform machine dependent byte swapping (Little Endian, * Big Endian, Bad Little Endian, Bad Big Endian). * TODO: bswap_32 / bswap_64 ... */ diff --git a/Source/Common/gdcmByteSwap.txx b/Source/Common/gdcmByteSwap.txx index b9f1a19..a45fef1 100644 --- a/Source/Common/gdcmByteSwap.txx +++ b/Source/Common/gdcmByteSwap.txx @@ -105,10 +105,10 @@ template void Swap4(T &a, SwapCode const &swapcode) { #ifndef GDCM_WORDS_BIGENDIAN - if ( swapcode == 4321 || swapcode == 2143 ) - a = (T)(( a << 8 ) | ( a >> 8 )); + if ( swapcode == gdcm::SwapCode::BigEndian || swapcode == gdcm::SwapCode::BadBigEndian ) + a = ( a << 8 ) | ( a >> 8 ); #else - if ( swapcode == 1234 || swapcode == 3412 ) + if ( swapcode == gdcm::SwapCode::LittleEndian || swapcode == gdcm::SwapCode::BadLittleEndian ) a = ( a << 8 ) | ( a >> 8 ); // On big endian as long as the SwapCode is Unknown let's pretend we were // on a LittleEndian system (might introduce overhead on those system). @@ -129,20 +129,20 @@ inline void Swap8(T &a, SwapCode const &swapcode) a= (( a<<24) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) ); #endif break; - case 1234 : + case gdcm::SwapCode::LittleEndian : #ifdef GDCM_WORDS_BIGENDIAN a= (( a<<24) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) ); #endif break; - case 4321 : + case gdcm::SwapCode::BigEndian : #ifndef GDCM_WORDS_BIGENDIAN a= (( a<<24) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) ); #endif break; - case 3412 : + case gdcm::SwapCode::BadLittleEndian : a= ((a<<16) | (a>>16) ); break; - case 2143 : + case gdcm::SwapCode::BadBigEndian : a= (((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) ); break; default : @@ -160,21 +160,21 @@ inline void Swap8(uint16_t &a, SwapCode const &swapcode) a= (( a<<24) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) ); #endif break; - case 1234 : + case gdcm::SwapCode::LittleEndian : #ifdef GDCM_WORDS_BIGENDIAN a= (( a<<24) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) ); #endif break; - case 4321 : + case gdcm::SwapCode::BigEndian : #ifndef GDCM_WORDS_BIGENDIAN // probably not really useful since the lowest 0x0000 are what's used in unsigned shorts // a= (( a<<24) | ((a<<8) & 0x00ff0000) | ((a>>8) & 0x0000ff00) | (a>>24) ); #endif break; - case 3412 : + case gdcm::SwapCode::BadLittleEndian : //a= ((a<<16) | (a>>16) );//do nothing, a = a break; - case 2143 : + case gdcm::SwapCode::BadBigEndian : a= (uint16_t)(((a<< 8) & 0xff00) | ((a>>8) & 0x00ff) ); break; default : diff --git a/Source/Common/gdcmConfigure.h.in b/Source/Common/gdcmConfigure.h.in index 716f5bd..4a5d68f 100644 --- a/Source/Common/gdcmConfigure.h.in +++ b/Source/Common/gdcmConfigure.h.in @@ -32,13 +32,10 @@ # define GDCM_WORDS_BIGENDIAN #endif -/* Allow access to UINT32_MAX , cf gdcmCommon.h */ -#define __STDC_LIMIT_MACROS - /* Hard code the path to the public dictionary */ #define PUB_DICT_PATH "@GDCM_PUB_DICT_PATH@" -/* Usefull in particular for loadshared where the full path +/* Useful in particular for loadshared where the full path * to the lib is needed */ #define GDCM_SOURCE_DIR "@GDCM_SOURCE_DIR@" #define GDCM_EXECUTABLE_OUTPUT_PATH "@EXECUTABLE_OUTPUT_PATH@" @@ -78,10 +75,6 @@ #cmakedefine GDCM_AUTOLOAD_GDCMJNI -/* I guess something important */ -#cmakedefine GDCM_HAVE_STDINT_H -#cmakedefine GDCM_HAVE_INTTYPES_H - /* This variable allows you to have helpful debug statement */ /* That are in between #ifdef / endif in the gdcm code */ /* That means if GDCM_DEBUG is OFF there shouldn't be any 'cout' at all ! */ @@ -124,6 +117,10 @@ // UTF-8 #cmakedefine GDCM_HAVE_WCHAR_IFSTREAM +// https://stackoverflow.com/questions/15615136/is-codecvt-not-a-std-header +// https://stackoverflow.com/questions/50867257/c-use-of-wstring-convert-on-linux +#cmakedefine GDCM_HAVE_CODECVT + #cmakedefine GDCM_FORCE_BIGENDIAN_EMULATION #ifndef GDCM_OVERRIDE_BROKEN_IMPLEMENTATION diff --git a/Source/Common/gdcmCryptoFactory.h b/Source/Common/gdcmCryptoFactory.h index 7362b20..cd454da 100644 --- a/Source/Common/gdcmCryptoFactory.h +++ b/Source/Common/gdcmCryptoFactory.h @@ -22,7 +22,7 @@ namespace gdcm /** * \brief Class to do handle the crypto factory - * \details GDCM needs to access in a platform independant way + * \details GDCM needs to access in a platform independent way * the user specified crypto engine. It can be: * \li CAPI (windows only) * \li OPENSSL (portable) diff --git a/Source/Common/gdcmDirectory.cxx b/Source/Common/gdcmDirectory.cxx index 045cf2a..171dfbe 100644 --- a/Source/Common/gdcmDirectory.cxx +++ b/Source/Common/gdcmDirectory.cxx @@ -43,39 +43,54 @@ unsigned int Directory::Load(FilenameType const &name, bool recursive) return 0; } +#ifdef _MSC_VER +static inline std::string ToUtf8(std::wstring const &str) { + std::string ret; + int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int)str.length(), + nullptr, 0, NULL, NULL); + if (len > 0) { + ret.resize(len); + WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int)str.length(), &ret[0], + len, NULL, NULL); + } + return ret; +} +#endif + unsigned int Directory::Explore(FilenameType const &name, bool recursive) { unsigned int nFiles = 0; - std::string fileName; - std::string dirName = name; - //assert( System::FileIsDirectory( dirName ) ); - Directories.push_back( dirName ); #ifdef _MSC_VER - WIN32_FIND_DATA fileData; - if ('/' != dirName[dirName.size()-1]) dirName.push_back('/'); + std::wstring fileName; + std::wstring dirName = System::ConvertToUNC(name.c_str()); + Directories.push_back(ToUtf8(dirName)); + WIN32_FIND_DATAW fileData; + if ('\\' == dirName[dirName.size() - 1]) + dirName = dirName.substr(0, dirName.size() - 1); + if ('/' != dirName[dirName.size() - 1]) dirName.push_back('/'); assert( '/' == dirName[dirName.size()-1] ); - const FilenameType firstfile = dirName+"*"; - HANDLE hFile = FindFirstFile(firstfile.c_str(), &fileData); + const std::wstring firstfile = dirName+L"*"; + HANDLE hFile = FindFirstFileW(firstfile.c_str(), &fileData); for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b; - b = FindNextFile(hFile, &fileData)) + b = FindNextFileW(hFile, &fileData)) { fileName = fileData.cFileName; if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { // Need to check for . and .. to avoid infinite loop - if ( fileName != "." && fileName != ".." + if ( fileName != L"." && fileName != L".." && fileName[0] != '.' // discard any hidden dir && recursive ) { - nFiles += Explore(dirName+fileName,recursive); + nFiles += Explore(ToUtf8(dirName + fileName), recursive); } } else { if (fileName[0] != '.') // discard "unix like" hidden files such as .git in submodules { - Filenames.push_back(dirName+fileName); + Filenames.push_back(ToUtf8(dirName+fileName)); nFiles++; } } @@ -89,6 +104,10 @@ unsigned int Directory::Explore(FilenameType const &name, bool recursive) } #else + std::string fileName; + std::string dirName = name; + // assert( System::FileIsDirectory( dirName ) ); + Directories.push_back(dirName); // Real POSIX implementation: scandir is a BSD extension only, and doesn't // work on debian for example @@ -101,7 +120,7 @@ unsigned int Directory::Explore(FilenameType const &name, bool recursive) } // According to POSIX, the dirent structure contains a field char d_name[] - // of unspecified size, with at most NAME_MAX characters preceeding the + // of unspecified size, with at most NAME_MAX characters preceding the // terminating null character. Use of other fields will harm the porta- // bility of your programs. diff --git a/Source/Common/gdcmDirectory.h b/Source/Common/gdcmDirectory.h index 6b261a8..dd59e26 100644 --- a/Source/Common/gdcmDirectory.h +++ b/Source/Common/gdcmDirectory.h @@ -27,7 +27,7 @@ namespace gdcm * \brief Class for manipulation directories * * \note This implementation provide a cross platform implementation - * for manipulating directores: basically traversing directories + * for manipulating directories: basically traversing directories * and harvesting files * * \note diff --git a/Source/Common/gdcmEvent.h b/Source/Common/gdcmEvent.h index ae3ef93..9de2455 100644 --- a/Source/Common/gdcmEvent.h +++ b/Source/Common/gdcmEvent.h @@ -41,7 +41,7 @@ public : virtual void Print(std::ostream& os) const; /** Return the StringName associated with the event. */ - virtual const char * GetEventName(void) const = 0; + virtual const char * GetEventName() const = 0; /** Check if given event matches or derives from this event. */ virtual bool CheckEvent(const Event*) const = 0; @@ -65,11 +65,11 @@ inline std::ostream& operator<<(std::ostream& os, Event &e) typedef classname Self; \ typedef super Superclass; \ classname() {} \ - virtual ~classname() {} \ - virtual const char * GetEventName() const { return #classname; } \ - virtual bool CheckEvent(const ::gdcm::Event* e) const \ + virtual ~classname() override = default; \ + virtual const char * GetEventName() const override { return #classname; } \ + virtual bool CheckEvent(const ::gdcm::Event* e) const override \ { return dynamic_cast(e) ? true : false; } \ - virtual ::gdcm::Event* MakeObject() const \ + virtual ::gdcm::Event* MakeObject() const override \ { return new Self; } \ classname(const Self&s) : super(s){}; \ private: \ diff --git a/Source/Common/gdcmException.h b/Source/Common/gdcmException.h index ef5b0f7..da87572 100644 --- a/Source/Common/gdcmException.h +++ b/Source/Common/gdcmException.h @@ -54,9 +54,9 @@ class Exception : public std::exception const unsigned int lineNumber, const char* const func) { - assert(desc != NULL); - assert(file != NULL); - assert(func != NULL); + assert(desc != nullptr); + assert(file != nullptr); + assert(func != nullptr); std::ostringstream oswhat; oswhat << file << ":" << lineNumber << " (" << func << "):\n"; oswhat << desc; diff --git a/Source/Common/gdcmFilename.h b/Source/Common/gdcmFilename.h index f90a067..c9ab1bd 100644 --- a/Source/Common/gdcmFilename.h +++ b/Source/Common/gdcmFilename.h @@ -22,7 +22,7 @@ namespace gdcm { /** * \brief Class to manipulate file name's - * \note OS independant representation of a filename (to query path, name and extension from a filename) + * \note OS independent representation of a filename (to query path, name and extension from a filename) */ class GDCM_EXPORT Filename { @@ -55,9 +55,9 @@ public: operator const char * () const { return GetFileName(); } // FIXME: I don't like this function - // It hides the realpath call (maybe usefull) + // It hides the realpath call (maybe useful) // and it forces file to exist on the disk whereas Filename - // should be independant from file existence. + // should be independent from file existence. bool IsIdentical(Filename const &fn) const; /// Does the filename ends with a particular string ? diff --git a/Source/Common/gdcmFilenameGenerator.cxx b/Source/Common/gdcmFilenameGenerator.cxx index b29b544..d3b40f1 100644 --- a/Source/Common/gdcmFilenameGenerator.cxx +++ b/Source/Common/gdcmFilenameGenerator.cxx @@ -84,7 +84,7 @@ bool FilenameGenerator::Generate() if ( num_percent != 1 ) { // Bug: what if someone wants to output file such as %%%02 ... oh well - gdcmDebugMacro( "No more than one % in string formating please" ); + gdcmDebugMacro( "No more than one % in string formatting please" ); return false; } bool success = true; diff --git a/Source/Common/gdcmLegacyMacro.h b/Source/Common/gdcmLegacyMacro.h index 5a8d323..65cde3a 100644 --- a/Source/Common/gdcmLegacyMacro.h +++ b/Source/Common/gdcmLegacyMacro.h @@ -45,6 +45,17 @@ # endif #endif +/** The `static_assert(true, "")` idiom is commonly employed for + * C++11 or greater to ensure that it is compile-time only + * check that can not be part of the binary file. + * This allows a macro to be used anywhere that a statement + * is expected, and to enforce consistent use of ; after + * a macro. The static_assert is a constexpr that can be used + * in places where raw statements (i.e. 'do{} while(0)') are + * not allowed (i.e. after class member function definitions). + * */ +# define GDCM_NOOP_STATEMENT static_assert(true, "") + // Macros to create runtime deprecation warning messages in function // bodies. Example usage: // diff --git a/Source/Common/gdcmMD5.cxx b/Source/Common/gdcmMD5.cxx index 7b3bf03..93acd64 100644 --- a/Source/Common/gdcmMD5.cxx +++ b/Source/Common/gdcmMD5.cxx @@ -21,6 +21,10 @@ #endif #include #include +#include +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf +#endif // http://stackoverflow.com/questions/13256446/compute-md5-hash-value-by-c-winapi namespace gdcm @@ -39,17 +43,17 @@ bool MD5::Compute(const char *buffer, size_t buf_len, char digest_str[33]) MD5_Update(&ctx, buffer, buf_len); MD5_Final(digest, &ctx); for (int di = 0; di < 16; ++di) - sprintf(digest_str+2*di, "%02x", digest[di]); + snprintf(digest_str+2*di, 3, "%02x", digest[di]); digest_str[2*16] = '\0'; return true; #elif defined(GDCM_BUILD_TESTING) md5_byte_t digest[16]; md5_state_t state; md5_init(&state); - md5_append(&state, (const md5_byte_t *)buffer, (int)buf_len); + md5_append(&state, (const md5_byte_t *)buffer, buf_len); md5_finish(&state, digest); for (int di = 0; di < 16; ++di) - sprintf(digest_str+2*di, "%02x", digest[di]); + snprintf(digest_str+2*di, 3, "%02x", digest[di]); digest_str[2*16] = '\0'; return true; #else @@ -95,7 +99,7 @@ static bool process_file(const char *filename, md5_byte_t *digest) md5_state_t state; md5_init(&state); - md5_append(&state, (const md5_byte_t *)buffer, (int)file_size); + md5_append(&state, (const md5_byte_t *)buffer, file_size); md5_finish(&state, digest); return true; @@ -124,7 +128,7 @@ bool MD5::ComputeFile(const char *filename, char digest_str[33]) for (int di = 0; di < 16; ++di) { - sprintf(digest_str+2*di, "%02x", digest[di]); + snprintf(digest_str+2*di, 3, "%02x", digest[di]); } digest_str[2*16] = '\0'; return true; diff --git a/Source/Common/gdcmObject.cxx b/Source/Common/gdcmObject.cxx index ed1e798..9338321 100644 --- a/Source/Common/gdcmObject.cxx +++ b/Source/Common/gdcmObject.cxx @@ -17,7 +17,7 @@ namespace gdcm { // Don't ask why, but this is EXTREMELY important on Win32 // Apparently the compiler is doing something special the first time it compiles - // this instanciation unit + // this instantiation unit // If this fake file is not present I get an unresolved symbol for each function // of the gdcm::Object class diff --git a/Source/Common/gdcmOpenSSLCryptographicMessageSyntax.cxx b/Source/Common/gdcmOpenSSLCryptographicMessageSyntax.cxx index 54c3a03..ffc9a9a 100644 --- a/Source/Common/gdcmOpenSSLCryptographicMessageSyntax.cxx +++ b/Source/Common/gdcmOpenSSLCryptographicMessageSyntax.cxx @@ -97,7 +97,11 @@ bool OpenSSLCryptographicMessageSyntax::Encrypt(char *output, size_t &outlen, co goto err; } +#ifdef OPENSSL_HAS_CONST_VOID_BIO_NEW_MEM_BUF in = BIO_new_mem_buf((const void*)array, (int)len); +#else + in = BIO_new_mem_buf((void*)array, (int)len); +#endif if(!in) { gdcmErrorMacro( "Error at creating the input memory buffer." ); @@ -115,7 +119,7 @@ bool OpenSSLCryptographicMessageSyntax::Encrypt(char *output, size_t &outlen, co cms = CMS_encrypt(recips, in, internalCipherType, flags); if (!cms) { - gdcmErrorMacro( "Error at creating the CMS strucutre." ); + gdcmErrorMacro( "Error at creating the CMS structure." ); goto err; } @@ -183,7 +187,11 @@ bool OpenSSLCryptographicMessageSyntax::Decrypt(char *output, size_t &outlen, co goto err; } +#ifdef OPENSSL_HAS_CONST_VOID_BIO_NEW_MEM_BUF in = BIO_new_mem_buf((const void*)array, (int)len); +#else + in = BIO_new_mem_buf((void*)array, (int)len); +#endif if (!in) { gdcmErrorMacro( "Error at creating the input memory buffer." ); diff --git a/Source/Common/gdcmOpenSSLP7CryptographicMessageSyntax.cxx b/Source/Common/gdcmOpenSSLP7CryptographicMessageSyntax.cxx index 640dadd..8e44d50 100644 --- a/Source/Common/gdcmOpenSSLP7CryptographicMessageSyntax.cxx +++ b/Source/Common/gdcmOpenSSLP7CryptographicMessageSyntax.cxx @@ -153,7 +153,11 @@ public: gdcmErrorMacro( "len is too big: " << len ); return false; } +#ifdef OPENSSL_HAS_CONST_VOID_BIO_NEW_MEM_BUF BIO *data = BIO_new_mem_buf((const void*)array, (int)len); +#else + BIO *data = BIO_new_mem_buf((void*)array, (int)len); +#endif if(!data) { gdcmErrorMacro( "BIO_new_mem_buf" ); @@ -308,7 +312,11 @@ bool OpenSSLP7CryptographicMessageSyntax::Decrypt(char *output, size_t &outlen, gdcmErrorMacro( "len is too big: " << len ); return false; } +#ifdef OPENSSL_HAS_CONST_VOID_BIO_NEW_MEM_BUF data = BIO_new_mem_buf((const void*)array, (int)len); +#else + data = BIO_new_mem_buf((void*)array, (int)len); +#endif if(!data) goto err; diff --git a/Source/Common/gdcmRegion.h b/Source/Common/gdcmRegion.h index 557d165..0aceab7 100644 --- a/Source/Common/gdcmRegion.h +++ b/Source/Common/gdcmRegion.h @@ -43,7 +43,7 @@ public : /// compute the area virtual size_t Area() const = 0; - // implementation detail of heterogenous container in C++ + // implementation detail of heterogeneous container in C++ virtual Region *Clone() const = 0; /// Return the Axis-Aligned minimum bounding box for all regions diff --git a/Source/Common/gdcmSHA1.cxx b/Source/Common/gdcmSHA1.cxx index f70d926..69acb5b 100644 --- a/Source/Common/gdcmSHA1.cxx +++ b/Source/Common/gdcmSHA1.cxx @@ -20,7 +20,7 @@ #include // memcmp #include // malloc -#include // sprintf +#include // snprintf /* */ @@ -62,7 +62,7 @@ bool SHA1::Compute(const char *buffer, unsigned long buf_len, char digest[]) for (int di = 0; di < 20; ++di) { - sprintf(digest+2*di, "%02x", output[di]); + snprintf(digest+2*di, 3, "%02x", output[di]); } digest[2*20] = '\0'; @@ -131,7 +131,7 @@ bool SHA1::ComputeFile(const char *filename, char digest_str[20*2+1]) for (int di = 0; di < 20; ++di) { - sprintf(digest_str+2*di, "%02x", digest[di]); + snprintf(digest_str+2*di, 3, "%02x", digest[di]); } digest_str[2*20] = '\0'; return true; diff --git a/Source/Common/gdcmString.h b/Source/Common/gdcmString.h index b456df9..64ab475 100644 --- a/Source/Common/gdcmString.h +++ b/Source/Common/gdcmString.h @@ -24,7 +24,7 @@ namespace gdcm * \brief String * * \note TDelimiter template parameter is used to separate multiple String (VM1 >) - * TMaxLength is only a hint. Noone actually respect the max length + * TMaxLength is only a hint. No one actually respect the max length * TPadChar is the string padding (0 or space) */ template @@ -57,7 +57,7 @@ public: } String(const value_type* s, size_type n): std::string(s, n) { - // We are being passed a const char* pointer, so s[n] == 0 (garanteed!) + // We are being passed a const char* pointer, so s[n] == 0 (guaranteed!) if( n % 2 ) { push_back( TPadChar ); diff --git a/Source/Common/gdcmSubject.h b/Source/Common/gdcmSubject.h index 7cbf5de..faf49bd 100644 --- a/Source/Common/gdcmSubject.h +++ b/Source/Common/gdcmSubject.h @@ -43,7 +43,7 @@ public: unsigned long AddObserver(const Event & event, Command *) const; /** Get the command associated with the given tag. NOTE: This returns - * a pointer to a Command, but it is safe to asign this to a + * a pointer to a Command, but it is safe to assign this to a * Command::Pointer. Since Command inherits from LightObject, at this * point in the code, only a pointer or a reference to the Command can * be used. */ diff --git a/Source/Common/gdcmSwapper.h b/Source/Common/gdcmSwapper.h index 1f1f95b..0ee2ae4 100644 --- a/Source/Common/gdcmSwapper.h +++ b/Source/Common/gdcmSwapper.h @@ -25,7 +25,7 @@ class SwapperDoOp { public: template static T Swap(T val) {return val;} - template static void SwapArray(T *, unsigned int ) {} + template static void SwapArray(T *, size_t ) {} }; class SwapperNoOp @@ -33,10 +33,10 @@ class SwapperNoOp public: template static T Swap(T val); template - static void SwapArray(T *array, unsigned int n) + static void SwapArray(T *array, size_t n) { // TODO: need to unroll loop: - for(unsigned int i = 0; i < n; ++i) + for(size_t i = 0; i < n; ++i) { array[i] = Swap(array[i]); } diff --git a/Source/Common/gdcmSwapper.txx b/Source/Common/gdcmSwapper.txx index 88e530a..d63ccd5 100644 --- a/Source/Common/gdcmSwapper.txx +++ b/Source/Common/gdcmSwapper.txx @@ -14,6 +14,8 @@ #ifndef GDCMSWAPPER_TXX #define GDCMSWAPPER_TXX +#include + #if defined(_MSC_VER) // http://msdn.microsoft.com/en-us/library/a3140177 @@ -106,7 +108,12 @@ namespace gdcm } template <> inline float SwapperNoOp::Swap(float val) { - return Swap((uint32_t)val); + uint32_t tempI; + memcpy(&tempI, &val, sizeof(uint32_t)); + tempI = Swap(tempI); + float tempF; + memcpy(&tempF, &tempI, sizeof(uint32_t)); + return tempF; } template <> inline uint64_t SwapperNoOp::Swap(uint64_t val) { @@ -118,7 +125,12 @@ namespace gdcm } template <> inline double SwapperNoOp::Swap(double val) { - return Swap((uint64_t)val); + uint64_t tempI; + memcpy(&tempI, &val, sizeof(uint64_t)); + tempI = Swap(tempI); + double tempF; + memcpy(&tempF, &tempI, sizeof(uint64_t)); + return tempF; } template <> inline Tag SwapperNoOp::Swap(Tag val) @@ -126,9 +138,9 @@ namespace gdcm return Tag( Swap(val.GetGroup()), Swap(val.GetElement()) ); } - template <> inline void SwapperNoOp::SwapArray(uint8_t *, unsigned int ) {} + template <> inline void SwapperNoOp::SwapArray(uint8_t *, size_t ) {} - template <> inline void SwapperNoOp::SwapArray(float *array, unsigned int n) + template <> inline void SwapperNoOp::SwapArray(float *array, size_t n) { switch( sizeof(float) ) { @@ -140,7 +152,7 @@ namespace gdcm } } - template <> inline void SwapperNoOp::SwapArray(double *array, unsigned int n) + template <> inline void SwapperNoOp::SwapArray(double *array, size_t n) { switch( sizeof(double) ) { @@ -172,7 +184,12 @@ namespace gdcm } template <> inline float SwapperDoOp::Swap(float val) { - return static_cast(Swap((uint32_t)val)); + uint32_t tempI; + memcpy(&tempI, &val, sizeof(uint32_t)); + tempI = Swap(tempI); + float tempF; + memcpy(&tempF, &tempI, sizeof(uint32_t)); + return tempF; } template <> inline uint64_t SwapperDoOp::Swap(uint64_t val) { @@ -184,7 +201,12 @@ namespace gdcm } template <> inline double SwapperDoOp::Swap(double val) { - return static_cast(Swap((uint64_t)val)); + uint64_t tempI; + memcpy(&tempI, &val, sizeof(uint64_t)); + tempI = Swap(tempI); + double tempF; + memcpy(&tempF, &tempI, sizeof(uint64_t)); + return tempF; } template <> inline Tag SwapperDoOp::Swap(Tag val) diff --git a/Source/Common/gdcmSystem.cxx b/Source/Common/gdcmSystem.cxx index 2cd8442..b778ed5 100644 --- a/Source/Common/gdcmSystem.cxx +++ b/Source/Common/gdcmSystem.cxx @@ -135,6 +135,16 @@ const char * System::GetCWD() */ } +static inline int Mkdir2(const char *utf8) +{ +#ifdef _MSC_VER + const std::wstring unc = System::ConvertToUNC(utf8); + return _wmkdir(unc.c_str()); +#else + return Mkdir(utf8); +#endif +} + bool System::MakeDirectory(const char *path) { if( !path || !*path ) @@ -156,7 +166,7 @@ bool System::MakeDirectory(const char *path) while(ok && (pos = dir.find('/', pos)) != std::string::npos) { topdir = dir.substr(0, pos+1); - ok = ok && (System::FileIsDirectory(topdir.c_str()) || 0 == Mkdir(topdir.c_str())); + ok = ok && (System::FileIsDirectory(topdir.c_str()) || 0 == Mkdir2(topdir.c_str())); pos++; } if( !ok ) return false; @@ -168,7 +178,7 @@ bool System::MakeDirectory(const char *path) { topdir = dir; } - if(Mkdir(topdir.c_str()) != 0) + if(Mkdir2(topdir.c_str()) != 0) { // There is a bug in the Borland Run time library which makes MKDIR // return EACCES when it should return EEXISTS @@ -189,13 +199,15 @@ bool System::MakeDirectory(const char *path) // return true if the file exists bool System::FileExists(const char* filename) { -#ifdef _MSC_VER -# define access _access -#endif #ifndef R_OK # define R_OK 04 #endif +#ifdef _MSC_VER + const std::wstring unc = System::ConvertToUNC(filename); + if (_waccess(unc.c_str(), R_OK) != 0) +#else if ( access(filename, R_OK) != 0 ) +#endif { return false; } @@ -208,8 +220,14 @@ bool System::FileExists(const char* filename) bool System::FileIsDirectory(const char* name) { +#ifdef _MSC_VER + struct _stat64i32 fs; + const std::wstring wname = System::ConvertToUNC(name); + if (_wstat(wname.c_str(), &fs) == 0) +#else struct stat fs; if(stat(name, &fs) == 0) +#endif { #if _WIN32 return ((fs.st_mode & _S_IFDIR) != 0); @@ -366,10 +384,83 @@ bool System::DeleteDirectory(const char *source) #define PATH_MAX 4096 #endif -#ifndef PATH_MAX -#define PATH_MAX 4096 +#ifdef _MSC_VER + namespace { + static inline std::wstring ToUtf16(std::string const &str) { + std::wstring ret; + int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), + nullptr, 0); + if (len > 0) { + ret.resize(len); + MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), &ret[0], + len); + } + return ret; + } + // http://arsenmk.blogspot.com/2015/12/handling-long-paths-on-windows.html + static inline bool ComputeFullPath(std::wstring const &in, + std::wstring &out) { + // consider an input fileName of type PCWSTR (const wchar_t*) + const wchar_t *fileName = in.c_str(); + DWORD requiredBufferLength = + GetFullPathNameW(fileName, 0, nullptr, nullptr); + + if (0 == requiredBufferLength) // means failure + { + return false; + } + + out.resize(requiredBufferLength); + wchar_t *buffer = &out[0]; + + DWORD result = + GetFullPathNameW(fileName, requiredBufferLength, buffer, nullptr); + + if (0 == result) { + return false; + } + + // buffer now contains the full path name of fileName, use it. + return true; + } + + static inline std::wstring HandleMaxPath(std::wstring const &in) { + if (in.size() >= MAX_PATH) { + std::wstring out; + bool ret = ComputeFullPath(in, out); + if (!ret) return in; + if (out.size() < 4) return in; + if (out[0] == '\\' && out[1] == '\\' && out[2] == '?') { + // nothing to do + } else if (out[0] == '\\' && out[1] == '\\' && out[2] != '?') { + // server path + const std::wstring prefix = LR"(\\?\UNC\)"; + out = prefix + (out.c_str() + 2); + } else { + // regular C:\ style path: + assert(out[1] == ':'); + const std::wstring prefix = LR"(\\?\)"; + out = prefix + out.c_str(); + } + return out; + } + return in; + } + } // namespace #endif +std::wstring System::ConvertToUNC(const char *utf8path) +{ +#ifdef _MSC_VER + const std::wstring uft16path = ToUtf16(utf8path); + const std::wstring uncpath = HandleMaxPath(uft16path); + return uncpath; +#else + (void)utf8path; + return std::wstring(); +#endif +} + // return size of file; also returns zero if no file exists size_t System::FileSize(const char* filename) { @@ -476,7 +567,7 @@ const char *System::GetCurrentModuleFileName() if (dladdr( (void*)&where_am_i, &info ) == 0) { size_t len = strlen(info.dli_fname); - if( len >= PATH_MAX ) return 0; // throw error ? + if( len >= PATH_MAX ) return nullptr; // throw error ? // else strcpy(path,info.dli_fname); return path; @@ -675,11 +766,11 @@ bool System::ParseDateTime(time_t &timep, long &milliseconds, const char date[22 { switch (n) { - case 1: mon = 1; - case 2: day = 1; - case 3: hour = 0; - case 4: min = 0; - case 5: sec = 0; + case 1: mon = 1; /* Falls through. */ + case 2: day = 1; /* Falls through. */ + case 3: hour = 0; /* Falls through. */ + case 4: min = 0; /* Falls through. */ + case 5: sec = 0; /* Falls through. */ break; // http://security.coverity.com/blog/2013/Sep/gimme-a-break.html } ptm.tm_year = year - 1900; @@ -1009,8 +1100,8 @@ const char *System::GetLocaleCharset() const char *codeset2; codeset1 = buf1; codeset2 = buf2; - sprintf(buf1, "CP%d", GetConsoleCP()); - sprintf(buf2, "CP%d", GetConsoleOutputCP()); + snprintf(buf1, sizeof(buf1), "CP%d", GetConsoleCP()); + snprintf(buf2, sizeof(buf2), "CP%d", GetConsoleOutputCP()); // BUG: both returns 'CP437' on debian + mingw32... // instead prefer GetACP() call: @@ -1018,7 +1109,7 @@ const char *System::GetLocaleCharset() static char buf[2+10+1]; // 2 char, 10 bytes + 0 // GetACP: Retrieves the current Windows ANSI code page identifier for the // operating system. - sprintf (buf, "CP%u", GetACP ()); + snprintf (buf, sizeof(buf), "CP%u", GetACP ()); codeset = CharsetAliasToName(buf); #endif diff --git a/Source/Common/gdcmSystem.h b/Source/Common/gdcmSystem.h index ef0cecc..4137b96 100644 --- a/Source/Common/gdcmSystem.h +++ b/Source/Common/gdcmSystem.h @@ -28,7 +28,7 @@ class GDCM_EXPORT System public: /// Create a directory name path static bool MakeDirectory(const char *path); - /// Check whether the specified file exist on the sytem + /// Check whether the specified file exist on the system static bool FileExists(const char* filename); /// Check whether the file specified is a directory: static bool FileIsDirectory(const char* name); @@ -39,6 +39,11 @@ public: /// remove a directory named source static bool DeleteDirectory(const char *source); + /// When needed convert a PATH into a UNC equivalent. This allow + /// transparent support for path longer that MAX_PATH. + /// Only on _MSC_VER compiler, return empty string otherwise. + static std::wstring ConvertToUNC(const char *utf8path); + /// Return the last error static const char *GetLastSystemError(); @@ -68,7 +73,7 @@ public: // Chdir // copy a file - /// Retrieve the hostname, only the first 255 byte are copyied. + /// Retrieve the hostname, only the first 255 byte are copied. /// This may come handy to specify the Station Name static bool GetHostName(char hostname[255]); diff --git a/Source/Common/gdcmTerminal.cxx b/Source/Common/gdcmTerminal.cxx index 700346a..d31cc00 100644 --- a/Source/Common/gdcmTerminal.cxx +++ b/Source/Common/gdcmTerminal.cxx @@ -16,6 +16,10 @@ #include #include #include +#include +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf +#endif #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -75,12 +79,12 @@ public: void setbgcolor(int col) { bgcolor = col; } //std::string resettextcolor() const { // char command[13]; - // sprintf(command, "%c[%d;%d;%dm", 0x1B, 0, 0, 0); + // snprintf(command, sizeof(command), "%c[%d;%d;%dm", 0x1B, 0, 0, 0); // return command; //} std::string textcolor() const { char command[16]; - int n = sprintf(command, "%c[%d;%d;%dm", 0x1B, attribute, fgcolor + 30, bgcolor + 40); + int n = snprintf(command, sizeof(command), "%c[%d;%d;%dm", 0x1B, attribute, fgcolor + 30, bgcolor + 40); assert( n < 16 ); (void)n; return command; } diff --git a/Source/Common/gdcmTesting.cxx b/Source/Common/gdcmTesting.cxx index 5650fb1..8d48b95 100644 --- a/Source/Common/gdcmTesting.cxx +++ b/Source/Common/gdcmTesting.cxx @@ -79,7 +79,7 @@ const char * const * Testing::GetMediaStorageDataFile(unsigned int file) { if( file < Testing::GetNumberOfMediaStorageDataFiles() ) return gdcmMediaStorageDataFiles[file]; // else return the {0x0, 0x0} sentinel: - assert( *gdcmMediaStorageDataFiles[ Testing::GetNumberOfMediaStorageDataFiles() ] == 0 ); + assert( *gdcmMediaStorageDataFiles[ Testing::GetNumberOfMediaStorageDataFiles() ] == nullptr ); return gdcmMediaStorageDataFiles[ Testing::GetNumberOfMediaStorageDataFiles() ]; } const char * Testing::GetMediaStorageFromFile(const char *filepath) @@ -119,7 +119,7 @@ const char * const * Testing::GetMD5DataImage(unsigned int file) { if( file < Testing::GetNumberOfMD5DataImages() ) return gdcmMD5DataImages[file]; // else return the {0x0, 0x0} sentinel: - assert( *gdcmMD5DataImages[ Testing::GetNumberOfMD5DataImages() ] == 0 ); + assert( *gdcmMD5DataImages[ Testing::GetNumberOfMD5DataImages() ] == nullptr ); return gdcmMD5DataImages[ Testing::GetNumberOfMD5DataImages() ]; } @@ -447,6 +447,11 @@ static const LossyFile gdcmLossyFilenames[] = { { 0,"FUJI-ffff-MONO1-J2K.dcm" }, { 0,"JPEGLosslessSeNonZero.dcm" }, { 1,"US-YBR_FULL_422-EVRLE.dcm" }, +{ 0,"Osirix10vs8BitsStored.dcm" }, +{ 0,"Bug_Siemens_PrivateIconNoItem.dcm" }, +{ 0,"HardcopyColor_YBR_RCT_J2K_PC1.dcm" }, +{ 0,"PET-GE-dicomwrite-PixelDataSQUNv2.dcm" }, +{ 0,"MEDILABValidCP246_EVRLESQasOB.dcm" }, { 0, nullptr } }; diff --git a/Source/Common/gdcmTrace.h b/Source/Common/gdcmTrace.h index 768c6a0..4dae851 100644 --- a/Source/Common/gdcmTrace.h +++ b/Source/Common/gdcmTrace.h @@ -114,7 +114,7 @@ private: * @param msg message part */ #if defined(NDEBUG) && !defined(GDCM_ALWAYS_TRACE_MACRO) -#define gdcmDebugMacro(msg) {} +#define gdcmDebugMacro(msg) GDCM_NOOP_STATEMENT #else #define gdcmDebugMacro(msg) \ { \ @@ -128,7 +128,8 @@ private: std::ostream &_os = gdcm::Trace::GetDebugStream(); \ _os << osmacro.str() << "\n\n" << std::endl; \ } \ -} +} \ +GDCM_NOOP_STATEMENT #endif //NDEBUG /** @@ -136,7 +137,7 @@ private: * @param msg message part */ #if defined(NDEBUG) && !defined(GDCM_ALWAYS_TRACE_MACRO) -#define gdcmWarningMacro(msg) {} +#define gdcmWarningMacro(msg) GDCM_NOOP_STATEMENT #else #define gdcmWarningMacro(msg) \ { \ @@ -149,7 +150,8 @@ private: std::ostream &_os = gdcm::Trace::GetWarningStream(); \ _os << osmacro.str() << std::endl; \ } \ -} +} \ +GDCM_NOOP_STATEMENT #endif //NDEBUG /** @@ -158,7 +160,7 @@ private: * @param msg second message part */ #if defined(NDEBUG) && !defined(GDCM_ALWAYS_TRACE_MACRO) -#define gdcmErrorMacro(msg) {} +#define gdcmErrorMacro(msg) GDCM_NOOP_STATEMENT #else #define gdcmErrorMacro(msg) \ { \ @@ -171,7 +173,8 @@ private: std::ostream &_os = gdcm::Trace::GetErrorStream(); \ _os << osmacro.str() << std::endl; \ } \ -} +} \ +GDCM_NOOP_STATEMENT #endif //NDEBUG /** @@ -181,7 +184,7 @@ private: * gdcmAssertMacro( "my message" && 2 < 3 ) */ #if defined(NDEBUG) && !defined(GDCM_ALWAYS_TRACE_MACRO) -#define gdcmAssertMacro(arg) {} +#define gdcmAssertMacro(arg) GDCM_NOOP_STATEMENT #else #define gdcmAssertMacro(arg) \ { \ @@ -195,7 +198,8 @@ private: _os << osmacro.str() << std::endl; \ assert ( arg ); \ } \ -} +} \ +GDCM_NOOP_STATEMENT #endif //NDEBUG /** @@ -217,7 +221,8 @@ private: << "\n\n"; \ throw osmacro.str(); \ } \ -} +} \ +GDCM_NOOP_STATEMENT #else // Simply reproduce gdcmAssertMacro behavior: #define gdcmAssertAlwaysMacro(arg) gdcmAssertMacro(arg) diff --git a/Source/Common/gdcmTypes.h b/Source/Common/gdcmTypes.h index a8d26d4..8ea5545 100644 --- a/Source/Common/gdcmTypes.h +++ b/Source/Common/gdcmTypes.h @@ -19,39 +19,7 @@ #include "gdcmLegacyMacro.h" //----------------------------------------------------------------------------- -#ifdef GDCM_HAVE_STDINT_H -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS -#endif // __STDC_LIMIT_MACROS -#include -//#undef __STDC_LIMIT_MACROS -#else -#ifdef GDCM_HAVE_INTTYPES_H -// Old system only have this -#include // For uint8_t uint16_t and uint32_t -#else -// Broken plateforms do not respect C99 and do not provide those typedef -// Special case for recent Borland compiler, comes with stdint.h -#if defined(__BORLANDC__) && (__BORLANDC__ < 0x0560) || defined(__MINGW32__) -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned __int64 uint64_t; -#elif defined(_MSC_VER) -#include "stdint.h" -#else -#error "Sorry, your platform is not supported" -#endif // defined(_MSC_VER) || defined(__BORLANDC__) && (__BORLANDC__ < 0x0560) || defined(__MINGW32__) -#endif // GDCM_HAVE_INTTYPES_H -#endif // GDCM_HAVE_STDINT_H - -// Basically for VS6 and bcc 5.5.1: -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif +#include //----------------------------------------------------------------------------- #endif //GDCMTYPES_H diff --git a/Source/Common/zipstreamimpl.h b/Source/Common/zipstreamimpl.h index 18373f9..b40e214 100644 --- a/Source/Common/zipstreamimpl.h +++ b/Source/Common/zipstreamimpl.h @@ -129,21 +129,21 @@ public: int memory_level, size_t buffer_size); - ~basic_zip_streambuf(void) override; + ~basic_zip_streambuf() override; - int sync (void) override; + int sync () override; int_type overflow (int_type c) override; - std::streamsize flush (void); + std::streamsize flush (); inline - ostream_reference get_ostream (void) const; + ostream_reference get_ostream () const; inline - int get_zerr (void) const; + int get_zerr () const; inline - unsigned long get_crc (void) const; + unsigned long get_crc () const; inline - unsigned long get_in_size (void) const; + unsigned long get_in_size () const; inline - long get_out_size(void) const; + long get_out_size() const; private: @@ -189,33 +189,33 @@ public: size_t read_buffer_size, size_t input_buffer_size); - ~basic_unzip_streambuf(void) override; + ~basic_unzip_streambuf() override; - int_type underflow(void) override; + int_type underflow() override; /// returns the compressed input istream inline - istream_reference get_istream (void); + istream_reference get_istream (); inline - z_stream& get_zip_stream (void); + z_stream& get_zip_stream (); inline - int get_zerr (void) const; + int get_zerr () const; inline - unsigned long get_crc (void) const; + unsigned long get_crc () const; inline - long get_out_size (void) const; + long get_out_size () const; inline - long get_in_size (void) const; + long get_in_size () const; private: - void put_back_from_zip_stream (void); + void put_back_from_zip_stream (); std::streamsize unzip_from_stream (char_type* buffer, std::streamsize buffer_size); - size_t fill_input_buffer (void); + size_t fill_input_buffer (); istream_reference _istream; z_stream _zip_stream; @@ -250,21 +250,21 @@ public: int memory_level = 8, size_t buffer_size = zstream_default_buffer_size); - ~basic_zip_ostream(void) override; + ~basic_zip_ostream() override; inline - bool is_gzip (void) const; + bool is_gzip () const; inline - basic_zip_ostream& zflush (void); - void finished (void); + basic_zip_ostream& zflush (); + void finished (); // void make_gzip() // { add_header(); _is_gzip = true; } private: - basic_zip_ostream& add_header(void); - basic_zip_ostream& add_footer(void); + basic_zip_ostream& add_header(); + basic_zip_ostream& add_footer(); bool _is_gzip; bool _added_footer; @@ -290,20 +290,20 @@ public: size_t input_buffer_size = zstream_default_buffer_size); inline - bool is_gzip (void) const; + bool is_gzip () const; inline - bool check_crc (void); + bool check_crc (); inline - bool check_data_size (void) const; + bool check_data_size () const; inline - long get_gzip_crc (void) const; + long get_gzip_crc () const; inline - long get_gzip_data_size(void) const; + long get_gzip_data_size() const; protected: - int check_header (void); - void read_footer (void); + int check_header (); + void read_footer (); bool _is_gzip; long _gzip_crc; diff --git a/Source/Common/zipstreamimpl.hpp b/Source/Common/zipstreamimpl.hpp index 33b1774..c044890 100644 --- a/Source/Common/zipstreamimpl.hpp +++ b/Source/Common/zipstreamimpl.hpp @@ -82,7 +82,7 @@ basic_zip_streambuf::basic_zip_streambuf(ostream_reference ostrea /** Destructor */ template -basic_zip_streambuf::~basic_zip_streambuf(void) +basic_zip_streambuf::~basic_zip_streambuf() { flush(); // _ostream.flush(); CM already done in flush() @@ -94,7 +94,7 @@ basic_zip_streambuf::~basic_zip_streambuf(void) * document correctly! */ template -int basic_zip_streambuf::sync(void) +int basic_zip_streambuf::sync() { if(this->pptr() && this->pptr() > this->pbase()) { @@ -141,7 +141,7 @@ basic_zip_streambuf::overflow(int_type c) * multiple times, will lower the compression ratio. */ template -std::streamsize basic_zip_streambuf::flush(void) +std::streamsize basic_zip_streambuf::flush() { std::streamsize written_byte_size = 0, total_written_byte_size = 0; @@ -158,7 +158,7 @@ std::streamsize basic_zip_streambuf::flush(void) { written_byte_size = static_cast(_output_buffer.size()) - _zip_stream.avail_out; total_written_byte_size += written_byte_size; - // ouput buffer is full, dumping to ostream + // output buffer is full, dumping to ostream _ostream.write( (const char_type*) &(_output_buffer[0]), static_cast(written_byte_size/sizeof(char_type)*sizeof(char))); @@ -189,7 +189,7 @@ std::streamsize basic_zip_streambuf::flush(void) */ template inline typename basic_zip_streambuf::ostream_reference -basic_zip_streambuf::get_ostream(void) const +basic_zip_streambuf::get_ostream() const { return _ostream; } @@ -197,7 +197,7 @@ basic_zip_streambuf::get_ostream(void) const /** returns the latest zlib error status */ template inline -int basic_zip_streambuf::get_zerr(void) const +int basic_zip_streambuf::get_zerr() const { return _err; } @@ -206,7 +206,7 @@ int basic_zip_streambuf::get_zerr(void) const */ template inline unsigned long -basic_zip_streambuf:: get_crc(void) const +basic_zip_streambuf:: get_crc() const { return _crc; } @@ -215,7 +215,7 @@ basic_zip_streambuf:: get_crc(void) const */ template inline unsigned long -basic_zip_streambuf::get_in_size(void) const +basic_zip_streambuf::get_in_size() const { return _zip_stream.total_in; } @@ -224,7 +224,7 @@ basic_zip_streambuf::get_in_size(void) const */ template inline long -basic_zip_streambuf::get_out_size(void) const +basic_zip_streambuf::get_out_size() const { return _zip_stream.total_out; } @@ -263,7 +263,7 @@ bool basic_zip_streambuf::zip_to_stream( written_byte_size= static_cast(_output_buffer.size()) - _zip_stream.avail_out; total_written_byte_size += written_byte_size; - // ouput buffer is full, dumping to ostream + // output buffer is full, dumping to ostream _ostream.write((const char_type*) &_output_buffer[0], static_cast(written_byte_size / sizeof(char_type))); @@ -334,7 +334,7 @@ basic_unzip_streambuf::basic_unzip_streambuf(istream_reference is * @todo document! */ template -basic_unzip_streambuf::~basic_unzip_streambuf(void) +basic_unzip_streambuf::~basic_unzip_streambuf() { inflateEnd(&_zip_stream); } @@ -345,7 +345,7 @@ basic_unzip_streambuf::~basic_unzip_streambuf(void) */ template typename basic_unzip_streambuf::int_type -basic_unzip_streambuf::underflow(void) +basic_unzip_streambuf::underflow() { if(this->gptr() && ( this->gptr() < this->egptr())) return * reinterpret_cast(this->gptr()); @@ -379,7 +379,7 @@ basic_unzip_streambuf::underflow(void) */ template inline typename basic_unzip_streambuf::istream_reference -basic_unzip_streambuf::get_istream(void) +basic_unzip_streambuf::get_istream() { return _istream; } @@ -388,7 +388,7 @@ basic_unzip_streambuf::get_istream(void) */ template inline z_stream & -basic_unzip_streambuf::get_zip_stream(void) +basic_unzip_streambuf::get_zip_stream() { return _zip_stream; } @@ -397,7 +397,7 @@ basic_unzip_streambuf::get_zip_stream(void) */ template inline int -basic_unzip_streambuf::get_zerr(void) const +basic_unzip_streambuf::get_zerr() const { return _err; } @@ -406,7 +406,7 @@ basic_unzip_streambuf::get_zerr(void) const */ template inline unsigned long -basic_unzip_streambuf::get_crc(void) const +basic_unzip_streambuf::get_crc() const { return _crc; } @@ -415,7 +415,7 @@ basic_unzip_streambuf::get_crc(void) const */ template inline long -basic_unzip_streambuf::get_out_size(void) const +basic_unzip_streambuf::get_out_size() const { return _zip_stream.total_out; } @@ -424,7 +424,7 @@ basic_unzip_streambuf::get_out_size(void) const */ template inline long -basic_unzip_streambuf::get_in_size(void) const +basic_unzip_streambuf::get_in_size() const { return _zip_stream.total_in; } @@ -438,7 +438,7 @@ basic_unzip_streambuf::get_in_size(void) const */ template inline void -basic_unzip_streambuf::put_back_from_zip_stream(void) +basic_unzip_streambuf::put_back_from_zip_stream() { if(_zip_stream.avail_in == 0) return; @@ -496,7 +496,7 @@ basic_unzip_streambuf::unzip_from_stream(char_type* buffer, */ template inline size_t -basic_unzip_streambuf::fill_input_buffer(void) +basic_unzip_streambuf::fill_input_buffer() { _zip_stream.next_in = &_input_buffer[0]; _istream.read((char_type*) &_input_buffer[0], @@ -565,7 +565,7 @@ basic_zip_ostream::basic_zip_ostream(ostream_reference ostream, /** Destructor */ template -basic_zip_ostream::~basic_zip_ostream(void) +basic_zip_ostream::~basic_zip_ostream() { //if(_is_gzip) add_footer(); @@ -574,7 +574,7 @@ basic_zip_ostream::~basic_zip_ostream(void) /** returns true if it is a gzip */ template inline -bool basic_zip_ostream::is_gzip(void) const +bool basic_zip_ostream::is_gzip() const { return _is_gzip; } @@ -583,7 +583,7 @@ bool basic_zip_ostream::is_gzip(void) const */ template inline -basic_zip_ostream& basic_zip_ostream::zflush(void) +basic_zip_ostream& basic_zip_ostream::zflush() { static_cast *>(this)->flush(); static_cast *>(this)->flush(); @@ -591,7 +591,7 @@ basic_zip_ostream& basic_zip_ostream::zflush(void) } template inline -void basic_zip_ostream::finished(void) +void basic_zip_ostream::finished() { if(_is_gzip) add_footer(); @@ -608,7 +608,7 @@ void basic_zip_ostream::finished(void) * @todo document! */ template -basic_zip_ostream& basic_zip_ostream::add_header(void) +basic_zip_ostream& basic_zip_ostream::add_header() { char_type zero = 0; @@ -627,7 +627,7 @@ basic_zip_ostream& basic_zip_ostream::add_header(vo * @todo document! */ template -basic_zip_ostream& basic_zip_ostream::add_footer(void) +basic_zip_ostream& basic_zip_ostream::add_footer() { if(_added_footer) return *this; @@ -701,7 +701,7 @@ basic_zip_istream::basic_zip_istream(istream_reference istream, */ template inline bool -basic_zip_istream::is_gzip(void) const +basic_zip_istream::is_gzip() const { return _is_gzip; } @@ -711,11 +711,11 @@ basic_zip_istream::is_gzip(void) const * This must be called after the reading of compressed data is finished! This * method compares it to the crc of the uncompressed data. * - * \return true if crc check is succesful + * \return true if crc check is successful */ template inline bool -basic_zip_istream::check_crc(void) +basic_zip_istream::check_crc() { read_footer(); return this->get_crc() == _gzip_crc; @@ -725,7 +725,7 @@ basic_zip_istream::check_crc(void) */ template inline bool -basic_zip_istream::check_data_size(void) const +basic_zip_istream::check_data_size() const { return this->get_out_size() == _gzip_data_size; } @@ -734,7 +734,7 @@ basic_zip_istream::check_data_size(void) const */ template inline long -basic_zip_istream::get_gzip_crc(void) const +basic_zip_istream::get_gzip_crc() const { return _gzip_crc; } @@ -743,7 +743,7 @@ basic_zip_istream::get_gzip_crc(void) const */ template inline long -basic_zip_istream::get_gzip_data_size(void) const +basic_zip_istream::get_gzip_data_size() const { return _gzip_data_size; } @@ -757,7 +757,7 @@ basic_zip_istream::get_gzip_data_size(void) const */ template int -basic_zip_istream::check_header(void) +basic_zip_istream::check_header() { int method; /* method byte */ int flagsbyte; /* flags byte */ @@ -831,7 +831,7 @@ basic_zip_istream::check_header(void) */ template void -basic_zip_istream::read_footer(void) +basic_zip_istream::read_footer() { if(_is_gzip) { diff --git a/Source/DataDictionary/CSADefaultDicts.xsl b/Source/DataDictionary/CSADefaultDicts.xsl index 56f8e39..6dd4c4d 100644 --- a/Source/DataDictionary/CSADefaultDicts.xsl +++ b/Source/DataDictionary/CSADefaultDicts.xsl @@ -166,7 +166,7 @@ generating group length for arbitrary even group number seems to get my xsltproc - {0,0,VR::INVALID,VM::VM0,0 } // Gard + {0,0,VR::INVALID,VM::VM0,0 } // Guard }; void CSAHeaderDict::LoadDefault() diff --git a/Source/DataDictionary/CSAHeader.xml b/Source/DataDictionary/CSAHeader.xml index 197bdb8..8615037 100644 --- a/Source/DataDictionary/CSAHeader.xml +++ b/Source/DataDictionary/CSAHeader.xml @@ -36,7 +36,7 @@ sKSpace.ucPhasePartialFourier = 0x10 --> - + @@ -51,11 +51,11 @@ sKSpace.ucPhasePartialFourier = 0x10 - + - + @@ -70,9 +70,9 @@ sKSpace.ucPhasePartialFourier = 0x10 - + - + @@ -97,7 +97,7 @@ sKSpace.ucPhasePartialFourier = 0x10 - + @@ -146,7 +146,7 @@ sKSpace.ucPhasePartialFourier = 0x10 - + @@ -177,7 +177,7 @@ sKSpace.ucPhasePartialFourier = 0x10 - + @@ -187,7 +187,7 @@ sKSpace.ucPhasePartialFourier = 0x10 - + @@ -208,8 +208,8 @@ sKSpace.ucPhasePartialFourier = 0x10 - - + + @@ -249,7 +249,7 @@ sKSpace.ucPhasePartialFourier = 0x10 - + diff --git a/Source/DataDictionary/DefaultDicts.xsl b/Source/DataDictionary/DefaultDicts.xsl index 6a89889..d7917e4 100644 --- a/Source/DataDictionary/DefaultDicts.xsl +++ b/Source/DataDictionary/DefaultDicts.xsl @@ -164,7 +164,7 @@ generating group length for arbitrary even group number seems to get my xsltproc // FIXME: need a dummy element {0xffff,0xffff,VR::INVALID,VM::VM0,"","",true }, // dummy - {0xffff,0xffff,VR::INVALID,VM::VM0,0,0,true } // Gard + {0xffff,0xffff,VR::INVALID,VM::VM0,0,0,true } // Guard }; void Dict::LoadDefault() diff --git a/Source/DataDictionary/DefaultPrivateDicts.xsl b/Source/DataDictionary/DefaultPrivateDicts.xsl index 9be337d..dc5acd8 100644 --- a/Source/DataDictionary/DefaultPrivateDicts.xsl +++ b/Source/DataDictionary/DefaultPrivateDicts.xsl @@ -36,8 +36,8 @@ =========================================================================*/ -#ifndef GDCMDEFAULTDICTS_CXX -#define GDCMDEFAULTDICTS_CXX +#ifndef GDCMPRIVATEDEFAULTDICTS_CXX +#define GDCMPRIVATEDEFAULTDICTS_CXX #include "gdcmDicts.h" #include "gdcmVR.h" @@ -153,7 +153,7 @@ generating group length for arbitrary even group number seems to get my xsltproc - {0xffff,0xffff,0,VR::INVALID,VM::VM0,0,true } // Gard + {0xffff,0xffff,0,VR::INVALID,VM::VM0,0,true } // Guard }; void Dict::LoadDefault() @@ -191,7 +191,7 @@ void PrivateDict::LoadDefault() } } // end namespace gdcm -#endif // GDCMDEFAULTDICTS_CXX +#endif // GDCMPRIVATEDEFAULTDICTS_CXX diff --git a/Source/DataDictionary/ParseDicts.py b/Source/DataDictionary/ParseDicts.py index 76abe9e..cfd39d0 100755 --- a/Source/DataDictionary/ParseDicts.py +++ b/Source/DataDictionary/ParseDicts.py @@ -124,7 +124,7 @@ class PdfTextParser: #print "Other Full line:", s2 self.AddOutputLine(s2) else: - # we have a suspicioulsy long line, so what that could + # we have a suspiciously long line, so what that could # happen, let's check: if self.IsAFullLine(previousbuffer): self.AddOutputLine(previousbuffer) diff --git a/Source/DataDictionary/Part6todcm4che.xsl b/Source/DataDictionary/Part6todcm4che.xsl index 459c6da..2859428 100644 --- a/Source/DataDictionary/Part6todcm4che.xsl +++ b/Source/DataDictionary/Part6todcm4che.xsl @@ -1,7 +1,7 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -19,6 +1104,7 @@ + @@ -31,14 +1117,14 @@ - + - + - + @@ -74,13 +1160,22 @@ + + + + + + + + + @@ -88,13 +1183,12 @@ - - + + + @@ -110,7 +1204,7 @@ - + @@ -124,12 +1218,14 @@ - + + + @@ -146,24 +1242,26 @@ - + - + - + + + @@ -176,13 +1274,17 @@ + + + + @@ -193,12 +1295,15 @@ - + + - - + + + + @@ -215,7 +1320,7 @@ - + @@ -225,13 +1330,15 @@ - - + + - + + + @@ -242,18 +1349,24 @@ - + + - + + - - + + + + - + @@ -263,9 +1376,11 @@ + + @@ -275,19 +1390,22 @@ - + - + + + + @@ -295,16 +1413,18 @@ + - + + @@ -312,9 +1432,14 @@ + + - + + + + @@ -329,14 +1454,17 @@ - + - + + + + @@ -348,26 +1476,26 @@ - - - + + + - + - + - + - + - + @@ -375,17 +1503,20 @@ - + - + + + - + + - + @@ -405,23 +1536,26 @@ + + + - - - - - - + + + + + + - + @@ -442,6 +1576,7 @@ + @@ -451,6 +1586,7 @@ + @@ -746,7 +1882,7 @@ - + @@ -1239,6 +2375,7 @@ + @@ -1250,12 +2387,15 @@ + + + @@ -1269,6 +2409,7 @@ + @@ -1339,6 +2480,9 @@ + + + @@ -1373,6 +2517,7 @@ + @@ -1406,83 +2551,83 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1517,66 +2662,68 @@ - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1607,7 +2754,7 @@ - + @@ -2203,7 +3350,7 @@ - + @@ -2306,7 +3453,7 @@ - + @@ -2316,7 +3463,7 @@ - + @@ -2332,6 +3479,7 @@ + @@ -2663,7 +3811,7 @@ - + @@ -2692,17 +3840,26 @@ - + - + - + + + + + + + + + + @@ -3689,7 +4846,7 @@ - + @@ -3791,8 +4948,8 @@ - - + + @@ -3972,84 +5129,444 @@ - + + - + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4581,7 +6098,7 @@ - + @@ -4642,10 +6159,10 @@ - + - + @@ -5029,6 +6546,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5046,6 +6601,10 @@ + + + + @@ -5056,7 +6615,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5518,7 +7127,7 @@ - + @@ -5684,6 +7293,7 @@ + @@ -5703,7 +7313,7 @@ - + @@ -5818,9 +7428,9 @@ - + - + @@ -6528,8 +8138,8 @@ - - + + @@ -6685,7 +8295,7 @@ - + @@ -7677,11 +9287,12 @@ - + - + + @@ -7752,7 +9363,7 @@ - + @@ -8293,7 +9904,7 @@ - + @@ -8671,11 +10282,13 @@ - + + + diff --git a/Source/DataStructureAndEncodingDefinition/gdcmAttribute.h b/Source/DataStructureAndEncodingDefinition/gdcmAttribute.h index c664a1b..2829603 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmAttribute.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmAttribute.h @@ -66,7 +66,7 @@ public: /** * \brief Attribute class * This class use template metaprograming tricks to let the user know when the template - * instanciation does not match the public dictionary. + * instantiation does not match the public dictionary. * * Typical example that compile is: * Attribute<0x0008,0x9007> a = {"ORIGINAL","PRIMARY","T1","NONE"}; @@ -118,7 +118,7 @@ public: os << GetTag() << " "; os << TagToType::GetVRString() << " "; os << TagToType::GetVMString() << " "; - os << Internal[0]; // VM is at least garantee to be one + os << Internal[0]; // VM is at least guarantee to be one for(unsigned int i=1; i::GetVRString() << " "; os << TagToType::GetVMString() << " "; - os << Internal; // VM is at least garantee to be one + os << Internal; // VM is at least guarantee to be one } // copy: //ArrayType GetValue(unsigned int idx = 0) { @@ -593,7 +593,7 @@ public: os << GetTag() << " "; os << GetVR() << " "; os << GetVM() << " "; - os << Internal[0]; // VM is at least garantee to be one + os << Internal[0]; // VM is at least guarantee to be one for(unsigned int i=1; i::Length; ++i) _os << "," << Internal[i]; } @@ -869,7 +869,7 @@ public: void Print(std::ostream &_os) const { assert( Length ); assert( Internal ); - _os << Internal[0]; // VM is at least garantee to be one + _os << Internal[0]; // VM is at least guarantee to be one const unsigned long length = GetLength() < 25 ? GetLength() : 25; for(unsigned long i=1; iSetLength(ValueLengthField); if( !bv->Read(is) ) { - assert(0 && "Should not happen"); + gdcmAssertAlwaysMacro(0 && "Should not happen"); return is; } ValueField = bv; diff --git a/Source/DataStructureAndEncodingDefinition/gdcmByteBuffer.h b/Source/DataStructureAndEncodingDefinition/gdcmByteBuffer.h index 0c5d393..bfe20cd 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmByteBuffer.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmByteBuffer.h @@ -26,7 +26,7 @@ namespace gdcm /** * \brief ByteBuffer * - * \details Detailled description here + * \details Detailed description here * \note * looks like a std::streambuf or std::filebuf class with the get and * peek pointer diff --git a/Source/DataStructureAndEncodingDefinition/gdcmByteValue.h b/Source/DataStructureAndEncodingDefinition/gdcmByteValue.h index cbcc54b..03fabe3 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmByteValue.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmByteValue.h @@ -41,7 +41,7 @@ public: { gdcmDebugMacro( "Odd length" ); Internal.resize(vl+1); - Length++; + ++Length; } } diff --git a/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.cxx b/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.cxx index 36e48ca..5b88806 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.cxx @@ -776,7 +776,7 @@ Series shadow data (0029,xx20) 54 - 'MrEvaProtocol' VM 1, VR UN, SyngoDT 0, NoOfItems 0, Data * * -WARNING: I think this is context dependant so 0029,1010 and 0029,1110 are not supposed to mean the same thing, eg: +WARNING: I think this is context dependent so 0029,1010 and 0029,1110 are not supposed to mean the same thing, eg: (CSA image data) (0029,0010)siemens csa header @@ -961,13 +961,13 @@ bool CSAHeader::LoadFromDataElement(DataElement const &de) if( v2 == t1.GetElement() ) { //std::cout << "Image shadow data (0029,xx10)\n\n"; - DataElementTag = t1;; + DataElementTag = t1; } //else if( de.GetTag().GetPrivateCreator() == t2 ) else if( v2 == t2.GetElement() ) { //std::cout << "Series shadow data (0029,xx20)\n\n"; - DataElementTag = t2;; + DataElementTag = t2; } else { @@ -1116,6 +1116,7 @@ bool CSAHeader::LoadFromDataElement(DataElement const &de) ss.read((char*)&nitems, sizeof(nitems)); SwapperNoOp::SwapArray(&nitems,1); csael.SetNoOfItems( nitems ); + if( InternalType == SV10) { assert( nitems % 6 == 0 );} //std::cout << "NoOfItems " << nitems << ", "; uint32_t xx; ss.read((char*)&xx, sizeof(xx)); @@ -1194,7 +1195,7 @@ void CSAHeader::Print(std::ostream &os) const for(; it != InternalCSADataSet.end(); ++it) { - std::cout << *it << std::endl; + os << *it << std::endl; } } @@ -1236,15 +1237,15 @@ bool CSAHeader::FindCSAElementByName(const char *name) } static const char csaheader[] = "SIEMENS CSA HEADER"; -static const gdcm::PrivateTag t1(0x0029,0x0010,csaheader); // CSA Image Header Info -static const gdcm::PrivateTag t2(0x0029,0x0020,csaheader); // CSA Series Header Info +static const gdcm::PrivateTag t1(0x0029,0x10,csaheader); // CSA Image Header Info +static const gdcm::PrivateTag t2(0x0029,0x20,csaheader); // CSA Series Header Info //static const char csaheader2[] = "SIEMENS MEDCOM HEADER2"; //static const gdcm::PrivateTag t4(0x0029,0x0010,csaheader2); // CSA Image Header Info //static const gdcm::PrivateTag t5(0x0029,0x0020,csaheader2); // CSA Series Header Info static const char csanonimage[] = "SIEMENS CSA NON-IMAGE"; -static const gdcm::PrivateTag t3(0x0029,0x0010,csanonimage); // CSA Data Info +static const gdcm::PrivateTag t3(0x0029,0x10,csanonimage); // CSA Data Info const PrivateTag & CSAHeader::GetCSAImageHeaderInfoTag() { diff --git a/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.h b/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.h index 6d2123d..3c4cf29 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmCSAHeader.h @@ -67,7 +67,7 @@ public : CSAHeader():InternalDataSet(),InternalType(UNKNOWN),InterfileData(nullptr) {}; ~CSAHeader() = default; - /// Divers format of CSAHeader as found 'in the wild' + /// Diverse format of CSAHeader as found 'in the wild' typedef enum { UNKNOWN = 0, SV10, @@ -94,15 +94,15 @@ public : CSAHeaderType GetFormat() const; /// Return the private tag used by SIEMENS to store the CSA Image Header - /// This is: PrivateTag(0x0029,0x0010,"SIEMENS CSA HEADER"); + /// This is: PrivateTag(0x0029,0x10,"SIEMENS CSA HEADER"); static const PrivateTag & GetCSAImageHeaderInfoTag(); /// Return the private tag used by SIEMENS to store the CSA Series Header - /// This is: PrivateTag(0x0029,0x0020,"SIEMENS CSA HEADER"); + /// This is: PrivateTag(0x0029,0x20,"SIEMENS CSA HEADER"); static const PrivateTag & GetCSASeriesHeaderInfoTag(); /// Return the private tag used by SIEMENS to store the CSA Data Info - /// This is: PrivateTag(0x0029,0x0010,"SIEMENS CSA NON-IMAGE"); + /// This is: PrivateTag(0x0029,0x10,"SIEMENS CSA NON-IMAGE"); static const PrivateTag & GetCSADataInfo(); /// Return the CSAElement corresponding to name 'name' diff --git a/Source/DataStructureAndEncodingDefinition/gdcmDataElement.cxx b/Source/DataStructureAndEncodingDefinition/gdcmDataElement.cxx index 94d915f..5012ed4 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmDataElement.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmDataElement.cxx @@ -156,6 +156,34 @@ namespace gdcm_ns return nullptr; } } + catch ( ... ) + { + gdcmErrorMacro( "Could not read SQ, unknown exception" ); + delete sqi; + return nullptr; + } + } + return sqi; + } + else if ( GetVR() & VR::OB_OW ) // pre-dicom 1993 ? + { + const ByteValue *bv = GetByteValue(); + assert( bv ); + SequenceOfItems *sqi = new SequenceOfItems; + sqi->SetLength( bv->GetLength() ); + std::string s( bv->GetPointer(), bv->GetLength() ); + try + { + std::stringstream ss; + ss.str( s ); + sqi->Read( ss, true ); + } + catch ( Exception &ex0 ) + { + gdcmErrorMacro( "Could not read SQ as OB. Giving up" ); + gdcmErrorMacro(ex0.what()); (void)ex0; + delete sqi; + return nullptr; } return sqi; } diff --git a/Source/DataStructureAndEncodingDefinition/gdcmDataElement.h b/Source/DataStructureAndEncodingDefinition/gdcmDataElement.h index f68eef0..b1ae738 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmDataElement.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmDataElement.h @@ -137,7 +137,7 @@ public: } /// Interpret the Value stored in the DataElement. This is more robust (but also more - /// expensive) to call this function rather than the simpliest form: GetSequenceOfItems() + /// expensive) to call this function rather than the simplest form: GetSequenceOfItems() /// It also return NULL when the Value is NOT of type SequenceOfItems /// \warning in case GetSequenceOfItems() succeed the function return this value, otherwise /// it creates a new SequenceOfItems, you should handle that in your case, for instance: @@ -186,7 +186,7 @@ public: return false; } - // The following fonctionalities are dependant on: + // The following functionalities are dependent on: // # The Transfer Syntax: Explicit or Implicit // # The Byte encoding: Little Endian / Big Endian diff --git a/Source/DataStructureAndEncodingDefinition/gdcmDataSet.cxx b/Source/DataStructureAndEncodingDefinition/gdcmDataSet.cxx index 40f8a69..3024625 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmDataSet.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmDataSet.cxx @@ -25,10 +25,10 @@ const DataElement& DataSet::GetDEEnd() const std::string DataSet::GetPrivateCreator(const Tag &t) const { - if( t.IsPrivate() && !t.IsPrivateCreator() ) + if( t.IsPrivate() && !t.IsGroupLength() && !t.IsPrivateCreator() && !t.IsIllegal() ) { Tag pc = t.GetPrivateCreator(); - if( pc.GetElement() ) + assert( pc.GetElement() ); { const DataElement r(pc); ConstIterator it = DES.find(r); @@ -41,7 +41,7 @@ std::string DataSet::GetPrivateCreator(const Tag &t) const if( de.IsEmpty() ) return ""; const ByteValue *bv = de.GetByteValue(); assert( bv ); - std::string owner = std::string(bv->GetPointer(),bv->GetLength()); + std::string owner = std::string(bv->GetPointer(),bv->GetLength()).c_str(); // There should not be any trailing space character... // TODO: tmp.erase(tmp.find_last_not_of(' ') + 1); while( !owner.empty() && owner[owner.size()-1] == ' ' ) @@ -56,9 +56,17 @@ std::string DataSet::GetPrivateCreator(const Tag &t) const return ""; } +PrivateTag DataSet::GetPrivateTag(const Tag &t) const +{ + const std::string str = this->GetPrivateCreator(t); + PrivateTag pt(t); + pt.SetOwner(str.c_str()); + return pt; +} + Tag DataSet::ComputeDataElement(const PrivateTag & t) const { - gdcmDebugMacro( "Entering ComputeDataElement" ); + //gdcmDebugMacro( "Entering ComputeDataElement" ); //assert( t.IsPrivateCreator() ); // No this is wrong to do the assert: eg. (0x07a1,0x000a,"ELSCINT1") // is valid because we have not yet done the mapping, so 0xa < 0x10 fails but might not later on const Tag start(t.GetGroup(), 0x0010 ); // First possible private creator (0x0 -> 0x9 are reserved...) @@ -87,7 +95,7 @@ Tag DataSet::ComputeDataElement(const PrivateTag & t) const } ++it; } - gdcmDebugMacro( "In compute found is:" << found ); + //gdcmDebugMacro( "In compute found is:" << found ); if (!found) return GetDEEnd().GetTag(); // else // ok we found the Private Creator Data Element, let's construct the proper data element diff --git a/Source/DataStructureAndEncodingDefinition/gdcmDataSet.h b/Source/DataStructureAndEncodingDefinition/gdcmDataSet.h index 4528539..5ae1500 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmDataSet.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmDataSet.h @@ -196,8 +196,12 @@ public: const DataElement& operator() (uint16_t group, uint16_t element) const { return GetDataElement( Tag(group,element) ); } /// Return the private creator of the private tag 't': + /// or an empty string when not found std::string GetPrivateCreator(const Tag &t) const; + /// Return the private tag of the private tag 't', private creator will be set to empty if not found + PrivateTag GetPrivateTag(const Tag &t) const; + /// Look up if private tag 't' is present in the dataset: bool FindDataElement(const PrivateTag &t) const; /// Return the dataelement @@ -230,19 +234,6 @@ public: DataSet& operator=(DataSet const &) = default; -/* - template - void ExecuteOperation(TOperation & operation) { - assert( !DES.empty() ); - DataElementSet::iterator it = Begin(); - for( ; it != End(); ++it) - { - DataElement &de = (DataElement&)*it; - operation( de ); - } - } -*/ - template std::istream &ReadNested(std::istream &is); diff --git a/Source/DataStructureAndEncodingDefinition/gdcmDataSet.txx b/Source/DataStructureAndEncodingDefinition/gdcmDataSet.txx index 4acdcc6..45301ac 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmDataSet.txx +++ b/Source/DataStructureAndEncodingDefinition/gdcmDataSet.txx @@ -421,7 +421,9 @@ namespace gdcm_ns } else if( /*pe.GetLastElement().GetTag() == Tag(0xffd8,0xffe0) &&*/ de.GetTag() == Tag(0x7fe0,0x0010) && de.IsUndefinedLength() ) { + // Bug_Siemens_PrivateIconNoItem.dcm // PET-GE-dicomwrite-PixelDataSQUN.dcm + // PET-GE-dicomwrite-PixelDataSQUNv2.dcm // some bozo crafted an undefined length Pixel Data but is actually // defined length. Since inside SQ/Item it should be possible to // compute the proper length diff --git a/Source/DataStructureAndEncodingDefinition/gdcmElement.h b/Source/DataStructureAndEncodingDefinition/gdcmElement.h index ae56136..b49b093 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmElement.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmElement.h @@ -81,9 +81,9 @@ public: } // Implementation of Print is common to all Mode (ASCII/Binary) // TODO: Can we print a \ when in ASCII...well I don't think so - // it would mean we used a bad VM then, right ? + // it would mean we used a bad VM then, right? void Print(std::ostream &_os) const { - _os << Internal[0]; // VM is at least garantee to be one + _os << Internal[0]; // VM is at least guarantee to be one for(int i=1; i::Length; ++i) _os << "," << Internal[i]; } @@ -314,7 +314,11 @@ static int doround(char *buf, unsigned int n) { return 0; } -static int roundat(char *buf, unsigned int i, int iexp) { +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf +#endif + +static int roundat(char *buf, size_t bufLen, unsigned int i, int iexp) { if (doround(buf, i) != 0) { iexp += 1; switch(iexp) { @@ -334,7 +338,7 @@ static int roundat(char *buf, unsigned int i, int iexp) { strcpy(buf, "100"); break; default: - sprintf(buf, "1e%d", iexp); + snprintf(buf, bufLen, "1e%d", iexp); } return 1; } @@ -353,20 +357,20 @@ static void x16printf(char *buf, int size, Float f) { size -= 1; *buf++ = '-'; } - sprintf(line, "%1.16e", f); + snprintf(line, sizeof(line), "%1.16e", f); if (line[0] == '-') { f = -f; size -= 1; *buf++ = '-'; - sprintf(line, "%1.16e", f); + snprintf(line, sizeof(line), "%1.16e", f); } *mant = line[0]; i = (int)strcspn(mant, "eE"); mant[i] = '\0'; iexp = (int)strtol(mant + i + 1, nullptr, 10); - lexp = sprintf(exp, "e%d", iexp); + lexp = snprintf(exp, sizeof(exp), "e%d", iexp); if ((iexp >= size) || (iexp < -3)) { - i = roundat(mant, size - 1 -lexp, iexp); + i = roundat(mant, sizeof(line) - 1, size - 1 -lexp, iexp); if(i == 1) { strcpy(buf, mant); return; @@ -379,11 +383,11 @@ static void x16printf(char *buf, int size, Float f) { strcat(buf, exp); } else if (iexp >= size - 2) { - roundat(mant, iexp + 1, iexp); + roundat(mant, sizeof(line) - 1, iexp + 1, iexp); strcpy(buf, mant); } else if (iexp >= 0) { - i = roundat(mant, size - 1, iexp); + i = roundat(mant, sizeof(line) - 1, size - 1, iexp); if (i == 1) { strcpy(buf, mant); return; @@ -396,7 +400,7 @@ static void x16printf(char *buf, int size, Float f) { } else { int j; - i = roundat(mant, size + 1 + iexp, iexp); + i = roundat(mant, sizeof(line) - 1, size + 1 + iexp, iexp); if (i == 1) { strcpy(buf, mant); return; @@ -405,15 +409,15 @@ static void x16printf(char *buf, int size, Float f) { for(j=0; j< -1 - iexp; j++) { buf[j+1] = '0'; } - if ((i == 1) && (iexp != -1)) { - buf[-iexp] = '1'; - buf++; - } strncpy(buf - iexp, mant, size + 1 + iexp); buf[size] = 0; clean(buf); } } +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#undef snprintf +#endif + #endif template<> inline void EncodingImplementation::Write(const double* data, unsigned long length, std::ostream &_os) { @@ -514,7 +518,7 @@ public: }; // For particular case for ASCII string -// WARNING: This template explicitly instanciates a particular +// WARNING: This template explicitly instantiates a particular // EncodingImplementation THEREFORE it is required to be declared after the // EncodingImplementation is needs (doh!) #if 0 @@ -546,7 +550,7 @@ public: } // Implementation of Print is common to all Mode (ASCII/Binary) void Print(std::ostream &_os) const { - _os << Internal[0]; // VM is at least garantee to be one + _os << Internal[0]; // VM is at least guarantee to be one for(int i=1; i::Length; ++i) _os << "," << Internal[i]; } @@ -624,7 +628,7 @@ public: else { // TODO rewrite this stupid code: assert( Length == 0 ); - assert( Internal == 0 ); + assert( Internal == nullptr ); assert( Save == false ); Length = len / sizeof(Type); //assert( (len / sizeof(Type)) * sizeof(Type) == len ); @@ -658,7 +662,7 @@ public: const Type* array = (const Type*)bv->GetVoidPointer(); if( array ) { assert( array ); // That would be bad... - assert( Internal == 0 ); + assert( Internal == nullptr ); SetArray(array, bv->GetLength() ); } } else @@ -697,7 +701,7 @@ public: void Print(std::ostream &_os) const { assert( Length ); assert( Internal ); - _os << Internal[0]; // VM is at least garantee to be one + _os << Internal[0]; // VM is at least guarantee to be one const unsigned long length = GetLength() < 25 ? GetLength() : 25; for(unsigned long i=1; iGetPointer(); if( array ) { assert( array ); // That would be bad... - assert( Internal == 0 ); + assert( Internal == nullptr ); SetArray(array, bv->GetLength() ); } } else @@ -840,6 +844,16 @@ public: Parent::SetLength(len); } }; +template +class Element : public Element +{ +public: + typedef Element Parent; + void SetLength(int len) { + if( len != 3 && len != 4 ) return; + Parent::SetLength(len); + } +}; //template struct VRToLength; diff --git a/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.txx b/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.txx index 2266f2e..47633b9 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.txx +++ b/Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.txx @@ -385,7 +385,7 @@ const std::ostream &ExplicitDataElement::Write(std::ostream &os) const if( TagField == itemDelItem ) { assert(0); - assert( ValueField == 0 ); + assert( ValueField == nullptr ); #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION if( ValueLengthField != 0 ) { @@ -405,20 +405,31 @@ const std::ostream &ExplicitDataElement::Write(std::ostream &os) const } return os; } - bool vr16bitsimpossible = (VRField & VR::VL16) && (ValueLengthField > (uint32_t)VL::GetVL16Max()); - if( VRField == VR::INVALID || vr16bitsimpossible ) + const bool vr16bitsimpossible = (VRField & VR::VL16) && (ValueLengthField > (uint32_t)VL::GetVL16Max()); + const bool vrOWpixeldata = (VRField == VR::OW) && ValueLengthField.IsUndefined(); + const bool vrUNbutSpecial = (VRField == VR::UN && (TagField.IsPrivateCreator() || TagField.IsGroupLength())); + if( VRField == VR::INVALID || vr16bitsimpossible || vrOWpixeldata || vrUNbutSpecial) { if ( TagField.IsPrivateCreator() ) { gdcmAssertAlwaysMacro( !vr16bitsimpossible ); VR lo = VR::LO; - if( TagField.IsGroupLength() ) - { - lo = VR::UL; - } lo.Write(os); ValueLengthField.Write16(os); } + else if ( TagField.IsGroupLength() ) + { + gdcmAssertAlwaysMacro( !vr16bitsimpossible ); + VR ul = VR::UL; + ul.Write(os); + ValueLengthField.Write16(os); + } + else if ( TagField == Tag(0x7fe0,0x0010) ) + { + const VR ob = VR::OB; + ob.Write(os); + ValueLengthField.Write(os); + } else { const VR un = VR::UN; diff --git a/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.cxx b/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.cxx index 75efd43..f86b465 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.cxx @@ -71,9 +71,10 @@ void FileMetaInformation::AppendImplementationClassUID(const char * imp) { if( imp ) { - ImplementationClassUID = GetGDCMImplementationClassUID(); - ImplementationClassUID += "."; - ImplementationClassUID += imp; + std::string tmp = GetGDCMImplementationClassUID(); + tmp += "."; + tmp += imp; + if( tmp.size() <= 64 ) { ImplementationClassUID = tmp; } } } @@ -287,7 +288,7 @@ void FileMetaInformation::FillFromDataSet(DataSet const &ds) { // Very bad !! //throw Exception( "No (0002,0010) element found" ); - // Constuct it from DataSetTS + // Construct it from DataSetTS if( DataSetTS == TransferSyntax::TS_END ) { throw gdcm::Exception( "No TransferSyntax specified." ); @@ -358,7 +359,7 @@ void FileMetaInformation::FillFromDataSet(DataSet const &ds) } // FIXME -// This code should clearly be rewritten with some template meta programing to +// This code should clearly be rewritten with some template meta-programming to // enable reuse of code... // // \postcondition after the file meta information (well before the dataset...) @@ -704,7 +705,7 @@ std::istream &FileMetaInformation::ReadCompat(std::istream &is) #define ADDVRIMPLICIT( element ) \ case element: \ de.SetVR( (VR::VRType)TagToType<0x0002,element>::VRType ); \ - break; + break bool AddVRToDataElement(DataElement &de) { diff --git a/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.h b/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.h index 3ea40fe..4209396 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmFileMetaInformation.h @@ -100,6 +100,13 @@ public: MetaInformationTS = fmi.MetaInformationTS; DataSetMS = fmi.DataSetMS; } + FileMetaInformation& operator=(const FileMetaInformation& fmi) + { + DataSetTS = fmi.DataSetTS; + MetaInformationTS = fmi.MetaInformationTS; + DataSetMS = fmi.DataSetMS; + return *this; + } VL GetFullLength() const { return P.GetLength() + DataSet::GetLength(); diff --git a/Source/DataStructureAndEncodingDefinition/gdcmFragment.h b/Source/DataStructureAndEncodingDefinition/gdcmFragment.h index 42a88b3..576585f 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmFragment.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmFragment.h @@ -70,15 +70,13 @@ public: { // BogusItemStartItemEnd.dcm throw Exception( "Problem #1" ); - return is; } if( !ValueLengthField.Read(is) ) { // GENESIS_SIGNA-JPEG-CorruptFrag.dcm - // JPEG fragment is declared to have 61902, but infact really is only 61901 + // JPEG fragment is declared to have 61902, but in fact really is only 61901 // so we end up reading 0xddff,0x00e0, and VL = 0x0 (1 byte) throw Exception( "Problem #2" ); - return is; } #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION if( TagField != itemStart && TagField != seqDelItem ) @@ -107,7 +105,6 @@ public: ParseException pe; pe.SetLastElement( *this ); throw pe; - return is; } ValueField = bv; return is; @@ -136,7 +133,6 @@ public: { gdcmErrorMacro( "Giving up" ); throw "Impossible to backtrack"; - return is; } } else @@ -162,7 +158,6 @@ public: ParseException pe; pe.SetLastElement( *this ); throw pe; - return is; } ValueField = bv; return is; diff --git a/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.txx b/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.txx index 72fa99c..b7dfade 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.txx +++ b/Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.txx @@ -538,6 +538,9 @@ const std::ostream &ImplicitDataElement::Write(std::ostream &os) const return os; } // Write Value Length + // The following code should always work since we are in the case of IVRLE - CP246 + // however broken file such as PET-GE-dicomwrite-PixelDataSQUNv2.dcm breaks this assumption right here: + // see bug #502 const SequenceOfItems *sqi = dynamic_cast( ValueField.GetPointer() ); //GetSequenceOfItems(); if( sqi && !ValueLengthField.IsUndefined() ) { diff --git a/Source/DataStructureAndEncodingDefinition/gdcmItem.h b/Source/DataStructureAndEncodingDefinition/gdcmItem.h index 6fd9a6d..6638aa3 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmItem.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmItem.h @@ -34,7 +34,7 @@ class DataSet; * Sequence of Items. * An Item contains a Data Set . * See PS 3.5 7.5.1 Item Encoding Rules - * Each Item of a Data Element of VR SQ shall be encoded as a DICOM Standart + * Each Item of a Data Element of VR SQ shall be encoded as a DICOM Standard * Data Element with a specific Data Element Tag of Value (FFFE,E000). The Item * Tag is followed by a 4 byte Item Length field encoded in one of the * following two ways Explicit/ Implicit @@ -123,7 +123,7 @@ public: return is; } // Self - // Some file written by GDCM 1.0 we writting 0xFFFFFFFF instead of 0x0 + // Some file written by GDCM 1.0 we write 0xFFFFFFFF instead of 0x0 if( TagField == Tag(0xfffe,0xe0dd) ) { if( ValueLengthField ) @@ -251,7 +251,7 @@ public: // Not sure how this happen if( TagField == Tag(0xfffe, 0xe0dd) ) { - gdcmWarningMacro( "SegDelItem found in defined length Sequence" ); + gdcmWarningMacro( "SeqDelItem found in defined length Sequence" ); assert( ValueLengthField == 0 ); assert( NestedDataSet.Size() == 0 ); } diff --git a/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.cxx b/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.cxx index e080f51..dc63307 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.cxx @@ -145,6 +145,11 @@ static const char *MSStrings[] = { "1.2.840.10008.5.1.4.1.1.128.1", // Legacy Converted Enhanced PET Image Storage "1.2.840.10008.5.1.4.1.1.13.1.4", // Breast Projection X-Ray Image Storage - For Presentation "1.2.840.10008.5.1.4.1.1.13.1.5", // Breast Projection X-Ray Image Storage - For Processing + "1.2.840.10008.5.1.1.30", // HardcopyColorImageStorage + "1.2.840.10008.5.1.4.1.1.4.3", // EnhancedMRColorImageStorage + "1.2.392.200036.9125.1.1.4", // FujiPrivateMammoCRImageStorage (aka FUJI MAMMO CR Storage) + "1.2.840.10008.5.1.4.1.1.77.1.5.2", // Ophthalmic Photography 16 Bit Image Storage + "1.2.840.10008.5.1.4.1.1.77.1.2.1", // VideoMicroscopicImageStorage nullptr }; @@ -320,7 +325,7 @@ static const MSModalityType MSModalityTypes[] = { {"ES", 2, false},// VLEndoscopicImageStorage {"MG", 3, false},// BreastTomosynthesisImageStorage {"CR", 2, false},// FujiPrivateCRImageStorage - {"OP", 2, false},// OphthalmicPhotography8BitImageStorage + {"OP", 3, false},// OphthalmicPhotography8BitImageStorage {"OPT", 3, false},// OphthalmicTomographyImageStorage {"GM", 3, false},// VLMicroscopicImageStorage {"PT", 3, false},//EnhancedPETImageStorage, @@ -328,11 +333,16 @@ static const MSModalityType MSModalityTypes[] = { {"DX", 3, false},// XRay3DCraniofacialImageStorage {"IVOCT", 3, false},// IVOCTForPresentation, {"IVOCT", 3, false},// IVCOTForProcessing, - {"CT", 3, false},//LegacyConvertedEnhancedCTImageStorage, - {"MR", 3, false},//LegacyConvertedEnhancedMRImageStorage, - {"PT", 3, false},//LegacyConvertedEnhancedPETImageStorage, - {"MG", 3, false},//BreastProjectionXRayImageStorageForPresentation - {"MG", 3, false},//BreastProjectionXRayImageStorageForProcessing + {"CT", 3, false},// LegacyConvertedEnhancedCTImageStorage, + {"MR", 3, false},// LegacyConvertedEnhancedMRImageStorage, + {"PT", 3, false},// LegacyConvertedEnhancedPETImageStorage, + {"MG", 3, false},// BreastProjectionXRayImageStorageForPresentation + {"MG", 3, false},// BreastProjectionXRayImageStorageForProcessing + {"HC", 2, false},// HardcopyGrayscaleImageStorage + {"MR", 3, false},// EnhancedMRColorImageStorage + {"MG", 2, false},// FujiPrivateMammoCRImageStorage + {"OP", 3, false},// OphthalmicPhotography16BitImageStorage + {"GM", 3, false},// VideoMicroscopicImageStorage {nullptr, 0, false} //MS_END }; @@ -393,15 +403,14 @@ void MediaStorage::GuessFromModality(const char *modality, unsigned int dim ) } } -const char* MediaStorage::GetFromDataSetOrHeader(DataSet const &ds, const Tag & tag) +std::string MediaStorage::GetFromDataSetOrHeader(DataSet const &ds, const Tag & tag) { - static std::string ret; if( ds.FindDataElement( tag ) ) { const ByteValue *sopclassuid = ds.GetDataElement( tag ).GetByteValue(); // Empty SOP Class UID: // lifetechmed/A0038329.DCM - if( !sopclassuid || !sopclassuid->GetPointer() ) return nullptr; + if( !sopclassuid || !sopclassuid->GetPointer() ) return std::string(); std::string sopclassuid_str( sopclassuid->GetPointer(), sopclassuid->GetLength() ); @@ -411,18 +420,17 @@ const char* MediaStorage::GetFromDataSetOrHeader(DataSet const &ds, const Tag & std::string::size_type pos = sopclassuid_str.find_last_of(' '); sopclassuid_str = sopclassuid_str.substr(0,pos); } - ret = sopclassuid_str.c_str(); - return ret.c_str(); + return sopclassuid_str; } - return nullptr; + return std::string(); } bool MediaStorage::SetFromDataSetOrHeader(DataSet const &ds, const Tag & tag) { - const char * ms_str = GetFromDataSetOrHeader(ds,tag); - if( ms_str ) + std::string ms_str = GetFromDataSetOrHeader(ds,tag); + if( !ms_str.empty() ) { - MediaStorage ms = MediaStorage::GetMSType(ms_str); + MediaStorage ms = MediaStorage::GetMSType(ms_str.c_str()); MSField = ms; if( ms == MS_END ) { @@ -434,7 +442,7 @@ bool MediaStorage::SetFromDataSetOrHeader(DataSet const &ds, const Tag & tag) return false; } -const char* MediaStorage::GetFromHeader(FileMetaInformation const &fmi) +std::string MediaStorage::GetFromHeader(FileMetaInformation const &fmi) { const Tag tmediastoragesopclassuid(0x0002, 0x0002); return GetFromDataSetOrHeader(fmi, tmediastoragesopclassuid); @@ -446,7 +454,7 @@ bool MediaStorage::SetFromHeader(FileMetaInformation const &fmi) return SetFromDataSetOrHeader(fmi, tmediastoragesopclassuid); } -const char* MediaStorage::GetFromDataSet(DataSet const &ds) +std::string MediaStorage::GetFromDataSet(DataSet const &ds) { const Tag tsopclassuid(0x0008, 0x0016); return GetFromDataSetOrHeader(ds, tsopclassuid); @@ -547,38 +555,24 @@ bool MediaStorage::SetFromFile(File const &file) * are a pain to handle ... */ const FileMetaInformation &header = file.GetHeader(); - const char* header_ms_ptr = GetFromHeader(header); - std::string copy1; - const char *header_ms_str = nullptr; - if( header_ms_ptr ) - { - copy1 = header_ms_ptr; - header_ms_str = copy1.c_str(); - } + std::string header_ms_str = GetFromHeader(header); const DataSet &ds = file.GetDataSet(); - const char* ds_ms_ptr = GetFromDataSet(ds); - std::string copy2; - const char *ds_ms_str = nullptr; - if( ds_ms_ptr ) - { - copy2 = ds_ms_ptr; - ds_ms_str = copy2.c_str(); - } + std::string ds_ms_str = GetFromDataSet(ds); // Easy case: - if( header_ms_str && ds_ms_str && strcmp(header_ms_str, ds_ms_str) == 0 ) + if( !header_ms_str.empty() && !ds_ms_str.empty() && (header_ms_str == ds_ms_str) ) { return SetFromHeader( header ); } - if( ds_ms_str ) + if( !ds_ms_str.empty() ) { // means either no header ms or different, take from dataset just in case return SetFromDataSet( ds ); } // Looks suspicious or DICOMDIR... - if( header_ms_str ) + if( !header_ms_str.empty() ) { return SetFromHeader( header ); } diff --git a/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.h b/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.h index cb06b1e..8952d19 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmMediaStorage.h @@ -138,6 +138,11 @@ public: LegacyConvertedEnhancedPETImageStorage, BreastProjectionXRayImageStorageForPresentation, BreastProjectionXRayImageStorageForProcessing, + HardcopyColorImageStorage, + EnhancedMRColorImageStorage, + FujiPrivateMammoCRImageStorage, + OphthalmicPhotography16BitImageStorage, + VideoMicroscopicImageStorage, MS_END } MSType; // Media Storage Type @@ -197,12 +202,10 @@ protected: private: bool SetFromDataSetOrHeader(DataSet const &ds, const Tag & tag); - /// NOT THREAD SAFE - const char* GetFromDataSetOrHeader(DataSet const &ds, const Tag & tag); - /// NOT THREAD SAFE - const char* GetFromHeader(FileMetaInformation const &fmi); - /// NOT THREAD SAFE - const char* GetFromDataSet(DataSet const &ds); + + std::string GetFromDataSetOrHeader(DataSet const &ds, const Tag & tag); + std::string GetFromHeader(FileMetaInformation const &fmi); + std::string GetFromDataSet(DataSet const &ds); private: MSType MSField; diff --git a/Source/DataStructureAndEncodingDefinition/gdcmMrProtocol.cxx b/Source/DataStructureAndEncodingDefinition/gdcmMrProtocol.cxx index 3b000dd..046ca32 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmMrProtocol.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmMrProtocol.cxx @@ -16,13 +16,18 @@ #include #include +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define snprintf _snprintf +#endif + + namespace gdcm { struct MrProtocol::Element { }; -typedef std::map< std::string, std::string > MyMapType; +using MyMapType = std::map; struct MrProtocol::Internals { MyMapType mymap; std::string csastr; @@ -55,14 +60,19 @@ bool MrProtocol::Load( const ByteValue * bv, const char * csastr, int version ) // ### ASCCONV BEGIN ### // as well as: // ### ASCCONV BEGIN object=MrProtDataImpl@MrProtocolData version=41310008 converter=%MEASCONST%/ConverterList/Prot_Converter.txt ### + // and + // "### ASCCONV BEGIN object=MrProtDataImpl@MrProtocolData version=51130001 converter=%MEASCONST%/ConverterList/Prot_Converter.txt ### static const char begin[] = "### ASCCONV BEGIN "; + static const char begin2[] = "\"### ASCCONV BEGIN "; static const char end[] = "### ASCCONV END ###"; bool hasstarted = false; while( std::getline(is, s ) ) { if( !hasstarted ) { - hasstarted = starts_with(s, begin); + // syngo E11C does not write on begin of line anymore + s.erase(0, s.find_first_not_of(' ')); + hasstarted = starts_with(s, begin) || starts_with(s, begin2); if( hasstarted ) { if( version == -1 ) { // find version if not specified: @@ -186,7 +196,7 @@ bool MrProtocol::GetSliceArray( MrProtocol::SliceArray & sa ) const double v[3]; for( int j = 0; j < 3; ++j ) { - sprintf( buf, templ1, i, dir[j] ); + snprintf( buf, sizeof(buf), templ1, i, dir[j] ); const char * valstr = GetMrProtocolByName(buf); // when not present this means 0.0 double val = 0.0; @@ -202,7 +212,7 @@ bool MrProtocol::GetSliceArray( MrProtocol::SliceArray & sa ) const double v[3]; for( int j = 0; j < 3; ++j ) { - sprintf( buf, templ2, i, dir[j] ); + snprintf( buf, sizeof(buf), templ2, i, dir[j] ); const char * valstr = GetMrProtocolByName(buf); // when not present this means 0.0 double val = 0.0; diff --git a/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.cxx b/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.cxx index 20f72da..9098651 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.cxx @@ -162,6 +162,7 @@ int PDBHeader::readprotocoldatablock(const char *input, size_t inputlen, bool ve uint32_t len; // = *(const uint32_t*)input; memcpy(&len, input, sizeof len); SwapperNoOp::SwapArray(&len,1); + uint32_t offset = 4; //if( verbose ) // std::cout << len << "," << inputlen << std::endl; if( len + 4 + 1 == inputlen ) @@ -177,11 +178,20 @@ int PDBHeader::readprotocoldatablock(const char *input, size_t inputlen, bool ve else { //std::cerr << "Found the Protocol Data Block but could not read length..." << std::endl; - return 1; + if( len == 0x8088b1f ) + { + offset = 0; + len = (uint32_t)inputlen; + } + else + { + gdcmWarningMacro("Unhandled Protocol Data Block magic value: " << len ); + return 1; + } } // Alright we need to check if the binary blob was padded, if padded we need to // discard the trailing \0 to please gzip: - std::string str( input + 4, input + len ); + std::string str( input + offset, input + len ); std::istringstream is( str ); zlib_stream::zip_istream gzis( is ); @@ -196,7 +206,7 @@ int PDBHeader::readprotocoldatablock(const char *input, size_t inputlen, bool ve // We need to handle the old format and the new XML format here: // test: // - static const char xmlstr[] = ""; + static const char xmlstr[] = R"()"; bool isxml = false; while( std::getline(gzis, out) ) { diff --git a/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.h b/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.h index 5f552c1..5d26684 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmPDBHeader.h @@ -46,6 +46,8 @@ class PrivateTag; * * \warning: the API of this class might change. * + * \warning: SEDESC is not always pure ASCII it can contains latin1 + * * \see CSAHeader */ class GDCM_EXPORT PDBHeader diff --git a/Source/DataStructureAndEncodingDefinition/gdcmParseException.h b/Source/DataStructureAndEncodingDefinition/gdcmParseException.h index a72dd2a..ffdc43e 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmParseException.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmParseException.h @@ -36,17 +36,19 @@ namespace gdcm_ns class ParseException : public Exception { public: - ParseException() - = default; + ParseException() = default; ~ParseException() throw() override {}; /** Assignment operator. */ ParseException &operator= ( const ParseException &orig ) { - (void)orig; - //TODO + LastElement = orig.LastElement; return *this; } + ParseException(const ParseException& orig):Exception(orig) + { + LastElement = orig.LastElement; + } /** Equivalence operator. */ /* virtual bool operator==( const ParseException &orig ) diff --git a/Source/DataStructureAndEncodingDefinition/gdcmParser.h b/Source/DataStructureAndEncodingDefinition/gdcmParser.h index 175cc08..2ae5573 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmParser.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmParser.h @@ -26,7 +26,7 @@ namespace gdcm /** * \brief Parser ala XML_Parser from expat (SAX) * - * \details Detailled description here + * \details Detailed description here * \note Simple API for DICOM */ class GDCM_EXPORT Parser /*: private IStream*/ diff --git a/Source/DataStructureAndEncodingDefinition/gdcmPreamble.cxx b/Source/DataStructureAndEncodingDefinition/gdcmPreamble.cxx index bb6e77b..213e3e9 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmPreamble.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmPreamble.cxx @@ -29,7 +29,7 @@ Preamble::~Preamble() std::istream &Preamble::Read(std::istream &is) { - // \precondition: we are at beg of Preamble + // \precondition: we are at beginning of Preamble gdcmAssertAlwaysMacro( !IsEmpty() /*&& is.tellg() == 0*/ ); if( is.read(Internal, 128+4) ) { @@ -47,7 +47,7 @@ std::istream &Preamble::Read(std::istream &is) Internal = nullptr; throw Exception( "Not a DICOM V3 file (No Preamble)" ); - // \postcondition we are after the Preamble (or at beg of file if none) + // \postcondition we are after the Preamble (or at the beginning of file if none) } void Preamble::Valid() @@ -79,7 +79,7 @@ std::ostream const &Preamble::Write(std::ostream &os) const os.write( Internal, 128+4); } - // \postcondition a valid Preamble has been writen to stream + // \postcondition a valid Preamble has been written to stream return os; } diff --git a/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.cxx b/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.cxx index 44917f6..00d457a 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.cxx @@ -24,22 +24,27 @@ namespace gdcm_ns { if( !str ) return false; unsigned int group = 0, element = 0; - std::string owner; - owner.resize( strlen(str) ); // str != NULL - if( sscanf(str, "%04x,%04x,%[^\"]", &group , &element, &owner[0] ) != 3 + int nchar = -1; + if( sscanf(str, "%04x,%04x,%n", &group , &element, &nchar ) != 2 + || nchar == -1 || group > std::numeric_limits::max() || element > std::numeric_limits::max() + || group % 2 == 0 /*|| strlen(owner.c_str()) == 0*/ ) // can't use owner.empty() { - gdcmDebugMacro( "Problem reading Private Tag: " << str ); + // comment out the following since too verbose + //gdcmDebugMacro( "Problem reading Private Tag: " << str ); return false; } SetGroup( (uint16_t)group ); // This is not considered an error to specify element as 1010 for example. // just keep the lower bits of element: SetElement( (uint8_t)element ); - SetOwner( owner.c_str() ); - if( !*GetOwner() ) + const char *owner = str + nchar; + SetOwner( owner ); + const bool hasBackslash = strchr(owner,'\\') != NULL; + const char * creator = GetOwner(); + if( !*creator || hasBackslash ) { gdcmDebugMacro( ": " << str ); return false; diff --git a/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.h b/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.h index 6194373..84b6fea 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmPrivateTag.h @@ -51,6 +51,30 @@ public: const char *GetOwner() const { return Owner.c_str(); } void SetOwner(const char *owner) { if(owner) Owner = LOComp::Trim(owner); } + PrivateTag &operator=(const PrivateTag &_val) + { + SetElementTag( _val.GetElementTag() ); + Owner = _val.Owner; + return *this; + } + + bool operator==(const Tag &_val) const + { + return GetElementTag() == _val.GetElementTag(); + } + bool operator==(const PrivateTag &_val) const + { + return GetElementTag() == _val.GetElementTag() && Owner == _val.Owner; + } + bool operator!=(const Tag &_val) const + { + return GetElementTag() != _val.GetElementTag(); + } + bool operator!=(const PrivateTag &_val) const + { + return GetElementTag() != _val.GetElementTag() || Owner != _val.Owner; + } + bool operator<(const PrivateTag &_val) const; /// Read PrivateTag from a string. Element number will be truncated diff --git a/Source/DataStructureAndEncodingDefinition/gdcmReader.cxx b/Source/DataStructureAndEncodingDefinition/gdcmReader.cxx index fc57bbc..6b9d584 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmReader.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmReader.cxx @@ -172,7 +172,7 @@ TransferSyntax Reader::GuessTransferSyntax() { nts = TransferSyntax::Implicit; // We are reading a private creator (0x0010) so it's LO, it's - // difficult to come up with someting to check, maybe that + // difficult to come up with something to check, maybe that // VL < 256 ... gdcmWarningMacro( "Very dangerous assertion needs some work" ); } @@ -735,6 +735,8 @@ static inline bool isasciiupper( char c ) { // scope of this function. bool Reader::CanRead() const { + if( !Stream ) return false; + // fastpath std::istream &is = *Stream; if( is.bad() ) return false; @@ -827,78 +829,16 @@ bool Reader::CanRead() const return false; } -#ifdef _MSC_VER -namespace { -static inline std::wstring ToUtf16(std::string const & str) { - std::wstring ret; - int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), nullptr, 0); - if (len > 0) { - ret.resize(len); - MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), &ret[0], len); - } - return ret; -} -// http://arsenmk.blogspot.com/2015/12/handling-long-paths-on-windows.html -static inline bool ComputeFullPath(std::wstring const &in, std::wstring &out) { - // consider an input fileName of type PCWSTR (const wchar_t*) - const wchar_t *fileName = in.c_str(); - DWORD requiredBufferLength = GetFullPathNameW(fileName, 0, nullptr, nullptr); - - if (0 == requiredBufferLength) // means failure - { - return false; - } - - out.resize(requiredBufferLength); - wchar_t *buffer = &out[0]; - - DWORD result = - GetFullPathNameW(fileName, requiredBufferLength, buffer, nullptr); - - if (0 == result) { - return false; - } - - // buffer now contains the full path name of fileName, use it. - return true; -} - -static inline std::wstring HandleMaxPath(std::wstring const &in) { - if (in.size() >= MAX_PATH) { - std::wstring out; - bool ret = ComputeFullPath(in, out); - if (!ret) return in; - if (out.size() < 4) return in; - if (out[0] == '\\' && out[1] == '\\' && out[2] == '?') { - // nothing to do - } else if (out[0] == '\\' && out[1] == '\\' && out[2] != '?') { - // server path - const std::wstring prefix = LR"(\\?\UNC\)"; - out = prefix + (out.c_str() + 2); - } else { - // regular C:\ style path: - assert(out[1] == ':'); - const std::wstring prefix = LR"(\\?\)"; - out = prefix + out.c_str(); - } - return out; - } - return in; -} -} // namespace -#endif - -void Reader::SetFileName(const char *uft8path) +void Reader::SetFileName(const char *utf8path) { if(Ifstream) delete Ifstream; Ifstream = new std::ifstream(); - if (uft8path && *uft8path) { + if (utf8path && *utf8path) { #ifdef _MSC_VER - const std::wstring uft16path = ToUtf16(uft8path); - const std::wstring uncpath = HandleMaxPath(uft16path); + const std::wstring uncpath = System::ConvertToUNC(utf8path); Ifstream->open(uncpath.c_str(), std::ios::binary); #else - Ifstream->open( uft8path, std::ios::binary); + Ifstream->open( utf8path, std::ios::binary); #endif } if( Ifstream->is_open() ) diff --git a/Source/DataStructureAndEncodingDefinition/gdcmReader.h b/Source/DataStructureAndEncodingDefinition/gdcmReader.h index 0936be5..1c405ab 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmReader.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmReader.h @@ -28,7 +28,7 @@ namespace gdcm_ns * formedness check only, and to some extent catch known error (non * well-formed document). * - * Detailled description here + * Detailed description here * * A DataSet DOES NOT contains group 0x0002 (see FileMetaInformation) * @@ -120,6 +120,12 @@ private: TransferSyntax GuessTransferSyntax(); std::istream *Stream; std::ifstream *Ifstream; + + // prevent copy/move to avoid 2 ifstream leak + Reader(const Reader &) = delete; + Reader &operator=(const Reader &) = delete; + Reader(const Reader &&) = delete; + Reader &operator=(const Reader &&) = delete; }; /** diff --git a/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.cxx b/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.cxx index 125b6be..d756ed5 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.cxx @@ -50,7 +50,7 @@ VL SequenceOfFragments::ComputeLength() const length += fraglen; } assert( SequenceLengthField.IsUndefined() ); - length += 8; // seq end delimitor (tag + vl) + length += 8; // seq end delimiter (tag + vl) return length; } diff --git a/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h b/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h index 8868d40..791a77e 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfFragments.h @@ -60,7 +60,7 @@ public: /// \brief Appends a Fragment to the already added ones void AddFragment(Fragment const &item); - // Compute the length of all fragments (and framents only!). + // Compute the length of all fragments (and fragments only!). // Basically the size of the PixelData as stored (in bytes). unsigned long ComputeByteLength() const; diff --git a/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.h b/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.h index 06ec32e..3eae247 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.h @@ -148,7 +148,7 @@ public: #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION if( item.GetTag() == seqDelItem ) { - gdcmWarningMacro( "SegDelItem found in defined length Sequence. Skipping" ); + gdcmWarningMacro( "SeqDelItem found in defined length Sequence. Skipping" ); assert( item.GetVL() == 0 ); assert( item.GetNestedDataSet().Size() == 0 ); // we need to pay attention that the length of the Sequence of Items will be wrong @@ -166,7 +166,7 @@ public: l += item.template GetLength(); if( l > SequenceLengthField ) { - gdcmDebugMacro( "Found: Length of Item larger than expected" ) + gdcmDebugMacro( "Found: Length of Item larger than expected" ); throw "Length of Item larger than expected"; } assert( l <= SequenceLengthField ); diff --git a/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.txx b/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.txx index 8a0b2ef..3dc251e 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.txx +++ b/Source/DataStructureAndEncodingDefinition/gdcmSequenceOfItems.txx @@ -28,7 +28,7 @@ VL SequenceOfItems::ComputeLength() const } if( SequenceLengthField.IsUndefined() ) { - length += 8; // item end delimitor (tag + vl) + length += 8; // item end delimiter (tag + vl) } // For defined length SQ, make sure computation is correct (compare // to original length) diff --git a/Source/DataStructureAndEncodingDefinition/gdcmTag.cxx b/Source/DataStructureAndEncodingDefinition/gdcmTag.cxx index b55879f..a4f5d40 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmTag.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmTag.cxx @@ -23,7 +23,7 @@ namespace gdcm unsigned int group = 0, element = 0; if( !str || sscanf(str, "%04x,%04x", &group , &element) != 2 ) { - gdcmDebugMacro( "Problem reading Tag: " << str ); + //gdcmDebugMacro( "Problem reading Tag: " << str ); return false; } SetGroup( (uint16_t)group ); diff --git a/Source/DataStructureAndEncodingDefinition/gdcmTag.h b/Source/DataStructureAndEncodingDefinition/gdcmTag.h index 8abfe03..dc21df3 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmTag.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmTag.h @@ -114,7 +114,7 @@ public: // FIXME FIXME FIXME TODO // the following is pretty dumb. Since we have control over who is group // and who is element, we should reverse them in little endian and big endian case - // since what we really want is fast comparison and not garantee that group is in #0 + // since what we really want is fast comparison and not guarantee that group is in #0 // ... bool operator<(const Tag &_val) const { @@ -237,7 +237,7 @@ public: } /// Read from a comma separated string. - /// This is a highly user oriented function, the string should be formated as: + /// This is a highly user oriented function, the string should be formatted as: /// 1234,5678 to specify the tag (0x1234,0x5678) /// The notation comes from the DICOM standard, and is handy to use from a /// command line program diff --git a/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.cxx b/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.cxx index 9c8cf14..437504c 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.cxx @@ -175,7 +175,7 @@ bool TransferSyntax::IsLossy() const // transfer syntax. If you use the JPEG compression algorithm (ITU-T T.81, // ISO/IEC IS 10918-1), You will not be able to declare a lossy compress pixel // data using JPEGLosslessProcess14_1 For the same reason using J2K (ITU-T -// T.800, ISO/IEC IS 15444-1), you shoult not be allowed to stored an +// T.800, ISO/IEC IS 15444-1), you should not be allowed to stored an // irreversible wavelet compressed pixel data in a file declared with transfer // syntax JPEG2000Lossless. // Same goes for JPEG-LS (ITU-T T.87, ISO/IEC IS 14495-1), and to some extent diff --git a/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.h b/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.h index 51fcdf9..8be7a3e 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmTransferSyntax.h @@ -46,7 +46,7 @@ public: } NegociatedType; #if 0 - //NOT FLEXIBLE, since force user to update lib everytime new module + //NOT FLEXIBLE, since forces user to update lib every time new module //comes out... // TODO typedef enum { diff --git a/Source/DataStructureAndEncodingDefinition/gdcmVL.h b/Source/DataStructureAndEncodingDefinition/gdcmVL.h index c4d5ec5..764707b 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmVL.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmVL.h @@ -73,7 +73,7 @@ public: friend std::ostream& operator<<(std::ostream& os, const VL& vl); - // PURPOSELY not implemented (could not differenciate 16bits vs 32bits VL) + // PURPOSELY not implemented (could not differentiate 16bits vs 32bits VL) //friend std::istream& operator>>(std::istream& is, VL& n); template diff --git a/Source/DataStructureAndEncodingDefinition/gdcmVR.cxx b/Source/DataStructureAndEncodingDefinition/gdcmVR.cxx index 746078e..3bc0326 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmVR.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmVR.cxx @@ -369,7 +369,7 @@ VR::VRType VR::GetVRTypeFromFile(const char *vr) assert( r == (VR::VRType)(1 << (p-start)) ); #else // old version not optimized VRType r = VR::VR_END; - for (int i = 1; VRStrings[i] != NULL; i++) + for (int i = 1; VRStrings[i] != nullptr; i++) { const char *ref = VRStrings[i]; // Use lazy evaluation instead of strncmp diff --git a/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.h b/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.h index 035c2e9..61cbbb9 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.h @@ -21,7 +21,7 @@ namespace gdcm // Data Element (Explicit) /** * \brief Class to read/write a DataElement as Explicit Data Element - * \note This class support 16 bits when finding an unkown VR: + * \note This class support 16 bits when finding an unknown VR: * For instance: * Siemens_CT_Sensation64_has_VR_RT.dcm */ diff --git a/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.txx b/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.txx index 372780d..39b4706 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.txx +++ b/Source/DataStructureAndEncodingDefinition/gdcmVR16ExplicitDataElement.txx @@ -97,7 +97,7 @@ std::istream &VR16ExplicitDataElement::ReadPreValue(std::istream &is) // gdcm-MR-PHILIPS-16-Multi-Seq.dcm if( TagField == Tag(0xfffe, 0xe000) ) { - gdcmWarningMacro( "Found item delimitor in item" ); + gdcmWarningMacro( "Found item delimiter in item" ); ParseException pe; pe.SetLastElement( *this ); throw pe; diff --git a/Source/DataStructureAndEncodingDefinition/gdcmWriter.cxx b/Source/DataStructureAndEncodingDefinition/gdcmWriter.cxx index 636e707..bf15837 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmWriter.cxx +++ b/Source/DataStructureAndEncodingDefinition/gdcmWriter.cxx @@ -162,7 +162,7 @@ bool Writer::Write() return !os.fail(); } -void Writer::SetFileName(const char *filename) +void Writer::SetFileName(const char *utf8path) { //std::cerr << "Stream: " << filename << std::endl; //std::cerr << "Ofstream: " << Ofstream << std::endl; @@ -175,9 +175,17 @@ void Writer::SetFileName(const char *filename) delete Ofstream; } Ofstream = new std::ofstream(); - Ofstream->open(filename, std::ios::out | std::ios::binary ); - assert( Ofstream->is_open() ); - assert( !Ofstream->fail() ); + if (utf8path && *utf8path) + { +#ifdef _MSC_VER + const std::wstring uncpath = System::ConvertToUNC(utf8path); + Ofstream->open(uncpath.c_str(), std::ios::out | std::ios::binary); +#else + Ofstream->open(utf8path, std::ios::out | std::ios::binary); +#endif + assert(Ofstream->is_open()); + assert(!Ofstream->fail()); + } //std::cerr << Stream.is_open() << std::endl; Stream = Ofstream; } diff --git a/Source/DataStructureAndEncodingDefinition/gdcmWriter.h b/Source/DataStructureAndEncodingDefinition/gdcmWriter.h index 807619b..3b9acc4 100644 --- a/Source/DataStructureAndEncodingDefinition/gdcmWriter.h +++ b/Source/DataStructureAndEncodingDefinition/gdcmWriter.h @@ -26,7 +26,7 @@ class FileMetaInformation; * \details This class is a non-validating writer, it will only performs well- * formedness check only. * - * \details Detailled description here + * \details Detailed description here * To avoid GDCM being yet another broken DICOM lib we try to * be user level and avoid writing illegal stuff (odd length, * non-zero value for Item start/end length ...) @@ -36,7 +36,7 @@ class FileMetaInformation; * - Correct Meta Information Header (see gdcm::FileMetaInformation) * - Zero value for Item Length (0xfffe, 0xe00d/0xe0dd) * - Even length for any elements - * - Alphabetical order for elements (garanteed by design of internals) + * - Alphabetical order for elements (guaranteed by design of internals) * - 32bits VR will be rewritten with 00 * * \warning diff --git a/Source/InformationObjectDefinition/Part3.xml b/Source/InformationObjectDefinition/Part3.xml index 27bec75..6e6d9b7 100644 --- a/Source/InformationObjectDefinition/Part3.xml +++ b/Source/InformationObjectDefinition/Part3.xml @@ -2135,6 +2135,43 @@ Totally made up, do not copy: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Uniquely identifies the Study SOP Instances associated with the Patient SOP Instance. One or more Items may be included in this Sequence. @@ -2224,7 +2261,7 @@ Zero or more Items may be included in the sequence. The sequence items are order - A modifer for a Patient's Primary Language. Can be used to specify a national language variant. + A modifier for a Patient's Primary Language. Can be used to specify a national language variant. Exactly one Item may be included in the sequence. @@ -3860,7 +3897,7 @@ The sequence may have one or more Items. A number that identifies this Series. Notes: 1. The value of this attribute should be unique for all series in a study created on the same equipment. -2. Because series can be created on more than one equipment, it can not be guranteed that the value of Series Number (0020,0011) is unique in a study. +2. Because series can be created on more than one equipment, it can not be guaranteed that the value of Series Number (0020,0011) is unique in a study. Uniquely identifies the Performed Procedure Step SOP Instance to which the Series is related (e.g. a Modality or General-Purpose Performed Procedure Step SOP Instance). Only a single Item is permitted in this sequence. @@ -5172,7 +5209,7 @@ Required if Concatenation UID (0020,9161) is present. Required if a group of multi-frame image SOP Instances within a Series are part of a Concatenation. - Identifier for one SOP Instance belonging to a concatenation. See C.7.6.16.2.2.4 for further specification. The first instance in a concatentation (that with the lowest Concatenation Frame Offset Number (0020,9228) value) shall have an In-concatenation Number (0020,9162) value of 1, and subsequent instances shall have values monotonically increasing by 1. + Identifier for one SOP Instance belonging to a concatenation. See C.7.6.16.2.2.4 for further specification. The first instance in a concatenation (that with the lowest Concatenation Frame Offset Number (0020,9228) value) shall have an In-concatenation Number (0020,9162) value of 1, and subsequent instances shall have values monotonically increasing by 1. Required if Concatenation UID (0020,9161) is present.
Due to implementation specific reasons (such as maximum object size) the information of a multi-frame image may be split into more than one SOP Instance. These SOP Instances form together a Concatenation. This is a group of SOP Instances within a Series that is uniquely identified by the Concatenation UID (0020,9161). The Dimension Index Sequence (0020,9222) for each SOP Instance with the same Concatenation UID (0020,9161) shall contain exactly the same tags and values. @@ -13033,7 +13070,7 @@ DOUBLE_SIDED = the Compensator has a shaped (i.e. non-flat) surface on both side Compensator Linear Stopping Power Ratio, relative to water, at the beam energy specified by the Nominal Beam Energy (300A,0114) of the first Control Point of the Ion Control Point Sequence (300A,03A8). - The diameter (in mm) of the milling tool to be used to create the compensator. The diameter is expressed as the actual physcial size and not a projected size at isocenter. + The diameter (in mm) of the milling tool to be used to create the compensator. The diameter is expressed as the actual physical size and not a projected size at isocenter. Number of boli associated with current Beam. @@ -13124,7 +13161,7 @@ SOURCE_SIDE = the block is mounted on the side of the Block Tray that is towards Defined Terms: ION_SQUARE = square ion applicator -ION_RECT = rectangluar ion applicator +ION_RECT = rectangular ion applicator ION_CIRC = circular ion applicator ION_SHORT = short ion applicator ION_OPEN = open (dummy) ion applicator @@ -13699,7 +13736,7 @@ Only a single item shall be permitted in this sequence. Defined Terms: ION_SQUARE = square ion applicator -ION_RECT = rectangluar ion applicator +ION_RECT = rectangular ion applicator ION_CIRC = circular ion applicator ION_SHORT = short ion applicator ION_OPEN = open (dummy) ion applicator @@ -14075,13 +14112,13 @@ c) Table Angle moves from 170 degrees to 160 degrees, Table Rotation Direction Introduces sequence of parameters that were overridden during the administration of the beam segment immediately prior to the current control point. The sequence may contain one or more items. - Contains the Data Element Tag of the parent sequence containing the attribute that was overriden. The value is limited in scope to the Treatment Session Ion Beam Sequence (3008,0021) and all nested sequences therein. + Contains the Data Element Tag of the parent sequence containing the attribute that was overridden. The value is limited in scope to the Treatment Session Ion Beam Sequence (3008,0021) and all nested sequences therein. Contains the Data Element Tag of the attribute that was overridden. - Contains the ones-based sequence item index of the overriden attributes within it's parent sequence. The value is limited in scope to the Treatment Session Ion Beam Sequence (3008,0021) and all nested sequences therein. + Contains the ones-based sequence item index of the overridden attributes within it's parent sequence. The value is limited in scope to the Treatment Session Ion Beam Sequence (3008,0021) and all nested sequences therein. Name of operator who authorized override. @@ -14955,7 +14992,7 @@ The application of the Window Center (0028,1050) and Window Width (0028,1051) sh Note: If the Presentation LUT Shape (2050,0020) is IDENTITY, then the result of applying the Window Center (0028,1050) and Window Width (0028,1051) is P-Values. If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views should be presented. -The VOI LUT Sequence specifes a (potentially non-linear) conversion from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. +The VOI LUT Sequence specifies a (potentially non-linear) conversion from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. If multiple items are present in VOI LUT Sequence (0028,3010), only one shall be applied. Multiple items indicate that multiple alternative views should be presented. If any VOI LUT Attributes are included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, shall be applied to the Image for display. Inclusion of both indicates that multiple alternative views should be presented. The three values of the LUT Descriptor (0028,3002) describe the format of the LUT Data (0028,3006). @@ -14978,7 +15015,7 @@ The application of the Window Center (0028,1050) and Window Width (0028,1051) sh Note: If the Presentation LUT Shape (2050,0020) is IDENTITY, then the result of applying the Window Center (0028,1050) and Window Width (0028,1051) is P-Values. If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views should be presented. -The VOI LUT Sequence specifes a (potentially non-linear) conversion from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. +The VOI LUT Sequence specifies a (potentially non-linear) conversion from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. If multiple items are present in VOI LUT Sequence (0028,3010), only one shall be applied. Multiple items indicate that multiple alternative views should be presented. If any VOI LUT Attributes are included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, shall be applied to the Image for display. Inclusion of both indicates that multiple alternative views should be presented. The three values of the LUT Descriptor (0028,3002) describe the format of the LUT Data (0028,3006). @@ -15008,7 +15045,7 @@ The application of the Window Center (0028,1050) and Window Width (0028,1051) sh Note: If the Presentation LUT Shape (2050,0020) is IDENTITY, then the result of applying the Window Center (0028,1050) and Window Width (0028,1051) is P-Values. If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views should be presented. -The VOI LUT Sequence specifes a (potentially non-linear) conversion from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. +The VOI LUT Sequence specifies a (potentially non-linear) conversion from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. If multiple items are present in VOI LUT Sequence (0028,3010), only one shall be applied. Multiple items indicate that multiple alternative views should be presented. If any VOI LUT Attributes are included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, shall be applied to the Image for display. Inclusion of both indicates that multiple alternative views should be presented. The three values of the LUT Descriptor (0028,3002) describe the format of the LUT Data (0028,3006). @@ -15030,7 +15067,7 @@ The application of the Window Center (0028,1050) and Window Width (0028,1051) sh Note: If the Presentation LUT Shape (2050,0020) is IDENTITY, then the result of applying the Window Center (0028,1050) and Window Width (0028,1051) is P-Values. If multiple values are present, both Attributes shall have the same number of values and shall be considered as pairs. Multiple values indicate that multiple alternative views should be presented. -The VOI LUT Sequence specifes a (potentially non-linear) conversion from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. +The VOI LUT Sequence specifies a (potentially non-linear) conversion from the output of the (conceptual) Modality LUT values to the input to the (conceptual) Presentation LUT. If multiple items are present in VOI LUT Sequence (0028,3010), only one shall be applied. Multiple items indicate that multiple alternative views should be presented. If any VOI LUT Attributes are included by an Image, a Window Width and Window Center or the VOI LUT Table, but not both, shall be applied to the Image for display. Inclusion of both indicates that multiple alternative views should be presented. The three values of the LUT Descriptor (0028,3002) describe the format of the LUT Data (0028,3006). @@ -20015,7 +20052,7 @@ Required if present and have an equal value in the contributing SOP Instances. - + A Sequence that identifies the set of Images that constitute this acquisition context. Required if the reconstruction is created from DICOM SOP Instances. @@ -20583,7 +20620,7 @@ Note: Values of 0\0 indicate that the overlay pixels start 1 row above and one c Number of Bits Allocated in the Overlay. -Tthe value of this Attribute shall be 1. +The value of this Attribute shall be 1. Note: Formerly the standard described embedding the overlay data in the Image Pixel Data (7FE0,0010), in which case the value of this Attribute was required to be the same as Bits Allocated (0028,0100). This usage has been retired. See PS 3.3 2004. @@ -22635,7 +22672,7 @@ BASIC FILM BOX PRESENTATION MODULE ATTRIBUTES Maximum density that can be printed, expressed in hundredths of OD. - A sequence which specifies combinations of Medium Type and Film Size ID for which the printer will accept an N-CREATE of a Film Box, but are not physically installed in the printer at this time. It also specifies the Min and Max Densities supported by these media. User intervention may be required to instal these media in the printer. + A sequence which specifies combinations of Medium Type and Film Size ID for which the printer will accept an N-CREATE of a Film Box, but are not physically installed in the printer at this time. It also specifies the Min and Max Densities supported by these media. User intervention may be required to install these media in the printer. One item for each Medium Type and Film Size ID available, but not installed shall be included. @@ -27554,7 +27591,7 @@ Notes: 1. The following attributes from image IODs are examples of some possibl Sequence that defines sorting criteria to be applied to the result of filter and reformat operations, to define the order in which to present the images in the Image Boxes. Zero or more items shall be included in this sequence. See C.23.3.1.2. -
The Items in the Sorting Operations Sequence (0072,0600) define the order in which the images resulting from the filter and reformat operations on the Image Set are to be displayed in the associated Image Boxes of the Display Set. The sorting criteria may include the value of a numeric, date, or time Attribute that is expected to be present in each of the image objects in the filtered Image Set, and/or an abstract sorting category. A sorting direction shall be associated with each sorting criterion. If a textual Attribute is used for sorting, then the INCREASING sorting direction indicates alpabetical order, and DECREASING indicates reverse alphabetical order. +
The Items in the Sorting Operations Sequence (0072,0600) define the order in which the images resulting from the filter and reformat operations on the Image Set are to be displayed in the associated Image Boxes of the Display Set. The sorting criteria may include the value of a numeric, date, or time Attribute that is expected to be present in each of the image objects in the filtered Image Set, and/or an abstract sorting category. A sorting direction shall be associated with each sorting criterion. If a textual Attribute is used for sorting, then the INCREASING sorting direction indicates alphabetical order, and DECREASING indicates reverse alphabetical order. If a code sequence Attribute is used for sorting, then the Code Meaning (0008,0104) shall be sorted alphabetically. If a string numeric Attribute is used for sorting (VR of IS or DS), then sorting shall be on the numeric value, and padding shall be ignored. When sorting by date or time Attribute, then sorting shall be on the temporal value, not the alphabetic string. If there are multiple Items in the Sorting Operations Sequence (0072,0600), then the sorting operations shall be applied in Item order. The least rapidly varying attribute for the sorting operation shall be the first Item in the sequence. Note: For example, a Sorting Operations Sequence (0072,0600) with two Items: @@ -27572,7 +27609,7 @@ Notes: 1. The following attributes from image IODs are examples of some possibl Data Element Tag of an Attribute from an Image IOD to be used for sorting. See C.23.3.1.2 for potential attributes. Required if Sort-by Category (0072,0602) is not present. -
The Items in the Sorting Operations Sequence (0072,0600) define the order in which the images resulting from the filter and reformat operations on the Image Set are to be displayed in the associated Image Boxes of the Display Set. The sorting criteria may include the value of a numeric, date, or time Attribute that is expected to be present in each of the image objects in the filtered Image Set, and/or an abstract sorting category. A sorting direction shall be associated with each sorting criterion. If a textual Attribute is used for sorting, then the INCREASING sorting direction indicates alpabetical order, and DECREASING indicates reverse alphabetical order. +
The Items in the Sorting Operations Sequence (0072,0600) define the order in which the images resulting from the filter and reformat operations on the Image Set are to be displayed in the associated Image Boxes of the Display Set. The sorting criteria may include the value of a numeric, date, or time Attribute that is expected to be present in each of the image objects in the filtered Image Set, and/or an abstract sorting category. A sorting direction shall be associated with each sorting criterion. If a textual Attribute is used for sorting, then the INCREASING sorting direction indicates alphabetical order, and DECREASING indicates reverse alphabetical order. If a code sequence Attribute is used for sorting, then the Code Meaning (0008,0104) shall be sorted alphabetically. If a string numeric Attribute is used for sorting (VR of IS or DS), then sorting shall be on the numeric value, and padding shall be ignored. When sorting by date or time Attribute, then sorting shall be on the temporal value, not the alphabetic string. If there are multiple Items in the Sorting Operations Sequence (0072,0600), then the sorting operations shall be applied in Item order. The least rapidly varying attribute for the sorting operation shall be the first Item in the sequence. Note: For example, a Sorting Operations Sequence (0072,0600) with two Items: @@ -27598,7 +27635,7 @@ Defined terms: ALONG_AXIS: for CT, MR, other cross-sectional image sets BY_ACQ_TIME Required if Selector Attribute (0072,0026) is not present. -
The Items in the Sorting Operations Sequence (0072,0600) define the order in which the images resulting from the filter and reformat operations on the Image Set are to be displayed in the associated Image Boxes of the Display Set. The sorting criteria may include the value of a numeric, date, or time Attribute that is expected to be present in each of the image objects in the filtered Image Set, and/or an abstract sorting category. A sorting direction shall be associated with each sorting criterion. If a textual Attribute is used for sorting, then the INCREASING sorting direction indicates alpabetical order, and DECREASING indicates reverse alphabetical order. +
The Items in the Sorting Operations Sequence (0072,0600) define the order in which the images resulting from the filter and reformat operations on the Image Set are to be displayed in the associated Image Boxes of the Display Set. The sorting criteria may include the value of a numeric, date, or time Attribute that is expected to be present in each of the image objects in the filtered Image Set, and/or an abstract sorting category. A sorting direction shall be associated with each sorting criterion. If a textual Attribute is used for sorting, then the INCREASING sorting direction indicates alphabetical order, and DECREASING indicates reverse alphabetical order. If a code sequence Attribute is used for sorting, then the Code Meaning (0008,0104) shall be sorted alphabetically. If a string numeric Attribute is used for sorting (VR of IS or DS), then sorting shall be on the numeric value, and padding shall be ignored. When sorting by date or time Attribute, then sorting shall be on the temporal value, not the alphabetic string. If there are multiple Items in the Sorting Operations Sequence (0072,0600), then the sorting operations shall be applied in Item order. The least rapidly varying attribute for the sorting operation shall be the first Item in the sequence. Note: For example, a Sorting Operations Sequence (0072,0600) with two Items: diff --git a/Source/InformationObjectDefinition/Template.xml.in b/Source/InformationObjectDefinition/Template.xml.in index 3197f73..3c5e0ca 100644 --- a/Source/InformationObjectDefinition/Template.xml.in +++ b/Source/InformationObjectDefinition/Template.xml.in @@ -1,8 +1,8 @@ +why we should repeat it. Type is compulsory and Description is not necessary either.--> - + diff --git a/Source/InformationObjectDefinition/gdcmDefs.cxx b/Source/InformationObjectDefinition/gdcmDefs.cxx index 3254643..956a2c5 100644 --- a/Source/InformationObjectDefinition/gdcmDefs.cxx +++ b/Source/InformationObjectDefinition/gdcmDefs.cxx @@ -55,6 +55,7 @@ void Defs::LoadFromFile(const char *filename) tr.Read(); } +// http://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_B.5.html#table_B.5-1 const char *Defs::GetIODNameFromMediaStorage(MediaStorage const &ms) { const char *iodname; @@ -232,12 +233,18 @@ const char *Defs::GetIODNameFromMediaStorage(MediaStorage const &ms) case MediaStorage::FujiPrivateCRImageStorage: iodname = "Fuji Private CR Image IOD Modules"; break; + case MediaStorage::FujiPrivateMammoCRImageStorage: + iodname = "Fuji Private Mammo CR Image IOD Modules"; + break; case MediaStorage::CSANonImageStorage: iodname = "Siemens Non-image IOD Modules"; break; case MediaStorage::VLMicroscopicImageStorage: iodname = "VL Microscopic Image IOD Modules"; break; + case MediaStorage::XRay3DCraniofacialImageStorage: + iodname = "X Ray 3D Craniofacial Image IOD Modules"; + break; default: iodname = nullptr; } diff --git a/Source/InformationObjectDefinition/gdcmDefs.h b/Source/InformationObjectDefinition/gdcmDefs.h index b2a462f..d80d646 100644 --- a/Source/InformationObjectDefinition/gdcmDefs.h +++ b/Source/InformationObjectDefinition/gdcmDefs.h @@ -41,7 +41,7 @@ public: Modules &GetModules() { return Part3Modules; } /// Users should not directly use Macro. Macro are simply a way for DICOM WG to re-use Tables. - /// Macros are conviently wraped within Modules. See gdcm::Module API directly + /// Macros are conveniently wrapped within Modules. See gdcm::Module API directly const Macros &GetMacros() const { return Part3Macros; } Macros &GetMacros() { return Part3Macros; } diff --git a/Source/InformationObjectDefinition/gdcmMacro.h b/Source/InformationObjectDefinition/gdcmMacro.h index dde90f1..dab3334 100644 --- a/Source/InformationObjectDefinition/gdcmMacro.h +++ b/Source/InformationObjectDefinition/gdcmMacro.h @@ -51,7 +51,7 @@ public: void Clear() { ModuleInternal.clear(); } - /// Will add a ModuleEntry direcly at root-level. See Macro for nested-included level. + /// Will add a ModuleEntry directly at root-level. See Macro for nested-included level. void AddMacroEntry(const Tag& tag, const MacroEntry & module) { ModuleInternal.insert( diff --git a/Source/InformationObjectDefinition/gdcmModule.h b/Source/InformationObjectDefinition/gdcmModule.h index 352442b..2df2315 100644 --- a/Source/InformationObjectDefinition/gdcmModule.h +++ b/Source/InformationObjectDefinition/gdcmModule.h @@ -52,7 +52,7 @@ public: void Clear() { ModuleInternal.clear(); } - /// Will add a ModuleEntry direcly at root-level. See Macro for nested-included level. + /// Will add a ModuleEntry directly at root-level. See Macro for nested-included level. void AddModuleEntry(const Tag& tag, const ModuleEntry & module) { ModuleInternal.insert( diff --git a/Source/InformationObjectDefinition/gdcmTableReader.cxx b/Source/InformationObjectDefinition/gdcmTableReader.cxx index 5daa2e4..fb08e67 100644 --- a/Source/InformationObjectDefinition/gdcmTableReader.cxx +++ b/Source/InformationObjectDefinition/gdcmTableReader.cxx @@ -72,7 +72,7 @@ void TableReader::HandleMacroEntryDescription(const char **atts) (void)atts; assert( ParsingMacroEntryDescription == false ); ParsingMacroEntryDescription = true; - assert( *atts == NULL ); + assert( *atts == nullptr ); assert( Description == "" ); } @@ -91,7 +91,7 @@ void TableReader::HandleModuleEntryDescription(const char **atts) (void)atts; assert( ParsingModuleEntryDescription == false ); ParsingModuleEntryDescription = true; - assert( *atts == NULL ); + assert( *atts == nullptr ); assert( Description == "" ); } @@ -586,7 +586,7 @@ int TableReader::Read() int ret = 0; do { is.read(buf, sizeof(buf)); - std::streamsize len = is.gcount(); + std::streamsize len = is.gcount(); done = (unsigned int)len < sizeof(buf); if (XML_Parse(parser, buf, (int)len, done) == XML_STATUS_ERROR) { fprintf(stderr, diff --git a/Source/InformationObjectDefinition/gdcmXMLDictReader.cxx b/Source/InformationObjectDefinition/gdcmXMLDictReader.cxx index 4cd18db..aab3c11 100644 --- a/Source/InformationObjectDefinition/gdcmXMLDictReader.cxx +++ b/Source/InformationObjectDefinition/gdcmXMLDictReader.cxx @@ -61,7 +61,7 @@ void XMLDictReader::HandleEntry(const char **atts) assert( v <= 0xFFFF ); char sv[4+1]; - r = sprintf(sv, "%04x", v); + r = snprintf(sv, sizeof(sv), "%04x", v); assert( r == 4 ); if( strncmp(raw, sv, 4) == 0 ) // GroupXX { @@ -84,7 +84,7 @@ void XMLDictReader::HandleEntry(const char **atts) assert( v <= 0xFFFF ); char sv[4+1]; - r = sprintf(sv, "%04x", v); + r = snprintf(sv, sizeof(sv), "%04x", v); assert( r == 4 ); if( strncmp(raw, sv, 4) == 0 ) { diff --git a/Source/InformationObjectDefinition/gdcmXMLPrivateDictReader.cxx b/Source/InformationObjectDefinition/gdcmXMLPrivateDictReader.cxx index 2f249ff..cb42c1d 100644 --- a/Source/InformationObjectDefinition/gdcmXMLPrivateDictReader.cxx +++ b/Source/InformationObjectDefinition/gdcmXMLPrivateDictReader.cxx @@ -62,7 +62,7 @@ void XMLPrivateDictReader::HandleEntry(const char **atts) assert( v <= 0xFFFF ); char sv[4+1]; - r = sprintf(sv, "%04x", v); + r = snprintf(sv, sizeof(sv), "%04x", v); assert( r == 4 ); if( strncmp(raw, sv, 4) == 0 ) // GroupXX { @@ -109,7 +109,7 @@ void XMLPrivateDictReader::HandleEntry(const char **atts) assert( v <= 0xFF ); char sv[4+1]; - r = sprintf(sv, "xx%02x", v); + r = snprintf(sv, sizeof(sv), "xx%02x", v); assert( r == 4 ); if( strncmp(raw, sv, 4) == 0 ) { diff --git a/Source/InformationObjectDefinition/getelements.xsl b/Source/InformationObjectDefinition/getelements.xsl index e538107..2d63366 100644 --- a/Source/InformationObjectDefinition/getelements.xsl +++ b/Source/InformationObjectDefinition/getelements.xsl @@ -1,7 +1,7 @@ - + + +