# HG changeset patch # User Alain Mazy # Date 1727170792 -7200 # Node ID 8279eaab0d1dd800aa7b0643dbcde2c8e5562a69 # Parent 79f98ee4f04b5c722f628957cc8a2dc8fde93a6e# Parent 16df205057106f4246107cfe45710e56324007e8 merged default -> attach-custom-data diff -r 79f98ee4f04b -r 8279eaab0d1d .hgignore --- a/.hgignore Thu Sep 15 18:13:17 2022 +0200 +++ b/.hgignore Tue Sep 24 11:39:52 2024 +0200 @@ -6,6 +6,7 @@ .vs/ .vscode/ *~ +*.cmake.orig # when opening Orthanc in VSCode, it might find a java project and create files we wan't to ignore: .settings/ diff -r 79f98ee4f04b -r 8279eaab0d1d AUTHORS --- a/AUTHORS Thu Sep 15 18:13:17 2022 +0200 +++ b/AUTHORS Tue Sep 24 11:39:52 2024 +0200 @@ -14,13 +14,19 @@ 4000 Liege Belgium -* Osimis S.A. +* Osimis S.A. Quai Banning 6 4000 Liege Belgium - http://www.osimis.io/ + +* Orthanc Team SRL + Rue Joseph Marchal 14 + 4910 Theux + Belgium + https://orthanc.team/ * ICTEAM, UCLouvain Place de l'Universite 1 1348 Ottignies-Louvain-la-Neuve Belgium + https://uclouvain.be/icteam diff -r 79f98ee4f04b -r 8279eaab0d1d CITATION.cff --- a/CITATION.cff Thu Sep 15 18:13:17 2022 +0200 +++ b/CITATION.cff Tue Sep 24 11:39:52 2024 +0200 @@ -9,6 +9,6 @@ given-names: "Sébastien" doi: "10.1007/s10278-018-0082-y" license: "GPL-3.0-or-later" -repository-code: "https://hg.orthanc-server.com/orthanc/" -version: 1.10.1 -date-released: 2022-03-23 +repository-code: "https://orthanc.uclouvain.be/hg/orthanc/" +version: 1.12.4 +date-released: 2024-06-05 diff -r 79f98ee4f04b -r 8279eaab0d1d LinuxCompilation.txt --- a/LinuxCompilation.txt Thu Sep 15 18:13:17 2022 +0200 +++ b/LinuxCompilation.txt Tue Sep 24 11:39:52 2024 +0200 @@ -161,7 +161,7 @@ uuid-dev libcurl4-openssl-dev liblua5.3-dev \ libgtest-dev libpng-dev libsqlite3-dev libssl-dev libjpeg-dev \ zlib1g-dev libdcmtk-dev libboost-all-dev libwrap0-dev \ - libcharls-dev libjsoncpp-dev libpugixml-dev locales + libcharls-dev libjsoncpp-dev libpugixml-dev locales protobuf-compiler # cd ./Build # cmake -DALLOW_DOWNLOADS=ON \ @@ -235,7 +235,7 @@ You can find build instructions for Orthanc up to 0.7.0 on the following Wiki page: -https://book.orthanc-server.com/faq/compiling-old.html +https://orthanc.uclouvain.be/book/faq/compiling-old.html These instructions will not work as such beyond Orthanc 0.7.0, but they might give indications. diff -r 79f98ee4f04b -r 8279eaab0d1d NEWS --- a/NEWS Thu Sep 15 18:13:17 2022 +0200 +++ b/NEWS Tue Sep 24 11:39:52 2024 +0200 @@ -1,6 +1,7 @@ Pending changes in the mainline =============================== +<<<<<<< working copy General ------- @@ -18,6 +19,387 @@ version 1.11.2 (2022-08-30) +======= +REST API +----------- + +* Improved parsing of multiple numerical values in DICOM tags. + https://discourse.orthanc-server.org/t/qido-includefield-with-sequences/4746/6 + + +Maintenance +----------- + +* DICOM TLS: "DicomTlsTrustedCertificates" is not required anymore when issuing + an outgoing SCU connexion when "DicomTlsRemoteCertificateRequired" is set to false. +* Introduced a new thread to update the statistics at regular interval for the + DB plugins that are implementing the UpdateAndGetStatistics function (currently only + PostgreSQL). This avoids very long update times in case you don't call /statistics + for a long period. +* Fix C-Find queries not returning computed tags like ModalitiesInStudy, NumberOfStudyRelatedSeries, ... + in very specific use-cases. +* Fix extremely rare error when 2 threads are trying to create the same folder in the File Storage + at the same time. +* Metrics: + - fix a few metrics that were not published + - added 2 metrics: orthanc_storage_cache_miss_count & orthanc_storage_cache_hit_count +* Upgraded dependencies for static builds: + - curl 8.9.0 +* Added a new fallback when trying to decode a frame: transcode the file using the plugin + before decoding the frame. This solves some issues with JP2K Lossy compression: + https://discourse.orthanc-server.org/t/decoding-displaying-jpeg2000-lossy-images/5117 +* Added a new warning that can be disabled in the configuration: W003_DecoderFailure + + + +Version 1.12.4 (2024-06-05) +=========================== + +REST API +-------- + +* API version upgraded to 24 +* Added "MaximumPatientCount" in /system +* Added a new "LimitToThisLevelMainDicomTags" field in the payload of + /patients|studies|series/instances/../reconstruct to speed up the reconstruction + in case you just want to update the MainDicomTags of that resource level only + (e.g., after you have updated the "ExtraMainDicomTags" for this level) +* The "requestedTags" GET argument is deprecated in favor of "requested-tags" +* Added "?whole" option to "/instances/{id}/tags" to access tags stored after pixel data + +Plugins +------- + +* Multitenant DICOM plugin: added support for locales. +* Housekeeper plugin: + - Added an option "LimitMainDicomTagsReconstructLevel" + (allowed values: "Patient", "Study", "Series", "Instance"). This can greatly speed + up the housekeeper process, e.g. if you have only update the Study level ExtraMainDicomTags. + - Fixed broken /instances/../tags route after running the Housekeeper + after having changed the "IngestTranscoding". +* SDK: added OrthancPluginLogMessage() as a new primitive for plugins + to log messages. This new primitive will display the plugin name, + the plugin file name, and the plugin line number in the logs. If + they are not using the LOG() facilities provided by the + OrthancFramework, plugins should now use ORTHANC_PLUGINS_LOG_INFO(), + ORTHANC_PLUGINS_LOG_WARNING(), and ORTHANC_PLUGINS_LOG_ERROR(). + +Maintenance +----------- + +* C-Find queries: + - In C-Find queries including "GenericGroupLength" tags, Orthanc was still + extracting these tags from the storage although they were already ignored + and not returned in the response. + They are now removed from the query earlier to avoid this disk access that + could slow down the response time. Note that this seems to happen mainly + when the query originates from some GE devices (AWS). + - "TimezoneOffsetFromUTC" is now ignored for matching. +* The 0x0111 DIMSE Status is now considered as a warning instead of an error + when received as a response to a C-Store. + See https://discourse.orthanc-server.org/t/ignore-dimse-status-0x0111-when-sending-partial-duplicate-studies/4555/3 +* Removed potential PHI from the logs when Orthanc encounters an error while + creating a ZIP archive. +* Monitoring of stable resources now also takes into consideration the + resource type, not only the resource identifier identifier. +* DICOM TLS: + - In prior versions, when "DicomTlsRemoteCertificateRequired" was set to false, Orthanc + was still sending a client certificate request during the TLS handshake but was not + triggering and error if the client certificate was not trusted (equivalent to the + "--verify-peer-cert" DCMTK option). Starting with Orthanc 1.12.4, if this option is + set to "false", Orthanc will not send a client certificate request during the TLS + handshake anymore (equivalent to the "--ignore-peer-cert" DCMTK option). + - When working with "DicomTlsEnabled": true and "DicomTlsRemoteCertificateRequired": false, + Orthanc was refusing to start if no "DicomTlsTrustedCertificates" was provided. + - New configuration options: + - "DicomTlsMinimumProtocolVersion" to select the minimum TLS protocol version + - "DicomTlsCiphersAccepted" to fine tune the list of accepted ciphers +* Fixed broken /instances/../tags route after calling of + /studies/../reconstruct after having changed the "IngestTranscoding". +* Upgraded dependencies for static builds: + - boost 1.85.0 + + +Version 1.12.3 (2024-01-31) +=========================== + +General +------- + +* Performance of databases: + - At startup, if using a database plugin, displays the latency to access the DB. + - Added support for new DB primitives to enable the "READ COMMITTED" + transaction mode in the PostgreSQL plugin. + +REST API +-------- + +* API version upgraded to 23 +* Added a 'KeepLabels' option in /modify routes (default = false) + +Maintenance +----------- + +* Upgraded dependencies for static builds: + - boost 1.84.0 + - curl 8.5.0 + - dcmtk 3.6.8 + - jsoncpp 1.9.5 + - libjpeg 9f + - libpng 1.6.40 + - openssl 3.1.4 + - pugixml 1.14 + - zlib 1.3.1 + + +Version 1.12.2 (2023-12-19) +=========================== + +General +------- + +* Performance: + - Allow multiple plugins to use the plugin SDK at the same time. In previous versions, + functions like instance transcoding or instance reading where mutually exclusive. + This can bring some significant improvements, especially in viewers. + - Optimized the StorageCache to prevent loading the same file multiple times if + multiple users request the same file at the same time. + - The StorageCache is now also storing transcoded instances that have been requested by /file?transcode=... + that is now used by the DICOMweb plugin. This speeds up retrieval of transcoded frames through WADO-RS. + - Now displaying timings when reading from/writing to disk in the verbose logs. +* HTTP compression: + - The default value of the "HttpCompressionEnabled" is now false by default. This reduces + the Orthanc overall CPU usage and latency. This is suitable for setups with large + bandwidth network like LAN. + - When "HttpCompressionEnabled" is true, only the content that is clearly identified as + compressible is compressed (JSON, XML, HTML, text, ...). DICOM files are never + compressed over HTTP. In prior versions, all content types were compressed. + This notably greatly improves loading time of large DICOM + files through WADO-RS e.g in StoneViewer when working on large bandwidth networks. + - When "HttpCompressionEnabled" is true, content < 2KB are never compressed. +* Logs: + - Each line of log now contains the name of the thread that is logging the message. + A new "--logs-no-thread" command line option can be used to get back to the previous behavior to + keep backward compatibility. + +REST API +-------- + +* API version upgraded to 22 +* Added a route to delete completed jobs from history: DELETE /jobs/{id} +* Added a "transcode" option to the /file route: + e.g: /instances/../file?transcode=1.2.840.10008.1.2.4.80 +* now accepting GET requests on these 3 routes to create archive/media: + /tools/create-archive?resources=..,..2&transcode=1.2.840.10008.1.2.4.80 + /tools/create-media?resources=..,..2&transcode=1.2.840.10008.1.2.4.80 + /tools/create-media-extended?resources=..,..2&transcode=1.2.840.10008.1.2.4.80 +* All "expand" GET arguments now accepts "expand=true" and "expand=false" values. + The /studies/../instances and sibling routes are the only whose expand is true if not specified. + These routes now accepts "expand=false" to simply list the child resources ids. +* In /tools/metrics-prometheus: + - "orthanc_dicom_cache_size" renamed as "orthanc_dicom_cache_size_mb" + - added "orthanc_storage_cache_count" and "orthanc_storage_cache_size_mb" + +Plugins +------- + +* Housekeeper plugin: + - Update to rebuild the cache of the DICOMweb plugin when updating to DICOMweb 1.15. + - New trigger configuration: "DicomWebCacheChange" + - Fixed reading the triggers configuration. + - Introduced a "sleep" to lower CPU usage when idle. +* Plugins are now allowed to modify/delete private metadata/attachments + (i.e. whose identifiers are < 1024) +* Added "OrthancPluginSetCurrentThreadName()" in the plugin SDK. + +Maintenance +----------- + +* Fix unit test PngWriter.Color16Pattern on big-endian architectures, + as suggested by Etienne Mollier: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1041813 +* Prevent the leak of the full path of the source files in the binaries +* Fix loading of DCMTK dictionary in the MultitenantDicom plugin when built dynamically: + https://discourse.orthanc-server.org/t/dimse-failure-using-multitenant-plugin/3665 +* Support multiple values in SpecificCharacterSet in C-Find answers: + https://discourse.orthanc-server.org/t/c-find-fails-on-unknown-specific-character-set-iso-2022-ir-6-iso-2022-ir-100/3947 +* When exporting a study archive, make sure to use the PatientName from the study and not from the patient + in case of PatientID collision. +* DICOM C-Store: + - Avoid some unnecessary renegotiation of DICOM association. + - Force renegotiation in case no presentation context were accepted in previous association (we have + observed PACS that were not consistent in the accepted presentation contexts) + - Improved logging +* Solved a deadlock related to the Job Engine events and plugins. Job events are now pushed + into a queue to be handled asynchronously by plugins. +* ZIP of studies whose PatientName and PatientID did not contain any ASCII character are now valid. +* Upgraded minizip library to stay away from CVE-2023-45853 although Orthanc is likely not affected since ZIP + filenames are based on DICOM Tag values whose length is limited in size. + Great thanks to James Addison for notifying us about the vulnerability and patch to apply ! +* Fix XSS in Orthanc error reporting (as reported by Sébastien Doria, Vumetric Cybersecurity) by: + - always including a "Content-Type" header in HTTP responses with a body. + - always including "X-Content-Type-Options: nosniff" +* Upgraded dependencies for static builds: + - boost 1.83.0 + + +Version 1.12.1 (2023-07-04) +=========================== + +General +------- + +* Orthanc now anonymizes according to Basic Profile of PS 3.15-2023b Table E.1-1 +* Added metrics: + - "orthanc_storage_read_bytes" + - "orthanc_storage_written_bytes" + - "orthanc_memory_trimming_duration_ms" + +REST API +-------- + +* API version upgraded to 21 +* "/tools/create-dicom" can now be used to create Encapsulated 3D + Manufacturing Model IODs (MTL, OBJ, or STL) +* Added a route to delete the output of an asynchronous job (right now + only for archive jobs): e.g. DELETE /jobs/../archive + +Plugins +------- + +* Added "OrthancPluginLoadDicomInstance()" to load DICOM instances from the database +* Added "OrthancPluginSetMetricsIntegerValue()" to track metrics with integer values + +Maintenance +----------- + +* Fix decoding of YBR_FULL RLE images for which the "Planar Configuration" + tag (0028,0006) equals 1 +* Made Orthanc more resilient to common spelling errors in SpecificCharacterSet +* Modality worklists plugin: Allow searching on private tags (exact match only) +* Fix orphan files remaining in storage when working with MaximumStorageSize + (https://discourse.orthanc-server.org/t/issue-with-deleting-incoming-dicoms-when-maximumstoragesize-is-reached/3510) +* When deleting a resource, the "LastUpdate" metadata of its parents are now updated +* Reduced the memory usage when downloading archives when "ZipLoaderThreads" > 0 +* Metrics can be stored either as floating-point numbers, or as integers +* Reduce the frequency of memory trimming from 100ms to 30s to avoid high idle + CPU load (https://discourse.orthanc-server.org/t/onchange-callbacks-and-cpu-loads/3534). +* Upgraded dependencies for static builds: + - boost 1.82.0 + + +Version 1.12.0 (2023-04-14) +=========================== + +General +------- + +* Support for labels associated with patients, studies, series, and instances +* Added a sample plugin bringing multitenant DICOM support through labels + +REST API +-------- + +* API version upgraded to 20 +* New URIs "/.../{id}/labels/{label}" to test/set/remove labels +* "/patients/{id}", "/studies/{id}", "/series/{id}" and "/instances/{id}" + contain the "Labels" field +* "/tools/find" now accepts the "Labels" and "LabelsConstraint" arguments +* "/tools/labels" lists all the labels that are associated with any resource +* "/system": added "UserMetadata" and "HasLabels" +* Added option "?numeric" if listing metadata + +Plugins +------- + +* Added "OrthancPluginRegisterDatabaseBackendV4()" to communicate using Google + Protocol Buffers between the Orthanc core and database plugins + +Orthanc Explorer +---------------- + +* Added support for labels +* Added buttons to copy the URL of ZIP archives and DICOM files to the clipboard + +Maintenance +----------- + +* Enforce the existence of the patient/study/instance while creating its archive +* Security: New configuration option "RestApiWriteToFileSystemEnabled" + to allow "/instances/../export" (the latter is now disabled by default) +* Fix issue 214: VOILUTSequence is not returned in Wado-RS +* Fix /tools/reset crashing when ExtraMainDicomTags were defined +* Fix Housekeeper plugin infinite loop if Orthanc is empty. +* Fix a crash in /tools/reconstruct triggered by the Housekeeper plugin + when only changing the StorageCompression. +* Avoid the use of "externalproject_add()" to build the sample plugins +* Upgraded dependencies for static builds: + - openssl 3.1.0 + + +Version 1.11.3 (2023-02-03) +=========================== + +General +------- + +* C-Store SCU now gives priority to the preferred TransferSyntax + proposed by the receiving SCP instead of Orthanc own + AcceptedTransferSyntaxes. +* Made the default SQLite DB more robust wrt future updates like + adding new columns in DB. +* Made the HTTP Client errors more verbose by including the URL in the logs. +* Optimization: now using multiple threads to transcode files for + asynchronous download of studies archive. +* New configuration "KeepAliveTimeout" with a default value of 1 second. +* ResourceModification jobs (/modify + /anonymize) can now use multiple threads to speed up processing + - New configuration "JobsEngineThreadsCount.ResourceModification" to configure the number of threads. +* For systems using glibc > 2.8 (most of Linux systems except LSB + binaries): Introduced a new thread for to trim memory in Orthanc (different + from the Housekeeper sample plugin). This thread regularly try to + give back memory that Orthanc no longer uses to the system. This + reduces the overall memory consumption. More information in + OrthancServer/Resources/ImplementationNotes/memory_consumption.txt. + +REST API +-------- + +* API version upgraded to 19 +* Loosen the sanity checks for DICOM modifications, if "Force" option is given: + - allow modification of PatientID at study level + - allow modification of PatientID, StudyInstanceUID at series level + - allow modification of PatientID, StudyInstanceUID, SeriesInstanceUID at instance level + - allow modification of a patient without changing her PatientID + Added sanity checks for modifications to make sure the user preserves the DICOM model when modifying high level tags. + E.g. if you modify the PatientID at study level, also make sure to modify all other Patient related + tags (PatientName, PatientBirthDate, ...) +* Automatically reconstruct the modified resources at the end of the DICOM modifications job to ensure + improved consistency of the DICOM model. +* If specifying 'Transcode' option to /modify or /anonymize, this value will take over the 'IngestTranscoding' + global configuration +* Allow the HTTP server to return responses > 2GB (fixes asynchronous download of zip studies > 2GB) +* /modalities/.../store now accepts "CalledAet", "Host", "Port" to override the modality configuration + from the configuration file for a specific operation. +* /tools/metrics-prometheus: added orthanc_last_change and orthanc_up_time_s +* Tolerance for "image/jpg" MIME type instead of "image/jpeg" in /tools/create-dicom +* /system: added MaximumStorageMode and MaximumStorageSize + +Plugins +------- + +* Added a "header" argument to all OrthancPeers::DoPost, DoPut, ... in the "OrthancPluginCppWrapper" +* Added "OrthancPluginCreateJob2()" in the plugin SDK to avoid + possible crashes when "OrthancPluginJobGetContent()" or + "OrthancPluginJobGetSerialized()" get called + +Maintenance +----------- + +* Fix decoding of RLE images for which the "Planar Configuration" tag (0028,0006) equals 1 +* Fix issue #212 (Anonymization process transcodes data and loses resource link). + + +Version 1.11.2 (2022-08-30) +>>>>>>> merge rev =========================== General @@ -77,7 +459,7 @@ * Housekeeper plugin: Fix resume of previous processing * Added missing MOVEPatientRootQueryRetrieveInformationModel in DicomControlUserConnection::SetupPresentationContexts() -* Improved HttpClient error logging (add method + url) +* Improved HttpClient error logging (add method + URL) REST API -------- diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/AutoGeneratedCode.cmake --- a/OrthancFramework/Resources/CMake/AutoGeneratedCode.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/AutoGeneratedCode.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/BoostConfiguration.cmake --- a/OrthancFramework/Resources/CMake/BoostConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/BoostConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -54,7 +55,7 @@ # Patch by xnox to fix issue #166 (CMake find_boost version is now # broken with newer boost/cmake) - # https://bugs.orthanc-server.com/show_bug.cgi?id=166 + # https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=166 if (POLICY CMP0093) set(BOOST144 1.44) else() @@ -90,11 +91,11 @@ ## Parameters for static compilation of Boost ## - set(BOOST_NAME boost_1_80_0) - set(BOOST_VERSION 1.80.0) - set(BOOST_BCP_SUFFIX bcpdigest-1.11.2) - set(BOOST_MD5 "7734e19f9a39a4411b807a9913e4a5ff") - set(BOOST_URL "http://orthanc.osimis.io/ThirdPartyDownloads/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz") + set(BOOST_NAME boost_1_85_0) + set(BOOST_VERSION 1.85.0) + set(BOOST_BCP_SUFFIX bcpdigest-1.12.4) + set(BOOST_MD5 "1017e9c8383efdea01c059a8d3cc4dda") + set(BOOST_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz") set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME}) if (IS_DIRECTORY "${BOOST_SOURCES_DIR}") @@ -107,6 +108,25 @@ ## + ## Apply the patches to remove threads from boost::locale (required + ## since around Emscripten 3.x) + ## + + if (FirstRun) + execute_process( + COMMAND ${PATCH_EXECUTABLE} -p0 -N -i + ${CMAKE_CURRENT_LIST_DIR}/../Patches/boost-1.85.0-emscripten.patch + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + + if (Failure) + message(FATAL_ERROR "Error while patching a file") + endif() + endif() + + + ## ## Generic configuration of Boost ## @@ -300,6 +320,7 @@ ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/icu/conversion.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/icu/date_time.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/icu/formatter.cpp + ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/icu/formatters_cache.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/icu/icu_backend.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/icu/numeric.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/icu/time_zone.cpp @@ -310,12 +331,14 @@ ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/shared/date_time.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/shared/formatting.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/shared/generator.cpp + ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/shared/iconv_codecvt.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/shared/ids.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/shared/localization_backend.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/shared/message.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/shared/mo_lambda.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/util/codecvt_converter.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/util/default_locale.cpp + ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/util/encoding.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/util/gregorian.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/util/info.cpp ${BOOST_SOURCES_DIR}/libs/locale/src/boost/locale/util/locale_data.cpp diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/BoostConfiguration.sh --- a/OrthancFramework/Resources/CMake/BoostConfiguration.sh Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/BoostConfiguration.sh Tue Sep 24 11:39:52 2024 +0200 @@ -22,10 +22,14 @@ ## - Orthanc between 1.4.0 and 1.4.2: Boost 1.67.0 ## - Orthanc between 1.5.0 and 1.5.4: Boost 1.68.0 ## - Orthanc between 1.5.5 and 1.11.1: Boost 1.69.0 -## - Orthanc >= 1.11.2: Boost 1.80.0 +## - Orthanc between 1.11.2 and 1.12.0: Boost 1.80.0 +## - Orthanc 1.12.1: Boost 1.82.0 +## - Orthanc 1.12.2: Boost 1.83.0 +## - Orthanc 1.12.3: Boost 1.84.0 +## - Orthanc > 1.12.3: Boost 1.85.0 -BOOST_VERSION=1_80_0 -ORTHANC_VERSION=1.11.2 +BOOST_VERSION=1_85_0 +ORTHANC_VERSION=1.12.4 rm -rf /tmp/boost_${BOOST_VERSION} rm -rf /tmp/bcp/boost_${BOOST_VERSION} diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/BoostConfigurationStatic-1.69.0.cmake --- a/OrthancFramework/Resources/CMake/BoostConfigurationStatic-1.69.0.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/BoostConfigurationStatic-1.69.0.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -28,7 +29,7 @@ set(BOOST_VERSION 1.69.0) set(BOOST_BCP_SUFFIX bcpdigest-1.5.6) set(BOOST_MD5 "579bccc0ea4d1a261c1d0c5e27446c3d") - set(BOOST_URL "http://orthanc.osimis.io/ThirdPartyDownloads/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz") + set(BOOST_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz") set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME}) if (IS_DIRECTORY "${BOOST_SOURCES_DIR}") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/CivetwebConfiguration.cmake --- a/OrthancFramework/Resources/CMake/CivetwebConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/CivetwebConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -27,14 +28,14 @@ ## "civetweb-1.14-fixed.tar.gz" as follows: ## ## $ cd /tmp - ## $ wget http://orthanc.osimis.io/ThirdPartyDownloads/civetweb-1.14.tar.gz + ## $ wget https://orthanc.uclouvain.be/downloads/third-party-downloads/civetweb-1.14.tar.gz ## $ tar xvf civetweb-1.14.tar.gz ## $ rm -rf civetweb-1.14/src/third_party/ civetweb-1.14/test/ ## $ tar cvfz civetweb-1.14-fixed.tar.gz civetweb-1.14 ## set(CIVETWEB_SOURCES_DIR ${CMAKE_BINARY_DIR}/civetweb-1.14) - set(CIVETWEB_URL "http://orthanc.osimis.io/ThirdPartyDownloads/civetweb-1.14-fixed.tar.gz") + set(CIVETWEB_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/civetweb-1.14-fixed.tar.gz") set(CIVETWEB_MD5 "1f25d516b7a4e65d8b270d1cc399e0a9") if (IS_DIRECTORY "${CIVETWEB_SOURCES_DIR}") @@ -140,9 +141,3 @@ unset(CMAKE_REQUIRED_LIBRARIES) # This reset must be after "CHECK_LIBRARY_EXISTS" endif() - - -# New in Orthanc 1.8.1 -add_definitions( - -DCIVETWEB_KEEP_ALIVE_TIMEOUT_SECONDS=1 - ) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/Compiler.cmake --- a/OrthancFramework/Resources/CMake/Compiler.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/Compiler.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -43,6 +44,13 @@ # use by "ExternalProject" in CMake SET(CMAKE_LSB_CC $ENV{LSB_CC} CACHE STRING "") SET(CMAKE_LSB_CXX $ENV{LSB_CXX} CACHE STRING "") + + # This is necessary to build "Orthanc mainline - Framework LSB + # Release" on "buildbot-worker-debian11" + set(LSB_PTHREAD_NONSHARED "${LSB_PATH}/lib64-${LSB_TARGET_VERSION}/libpthread_nonshared.a") + if (EXISTS ${LSB_PTHREAD_NONSHARED}) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LSB_PTHREAD_NONSHARED}") + endif() endif() @@ -124,12 +132,17 @@ ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") - if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" AND + if (# NOT ${CMAKE_SYSTEM_VERSION} STREQUAL "LinuxStandardBase" AND + NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") # The "--no-undefined" linker flag makes the shared libraries # (plugins ModalityWorklists and ServeFolders) fail to compile on # OpenBSD, and make the PostgreSQL plugin complain about missing - # "environ" global variable in FreeBSD + # "environ" global variable in FreeBSD. + # + # TODO - Furthermore, on Linux Standard Base running on Debian 12, + # the "-Wl,--no-undefined" seems to break the compilation (added + # after Orthanc 1.12.2). This is disabled for now. set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") endif() @@ -219,6 +232,10 @@ endif() elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + + # fix this error that appears with recent compilers on MacOS: boost/mpl/aux_/integral_wrapper.hpp:73:31: error: integer value -1 is outside the valid range of values [0, 3] for this enumeration type [-Wenum-constexpr-conversion] + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-enum-constexpr-conversion") + add_definitions( -D_XOPEN_SOURCE=1 ) @@ -237,7 +254,8 @@ if (DEFINED ENABLE_PROFILING AND ENABLE_PROFILING) - if (CMAKE_COMPILER_IS_GNUCXX) + if (CMAKE_COMPILER_IS_GNUCXX OR + CMAKE_CXX_COMPILER_ID STREQUAL "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg") @@ -262,3 +280,24 @@ # preceding batches. https://cmake.org/Bug/view.php?id=14874 set(CMAKE_CXX_ARCHIVE_APPEND " q ") endif() + + +# This function defines macro "__ORTHANC_FILE__" as a replacement to +# macro "__FILE__", as the latter leaks the full path of the source +# files in the binaries +# https://stackoverflow.com/questions/8487986/file-macro-shows-full-path +# https://twitter.com/wget42/status/1676877802375634944?s=20 +function(DefineSourceBasenameForTarget targetname) + # Microsoft Visual Studio is extremely slow if using + # "set_property()", we only enable this feature for gcc and clang + if (CMAKE_COMPILER_IS_GNUCXX OR + CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + get_target_property(source_files "${targetname}" SOURCES) + foreach(sourcefile ${source_files}) + get_filename_component(basename "${sourcefile}" NAME) + set_property( + SOURCE "${sourcefile}" APPEND + PROPERTY COMPILE_DEFINITIONS "__ORTHANC_FILE__=\"${basename}\"") + endforeach() + endif() +endfunction() diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/DcmtkConfiguration.cmake --- a/OrthancFramework/Resources/CMake/DcmtkConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -36,6 +37,8 @@ include(${CMAKE_CURRENT_LIST_DIR}/DcmtkConfigurationStatic-3.6.6.cmake) elseif (DCMTK_STATIC_VERSION STREQUAL "3.6.7") include(${CMAKE_CURRENT_LIST_DIR}/DcmtkConfigurationStatic-3.6.7.cmake) + elseif (DCMTK_STATIC_VERSION STREQUAL "3.6.8") + include(${CMAKE_CURRENT_LIST_DIR}/DcmtkConfigurationStatic-3.6.8.cmake) else() message(FATAL_ERROR "Unsupported version of DCMTK: ${DCMTK_STATIC_VERSION}") endif() @@ -280,6 +283,7 @@ if (DCMTK_DICTIONARY_DIR STREQUAL "") find_path(DCMTK_DICTIONARY_DIR_AUTO dicom.dic /usr/share/dcmtk + /usr/share/dcmtk-3.6.8 /usr/share/libdcmtk1 /usr/share/libdcmtk2 /usr/share/libdcmtk3 @@ -301,6 +305,7 @@ /usr/share/libdcmtk19 /usr/share/libdcmtk20 /usr/local/share/dcmtk + /usr/local/share/dcmtk-3.6.8 ) if (${DCMTK_DICTIONARY_DIR_AUTO} MATCHES "DCMTK_DICTIONARY_DIR_AUTO-NOTFOUND") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.0.cmake --- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.0.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.0.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -22,7 +23,7 @@ SET(DCMTK_VERSION_NUMBER 360) SET(DCMTK_PACKAGE_VERSION "3.6.0") SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.0) -SET(DCMTK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/dcmtk-3.6.0.zip") +SET(DCMTK_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/dcmtk-3.6.0.zip") SET(DCMTK_MD5 "219ad631b82031806147e4abbfba4fa4") if (IS_DIRECTORY "${DCMTK_SOURCES_DIR}") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.2.cmake --- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.2.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.2.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -22,7 +23,7 @@ SET(DCMTK_VERSION_NUMBER 362) SET(DCMTK_PACKAGE_VERSION "3.6.2") SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.2) -SET(DCMTK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/dcmtk-3.6.2.tar.gz") +SET(DCMTK_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/dcmtk-3.6.2.tar.gz") SET(DCMTK_MD5 "d219a4152772985191c9b89d75302d12") macro(DCMTK_UNSET) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.4.cmake --- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.4.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.4.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -22,7 +23,7 @@ SET(DCMTK_VERSION_NUMBER 364) SET(DCMTK_PACKAGE_VERSION "3.6.4") SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.4) -SET(DCMTK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/dcmtk-3.6.4.tar.gz") +SET(DCMTK_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/dcmtk-3.6.4.tar.gz") SET(DCMTK_MD5 "97597439a2ae7a39086066318db5f3bc") macro(DCMTK_UNSET) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.5.cmake --- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.5.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.5.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -22,7 +23,7 @@ SET(DCMTK_VERSION_NUMBER 365) SET(DCMTK_PACKAGE_VERSION "3.6.5") SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.5) -SET(DCMTK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/dcmtk-3.6.5.tar.gz") +SET(DCMTK_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/dcmtk-3.6.5.tar.gz") SET(DCMTK_MD5 "e19707f64ee5695c496b9c1e48e39d07") macro(DCMTK_UNSET) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.6.cmake --- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.6.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.6.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -22,7 +23,7 @@ SET(DCMTK_VERSION_NUMBER 366) SET(DCMTK_PACKAGE_VERSION "3.6.6") SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.6) -SET(DCMTK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/dcmtk-3.6.6.tar.gz") +SET(DCMTK_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/dcmtk-3.6.6.tar.gz") SET(DCMTK_MD5 "f815879d315b916366a9da71339c7575") macro(DCMTK_UNSET) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.7.cmake --- a/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.7.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.7.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -22,7 +23,7 @@ SET(DCMTK_VERSION_NUMBER 367) SET(DCMTK_PACKAGE_VERSION "3.6.7") SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.7) -SET(DCMTK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/dcmtk-3.6.7.tar.gz") +SET(DCMTK_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/dcmtk-3.6.7.tar.gz") SET(DCMTK_MD5 "e4d519bb315ec3944f3f1d61df465cbd") macro(DCMTK_UNSET) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.8.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/CMake/DcmtkConfigurationStatic-3.6.8.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,285 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + +SET(DCMTK_VERSION_NUMBER 368) +SET(DCMTK_PACKAGE_VERSION "3.6.8") +SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-DCMTK-3.6.8) +SET(DCMTK_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/dcmtk-3.6.8.tar.gz") +SET(DCMTK_MD5 "ce3e878c05165f1a3322c29e67f2426f") + +macro(DCMTK_UNSET) +endmacro() + +macro(DCMTK_UNSET_CACHE) +endmacro() + +set(DCMTK_BINARY_DIR ${DCMTK_SOURCES_DIR}/) +set(DCMTK_CMAKE_INCLUDE ${DCMTK_SOURCES_DIR}/) + +if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + set(DCMTK_WITH_THREADS OFF) # Disable thread support in wasm/asm.js +else() + set(DCMTK_WITH_THREADS ON) +endif() + +add_definitions(-DDCMTK_INSIDE_LOG4CPLUS=1) + +if (IS_DIRECTORY "${DCMTK_SOURCES_DIR}") + set(FirstRun OFF) +else() + set(FirstRun ON) +endif() + +DownloadPackage(${DCMTK_MD5} ${DCMTK_URL} "${DCMTK_SOURCES_DIR}") + + +if (FirstRun) + # Apply the patches + execute_process( + COMMAND ${PATCH_EXECUTABLE} -p0 -N -i + ${CMAKE_CURRENT_LIST_DIR}/../Patches/dcmtk-3.6.8.patch + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + + if (Failure) + message(FATAL_ERROR "Error while patching a file") + endif() + + if (MSVC) + # Older versions of Microsoft Visual Studio (notably MSVC2008) + # don't like void usage of function arguments in C source files, + # in order to avoid a warning about unused arguments. This patch + # removes such usages that were not present in DCMTK <= 3.6.6. + execute_process( + COMMAND ${PATCH_EXECUTABLE} -p0 -N -i + ${CMAKE_CURRENT_LIST_DIR}/../Patches/dcmtk-3.6.8-visual-studio.patch + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + + if (Failure) + message(FATAL_ERROR "Error while patching a file") + endif() + endif() + + configure_file( + ${CMAKE_CURRENT_LIST_DIR}/../Patches/dcmtk-dcdict_orthanc.cc + ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/dcdict_orthanc.cc + COPYONLY) +else() + message("The patches for DCMTK have already been applied") +endif() + + +include_directories( + ${DCMTK_SOURCES_DIR}/dcmiod/include + ${DCMTK_SOURCES_DIR}/oficonv/include + ) + + +# C_CHAR_UNSIGNED *must* be set before calling "GenerateDCMTKConfigure.cmake" +IF (CMAKE_CROSSCOMPILING) + if (CMAKE_COMPILER_IS_GNUCXX AND + CMAKE_SYSTEM_NAME STREQUAL "Windows") # MinGW + SET(C_CHAR_UNSIGNED 1 CACHE INTERNAL "Whether char is unsigned.") + + elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # WebAssembly or asm.js + + # Check out "../WebAssembly/ArithmeticTests/" to regenerate the + # "arith.h" file + configure_file( + ${CMAKE_CURRENT_LIST_DIR}/WebAssembly/arith.h + ${DCMTK_SOURCES_DIR}/config/include/dcmtk/config/arith.h + COPYONLY) + + UNSET(C_CHAR_UNSIGNED CACHE) + SET(C_CHAR_UNSIGNED 0 CACHE INTERNAL "") + + else() + message(FATAL_ERROR "Support your platform here") + endif() +ENDIF() + + +if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") + SET(DCMTK_ENABLE_CHARSET_CONVERSION "iconv" CACHE STRING "") + SET(HAVE_SYS_GETTID 0 CACHE INTERNAL "") +endif() + + +SET(DCMTK_SOURCE_DIR ${DCMTK_SOURCES_DIR}) +include(${DCMTK_SOURCES_DIR}/CMake/CheckFunctionWithHeaderExists.cmake) +include(${DCMTK_SOURCES_DIR}/CMake/GenerateDCMTKConfigure.cmake) + + +if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # WebAssembly or + # asm.js The macros below are not properly discovered by DCMTK + # when using WebAssembly. Check out "../WebAssembly/arith.h" for + # how we produced these values. This step MUST be after + # "GenerateDCMTKConfigure" and before the generation of + # "osconfig.h". + UNSET(SIZEOF_VOID_P CACHE) + UNSET(SIZEOF_CHAR CACHE) + UNSET(SIZEOF_DOUBLE CACHE) + UNSET(SIZEOF_FLOAT CACHE) + UNSET(SIZEOF_INT CACHE) + UNSET(SIZEOF_LONG CACHE) + UNSET(SIZEOF_SHORT CACHE) + UNSET(SIZEOF_VOID_P CACHE) + + SET(SIZEOF_VOID_P 4 CACHE INTERNAL "") + SET(SIZEOF_CHAR 1 CACHE INTERNAL "") + SET(SIZEOF_DOUBLE 8 CACHE INTERNAL "") + SET(SIZEOF_FLOAT 4 CACHE INTERNAL "") + SET(SIZEOF_INT 4 CACHE INTERNAL "") + SET(SIZEOF_LONG 4 CACHE INTERNAL "") + SET(SIZEOF_SHORT 2 CACHE INTERNAL "") + SET(SIZEOF_VOID_P 4 CACHE INTERNAL "") +endif() + + +set(DCMTK_PACKAGE_VERSION_SUFFIX "") +set(DCMTK_PACKAGE_VERSION_NUMBER ${DCMTK_VERSION_NUMBER}) + + +# For the dcmtls module, necessary since DCMTK 3.6.7 (cf. file +# "dcmtls/libsrc/tlslayer.cc"). This must be done before the +# invokation of "configure_file()"! +if (STATIC_BUILD OR NOT USE_SYSTEM_OPENSSL) + # The "CHECK_FUNCTIONWITHHEADER_EXISTS()" provided by DCMTK only + # works with the system-wide version of OpenSSL. If statically + # linking against OpenSSL, we manually provide information about + # OpenSSL 3.0.x + set(HAVE_OPENSSL_PROTOTYPE_DH_BITS 1) + set(HAVE_OPENSSL_PROTOTYPE_EVP_PKEY_BASE_ID 1) + set(HAVE_OPENSSL_PROTOTYPE_SSL_CTX_GET0_PARAM 1) + set(HAVE_OPENSSL_PROTOTYPE_SSL_CTX_GET_CERT_STORE 1) + set(HAVE_OPENSSL_PROTOTYPE_SSL_CTX_GET_CIPHERS 1) + set(HAVE_OPENSSL_PROTOTYPE_X509_GET_SIGNATURE_NID 1) + set(HAVE_OPENSSL_PROTOTYPE_X509_STORE_GET0_PARAM 1) +else() + CHECK_FUNCTIONWITHHEADER_EXISTS("DH_bits" "openssl/dh.h" HAVE_OPENSSL_PROTOTYPE_DH_BITS) + CHECK_FUNCTIONWITHHEADER_EXISTS("EVP_PKEY_base_id" "openssl/evp.h" HAVE_OPENSSL_PROTOTYPE_EVP_PKEY_BASE_ID) + CHECK_FUNCTIONWITHHEADER_EXISTS("SSL_CTX_get0_param" "openssl/ssl.h" HAVE_OPENSSL_PROTOTYPE_SSL_CTX_GET0_PARAM) + CHECK_FUNCTIONWITHHEADER_EXISTS("SSL_CTX_get_cert_store" "openssl/ssl.h" HAVE_OPENSSL_PROTOTYPE_SSL_CTX_GET_CERT_STORE) + CHECK_FUNCTIONWITHHEADER_EXISTS("SSL_CTX_get_ciphers" "openssl/ssl.h" HAVE_OPENSSL_PROTOTYPE_SSL_CTX_GET_CIPHERS) + CHECK_FUNCTIONWITHHEADER_EXISTS("X509_STORE_get0_param" "openssl/x509.h" HAVE_OPENSSL_PROTOTYPE_X509_STORE_GET0_PARAM) + CHECK_FUNCTIONWITHHEADER_EXISTS("X509_get_signature_nid" "openssl/x509.h" HAVE_OPENSSL_PROTOTYPE_X509_GET_SIGNATURE_NID) +endif() + + +# "DCMTK_ENABLE_CHARSET_CONVERSION" is defined by "osconfig.h.in" +if (NOT DEFINED BOOST_LOCALE_BACKEND OR # This is the case if locale support is disabled (e.g. in Stone) + BOOST_LOCALE_BACKEND STREQUAL "gcc") + set(DCMTK_ENABLE_CHARSET_CONVERSION "DCMTK_CHARSET_CONVERSION_STDLIBC_ICONV" CACHE STRING "" FORCE) +elseif (BOOST_LOCALE_BACKEND STREQUAL "libiconv") + set(DCMTK_ENABLE_CHARSET_CONVERSION "DCMTK_CHARSET_CONVERSION_ICONV" CACHE STRING "" FORCE) +elseif (BOOST_LOCALE_BACKEND STREQUAL "icu") + set(DCMTK_ENABLE_CHARSET_CONVERSION "DCMTK_CHARSET_CONVERSION_ICU" CACHE STRING "" FORCE) +else() + message(FATAL_ERROR "Invalid value for BOOST_LOCALE_BACKEND: ${BOOST_LOCALE_BACKEND}") +endif() + +CONFIGURE_FILE( + ${DCMTK_SOURCES_DIR}/CMake/osconfig.h.in + ${DCMTK_SOURCES_DIR}/config/include/dcmtk/config/osconfig.h) + + + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + link_libraries(netapi32) # For NetWkstaUserGetInfo@12 + link_libraries(iphlpapi) # For GetAdaptersInfo@8 + + # Configure Wine if cross-compiling for Windows + if (CMAKE_COMPILER_IS_GNUCXX) + include(${DCMTK_SOURCES_DIR}/CMake/dcmtkUseWine.cmake) + FIND_PROGRAM(WINE_WINE_PROGRAM wine) + FIND_PROGRAM(WINE_WINEPATH_PROGRAM winepath) + list(APPEND DCMTK_TRY_COMPILE_REQUIRED_CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=-static") + endif() +endif() + +# This step must be after the generation of "osconfig.h" +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + INSPECT_FUNDAMENTAL_ARITHMETIC_TYPES() +endif() + + +# Source for the logging facility of DCMTK +AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/oflog/libsrc DCMTK_SOURCES) +if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten") + list(REMOVE_ITEM DCMTK_SOURCES + ${DCMTK_SOURCES_DIR}/oflog/libsrc/clfsap.cc + ${DCMTK_SOURCES_DIR}/oflog/libsrc/windebap.cc + ${DCMTK_SOURCES_DIR}/oflog/libsrc/winsock.cc + ) + +elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + list(REMOVE_ITEM DCMTK_SOURCES + ${DCMTK_SOURCES_DIR}/oflog/libsrc/unixsock.cc + ${DCMTK_SOURCES_DIR}/oflog/libsrc/clfsap.cc + ) +endif() + + +# Starting with DCMTK 3.6.2, the Nagle algorithm is not disabled by +# default since this does not seem to be appropriate (anymore) for +# most modern operating systems. In order to change this default, the +# environment variable NO_TCPDELAY can be set to "1" (see envvars.txt +# for details). Alternatively, the macro DISABLE_NAGLE_ALGORITHM can +# be defined to change this setting at compilation time (see +# macros.txt for details). +# https://forum.dcmtk.org/viewtopic.php?t=4632 +add_definitions( + -DDISABLE_NAGLE_ALGORITHM=1 + ) + + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + # For compatibility with Windows XP, avoid using fiber-local-storage + # in log4cplus, but use thread-local-storage instead. Otherwise, + # Windows XP complains about missing "FlsGetValue()" in KERNEL32.dll + add_definitions( + -DDCMTK_LOG4CPLUS_AVOID_WIN32_FLS + ) + + if (CMAKE_COMPILER_IS_GNUCXX OR # MinGW + "${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") # MSVC for 32bit (*) + + # (*) With multithreaded logging enabled, Visual Studio 2008 fails + # with error: ".\dcmtk-3.6.7\oflog\libsrc\globinit.cc(422) : error + # C2664: 'dcmtk::log4cplus::thread::impl::tls_init' : cannot + # convert parameter 1 from 'void (__stdcall *)(void *)' to + # 'dcmtk::log4cplus::thread::impl::tls_init_cleanup_func_type'" + # None of the functions with this name in scope match the target type + + add_definitions( + -DDCMTK_LOG4CPLUS_SINGLE_THREADED + ) + endif() +endif() diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/DownloadOrthancFramework.cmake --- a/OrthancFramework/Resources/CMake/DownloadOrthancFramework.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/DownloadOrthancFramework.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -150,6 +151,20 @@ set(ORTHANC_FRAMEWORK_MD5 "962c4a4a706a2ef28b390d8515dd7091") elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.11.1") set(ORTHANC_FRAMEWORK_MD5 "a39661c406adf22cf574fde290cf4bbf") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.11.2") + set(ORTHANC_FRAMEWORK_MD5 "ede3de356493a8868545f8cb4b8bc8b5") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.11.3") + set(ORTHANC_FRAMEWORK_MD5 "e48fc0cb09c4856803791a1be28c07dc") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.0") + set(ORTHANC_FRAMEWORK_MD5 "d32a0cde03b6eb603d8dd2b33d38bf1b") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.1") + set(ORTHANC_FRAMEWORK_MD5 "8a435140efc8ff4a01d8242f092f21de") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.2") + set(ORTHANC_FRAMEWORK_MD5 "d2476b9e796e339ac320b5333489bdb3") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.3") + set(ORTHANC_FRAMEWORK_MD5 "975f5bf2142c22cb1777b4f6a0a614c5") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.4") + set(ORTHANC_FRAMEWORK_MD5 "1e61779ea4a7cd705720bdcfed8a6a73") # Below this point are development snapshots that were used to # release some plugin, before an official release of the Orthanc @@ -160,19 +175,28 @@ # elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "ae0e3fd609df") # DICOMweb 1.1 (framework pre-1.6.0) + set(ORTHANC_FRAMEWORK_PRE_RELEASE ON) set(ORTHANC_FRAMEWORK_MD5 "7e09e9b530a2f527854f0b782d7e0645") elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "82652c5fc04f") # Stone Web viewer 1.0 (framework pre-1.8.1) + set(ORTHANC_FRAMEWORK_PRE_RELEASE ON) set(ORTHANC_FRAMEWORK_MD5 "d77331d68917e66a3f4f9b807bbdab7f") elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "4a3ba4bf4ba7") # PostgreSQL 3.3 (framework pre-1.8.2) + set(ORTHANC_FRAMEWORK_PRE_RELEASE ON) set(ORTHANC_FRAMEWORK_MD5 "2d82bddf06f9cfe82095495cb3b8abde") elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "23ad1b9c7800") # For "Toolbox::ReadJson()" and "Toolbox::Write{...}Json()" (pre-1.9.0) + set(ORTHANC_FRAMEWORK_PRE_RELEASE ON) set(ORTHANC_FRAMEWORK_MD5 "9af92080e57c60dd288eba46ce606c00") elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "b2e08d83e21d") # WSI 1.1 (framework pre-1.10.0), to remove "-std=c++11" + set(ORTHANC_FRAMEWORK_PRE_RELEASE ON) set(ORTHANC_FRAMEWORK_MD5 "2eaa073cbb4b44ffba199ad93393b2b1") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "daf4807631c5") + # DICOMweb 1.15 (framework pre-1.12.2) + set(ORTHANC_FRAMEWORK_PRE_RELEASE ON) + set(ORTHANC_FRAMEWORK_MD5 "ebe8bdf388319f1c9536b2b680451848") endif() endif() endif() @@ -260,7 +284,7 @@ else() message("Forking the Orthanc source repository using Mercurial") execute_process( - COMMAND ${ORTHANC_FRAMEWORK_HG} clone "https://hg.orthanc-server.com/orthanc/" + COMMAND ${ORTHANC_FRAMEWORK_HG} clone "https://orthanc.uclouvain.be/hg/orthanc/" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE Failure ) @@ -309,7 +333,11 @@ else() # Default case: Download from the official Web site set(ORTHANC_FRAMEMORK_FILENAME Orthanc-${ORTHANC_FRAMEWORK_VERSION}.tar.gz) - set(ORTHANC_FRAMEWORK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/orthanc-framework/${ORTHANC_FRAMEMORK_FILENAME}") + if (ORTHANC_FRAMEWORK_PRE_RELEASE) + set(ORTHANC_FRAMEWORK_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/orthanc-framework/${ORTHANC_FRAMEMORK_FILENAME}") + else() + set(ORTHANC_FRAMEWORK_URL "https://orthanc.uclouvain.be/downloads/sources/orthanc/${ORTHANC_FRAMEMORK_FILENAME}") + endif() endif() set(ORTHANC_FRAMEWORK_ARCHIVE "${CMAKE_SOURCE_DIR}/ThirdPartyDownloads/${ORTHANC_FRAMEMORK_FILENAME}") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/DownloadPackage.cmake --- a/OrthancFramework/Resources/CMake/DownloadPackage.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/DownloadPackage.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -101,19 +102,26 @@ message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON") endif() - if ("${MD5}" STREQUAL "no-check") - message(WARNING "Not checking the MD5 of: ${Url}") - file(DOWNLOAD "${Url}" "${TMP_PATH}" - SHOW_PROGRESS TIMEOUT 300 INACTIVITY_TIMEOUT 60 - STATUS Failure) - else() - file(DOWNLOAD "${Url}" "${TMP_PATH}" - SHOW_PROGRESS TIMEOUT 300 INACTIVITY_TIMEOUT 60 - EXPECTED_MD5 "${MD5}" STATUS Failure) - endif() + foreach (retry RANGE 1 5) # Retries 5 times + if ("${MD5}" STREQUAL "no-check") + message(WARNING "Not checking the MD5 of: ${Url}") + file(DOWNLOAD "${Url}" "${TMP_PATH}" + SHOW_PROGRESS TIMEOUT 30 INACTIVITY_TIMEOUT 10 + STATUS Failure) + else() + file(DOWNLOAD "${Url}" "${TMP_PATH}" + SHOW_PROGRESS TIMEOUT 30 INACTIVITY_TIMEOUT 10 + EXPECTED_MD5 "${MD5}" STATUS Failure) + endif() - list(GET Failure 0 Status) + list(GET Failure 0 Status) + if (Status EQUAL 0) + break() # Successful download + endif() + endforeach() + if (NOT Status EQUAL 0) + file(REMOVE ${TMP_PATH}) message(FATAL_ERROR "Cannot download file: ${Url}") endif() diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/EmscriptenParameters.cmake --- a/OrthancFramework/Resources/CMake/EmscriptenParameters.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/EmscriptenParameters.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/GoogleTestConfiguration.cmake --- a/OrthancFramework/Resources/CMake/GoogleTestConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/GoogleTestConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -50,7 +51,7 @@ elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST) set(GOOGLE_TEST_SOURCES_DIR ${CMAKE_BINARY_DIR}/googletest-release-1.8.1) - set(GOOGLE_TEST_URL "http://orthanc.osimis.io/ThirdPartyDownloads/gtest-1.8.1.tar.gz") + set(GOOGLE_TEST_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/gtest-1.8.1.tar.gz") set(GOOGLE_TEST_MD5 "2e6fbeb6a91310a16efe181886c59596") DownloadPackage(${GOOGLE_TEST_MD5} ${GOOGLE_TEST_URL} "${GOOGLE_TEST_SOURCES_DIR}") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/JsonCppConfiguration.cmake --- a/OrthancFramework/Resources/CMake/JsonCppConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/JsonCppConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -24,13 +25,13 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_JSONCPP) if (USE_LEGACY_JSONCPP) set(JSONCPP_SOURCES_DIR ${CMAKE_BINARY_DIR}/jsoncpp-0.10.7) - set(JSONCPP_URL "http://orthanc.osimis.io/ThirdPartyDownloads/jsoncpp-0.10.7.tar.gz") + set(JSONCPP_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/jsoncpp-0.10.7.tar.gz") set(JSONCPP_MD5 "3a8072ca6a1fa9cbaf7715ae625f134f") add_definitions(-DORTHANC_LEGACY_JSONCPP=1) else() - set(JSONCPP_SOURCES_DIR ${CMAKE_BINARY_DIR}/jsoncpp-1.9.4) - set(JSONCPP_URL "http://orthanc.osimis.io/ThirdPartyDownloads/jsoncpp-1.9.4.tar.gz") - set(JSONCPP_MD5 "4757b26ec89798c5247fa638edfdc446") + set(JSONCPP_SOURCES_DIR ${CMAKE_BINARY_DIR}/jsoncpp-1.9.5) + set(JSONCPP_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/jsoncpp-1.9.5.tar.gz") + set(JSONCPP_MD5 "d6c8c609f2162eff373db62b90a051c7") add_definitions(-DORTHANC_LEGACY_JSONCPP=0) set(JSONCPP_CXX11 ON) endif() diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/LibCurlConfiguration.cmake --- a/OrthancFramework/Resources/CMake/LibCurlConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/LibCurlConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -20,9 +21,9 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_CURL) - SET(CURL_SOURCES_DIR ${CMAKE_BINARY_DIR}/curl-7.77.0) - SET(CURL_URL "http://orthanc.osimis.io/ThirdPartyDownloads/curl-7.77.0.tar.gz") - SET(CURL_MD5 "478e8b06801d9d030609c9e6cf859229") + SET(CURL_SOURCES_DIR ${CMAKE_BINARY_DIR}/curl-8.9.0) + SET(CURL_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/curl-8.9.0.tar.gz") + SET(CURL_MD5 "f9bca5d4d5bac1f04e6c5eb4d0418618") if (IS_DIRECTORY "${CURL_SOURCES_DIR}") set(FirstRun OFF) @@ -35,7 +36,7 @@ if (FirstRun) execute_process( COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${CMAKE_CURRENT_LIST_DIR}/../Patches/curl-7.77.0.patch + ${CMAKE_CURRENT_LIST_DIR}/../Patches/curl-8.9.0.patch WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE Failure ) @@ -51,7 +52,9 @@ AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib CURL_SOURCES) AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib/vauth CURL_SOURCES) + AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib/vssh CURL_SOURCES) AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib/vtls CURL_SOURCES) + AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib/vquic CURL_SOURCES) source_group(ThirdParty\\LibCurl REGULAR_EXPRESSION ${CURL_SOURCES_DIR}/.*) add_definitions( @@ -82,17 +85,18 @@ endif() if (NOT EXISTS "${CURL_SOURCES_DIR}/lib/vauth/vauth/vauth.h") - #file(WRITE ${CURL_SOURCES_DIR}/lib/curl_config.h "") - - file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/vauth.h "#include \"../vauth.h\"\n") file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/digest.h "#include \"../digest.h\"\n") file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/ntlm.h "#include \"../ntlm.h\"\n") + file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/vauth.h "#include \"../vauth.h\"\n") file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vtls/vtls.h "#include \"../../vtls/vtls.h\"\n") + file(WRITE ${CURL_SOURCES_DIR}/lib/vssh/curl_setup.h "#include \"../curl_setup.h\"\n") + file(WRITE ${CURL_SOURCES_DIR}/lib/vtls/vauth/vauth.h "#include \"../../vauth/vauth.h\"\n") file(GLOB CURL_LIBS_HEADERS ${CURL_SOURCES_DIR}/lib/*.h) foreach (header IN LISTS CURL_LIBS_HEADERS) get_filename_component(filename ${header} NAME) file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/${filename} "#include \"../${filename}\"\n") + file(WRITE ${CURL_SOURCES_DIR}/lib/vquic/${filename} "#include \"../${filename}\"\n") file(WRITE ${CURL_SOURCES_DIR}/lib/vtls/${filename} "#include \"../${filename}\"\n") endforeach() endif() @@ -109,7 +113,7 @@ endif() set_property( - SOURCE ${CURL_SOURCES} + SOURCE ${CURL_SOURCES} APPEND PROPERTY COMPILE_DEFINITIONS "HAVE_CONFIG_H=1;OS=\"${TMP_OS}\"" ) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/LibIconvConfiguration.cmake --- a/OrthancFramework/Resources/CMake/LibIconvConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/LibIconvConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -23,7 +24,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBICONV) set(LIBICONV_SOURCES_DIR ${CMAKE_BINARY_DIR}/libiconv-1.15) - set(LIBICONV_URL "http://orthanc.osimis.io/ThirdPartyDownloads/libiconv-1.15.tar.gz") + set(LIBICONV_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/libiconv-1.15.tar.gz") set(LIBICONV_MD5 "ace8b5f2db42f7b3b3057585e80d9808") DownloadPackage(${LIBICONV_MD5} ${LIBICONV_URL} "${LIBICONV_SOURCES_DIR}") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/LibIcuConfiguration.cmake --- a/OrthancFramework/Resources/CMake/LibIcuConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/LibIcuConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/LibJpegConfiguration.cmake --- a/OrthancFramework/Resources/CMake/LibJpegConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/LibJpegConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -20,10 +21,10 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBJPEG) - set(LIBJPEG_SOURCES_DIR ${CMAKE_BINARY_DIR}/jpeg-9c) + set(LIBJPEG_SOURCES_DIR ${CMAKE_BINARY_DIR}/jpeg-9f) DownloadPackage( - "93c62597eeef81a84d988bccbda1e990" - "http://orthanc.osimis.io/ThirdPartyDownloads/jpegsrc.v9c.tar.gz" + "9ca58d68febb0fa9c1c087045b9a5483" + "https://orthanc.uclouvain.be/downloads/third-party-downloads/jpegsrc.v9f.tar.gz" "${LIBJPEG_SOURCES_DIR}") include_directories( @@ -107,7 +108,7 @@ else() include(FindJPEG) - if (NOT ${JPEG_FOUND}) + if (NOT JPEG_FOUND) message(FATAL_ERROR "Unable to find libjpeg") endif() diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/LibP11Configuration.cmake --- a/OrthancFramework/Resources/CMake/LibP11Configuration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/LibP11Configuration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -25,7 +26,7 @@ endif() SET(LIBP11_SOURCES_DIR ${CMAKE_BINARY_DIR}/libp11-0.4.0) - SET(LIBP11_URL "http://orthanc.osimis.io/ThirdPartyDownloads/libp11-0.4.0.tar.gz") + SET(LIBP11_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/libp11-0.4.0.tar.gz") SET(LIBP11_MD5 "00b3e41db5be840d822bda12f3ab2ca7") if (IS_DIRECTORY "${LIBP11_SOURCES_DIR}") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/LibPngConfiguration.cmake --- a/OrthancFramework/Resources/CMake/LibPngConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/LibPngConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -20,9 +21,9 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBPNG) - SET(LIBPNG_SOURCES_DIR ${CMAKE_BINARY_DIR}/libpng-1.6.36) - SET(LIBPNG_URL "http://orthanc.osimis.io/ThirdPartyDownloads/libpng-1.6.36.tar.gz") - SET(LIBPNG_MD5 "65afdeaa05f5ec14e31d9276143012e9") + SET(LIBPNG_SOURCES_DIR ${CMAKE_BINARY_DIR}/libpng-1.6.40) + SET(LIBPNG_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/libpng-1.6.40.tar.gz") + SET(LIBPNG_MD5 "ec4b597c3a9b1f8d2826575f530367b7") DownloadPackage(${LIBPNG_MD5} ${LIBPNG_URL} "${LIBPNG_SOURCES_DIR}") @@ -71,7 +72,7 @@ else() include(FindPNG) - if (NOT ${PNG_FOUND}) + if (NOT PNG_FOUND) message(FATAL_ERROR "Unable to find libpng") endif() diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/LuaConfiguration.cmake --- a/OrthancFramework/Resources/CMake/LuaConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/LuaConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -22,7 +23,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LUA) SET(LUA_SOURCES_DIR ${CMAKE_BINARY_DIR}/lua-5.3.5) SET(LUA_MD5 "4f4b4f323fd3514a68e0ab3da8ce3455") - SET(LUA_URL "http://orthanc.osimis.io/ThirdPartyDownloads/lua-5.3.5.tar.gz") + SET(LUA_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/lua-5.3.5.tar.gz") DownloadPackage(${LUA_MD5} ${LUA_URL} "${LUA_SOURCES_DIR}") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/MongooseConfiguration.cmake --- a/OrthancFramework/Resources/CMake/MongooseConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/MongooseConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -32,7 +33,7 @@ # Use Mongoose 3.1 DownloadPackage( "e718fc287b4eb1bd523be3fa00942bb0" - "http://orthanc.osimis.io/ThirdPartyDownloads/mongoose-3.1.tgz" + "https://orthanc.uclouvain.be/downloads/third-party-downloads/mongoose-3.1.tgz" "${MONGOOSE_SOURCES_DIR}") add_definitions(-DMONGOOSE_USE_CALLBACKS=0) @@ -42,7 +43,7 @@ # Use Mongoose 3.8 DownloadPackage( "7e3296295072792cdc3c633f9404e0c3" - "http://orthanc.osimis.io/ThirdPartyDownloads/mongoose-3.8.tgz" + "https://orthanc.uclouvain.be/downloads/third-party-downloads/mongoose-3.8.tgz" "${MONGOOSE_SOURCES_DIR}") add_definitions(-DMONGOOSE_USE_CALLBACKS=1) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/OpenSslConfiguration.cmake --- a/OrthancFramework/Resources/CMake/OpenSslConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/OpenSslConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -59,7 +60,7 @@ else() include(FindOpenSSL) - if (NOT ${OPENSSL_FOUND}) + if (NOT OPENSSL_FOUND) message(FATAL_ERROR "Unable to find OpenSSL") endif() diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/OpenSslConfigurationStatic-1.1.1.cmake --- a/OrthancFramework/Resources/CMake/OpenSslConfigurationStatic-1.1.1.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/OpenSslConfigurationStatic-1.1.1.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -20,7 +21,7 @@ SET(OPENSSL_SOURCES_DIR ${CMAKE_BINARY_DIR}/openssl-1.1.1k) -SET(OPENSSL_URL "http://orthanc.osimis.io/ThirdPartyDownloads/openssl-1.1.1k.tar.gz") +SET(OPENSSL_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/openssl-1.1.1k.tar.gz") SET(OPENSSL_MD5 "c4e7d95f782b08116afa27b30393dd27") if (IS_DIRECTORY "${OPENSSL_SOURCES_DIR}") @@ -288,7 +289,7 @@ # crashes with segmentation fault in function # "build_SYS_str_reasons()", that is called from # "OPENSSL_init_ssl()" - # https://bugs.orthanc-server.com/show_bug.cgi?id=193 + # https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=193 -DOPENSSL_NO_ERR ) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/OpenSslConfigurationStatic-3.0.cmake --- a/OrthancFramework/Resources/CMake/OpenSslConfigurationStatic-3.0.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/OpenSslConfigurationStatic-3.0.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2021 Osimis S.A., Belgium -# Copyright (C) 2021-2021 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -20,13 +21,13 @@ set(OPENSSL_VERSION_MAJOR 3) -set(OPENSSL_VERSION_MINOR 0) -set(OPENSSL_VERSION_PATCH 5) +set(OPENSSL_VERSION_MINOR 1) +set(OPENSSL_VERSION_PATCH 4) set(OPENSSL_VERSION_PRE_RELEASE "") set(OPENSSL_VERSION_FULL "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_PATCH}${OPENSSL_VERSION_PRE_RELEASE}") SET(OPENSSL_SOURCES_DIR ${CMAKE_BINARY_DIR}/openssl-${OPENSSL_VERSION_FULL}) -SET(OPENSSL_URL "http://orthanc.osimis.io/ThirdPartyDownloads/openssl-${OPENSSL_VERSION_FULL}.tar.gz") -SET(OPENSSL_MD5 "163bb3e58c143793d1dc6a6ec7d185d5") +SET(OPENSSL_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/openssl-${OPENSSL_VERSION_FULL}.tar.gz") +SET(OPENSSL_MD5 "653ad58812c751b887e8ec37e02bba70") if (IS_DIRECTORY "${OPENSSL_SOURCES_DIR}") set(FirstRun OFF) @@ -293,7 +294,6 @@ ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win32.c ${OPENSSL_SOURCES_DIR}/crypto/LPdir_wince.c ${OPENSSL_SOURCES_DIR}/crypto/aes/aes_x86core.c - ${OPENSSL_SOURCES_DIR}/crypto/armcap.c ${OPENSSL_SOURCES_DIR}/crypto/des/ncbc_enc.c ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistp224.c ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistp256.c @@ -304,7 +304,6 @@ ${OPENSSL_SOURCES_DIR}/crypto/ec/ecx_s390x.c ${OPENSSL_SOURCES_DIR}/crypto/poly1305/poly1305_base2_44.c ${OPENSSL_SOURCES_DIR}/crypto/rsa/rsa_acvp_test_params.c - ${OPENSSL_SOURCES_DIR}/crypto/s390xcap.c ${OPENSSL_SOURCES_DIR}/engines/e_devcrypto.c ${OPENSSL_SOURCES_DIR}/engines/e_loader_attic.c ${OPENSSL_SOURCES_DIR}/providers/common/securitycheck_fips.c @@ -320,11 +319,17 @@ ${OPENSSL_SOURCES_DIR}/crypto/chacha/chacha_ppc.c ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_ppc.c ${OPENSSL_SOURCES_DIR}/crypto/poly1305/poly1305_ppc.c - ${OPENSSL_SOURCES_DIR}/crypto/ppccap.c ${OPENSSL_SOURCES_DIR}/crypto/sha/sha_ppc.c # Disable SPARC sources ${OPENSSL_SOURCES_DIR}/crypto/bn/bn_sparc.c + + # Disable CPUID for non-x86 platforms + ${OPENSSL_SOURCES_DIR}/crypto/armcap.c + ${OPENSSL_SOURCES_DIR}/crypto/loongarchcap.c + ${OPENSSL_SOURCES_DIR}/crypto/ppccap.c + ${OPENSSL_SOURCES_DIR}/crypto/riscvcap.c + ${OPENSSL_SOURCES_DIR}/crypto/s390xcap.c ${OPENSSL_SOURCES_DIR}/crypto/sparcv9cap.c ) @@ -389,7 +394,7 @@ # crashes with segmentation fault in function # "build_SYS_str_reasons()", that is called from # "OPENSSL_init_ssl()" - # https://bugs.orthanc-server.com/show_bug.cgi?id=193 + # https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=193 -DOPENSSL_NO_ERR ) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake --- a/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -141,6 +142,11 @@ unset(ENABLE_DCMTK_LOG CACHE) endif() +if (NOT ENABLE_PROTOBUF) + unset(USE_SYSTEM_PROTOBUF CACHE) + add_definitions(-DORTHANC_ENABLE_PROTOBUF=0) +endif() + ##################################################################### ## List of source files @@ -149,7 +155,6 @@ set(ORTHANC_CORE_SOURCES_INTERNAL ${CMAKE_CURRENT_LIST_DIR}/../../Sources/Cache/MemoryCache.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/Cache/MemoryObjectCache.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../Sources/Cache/MemoryStringCache.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/ChunkedBuffer.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomFormat/DicomTag.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/DicomFormat/DicomPath.cpp @@ -476,6 +481,16 @@ endif() +## +## Google Protocol Buffers +## + +if (ENABLE_PROTOBUF) + include(${CMAKE_CURRENT_LIST_DIR}/ProtobufConfiguration.cmake) + add_definitions(-DORTHANC_ENABLE_PROTOBUF=1) +endif() + + ##################################################################### ## Inclusion of mandatory third-party dependencies @@ -624,6 +639,7 @@ ) list(APPEND ORTHANC_CORE_SOURCES_INTERNAL + ${CMAKE_CURRENT_LIST_DIR}/../../Sources/Cache/MemoryStringCache.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/Cache/SharedArchive.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/FileBuffer.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/FileStorage/FilesystemStorage.cpp @@ -712,6 +728,7 @@ ${LUA_SOURCES} ${MONGOOSE_SOURCES} ${OPENSSL_SOURCES} + ${PROTOBUF_LIBRARY_SOURCES} ${PUGIXML_SOURCES} ${SQLITE_SOURCES} ${UUID_SOURCES} diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake --- a/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -38,7 +39,7 @@ # Version of the Orthanc API, can be retrieved from "/system" URI in # order to check whether new URI endpoints are available even if using # the mainline version of Orthanc -set(ORTHANC_API_VERSION "18") +set(ORTHANC_API_VERSION "24") ##################################################################### @@ -70,6 +71,7 @@ set(USE_SYSTEM_LUA ON CACHE BOOL "Use the system version of Lua") set(USE_SYSTEM_MONGOOSE ON CACHE BOOL "Use the system version of Mongoose") set(USE_SYSTEM_OPENSSL ON CACHE BOOL "Use the system version of OpenSSL") +set(USE_SYSTEM_PROTOBUF ON CACHE BOOL "Use the system version of Google Protocol Buffers") set(USE_SYSTEM_PUGIXML ON CACHE BOOL "Use the system version of Pugixml") set(USE_SYSTEM_SQLITE ON CACHE BOOL "Use the system version of SQLite") set(USE_SYSTEM_UUID ON CACHE BOOL "Use the system version of the uuid library from e2fsprogs") @@ -77,7 +79,7 @@ # Parameters specific to DCMTK set(DCMTK_DICTIONARY_DIR "" CACHE PATH "Directory containing the DCMTK dictionaries \"dicom.dic\" and \"private.dic\" (only when using system version of DCMTK)") -set(DCMTK_STATIC_VERSION "3.6.7" CACHE STRING "Version of DCMTK to be used in static builds (can be \"3.6.0\", \"3.6.2\", \"3.6.4\", \"3.6.5\", \"3.6.6\", or \"3.6.7\")") +set(DCMTK_STATIC_VERSION "3.6.8" CACHE STRING "Version of DCMTK to be used in static builds (can be \"3.6.0\", \"3.6.2\", \"3.6.4\", \"3.6.5\", \"3.6.6\", \"3.6.7\", or \"3.6.8\")") set(USE_DCMTK_362_PRIVATE_DIC ON CACHE BOOL "Use the dictionary of private tags from DCMTK 3.6.2 if using DCMTK 3.6.0") set(USE_SYSTEM_DCMTK ON CACHE BOOL "Use the system version of DCMTK") set(ENABLE_DCMTK_LOG ON CACHE BOOL "Enable logging internal to DCMTK") @@ -123,6 +125,8 @@ set(ENABLE_LOCALE OFF CACHE INTERNAL "Enable support for locales (notably in Boost)") set(ENABLE_LUA OFF CACHE INTERNAL "Enable support of Lua scripting") set(ENABLE_PNG OFF CACHE INTERNAL "Enable support of PNG") +set(ENABLE_PROTOBUF OFF CACHE INTERNAL "Enable support for Google Protocol Buffers' library") +set(ENABLE_PROTOBUF_COMPILER OFF CACHE INTERNAL "Enable support for Google Protocol Buffers' compiler") set(ENABLE_PUGIXML OFF CACHE INTERNAL "Enable support of XML through Pugixml") set(ENABLE_SQLITE OFF CACHE INTERNAL "Enable support of SQLite databases") set(ENABLE_ZLIB OFF CACHE INTERNAL "Enable support of zlib") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/ProtobufConfiguration.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/CMake/ProtobufConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,86 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + +if (STATIC_BUILD OR NOT USE_SYSTEM_PROTOBUF) + if (ENABLE_PROTOBUF_COMPILER) + include(ExternalProject) + externalproject_add(ProtobufCompiler + SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../ProtocolBuffers" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/ProtobufCompiler-build" + # this helps triggering build when changing the external project + BUILD_ALWAYS 1 + CMAKE_ARGS + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR} + ) + + # The "protoc" compiler is built using "externalproject_add", + # which builds for the host platform, not for the target platform + if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + set(Suffix ".exe") + else() + set(Suffix "") + endif() + + set(PROTOC_EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/protoc${Suffix}) + endif() + + include(${CMAKE_CURRENT_LIST_DIR}/../ProtocolBuffers/ProtobufLibrary.cmake) + source_group(ThirdParty\\Protobuf REGULAR_EXPRESSION ${PROTOBUF_SOURCE_DIR}/.*) + +else() + if (CMAKE_CROSSCOMPILING) + message(FATAL_ERROR "If cross-compiling, the static version of Protocol Buffers should be used to avoid version mismatch") + endif() + + if (ENABLE_PROTOBUF_COMPILER) + find_program(PROTOC_EXECUTABLE protoc) + if (${PROTOC_EXECUTABLE} MATCHES "PROTOC_EXECUTABLE-NOTFOUND") + message(FATAL_ERROR "Please install the 'protoc' compiler for Protocol Buffers (package 'protobuf-compiler' on Debian/Ubuntu)") + endif() + add_custom_target(ProtobufCompiler) + endif() + + check_include_file_cxx(google/protobuf/any.h HAVE_PROTOBUF_H) + if (NOT HAVE_PROTOBUF_H) + message(FATAL_ERROR "Please install the libprotobuf-dev package") + endif() + + set(CMAKE_REQUIRED_LIBRARIES "protobuf") + + include(CheckCXXSourceCompiles) + check_cxx_source_compiles( + " +#include +int main() +{ + google::protobuf::FieldDescriptor::TypeName(google::protobuf::FieldDescriptor::TYPE_FLOAT); +} +" HAVE_PROTOBUF_LIB) + if (NOT HAVE_PROTOBUF_LIB) + message(FATAL_ERROR "Cannot find the protobuf library") + endif() + + unset(CMAKE_REQUIRED_LIBRARIES) + + link_libraries(protobuf) +endif() diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/PugixmlConfiguration.cmake --- a/OrthancFramework/Resources/CMake/PugixmlConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/PugixmlConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -20,9 +21,9 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_PUGIXML) - set(PUGIXML_SOURCES_DIR ${CMAKE_BINARY_DIR}/pugixml-1.9) - set(PUGIXML_MD5 "7286ee2ed11376b6b780ced19fae0b64") - set(PUGIXML_URL "http://orthanc.osimis.io/ThirdPartyDownloads/pugixml-1.9.tar.gz") + set(PUGIXML_SOURCES_DIR ${CMAKE_BINARY_DIR}/pugixml-1.14) + set(PUGIXML_MD5 "06e4242ee2352ee63c2b6627c6e3addb") + set(PUGIXML_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/pugixml-1.14.tar.gz") DownloadPackage(${PUGIXML_MD5} ${PUGIXML_URL} "${PUGIXML_SOURCES_DIR}") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/SQLiteConfiguration.cmake --- a/OrthancFramework/Resources/CMake/SQLiteConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/SQLiteConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -38,7 +39,7 @@ if (SQLITE_STATIC) SET(SQLITE_SOURCES_DIR ${CMAKE_BINARY_DIR}/sqlite-amalgamation-3270100) SET(SQLITE_MD5 "16717b26358ba81f0bfdac07addc77da") - SET(SQLITE_URL "http://orthanc.osimis.io/ThirdPartyDownloads/sqlite-amalgamation-3270100.zip") + SET(SQLITE_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/sqlite-amalgamation-3270100.zip") set(ORTHANC_SQLITE_VERSION 3027001) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/UuidConfiguration.cmake --- a/OrthancFramework/Resources/CMake/UuidConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/UuidConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -23,7 +24,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_UUID) SET(E2FSPROGS_SOURCES_DIR ${CMAKE_BINARY_DIR}/e2fsprogs-1.44.5) - SET(E2FSPROGS_URL "http://orthanc.osimis.io/ThirdPartyDownloads/e2fsprogs-1.44.5.tar.gz") + SET(E2FSPROGS_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/e2fsprogs-1.44.5.tar.gz") SET(E2FSPROGS_MD5 "8d78b11d04d26c0b2dd149529441fa80") if (IS_DIRECTORY "${E2FSPROGS_SOURCES_DIR}") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/VisualStudioPrecompiledHeaders.cmake --- a/OrthancFramework/Resources/CMake/VisualStudioPrecompiledHeaders.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/VisualStudioPrecompiledHeaders.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/WebAssembly/ArithmeticTests/CMakeLists.txt --- a/OrthancFramework/Resources/CMake/WebAssembly/ArithmeticTests/CMakeLists.txt Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/WebAssembly/ArithmeticTests/CMakeLists.txt Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -51,7 +52,7 @@ include(${CMAKE_SOURCE_DIR}/../../DownloadPackage.cmake) set(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.2) -set(DCMTK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/dcmtk-3.6.2.tar.gz") +set(DCMTK_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/dcmtk-3.6.2.tar.gz") set(DCMTK_MD5 "d219a4152772985191c9b89d75302d12") if (IS_DIRECTORY "${DCMTK_SOURCES_DIR}") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CMake/ZlibConfiguration.cmake --- a/OrthancFramework/Resources/CMake/ZlibConfiguration.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CMake/ZlibConfiguration.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -20,9 +21,9 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_ZLIB) - SET(ZLIB_SOURCES_DIR ${CMAKE_BINARY_DIR}/zlib-1.2.11) - SET(ZLIB_URL "http://orthanc.osimis.io/ThirdPartyDownloads/zlib-1.2.11.tar.gz") - SET(ZLIB_MD5 "1c9f62f0778697a09d36121ead88e08e") + SET(ZLIB_SOURCES_DIR ${CMAKE_BINARY_DIR}/zlib-1.3.1) + SET(ZLIB_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads/zlib-1.3.1.tar.gz") + SET(ZLIB_MD5 "9855b6d802d7fe5b7bd5b196a2271655") DownloadPackage(${ZLIB_MD5} ${ZLIB_URL} "${ZLIB_SOURCES_DIR}") diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CheckOrthancFrameworkSymbols.py --- a/OrthancFramework/Resources/CheckOrthancFrameworkSymbols.py Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CheckOrthancFrameworkSymbols.py Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CodeGeneration/CheckDcmtkTransferSyntaxes.py --- a/OrthancFramework/Resources/CodeGeneration/CheckDcmtkTransferSyntaxes.py Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CodeGeneration/CheckDcmtkTransferSyntaxes.py Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CodeGeneration/ErrorCodes.json --- a/OrthancFramework/Resources/CodeGeneration/ErrorCodes.json Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CodeGeneration/ErrorCodes.json Tue Sep 24 11:39:52 2024 +0200 @@ -250,6 +250,18 @@ "Name": "MainDicomTagsMultiplyDefined", "Description": "A main DICOM Tag has been defined multiple times for the same resource level" }, + { + "Code": 45, + "HttpStatus": 403, + "Name": "ForbiddenAccess", + "Description": "Access to a resource is forbidden" + }, + { + "Code": 46, + "HttpStatus": 409, + "Name": "DuplicateResource", + "Description": "Duplicate resource" + }, diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CodeGeneration/GenerateErrorCodes.py --- a/OrthancFramework/Resources/CodeGeneration/GenerateErrorCodes.py Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CodeGeneration/GenerateErrorCodes.py Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -122,7 +123,7 @@ with open(path, 'r') as f: a = f.read() -e = filter(lambda x: 'SQLite' in x and x['SQLite'], ERRORS) +e = list(filter(lambda x: 'SQLite' in x and x['SQLite'], ERRORS)) s = ',\n'.join(map(lambda x: ' ErrorCode_%s' % x['Name'], e)) a = re.sub('(enum ErrorCode\s*{)[^}]*?(\s*};)', r'\1\n%s\2' % s, a, re.DOTALL) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxes.py --- a/OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxes.py Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxes.py Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxesDcmtk.mustache --- a/OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxesDcmtk.mustache Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxesDcmtk.mustache Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxesEnumerations.mustache --- a/OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxesEnumerations.mustache Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/CodeGeneration/GenerateTransferSyntaxesEnumerations.mustache Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/DcmtkTools/CMakeLists.txt --- a/OrthancFramework/Resources/DcmtkTools/CMakeLists.txt Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/DcmtkTools/CMakeLists.txt Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/DcmtkTools/dummy.cpp --- a/OrthancFramework/Resources/DcmtkTools/dummy.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/DcmtkTools/dummy.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/EmbedResources.py --- a/OrthancFramework/Resources/EmbedResources.py Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/EmbedResources.py Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Graveyard/FromDcmtkBridge.cpp --- a/OrthancFramework/Resources/Graveyard/FromDcmtkBridge.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Graveyard/FromDcmtkBridge.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -29,7 +30,7 @@ { // This raises BitBucket issue 140 (Modifying private tags with // REST API changes VR from LO to UN) - // https://bugs.orthanc-server.com/show_bug.cgi?id=140 + // https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=140 LOG(WARNING) << "You are using DCMTK < 3.6.1: All the private tags " "are considered as having a binary value representation"; return new DcmOtherByteOtherWord(key); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasks.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasks.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasks.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasksProcessor.cpp --- a/OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasksProcessor.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasksProcessor.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasksProcessor.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasksProcessor.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Graveyard/Multithreading/BagOfTasksProcessor.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Graveyard/Multithreading/ICommand.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/ICommand.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Graveyard/Multithreading/ICommand.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Graveyard/Multithreading/ILockable.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/ILockable.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Graveyard/Multithreading/ILockable.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Graveyard/Multithreading/Locker.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/Locker.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Graveyard/Multithreading/Locker.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Graveyard/Multithreading/Mutex.cpp --- a/OrthancFramework/Resources/Graveyard/Multithreading/Mutex.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Graveyard/Multithreading/Mutex.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Graveyard/Multithreading/Mutex.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/Mutex.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Graveyard/Multithreading/Mutex.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Graveyard/Multithreading/ReaderWriterLock.cpp --- a/OrthancFramework/Resources/Graveyard/Multithreading/ReaderWriterLock.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Graveyard/Multithreading/ReaderWriterLock.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Graveyard/Multithreading/ReaderWriterLock.h --- a/OrthancFramework/Resources/Graveyard/Multithreading/ReaderWriterLock.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Graveyard/Multithreading/ReaderWriterLock.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Graveyard/TestTranscoding.cpp --- a/OrthancFramework/Resources/Graveyard/TestTranscoding.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Graveyard/TestTranscoding.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/OpenSSL-ConfigureHeaders.py --- a/OrthancFramework/Resources/Patches/OpenSSL-ConfigureHeaders.py Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Patches/OpenSSL-ConfigureHeaders.py Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2021 Osimis S.A., Belgium -# Copyright (C) 2021-2021 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/OpenSSL-ExtractProvidersOIDs.py --- a/OrthancFramework/Resources/Patches/OpenSSL-ExtractProvidersOIDs.py Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Patches/OpenSSL-ExtractProvidersOIDs.py Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2021 Osimis S.A., Belgium -# Copyright (C) 2021-2021 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/boost-1.65.1-linux-standard-base.patch --- a/OrthancFramework/Resources/Patches/boost-1.65.1-linux-standard-base.patch Thu Sep 15 18:13:17 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -diff -urEb boost_1_65_1.orig/boost/move/adl_move_swap.hpp boost_1_65_1/boost/move/adl_move_swap.hpp ---- boost_1_65_1.orig/boost/move/adl_move_swap.hpp 2017-11-08 17:43:20.000000000 +0100 -+++ boost_1_65_1/boost/move/adl_move_swap.hpp 2018-01-02 15:34:48.829052917 +0100 -@@ -28,6 +28,8 @@ - //Try to avoid including , as it's quite big - #if defined(_MSC_VER) && defined(BOOST_DINKUMWARE_STDLIB) - #include //Dinkum libraries define std::swap in utility which is lighter than algorithm -+#elif defined(__LSB_VERSION__) -+# include - #elif defined(BOOST_GNU_STDLIB) - //For non-GCC compilers, where GNUC version is not very reliable, or old GCC versions - //use the good old stl_algobase header, which is quite lightweight diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/boost-1.66.0-linux-standard-base.patch --- a/OrthancFramework/Resources/Patches/boost-1.66.0-linux-standard-base.patch Thu Sep 15 18:13:17 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -diff -urEb boost_1_66_0.orig/boost/move/adl_move_swap.hpp boost_1_66_0/boost/move/adl_move_swap.hpp ---- boost_1_66_0.orig/boost/move/adl_move_swap.hpp 2018-04-11 11:56:16.761768726 +0200 -+++ boost_1_66_0/boost/move/adl_move_swap.hpp 2018-04-11 11:57:01.073881330 +0200 -@@ -28,6 +28,8 @@ - //Try to avoid including , as it's quite big - #if defined(_MSC_VER) && defined(BOOST_DINKUMWARE_STDLIB) - #include //Dinkum libraries define std::swap in utility which is lighter than algorithm -+#elif defined(__LSB_VERSION__) -+# include - #elif defined(BOOST_GNU_STDLIB) - //For non-GCC compilers, where GNUC version is not very reliable, or old GCC versions - //use the good old stl_algobase header, which is quite lightweight -Only in boost_1_66_0/boost/move: adl_move_swap.hpp~ diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/boost-1.67.0-linux-standard-base.patch --- a/OrthancFramework/Resources/Patches/boost-1.67.0-linux-standard-base.patch Thu Sep 15 18:13:17 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -diff -urEb boost_1_67_0.orig/boost/move/adl_move_swap.hpp boost_1_67_0/boost/move/adl_move_swap.hpp ---- boost_1_67_0.orig/boost/move/adl_move_swap.hpp 2018-06-20 17:42:27.000000000 +0200 -+++ boost_1_67_0/boost/move/adl_move_swap.hpp 2018-10-12 14:27:41.368076902 +0200 -@@ -28,6 +28,8 @@ - //Try to avoid including , as it's quite big - #if defined(_MSC_VER) && defined(BOOST_DINKUMWARE_STDLIB) - #include //Dinkum libraries define std::swap in utility which is lighter than algorithm -+#elif defined(__LSB_VERSION__) -+# include - #elif defined(BOOST_GNU_STDLIB) - //For non-GCC compilers, where GNUC version is not very reliable, or old GCC versions - //use the good old stl_algobase header, which is quite lightweight -diff -urEb boost_1_67_0.orig/boost/thread/detail/config.hpp boost_1_67_0/boost/thread/detail/config.hpp ---- boost_1_67_0.orig/boost/thread/detail/config.hpp 2018-06-20 17:42:27.000000000 +0200 -+++ boost_1_67_0/boost/thread/detail/config.hpp 2018-10-12 14:27:41.372076898 +0200 -@@ -417,6 +417,8 @@ - #define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO - #elif defined(BOOST_THREAD_CHRONO_MAC_API) - #define BOOST_THREAD_HAS_MONO_CLOCK -+#elif defined(__LSB_VERSION__) || defined(__ANDROID__) -+ #define BOOST_THREAD_HAS_MONO_CLOCK - #else - #include // check for CLOCK_MONOTONIC - #if defined(CLOCK_MONOTONIC) -diff -urEb boost_1_67_0.orig/boost/type_traits/detail/has_postfix_operator.hpp boost_1_67_0/boost/type_traits/detail/has_postfix_operator.hpp ---- boost_1_67_0.orig/boost/type_traits/detail/has_postfix_operator.hpp 2018-06-20 17:42:27.000000000 +0200 -+++ boost_1_67_0/boost/type_traits/detail/has_postfix_operator.hpp 2018-10-12 14:31:27.539874170 +0200 -@@ -32,8 +32,11 @@ - namespace boost { - namespace detail { - -+// https://stackoverflow.com/a/15474269 -+#ifndef Q_MOC_RUN - // This namespace ensures that argument-dependent name lookup does not mess things up. - namespace BOOST_JOIN(BOOST_TT_TRAIT_NAME,_impl) { -+#endif - - // 1. a function to have an instance of type T without requiring T to be default - // constructible -@@ -181,7 +184,9 @@ - BOOST_STATIC_CONSTANT(bool, value = (trait_impl1 < Lhs_noref, Ret, BOOST_TT_FORBIDDEN_IF >::value)); - }; - -+#ifndef Q_MOC_RUN - } // namespace impl -+#endif - } // namespace detail - - // this is the accessible definition of the trait to end user -diff -urEb boost_1_67_0.orig/boost/type_traits/detail/has_prefix_operator.hpp boost_1_67_0/boost/type_traits/detail/has_prefix_operator.hpp ---- boost_1_67_0.orig/boost/type_traits/detail/has_prefix_operator.hpp 2018-06-20 17:42:27.000000000 +0200 -+++ boost_1_67_0/boost/type_traits/detail/has_prefix_operator.hpp 2018-10-12 14:31:40.991862281 +0200 -@@ -45,8 +45,11 @@ - namespace boost { - namespace detail { - -+// https://stackoverflow.com/a/15474269 -+#ifndef Q_MOC_RUN - // This namespace ensures that argument-dependent name lookup does not mess things up. - namespace BOOST_JOIN(BOOST_TT_TRAIT_NAME,_impl) { -+#endif - - // 1. a function to have an instance of type T without requiring T to be default - // constructible -@@ -194,7 +197,9 @@ - BOOST_STATIC_CONSTANT(bool, value = (trait_impl1 < Rhs_noref, Ret, BOOST_TT_FORBIDDEN_IF >::value)); - }; - -+#ifndef Q_MOC_RUN - } // namespace impl -+#endif - } // namespace detail - - // this is the accessible definition of the trait to end user diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/boost-1.68.0-linux-standard-base.patch --- a/OrthancFramework/Resources/Patches/boost-1.68.0-linux-standard-base.patch Thu Sep 15 18:13:17 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -diff -urEb boost_1_68_0.orig/boost/move/adl_move_swap.hpp boost_1_68_0/boost/move/adl_move_swap.hpp ---- boost_1_68_0.orig/boost/move/adl_move_swap.hpp 2018-11-13 16:08:32.214434915 +0100 -+++ boost_1_68_0/boost/move/adl_move_swap.hpp 2018-11-13 16:09:03.558399048 +0100 -@@ -28,6 +28,8 @@ - //Try to avoid including , as it's quite big - #if defined(_MSC_VER) && defined(BOOST_DINKUMWARE_STDLIB) - #include //Dinkum libraries define std::swap in utility which is lighter than algorithm -+#elif defined(__LSB_VERSION__) -+# include - #elif defined(BOOST_GNU_STDLIB) - //For non-GCC compilers, where GNUC version is not very reliable, or old GCC versions - //use the good old stl_algobase header, which is quite lightweight -diff -urEb boost_1_68_0.orig/boost/thread/detail/config.hpp boost_1_68_0/boost/thread/detail/config.hpp ---- boost_1_68_0.orig/boost/thread/detail/config.hpp 2018-11-13 16:08:32.210434920 +0100 -+++ boost_1_68_0/boost/thread/detail/config.hpp 2018-11-13 16:10:03.386329911 +0100 -@@ -417,7 +417,7 @@ - #define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO - #elif defined(BOOST_THREAD_CHRONO_MAC_API) - #define BOOST_THREAD_HAS_MONO_CLOCK --#elif defined(__ANDROID__) -+#elif defined(__LSB_VERSION__) || defined(__ANDROID__) - #define BOOST_THREAD_HAS_MONO_CLOCK - #if defined(__ANDROID_API__) && __ANDROID_API__ >= 21 - #define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO -diff -urEb boost_1_68_0.orig/boost/type_traits/detail/has_postfix_operator.hpp boost_1_68_0/boost/type_traits/detail/has_postfix_operator.hpp ---- boost_1_68_0.orig/boost/type_traits/detail/has_postfix_operator.hpp 2018-11-13 16:08:32.206434924 +0100 -+++ boost_1_68_0/boost/type_traits/detail/has_postfix_operator.hpp 2018-11-13 16:11:08.374253901 +0100 -@@ -32,8 +32,11 @@ - namespace boost { - namespace detail { - -+// https://stackoverflow.com/a/15474269 -+#ifndef Q_MOC_RUN - // This namespace ensures that argument-dependent name lookup does not mess things up. - namespace BOOST_JOIN(BOOST_TT_TRAIT_NAME,_impl) { -+#endif - - // 1. a function to have an instance of type T without requiring T to be default - // constructible -@@ -181,7 +184,9 @@ - BOOST_STATIC_CONSTANT(bool, value = (trait_impl1 < Lhs_noref, Ret, BOOST_TT_FORBIDDEN_IF >::value)); - }; - -+#ifndef Q_MOC_RUN - } // namespace impl -+#endif - } // namespace detail - - // this is the accessible definition of the trait to end user -diff -urEb boost_1_68_0.orig/boost/type_traits/detail/has_prefix_operator.hpp boost_1_68_0/boost/type_traits/detail/has_prefix_operator.hpp ---- boost_1_68_0.orig/boost/type_traits/detail/has_prefix_operator.hpp 2018-11-13 16:08:32.206434924 +0100 -+++ boost_1_68_0/boost/type_traits/detail/has_prefix_operator.hpp 2018-11-13 16:14:30.278012856 +0100 -@@ -45,8 +45,11 @@ - namespace boost { - namespace detail { - -+// https://stackoverflow.com/a/15474269 -+#ifndef Q_MOC_RUN - // This namespace ensures that argument-dependent name lookup does not mess things up. - namespace BOOST_JOIN(BOOST_TT_TRAIT_NAME,_impl) { -+#endif - - // 1. a function to have an instance of type T without requiring T to be default - // constructible -@@ -194,7 +197,10 @@ - BOOST_STATIC_CONSTANT(bool, value = (trait_impl1 < Rhs_noref, Ret, BOOST_TT_FORBIDDEN_IF >::value)); - }; - -+ -+#ifndef Q_MOC_RUN - } // namespace impl -+#endif - } // namespace detail - - // this is the accessible definition of the trait to end user -Only in boost_1_68_0/boost/type_traits/detail: has_prefix_operator.hpp~ diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/boost-1.85.0-emscripten.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/Patches/boost-1.85.0-emscripten.patch Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,125 @@ +diff -urEb boost_1_85_0.orig/libs/locale/src/boost/locale/shared/date_time.cpp boost_1_85_0/libs/locale/src/boost/locale/shared/date_time.cpp +--- boost_1_85_0.orig/libs/locale/src/boost/locale/shared/date_time.cpp 2024-05-16 20:54:25.516816710 +0200 ++++ boost_1_85_0/libs/locale/src/boost/locale/shared/date_time.cpp 2024-05-16 20:55:09.144319528 +0200 +@@ -12,8 +12,10 @@ + #include + #include + #include +-#include +-#include ++#if !defined(__EMSCRIPTEN__) ++# include ++# include ++#endif + #include + + namespace boost { namespace locale { +@@ -400,6 +402,7 @@ + return impl_->get_option(abstract_calendar::is_dst) != 0; + } + ++#if !defined(__EMSCRIPTEN__) + namespace time_zone { + boost::mutex& tz_mutex() + { +@@ -422,6 +425,7 @@ + return boost::exchange(tz_id(), new_id); + } + } // namespace time_zone ++#endif + + }} // namespace boost::locale + +diff -urEb boost_1_85_0.orig/libs/locale/src/boost/locale/shared/generator.cpp boost_1_85_0/libs/locale/src/boost/locale/shared/generator.cpp +--- boost_1_85_0.orig/libs/locale/src/boost/locale/shared/generator.cpp 2024-05-16 20:54:25.516816710 +0200 ++++ boost_1_85_0/libs/locale/src/boost/locale/shared/generator.cpp 2024-05-16 20:56:20.231509636 +0200 +@@ -7,8 +7,10 @@ + #include + #include + #include +-#include +-#include ++#if !defined(__EMSCRIPTEN__) ++# include ++# include ++#endif + #include + #include + #include +@@ -21,7 +23,9 @@ + {} + + mutable std::map cached; ++#if !defined(__EMSCRIPTEN__) + mutable boost::mutex cached_lock; ++#endif + + category_t cats; + char_facet_t chars; +@@ -101,7 +105,9 @@ + std::locale generator::generate(const std::locale& base, const std::string& id) const + { + if(d->caching_enabled) { ++#if !defined(__EMSCRIPTEN__) + boost::unique_lock guard(d->cached_lock); ++#endif + const auto p = d->cached.find(id); + if(p != d->cached.end()) + return p->second; +@@ -126,7 +132,9 @@ + result = backend->install(result, facet, char_facet_t::nochar); + } + if(d->caching_enabled) { ++#if !defined(__EMSCRIPTEN__) + boost::unique_lock guard(d->cached_lock); ++#endif + const auto p = d->cached.find(id); + if(p == d->cached.end()) + d->cached[id] = result; +diff -urEb boost_1_85_0.orig/libs/locale/src/boost/locale/shared/localization_backend.cpp boost_1_85_0/libs/locale/src/boost/locale/shared/localization_backend.cpp +--- boost_1_85_0.orig/libs/locale/src/boost/locale/shared/localization_backend.cpp 2024-05-16 20:54:25.516816710 +0200 ++++ boost_1_85_0/libs/locale/src/boost/locale/shared/localization_backend.cpp 2024-05-16 20:56:58.823070064 +0200 +@@ -5,8 +5,10 @@ + // https://www.boost.org/LICENSE_1_0.txt + + #include +-#include +-#include ++#if !defined(__EMSCRIPTEN__) ++# include ++# include ++#endif + #include + #include + #include +@@ -211,11 +213,13 @@ + return mgr; + } + ++#if !defined(__EMSCRIPTEN__) + boost::mutex& localization_backend_manager_mutex() + { + static boost::mutex the_mutex; + return the_mutex; + } ++#endif + localization_backend_manager& localization_backend_manager_global() + { + static localization_backend_manager the_manager = make_default_backend_mgr(); +@@ -225,12 +229,16 @@ + + localization_backend_manager localization_backend_manager::global() + { ++#if !defined(__EMSCRIPTEN__) + boost::unique_lock lock(localization_backend_manager_mutex()); ++#endif + return localization_backend_manager_global(); + } + localization_backend_manager localization_backend_manager::global(const localization_backend_manager& in) + { ++#if !defined(__EMSCRIPTEN__) + boost::unique_lock lock(localization_backend_manager_mutex()); ++#endif + return exchange(localization_backend_manager_global(), in); + } + diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/civetweb-1.11.patch --- a/OrthancFramework/Resources/Patches/civetweb-1.11.patch Thu Sep 15 18:13:17 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -diff -urEb civetweb-1.11.orig/include/civetweb.h civetweb-1.11/include/civetweb.h ---- civetweb-1.11.orig/include/civetweb.h 2019-01-17 21:09:41.844888908 +0100 -+++ civetweb-1.11/include/civetweb.h 2019-01-21 12:05:08.138998659 +0100 -@@ -1507,6 +1507,10 @@ - #endif - - -+// Added by SJ -+CIVETWEB_API void mg_disable_keep_alive(struct mg_connection *conn); -+ -+ - #ifdef __cplusplus - } - #endif /* __cplusplus */ -diff -urEb civetweb-1.11.orig/src/civetweb.c civetweb-1.11/src/civetweb.c ---- civetweb-1.11.orig/src/civetweb.c 2019-01-17 21:09:41.852888857 +0100 -+++ civetweb-1.11/src/civetweb.c 2019-01-21 12:06:35.826868284 +0100 -@@ -59,6 +59,9 @@ - #if defined(__linux__) && !defined(_XOPEN_SOURCE) - #define _XOPEN_SOURCE 600 /* For flockfile() on Linux */ - #endif -+#if defined(__LSB_VERSION__) -+#define NEED_TIMEGM -+#endif - #if !defined(_LARGEFILE_SOURCE) - #define _LARGEFILE_SOURCE /* For fseeko(), ftello() */ - #endif -@@ -129,6 +132,12 @@ - - - /* Alternative queue is well tested and should be the new default */ -+#if defined(__LSB_VERSION__) -+/* Function "eventfd()" is not available in Linux Standard Base, can't -+ * use the alternative queue */ -+#define NO_ALTERNATIVE_QUEUE -+#endif -+ - #if defined(NO_ALTERNATIVE_QUEUE) - #if defined(ALTERNATIVE_QUEUE) - #error "Define ALTERNATIVE_QUEUE or NO_ALTERNATIVE_QUEUE or none, but not both" -@@ -536,6 +545,10 @@ - #if !defined(EWOULDBLOCK) - #define EWOULDBLOCK WSAEWOULDBLOCK - #endif /* !EWOULDBLOCK */ -+#if !defined(ECONNRESET) -+/* This macro is not defined e.g. in Visual Studio 2008 */ -+#define ECONNRESET WSAECONNRESET -+#endif /* !ECONNRESET */ - #define _POSIX_ - #define INT64_FMT "I64d" - #define UINT64_FMT "I64u" -@@ -2939,6 +2952,13 @@ - #endif - - -+#if defined(__LSB_VERSION__) -+static void -+mg_set_thread_name(const char *threadName) -+{ -+ /* prctl() does not seem to be available in Linux Standard Base */ -+} -+#else - static void - mg_set_thread_name(const char *name) - { -@@ -2980,6 +3000,7 @@ - (void)prctl(PR_SET_NAME, threadName, 0, 0, 0); - #endif - } -+#endif - #else /* !defined(NO_THREAD_NAME) */ - void - mg_set_thread_name(const char *threadName) -@@ -16919,6 +16940,10 @@ - /* Message is a valid request */ - - /* Is there a "host" ? */ -+ /* https://github.com/civetweb/civetweb/pull/675/commits/96e3e8c50acb4b8e0c946d02b5f880a3e62986e1 */ -+ if (conn->host!=NULL) { -+ mg_free((void *)conn->host); -+ } - conn->host = alloc_get_host(conn); - if (!conn->host) { - mg_snprintf(conn, -@@ -19857,4 +19882,13 @@ - } - - -+// Added by SJ -+void mg_disable_keep_alive(struct mg_connection *conn) -+{ -+ if (conn != NULL) { -+ conn->must_close = 1; -+ } -+} -+ -+ - /* End of civetweb.c */ diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/civetweb-1.12.patch --- a/OrthancFramework/Resources/Patches/civetweb-1.12.patch Thu Sep 15 18:13:17 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -diff -urEb civetweb-1.12.orig/include/civetweb.h civetweb-1.12/include/civetweb.h ---- civetweb-1.12.orig/include/civetweb.h 2020-10-06 12:39:10.634902843 +0200 -+++ civetweb-1.12/include/civetweb.h 2020-10-06 12:39:30.630872089 +0200 -@@ -1614,6 +1614,9 @@ - struct mg_error_data *error); - #endif - -+// Added by SJ -+CIVETWEB_API void mg_disable_keep_alive(struct mg_connection *conn); -+ - #ifdef __cplusplus - } - #endif /* __cplusplus */ -diff -urEb civetweb-1.12.orig/src/civetweb.c civetweb-1.12/src/civetweb.c ---- civetweb-1.12.orig/src/civetweb.c 2020-10-06 12:39:10.638902837 +0200 -+++ civetweb-1.12/src/civetweb.c 2020-10-06 12:41:40.110671929 +0200 -@@ -10525,6 +10525,11 @@ - /* + MicroSoft extensions - * https://msdn.microsoft.com/en-us/library/aa142917.aspx */ - -+ /* Added by SJ, for write access to WebDAV on Windows >= 7 */ -+ {"LOCK", 1, 1, 0, 0, 0}, -+ {"UNLOCK", 1, 0, 0, 0, 0}, -+ {"PROPPATCH", 1, 1, 0, 0, 0}, -+ - /* REPORT method (RFC 3253) */ - {"REPORT", 1, 1, 1, 1, 1}, - /* REPORT method only allowed for CGI/Lua/LSP and callbacks. */ -@@ -20704,5 +20709,12 @@ - return 1; - } - -+// Added by SJ -+void mg_disable_keep_alive(struct mg_connection *conn) -+{ -+ if (conn != NULL) { -+ conn->must_close = 1; -+ } -+} - - /* End of civetweb.c */ diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/civetweb-1.14.patch --- a/OrthancFramework/Resources/Patches/civetweb-1.14.patch Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Patches/civetweb-1.14.patch Tue Sep 24 11:39:52 2024 +0200 @@ -1,6 +1,38 @@ diff -urEb civetweb-1.14.orig/src/civetweb.c civetweb-1.14/src/civetweb.c ---- civetweb-1.14.orig/src/civetweb.c 2021-06-21 17:42:52.343136123 +0200 -+++ civetweb-1.14/src/civetweb.c 2021-06-21 17:43:11.623158128 +0200 +--- civetweb-1.14.orig/src/civetweb.c 2023-07-06 15:48:01.163703913 +0200 ++++ civetweb-1.14/src/civetweb.c 2023-07-06 15:48:51.207843938 +0200 +@@ -567,7 +567,7 @@ + #if (_MSC_VER < 1300) + #define STRX(x) #x + #define STR(x) STRX(x) +-#define __func__ __FILE__ ":" STR(__LINE__) ++#define __func__ __ORTHANC_FILE__ ":" STR(__LINE__) + #define strtoull(x, y, z) ((unsigned __int64)_atoi64(x)) + #define strtoll(x, y, z) (_atoi64(x)) + #else +@@ -1450,14 +1450,14 @@ + } + + +-#define mg_malloc(a) mg_malloc_ex(a, NULL, __FILE__, __LINE__) +-#define mg_calloc(a, b) mg_calloc_ex(a, b, NULL, __FILE__, __LINE__) +-#define mg_realloc(a, b) mg_realloc_ex(a, b, NULL, __FILE__, __LINE__) +-#define mg_free(a) mg_free_ex(a, __FILE__, __LINE__) +- +-#define mg_malloc_ctx(a, c) mg_malloc_ex(a, c, __FILE__, __LINE__) +-#define mg_calloc_ctx(a, b, c) mg_calloc_ex(a, b, c, __FILE__, __LINE__) +-#define mg_realloc_ctx(a, b, c) mg_realloc_ex(a, b, c, __FILE__, __LINE__) ++#define mg_malloc(a) mg_malloc_ex(a, NULL, __ORTHANC_FILE__, __LINE__) ++#define mg_calloc(a, b) mg_calloc_ex(a, b, NULL, __ORTHANC_FILE__, __LINE__) ++#define mg_realloc(a, b) mg_realloc_ex(a, b, NULL, __ORTHANC_FILE__, __LINE__) ++#define mg_free(a) mg_free_ex(a, __ORTHANC_FILE__, __LINE__) ++ ++#define mg_malloc_ctx(a, c) mg_malloc_ex(a, c, __ORTHANC_FILE__, __LINE__) ++#define mg_calloc_ctx(a, b, c) mg_calloc_ex(a, b, c, __ORTHANC_FILE__, __LINE__) ++#define mg_realloc_ctx(a, b, c) mg_realloc_ex(a, b, c, __ORTHANC_FILE__, __LINE__) + + + #else /* USE_SERVER_STATS */ @@ -1774,6 +1774,7 @@ #if !defined(OPENSSL_API_3_0) #define OPENSSL_API_3_0 diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/curl-7.77.0.patch --- a/OrthancFramework/Resources/Patches/curl-7.77.0.patch Thu Sep 15 18:13:17 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -diff -urEb curl-7.77.0.orig/CMake/Macros.cmake curl-7.77.0/CMake/Macros.cmake ---- curl-7.77.0.orig/CMake/Macros.cmake 2021-06-22 10:31:21.875004553 +0200 -+++ curl-7.77.0/CMake/Macros.cmake 2021-06-22 10:31:45.219024665 +0200 -@@ -59,7 +59,7 @@ - message(STATUS "Performing Curl Test ${CURL_TEST}") - try_compile(${CURL_TEST} - ${CMAKE_BINARY_DIR} -- ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c -+ ${CURL_SOURCES_DIR}/CMake/CurlTests.c - CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} - "${CURL_TEST_ADD_LIBRARIES}" - OUTPUT_VARIABLE OUTPUT) -diff -urEb curl-7.77.0.orig/lib/vssh/ssh.h curl-7.77.0/lib/vssh/ssh.h ---- curl-7.77.0.orig/lib/vssh/ssh.h 2021-06-22 10:31:21.843004526 +0200 -+++ curl-7.77.0/lib/vssh/ssh.h 2021-06-22 10:36:34.271266232 +0200 -@@ -22,7 +22,7 @@ - * - ***************************************************************************/ - --#include "curl_setup.h" -+#include "../curl_setup.h" - - #if defined(HAVE_LIBSSH2_H) - #include diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/curl-8.9.0.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/Patches/curl-8.9.0.patch Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,12 @@ +diff -urEb curl-8.9.0.orig/CMake/Macros.cmake curl-8.9.0/CMake/Macros.cmake +--- curl-8.9.0.orig/CMake/Macros.cmake 2024-07-26 18:47:52.920588300 +0200 ++++ curl-8.9.0/CMake/Macros.cmake 2024-07-26 18:48:08.345522100 +0200 +@@ -48,7 +48,7 @@ + message(STATUS "Performing Test ${CURL_TEST}") + try_compile(${CURL_TEST} + ${CMAKE_BINARY_DIR} +- ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c ++ ${CURL_SOURCES_DIR}/CMake/CurlTests.c + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} + "${CURL_TEST_ADD_LIBRARIES}" + OUTPUT_VARIABLE OUTPUT) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/dcmtk-3.6.8-visual-studio.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/Patches/dcmtk-3.6.8-visual-studio.patch Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,995 @@ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jccoefct.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jccoefct.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jccoefct.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jccoefct.c 2024-01-09 17:48:28.974677157 +0100 +@@ -343,7 +343,7 @@ + METHODDEF(boolean) + compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) + { +- (void)input_buf; ++ //(void)input_buf; + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jcdiffct.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jcdiffct.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jcdiffct.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jcdiffct.c 2024-01-09 17:48:36.414609533 +0100 +@@ -302,7 +302,7 @@ + METHODDEF(boolean) + compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) + { +- (void)input_buf; ++ //(void)input_buf; + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + /* JDIMENSION MCU_col_num; */ /* index of current MCU within row */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jcpred.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jcpred.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jcpred.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jcpred.c 2024-01-09 17:48:49.766488124 +0100 +@@ -213,7 +213,7 @@ + const JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) + { +- (void)prev_row; ++ //(void)prev_row; + DIFFERENCE_1D(INITIAL_PREDICTORx); + + /* +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jctrans.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jctrans.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jctrans.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jctrans.c 2024-01-09 17:49:00.070394388 +0100 +@@ -267,7 +267,7 @@ + METHODDEF(boolean) + compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) + { +- (void)input_buf; ++ //(void)input_buf; + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jdmerge.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jdmerge.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jdmerge.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jdmerge.c 2024-01-09 17:49:11.910286634 +0100 +@@ -148,7 +148,7 @@ + JDIMENSION out_rows_avail) + /* 2:1 vertical sampling case: may need a spare row. */ + { +- (void) in_row_groups_avail; ++ //(void) in_row_groups_avail; + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW work_ptrs[2]; + JDIMENSION num_rows; /* number of rows returned to caller */ +@@ -198,8 +198,8 @@ + JDIMENSION out_rows_avail) + /* 1:1 vertical sampling case: much easier, never need a spare row. */ + { +- (void) in_row_groups_avail; +- (void) out_rows_avail; ++ //(void) in_row_groups_avail; ++ //(void) out_rows_avail; + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Just do the upsampling. */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jdpostct.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jdpostct.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jdpostct.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jdpostct.c 2024-01-09 17:49:24.910168268 +0100 +@@ -161,8 +161,8 @@ + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) + { +- (void) output_buf; +- (void) out_rows_avail; ++ //(void) output_buf; ++ //(void) out_rows_avail; + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION old_next_row, num_rows; + +@@ -207,9 +207,9 @@ + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) + { +- (void) input_buf; +- (void) in_row_group_ctr; +- (void) in_row_groups_avail; ++ //(void) input_buf; ++ //(void) in_row_group_ctr; ++ //(void) in_row_groups_avail; + + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jdpred.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jdpred.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jdpred.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jdpred.c 2024-01-09 17:50:00.513843814 +0100 +@@ -101,8 +101,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_1D(INITIAL_PREDICTOR2); + } + +@@ -111,8 +111,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_2D(PREDICTOR2); + JPEG_UNUSED(Rc); + JPEG_UNUSED(Rb); +@@ -123,8 +123,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_2D(PREDICTOR3); + JPEG_UNUSED(Rc); + JPEG_UNUSED(Rb); +@@ -135,8 +135,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_2D(PREDICTOR4); + JPEG_UNUSED(Rc); + JPEG_UNUSED(Rb); +@@ -147,8 +147,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR5); + JPEG_UNUSED(Rc); +@@ -160,8 +160,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR6); + JPEG_UNUSED(Rc); +@@ -173,8 +173,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR7); + JPEG_UNUSED(Rc); +@@ -195,7 +195,7 @@ + JDIFFROW undiff_buf, JDIMENSION width) + { + +- (void)prev_row; ++ //(void)prev_row; + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + + UNDIFFERENCE_1D(INITIAL_PREDICTORx); +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jdsample.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jdsample.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jdsample.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jdsample.c 2024-01-09 17:50:36.545515066 +0100 +@@ -92,7 +92,7 @@ + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) + { +- (void)in_row_groups_avail; ++ //(void)in_row_groups_avail; + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int ci; + jpeg_component_info * compptr; +@@ -158,8 +158,8 @@ + fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + { +- (void)cinfo; +- (void)compptr; ++ //(void)cinfo; ++ //(void)compptr; + *output_data_ptr = input_data; + } + +@@ -173,9 +173,9 @@ + noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + { +- (void)cinfo; +- (void)compptr; +- (void)input_data; ++ //(void)cinfo; ++ //(void)compptr; ++ //(void)input_data; + *output_data_ptr = NULL; /* safety check */ + } + +@@ -239,7 +239,7 @@ + h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + { +- (void)compptr; ++ //(void)compptr; + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; +@@ -268,7 +268,7 @@ + h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + { +- (void)compptr; ++ //(void)compptr; + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jdscale.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jdscale.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jdscale.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jdscale.c 2024-01-09 17:50:42.833457657 +0100 +@@ -67,7 +67,7 @@ + const JDIFFROW diff_buf, JSAMPROW output_buf, + JDIMENSION width) + { +- (void)cinfo; ++ //(void)cinfo; + unsigned int xindex; + + for (xindex = 0; xindex < width; xindex++) +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jquant1.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jquant1.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jquant1.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jquant1.c 2024-01-09 17:51:03.049273013 +0100 +@@ -251,8 +251,8 @@ + * (Forcing the upper and lower values to the limits ensures that + * dithering can't produce a color outside the selected gamut.) + */ +- (void) cinfo; +- (void) ci; ++ //(void) cinfo; ++ //(void) ci; + return (int) (((IJG_INT32) j * MAXJSAMPLE + maxj/2) / maxj); + } + +@@ -262,8 +262,8 @@ + /* Return largest input value that should map to j'th output value */ + /* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */ + { +- (void) cinfo; +- (void) ci; ++ //(void) cinfo; ++ //(void) ci; + /* Breakpoints are halfway between values returned by output_value */ + return (int) (((IJG_INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj)); + } +@@ -744,7 +744,7 @@ + METHODDEF(void) + start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan) + { +- (void) is_pre_scan; ++ //(void) is_pre_scan; + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; +@@ -802,7 +802,7 @@ + METHODDEF(void) + finish_pass_1_quant (j_decompress_ptr cinfo) + { +- (void) cinfo; ++ //(void) cinfo; + /* no work in 1-pass case */ + } + +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jquant2.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jquant2.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg12/jquant2.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg12/jquant2.c 2024-01-09 17:51:16.685148405 +0100 +@@ -224,7 +224,7 @@ + prescan_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) + { +- (void) output_buf; ++ //(void) output_buf; + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register JSAMPROW ptr; + register histptr histp; +@@ -1156,7 +1156,7 @@ + METHODDEF(void) + finish_pass2 (j_decompress_ptr cinfo) + { +- (void) cinfo; ++ //(void) cinfo; + /* no work */ + } + +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jccoefct.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jccoefct.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jccoefct.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jccoefct.c 2024-01-09 17:51:24.997072424 +0100 +@@ -343,7 +343,7 @@ + METHODDEF(boolean) + compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) + { +- (void)input_buf; ++ //(void)input_buf; + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jcdiffct.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jcdiffct.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jcdiffct.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jcdiffct.c 2024-01-09 17:51:31.549012520 +0100 +@@ -302,7 +302,7 @@ + METHODDEF(boolean) + compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) + { +- (void)input_buf; ++ //(void)input_buf; + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + /* JDIMENSION MCU_col_num; */ /* index of current MCU within row */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jcpred.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jcpred.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jcpred.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jcpred.c 2024-01-09 17:51:40.740928459 +0100 +@@ -213,7 +213,7 @@ + const JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) + { +- (void)prev_row; ++ //(void)prev_row; + DIFFERENCE_1D(INITIAL_PREDICTORx); + + /* +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jctrans.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jctrans.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jctrans.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jctrans.c 2024-01-09 17:51:49.244850672 +0100 +@@ -267,7 +267,7 @@ + METHODDEF(boolean) + compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) + { +- (void)input_buf; ++ //(void)input_buf; + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jdmerge.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jdmerge.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jdmerge.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jdmerge.c 2024-01-09 17:51:59.852753613 +0100 +@@ -171,7 +171,7 @@ + JDIMENSION out_rows_avail) + /* 2:1 vertical sampling case: may need a spare row. */ + { +- (void) in_row_groups_avail; ++ //(void) in_row_groups_avail; + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW work_ptrs[2]; + JDIMENSION num_rows; /* number of rows returned to caller */ +@@ -221,8 +221,8 @@ + JDIMENSION out_rows_avail) + /* 1:1 vertical sampling case: much easier, never need a spare row. */ + { +- (void) in_row_groups_avail; +- (void) out_rows_avail; ++ //(void) in_row_groups_avail; ++ //(void) out_rows_avail; + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Just do the upsampling. */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jdpostct.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jdpostct.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jdpostct.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jdpostct.c 2024-01-09 17:52:12.796635145 +0100 +@@ -161,8 +161,8 @@ + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) + { +- (void) output_buf; +- (void) out_rows_avail; ++ //(void) output_buf; ++ //(void) out_rows_avail; + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION old_next_row, num_rows; + +@@ -207,9 +207,9 @@ + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) + { +- (void) input_buf; +- (void) in_row_group_ctr; +- (void) in_row_groups_avail; ++ //(void) input_buf; ++ //(void) in_row_group_ctr; ++ //(void) in_row_groups_avail; + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jdpred.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jdpred.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jdpred.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jdpred.c 2024-01-09 17:53:08.884121363 +0100 +@@ -101,8 +101,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_1D(INITIAL_PREDICTOR2); + } + +@@ -111,8 +111,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_2D(PREDICTOR2); + JPEG_UNUSED(Rc); + JPEG_UNUSED(Rb); +@@ -123,8 +123,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_2D(PREDICTOR3); + JPEG_UNUSED(Rc); + JPEG_UNUSED(Rb); +@@ -135,8 +135,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_2D(PREDICTOR4A); + JPEG_UNUSED(Rc); + JPEG_UNUSED(Rb); +@@ -147,8 +147,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_2D(PREDICTOR4); + JPEG_UNUSED(Rc); + JPEG_UNUSED(Rb); +@@ -159,8 +159,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR5); + JPEG_UNUSED(Rc); +@@ -172,8 +172,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR5A); + JPEG_UNUSED(Rc); +@@ -185,8 +185,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR6); + JPEG_UNUSED(Rc); +@@ -198,8 +198,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR6A); + JPEG_UNUSED(Rc); +@@ -211,8 +211,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR7); + JPEG_UNUSED(Rc); +@@ -224,8 +224,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR7A); + JPEG_UNUSED(Rc); +@@ -245,7 +245,7 @@ + const JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)prev_row; ++ //(void)prev_row; + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + + UNDIFFERENCE_1D(INITIAL_PREDICTORx); +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jdsample.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jdsample.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jdsample.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jdsample.c 2024-01-09 17:53:28.779938946 +0100 +@@ -92,7 +92,7 @@ + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) + { +- (void)in_row_groups_avail; ++ //(void)in_row_groups_avail; + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int ci; + jpeg_component_info * compptr; +@@ -158,8 +158,8 @@ + fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + { +- (void)cinfo; +- (void)compptr; ++ //(void)cinfo; ++ //(void)compptr; + *output_data_ptr = input_data; + } + +@@ -173,9 +173,9 @@ + noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + { +- (void)cinfo; +- (void)compptr; +- (void)input_data; ++ //(void)cinfo; ++ //(void)compptr; ++ //(void)input_data; + *output_data_ptr = NULL; /* safety check */ + } + +@@ -239,7 +239,7 @@ + h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + { +- (void)compptr; ++ //(void)compptr; + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; +@@ -268,7 +268,7 @@ + h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + { +- (void)compptr; ++ //(void)compptr; + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jdscale.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jdscale.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jdscale.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jdscale.c 2024-01-09 17:53:34.795883773 +0100 +@@ -67,7 +67,7 @@ + const JDIFFROW diff_buf, JSAMPROW output_buf, + JDIMENSION width) + { +- (void)cinfo; ++ //(void)cinfo; + unsigned int xindex; + + for (xindex = 0; xindex < width; xindex++) +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jquant1.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jquant1.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jquant1.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jquant1.c 2024-01-09 17:53:53.891708593 +0100 +@@ -251,8 +251,8 @@ + * (Forcing the upper and lower values to the limits ensures that + * dithering can't produce a color outside the selected gamut.) + */ +- (void) cinfo; +- (void) ci; ++ //(void) cinfo; ++ //(void) ci; + return (int) (((IJG_INT32) j * MAXJSAMPLE + maxj/2) / maxj); + } + +@@ -262,8 +262,8 @@ + /* Return largest input value that should map to j'th output value */ + /* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */ + { +- (void) cinfo; +- (void) ci; ++ //(void) cinfo; ++ //(void) ci; + /* Breakpoints are halfway between values returned by output_value */ + return (int) (((IJG_INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj)); + } +@@ -744,7 +744,7 @@ + METHODDEF(void) + start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan) + { +- (void) is_pre_scan; ++ //(void) is_pre_scan; + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; +@@ -802,7 +802,7 @@ + METHODDEF(void) + finish_pass_1_quant (j_decompress_ptr cinfo) + { +- (void) cinfo; ++ //(void) cinfo; + /* no work in 1-pass case */ + } + +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jquant2.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jquant2.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg16/jquant2.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg16/jquant2.c 2024-01-09 17:54:05.051606183 +0100 +@@ -224,7 +224,7 @@ + prescan_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) + { +- (void) output_buf; ++ //(void) output_buf; + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register JSAMPROW ptr; + register histptr histp; +@@ -1156,7 +1156,7 @@ + METHODDEF(void) + finish_pass2 (j_decompress_ptr cinfo) + { +- (void) cinfo; ++ //(void) cinfo; + /* no work */ + } + +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jccoefct.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jccoefct.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jccoefct.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jccoefct.c 2024-01-09 17:54:11.635545753 +0100 +@@ -343,7 +343,7 @@ + METHODDEF(boolean) + compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) + { +- (void)input_buf; ++ //(void)input_buf; + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jcdiffct.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jcdiffct.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jcdiffct.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jcdiffct.c 2024-01-09 17:54:16.815498204 +0100 +@@ -302,7 +302,7 @@ + METHODDEF(boolean) + compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) + { +- (void)input_buf; ++ //(void)input_buf; + j_lossless_c_ptr losslsc = (j_lossless_c_ptr) cinfo->codec; + c_diff_ptr diff = (c_diff_ptr) losslsc->diff_private; + /* JDIMENSION MCU_col_num; */ /* index of current MCU within row */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jcpred.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jcpred.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jcpred.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jcpred.c 2024-01-09 17:54:25.827415468 +0100 +@@ -213,7 +213,7 @@ + const JSAMPROW input_buf, JSAMPROW prev_row, + JDIFFROW diff_buf, JDIMENSION width) + { +- (void)prev_row; ++ //(void)prev_row; + DIFFERENCE_1D(INITIAL_PREDICTORx); + + /* +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jctrans.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jctrans.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jctrans.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jctrans.c 2024-01-09 17:54:33.939340981 +0100 +@@ -267,7 +267,7 @@ + METHODDEF(boolean) + compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) + { +- (void)input_buf; ++ //(void)input_buf; + j_lossy_c_ptr lossyc = (j_lossy_c_ptr) cinfo->codec; + c_coef_ptr coef = (c_coef_ptr) lossyc->coef_private; + JDIMENSION MCU_col_num; /* index of current MCU within row */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jdmerge.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jdmerge.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jdmerge.c 2024-01-09 17:13:10.345673450 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jdmerge.c 2024-01-09 17:54:41.019275962 +0100 +@@ -148,7 +148,7 @@ + JDIMENSION out_rows_avail) + /* 2:1 vertical sampling case: may need a spare row. */ + { +- (void) in_row_groups_avail; ++ //(void) in_row_groups_avail; + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW work_ptrs[2]; + JDIMENSION num_rows; /* number of rows returned to caller */ +@@ -198,8 +198,8 @@ + JDIMENSION out_rows_avail) + /* 1:1 vertical sampling case: much easier, never need a spare row. */ + { +- (void) in_row_groups_avail; +- (void) out_rows_avail; ++ //(void) in_row_groups_avail; ++ //(void) out_rows_avail; + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Just do the upsampling. */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jdpostct.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jdpostct.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jdpostct.c 2024-01-09 17:13:10.349673411 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jdpostct.c 2024-01-09 17:54:48.891203659 +0100 +@@ -161,8 +161,8 @@ + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) + { +- (void) output_buf; +- (void) out_rows_avail; ++ //(void) output_buf; ++ //(void) out_rows_avail; + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION old_next_row, num_rows; + +@@ -207,9 +207,9 @@ + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) + { +- (void) input_buf; +- (void) in_row_group_ctr; +- (void) in_row_groups_avail; ++ //(void) input_buf; ++ //(void) in_row_group_ctr; ++ //(void) in_row_groups_avail; + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jdpred.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jdpred.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jdpred.c 2024-01-09 17:13:10.349673411 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jdpred.c 2024-01-09 17:55:02.179081586 +0100 +@@ -101,8 +101,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_1D(INITIAL_PREDICTOR2); + } + +@@ -111,8 +111,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_2D(PREDICTOR2); + JPEG_UNUSED(Rc); + JPEG_UNUSED(Rb); +@@ -123,8 +123,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_2D(PREDICTOR3); + JPEG_UNUSED(Rc); + JPEG_UNUSED(Rb); +@@ -135,8 +135,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + UNDIFFERENCE_2D(PREDICTOR4); + JPEG_UNUSED(Rc); + JPEG_UNUSED(Rb); +@@ -147,8 +147,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR5); + JPEG_UNUSED(Rc); +@@ -160,8 +160,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR6); + JPEG_UNUSED(Rc); +@@ -173,8 +173,8 @@ + const JDIFFROW diff_buf, const JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)cinfo; +- (void)comp_index; ++ //(void)cinfo; ++ //(void)comp_index; + SHIFT_TEMPS + UNDIFFERENCE_2D(PREDICTOR7); + JPEG_UNUSED(Rc); +@@ -194,7 +194,7 @@ + const JDIFFROW diff_buf, JDIFFROW prev_row, + JDIFFROW undiff_buf, JDIMENSION width) + { +- (void)prev_row; ++ //(void)prev_row; + j_lossless_d_ptr losslsd = (j_lossless_d_ptr) cinfo->codec; + + UNDIFFERENCE_1D(INITIAL_PREDICTORx); +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jdsample.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jdsample.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jdsample.c 2024-01-09 17:13:10.349673411 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jdsample.c 2024-01-09 17:55:13.234979994 +0100 +@@ -92,7 +92,7 @@ + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) + { +- (void)in_row_groups_avail; ++ //(void)in_row_groups_avail; + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int ci; + jpeg_component_info * compptr; +@@ -158,8 +158,8 @@ + fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + { +- (void)cinfo; +- (void)compptr; ++ //(void)cinfo; ++ //(void)compptr; + *output_data_ptr = input_data; + } + +@@ -173,9 +173,9 @@ + noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + { +- (void)cinfo; +- (void)compptr; +- (void)input_data; ++ //(void)cinfo; ++ //(void)compptr; ++ //(void)input_data; + *output_data_ptr = NULL; /* safety check */ + } + +@@ -239,7 +239,7 @@ + h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + { +- (void)compptr; ++ //(void)compptr; + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; +@@ -268,7 +268,7 @@ + h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + { +- (void)compptr; ++ //(void)compptr; + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jdscale.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jdscale.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jdscale.c 2024-01-09 17:13:10.349673411 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jdscale.c 2024-01-09 17:55:21.722901985 +0100 +@@ -67,7 +67,7 @@ + const JDIFFROW diff_buf, JSAMPROW output_buf, + JDIMENSION width) + { +- (void)cinfo; ++ //(void)cinfo; + unsigned int xindex; + + for (xindex = 0; xindex < width; xindex++) +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jquant1.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jquant1.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jquant1.c 2024-01-09 17:13:10.349673411 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jquant1.c 2024-01-09 17:48:22.270738074 +0100 +@@ -251,8 +251,8 @@ + * (Forcing the upper and lower values to the limits ensures that + * dithering can't produce a color outside the selected gamut.) + */ +- (void) cinfo; +- (void) ci; ++ //(void) cinfo; ++ //(void) ci; + return (int) (((IJG_INT32) j * MAXJSAMPLE + maxj/2) / maxj); + } + +@@ -262,8 +262,8 @@ + /* Return largest input value that should map to j'th output value */ + /* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */ + { +- (void) cinfo; +- (void) ci; ++ //(void) cinfo; ++ //(void) ci; + /* Breakpoints are halfway between values returned by output_value */ + return (int) (((IJG_INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj)); + } +@@ -744,7 +744,7 @@ + METHODDEF(void) + start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan) + { +- (void) is_pre_scan; ++ //(void) is_pre_scan; + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; +@@ -802,7 +802,7 @@ + METHODDEF(void) + finish_pass_1_quant (j_decompress_ptr cinfo) + { +- (void) cinfo; ++ //(void) cinfo; + /* no work in 1-pass case */ + } + +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jquant2.c dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jquant2.c +--- dcmtk-DCMTK-3.6.8.orig/dcmjpeg/libijg8/jquant2.c 2024-01-09 17:13:10.349673411 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmjpeg/libijg8/jquant2.c 2024-01-09 17:47:42.343100533 +0100 +@@ -224,7 +224,7 @@ + prescan_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) + { +- (void) output_buf; ++ //(void) output_buf; + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register JSAMPROW ptr; + register histptr histp; +@@ -1156,7 +1156,7 @@ + METHODDEF(void) + finish_pass2 (j_decompress_ptr cinfo) + { +- (void) cinfo; ++ //(void) cinfo; + /* no work */ + } + diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/dcmtk-3.6.8.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/Patches/dcmtk-3.6.8.patch Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,139 @@ +diff -urEb dcmtk-DCMTK-3.6.8.orig/CMake/GenerateDCMTKConfigure.cmake dcmtk-DCMTK-3.6.8/CMake/GenerateDCMTKConfigure.cmake +--- dcmtk-DCMTK-3.6.8.orig/CMake/GenerateDCMTKConfigure.cmake 2024-01-09 17:13:10.329673608 +0100 ++++ dcmtk-DCMTK-3.6.8/CMake/GenerateDCMTKConfigure.cmake 2024-01-09 18:21:52.568142681 +0100 +@@ -224,6 +224,8 @@ + + # Check the sizes of various types + include (CheckTypeSize) ++if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") ++ # This doesn't work for wasm, Orthanc defines the macros manually + CHECK_TYPE_SIZE("char" SIZEOF_CHAR) + CHECK_TYPE_SIZE("double" SIZEOF_DOUBLE) + CHECK_TYPE_SIZE("float" SIZEOF_FLOAT) +@@ -231,6 +233,7 @@ + CHECK_TYPE_SIZE("long" SIZEOF_LONG) + CHECK_TYPE_SIZE("short" SIZEOF_SHORT) + CHECK_TYPE_SIZE("void*" SIZEOF_VOID_P) ++endif() + + # Check for include files, libraries, and functions + include("${DCMTK_CMAKE_INCLUDE}CMake/dcmtkTryCompile.cmake") +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmdata/include/dcmtk/dcmdata/dcdict.h dcmtk-DCMTK-3.6.8/dcmdata/include/dcmtk/dcmdata/dcdict.h +--- dcmtk-DCMTK-3.6.8.orig/dcmdata/include/dcmtk/dcmdata/dcdict.h 2024-01-09 17:13:10.337673529 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmdata/include/dcmtk/dcmdata/dcdict.h 2024-01-09 18:21:52.568142681 +0100 +@@ -162,6 +162,12 @@ + /// returns an iterator to the end of the repeating tag dictionary + DcmDictEntryListIterator repeatingEnd() { return repDict.end(); } + ++ // Function by the Orthanc project to load a dictionary from a ++ // memory buffer, which is necessary in sandboxed ++ // environments. This is an adapted version of ++ // DcmDataDictionary::loadDictionary(). ++ OFBool loadFromMemory(const std::string& content, OFBool errorIfAbsent = OFTrue); ++ + private: + + /** private undefined assignment operator +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmdata/libsrc/dcdict.cc dcmtk-DCMTK-3.6.8/dcmdata/libsrc/dcdict.cc +--- dcmtk-DCMTK-3.6.8.orig/dcmdata/libsrc/dcdict.cc 2024-01-09 17:13:10.337673529 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmdata/libsrc/dcdict.cc 2024-01-09 18:21:52.568142681 +0100 +@@ -914,3 +914,5 @@ + wrlock().clear(); + wrunlock(); + } ++ ++#include "dcdict_orthanc.cc" +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmdata/libsrc/dcpxitem.cc dcmtk-DCMTK-3.6.8/dcmdata/libsrc/dcpxitem.cc +--- dcmtk-DCMTK-3.6.8.orig/dcmdata/libsrc/dcpxitem.cc 2024-01-09 17:13:10.337673529 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmdata/libsrc/dcpxitem.cc 2024-01-09 18:21:52.568142681 +0100 +@@ -31,6 +31,9 @@ + #include "dcmtk/dcmdata/dcostrma.h" /* for class DcmOutputStream */ + #include "dcmtk/dcmdata/dcwcache.h" /* for class DcmWriteCache */ + ++#undef max ++#include "dcmtk/ofstd/oflimits.h" ++ + + // ******************************** + +diff -urEb dcmtk-DCMTK-3.6.8.orig/dcmnet/libsrc/scu.cc dcmtk-DCMTK-3.6.8/dcmnet/libsrc/scu.cc +--- dcmtk-DCMTK-3.6.8.orig/dcmnet/libsrc/scu.cc 2024-01-09 17:13:10.349673411 +0100 ++++ dcmtk-DCMTK-3.6.8/dcmnet/libsrc/scu.cc 2024-01-09 18:23:08.723435667 +0100 +@@ -19,6 +19,11 @@ + * + */ + ++#if defined(_WIN32) ++# define __STDC_LIMIT_MACROS // Get access to UINT16_MAX ++# include ++#endif ++ + #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ + + #include "dcmtk/dcmdata/dcostrmf.h" /* for class DcmOutputFileStream */ +diff -urEb dcmtk-DCMTK-3.6.8.orig/oflog/include/dcmtk/oflog/thread/syncpub.h dcmtk-DCMTK-3.6.8/oflog/include/dcmtk/oflog/thread/syncpub.h +--- dcmtk-DCMTK-3.6.8.orig/oflog/include/dcmtk/oflog/thread/syncpub.h 2024-01-09 17:13:10.389673016 +0100 ++++ dcmtk-DCMTK-3.6.8/oflog/include/dcmtk/oflog/thread/syncpub.h 2024-01-09 18:21:52.568142681 +0100 +@@ -63,7 +63,7 @@ + + DCMTK_LOG4CPLUS_INLINE_EXPORT + Mutex::Mutex (Mutex::Type t) +- : mtx (DCMTK_LOG4CPLUS_THREADED (new impl::Mutex (t) + 0)) ++ : mtx (DCMTK_LOG4CPLUS_THREADED (new impl::Mutex (t))) + { } + + +@@ -106,7 +106,7 @@ + DCMTK_LOG4CPLUS_INLINE_EXPORT + Semaphore::Semaphore (unsigned DCMTK_LOG4CPLUS_THREADED (max), + unsigned DCMTK_LOG4CPLUS_THREADED (initial)) +- : sem (DCMTK_LOG4CPLUS_THREADED (new impl::Semaphore (max, initial) + 0)) ++ : sem (DCMTK_LOG4CPLUS_THREADED (new impl::Semaphore (max, initial))) + { } + + +@@ -190,7 +190,7 @@ + + DCMTK_LOG4CPLUS_INLINE_EXPORT + ManualResetEvent::ManualResetEvent (bool DCMTK_LOG4CPLUS_THREADED (sig)) +- : ev (DCMTK_LOG4CPLUS_THREADED (new impl::ManualResetEvent (sig) + 0)) ++ : ev (DCMTK_LOG4CPLUS_THREADED (new impl::ManualResetEvent (sig))) + { } + + +@@ -252,7 +252,7 @@ + + DCMTK_LOG4CPLUS_INLINE_EXPORT + SharedMutex::SharedMutex () +- : sm (DCMTK_LOG4CPLUS_THREADED (new impl::SharedMutex + 0)) ++ : sm (DCMTK_LOG4CPLUS_THREADED (new impl::SharedMutex)) + { } + + +diff -urEb dcmtk-DCMTK-3.6.8.orig/oflog/libsrc/oflog.cc dcmtk-DCMTK-3.6.8/oflog/libsrc/oflog.cc +--- dcmtk-DCMTK-3.6.8.orig/oflog/libsrc/oflog.cc 2024-01-09 17:13:10.389673016 +0100 ++++ dcmtk-DCMTK-3.6.8/oflog/libsrc/oflog.cc 2024-01-09 18:21:52.568142681 +0100 +@@ -19,6 +19,11 @@ + * + */ + ++ ++#if defined(_WIN32) ++# include ++#endif ++ + #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ + #include "dcmtk/oflog/oflog.h" + +diff -urEb dcmtk-DCMTK-3.6.8.orig/ofstd/include/dcmtk/ofstd/offile.h dcmtk-DCMTK-3.6.8/ofstd/include/dcmtk/ofstd/offile.h +--- dcmtk-DCMTK-3.6.8.orig/ofstd/include/dcmtk/ofstd/offile.h 2024-01-09 17:13:10.389673016 +0100 ++++ dcmtk-DCMTK-3.6.8/ofstd/include/dcmtk/ofstd/offile.h 2024-01-09 18:21:52.568142681 +0100 +@@ -570,7 +570,7 @@ + */ + void setlinebuf() + { +-#if defined(_WIN32) || defined(__hpux) ++#if defined(_WIN32) || defined(__hpux) || defined(__LSB_VERSION__) + this->setvbuf(NULL, _IOLBF, 0); + #else + :: setlinebuf(file_); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/openssl-3.0.5.patch --- a/OrthancFramework/Resources/Patches/openssl-3.0.5.patch Thu Sep 15 18:13:17 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -diff -urEb openssl-3.0.5.orig/crypto/threads_win.c openssl-3.0.5/crypto/threads_win.c ---- openssl-3.0.5.orig/crypto/threads_win.c 2022-08-15 15:37:28.944910076 +0200 -+++ openssl-3.0.5/crypto/threads_win.c 2022-08-15 15:38:34.120081931 +0200 -@@ -207,13 +207,30 @@ - int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret, - CRYPTO_RWLOCK *lock) - { -+#if defined(_WIN32) && !defined(_WIN64) -+ /** -+ * Prevents the following error, at least on Visual Studio 2008, -+ * but most probably on any Window 32bit system: -+ * "CoreLibrary.lib(threads_win.obj) : error LNK2019: unresolved -+ * external symbol _InterlockedOr64 referenced in function -+ * _CRYPTO_atomic_or". TODO - The lock should be locked! -+ * https://developercommunity.visualstudio.com/t/-interlockedexchangeadd64-is-unresolved-on-x86/1227636 -+ **/ -+ *ret = (*val) | op; -+#else - *ret = (uint64_t)InterlockedOr64((LONG64 volatile *)val, (LONG64)op) | op; -+#endif - return 1; - } - - int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock) - { -+#if defined(_WIN32) && !defined(_WIN64) -+ /* See comment above */ -+ *ret = *val; -+#else - *ret = (uint64_t)InterlockedOr64((LONG64 volatile *)val, 0); -+#endif - return 1; - } - -diff -urEb openssl-3.0.5.orig/providers/implementations/rands/seeding/rand_unix.c openssl-3.0.5/providers/implementations/rands/seeding/rand_unix.c ---- openssl-3.0.5.orig/providers/implementations/rands/seeding/rand_unix.c 2022-08-15 15:37:28.968909770 +0200 -+++ openssl-3.0.5/providers/implementations/rands/seeding/rand_unix.c 2022-08-15 15:39:00.963742658 +0200 -@@ -453,6 +453,7 @@ - * system call and this should always succeed which renders - * this alternative but essentially identical source moot. - */ -+#if !defined(__LSB_VERSION__) // "syscall()" is not available in LSB - if (uname(&un) == 0) { - kernel[0] = atoi(un.release); - p = strchr(un.release, '.'); -@@ -463,6 +464,7 @@ - return 0; - } - } -+#endif - /* Open /dev/random and wait for it to be readable */ - if ((fd = open(DEVRANDOM_WAIT, O_RDONLY)) != -1) { - if (DEVRANDM_WAIT_USE_SELECT && fd < FD_SETSIZE) { diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/openssl-3.1.4.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/Patches/openssl-3.1.4.patch Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,47 @@ +diff -urEb openssl-3.1.4.orig/crypto/riscvcap.c openssl-3.1.4/crypto/riscvcap.c +--- openssl-3.1.4.orig/crypto/riscvcap.c 2024-01-24 16:58:48.308108757 +0100 ++++ openssl-3.1.4/crypto/riscvcap.c 2024-01-24 17:01:04.114914015 +0100 +@@ -37,7 +37,8 @@ + + static void strtoupper(char *str) + { +- for (char *x = str; *x; ++x) ++ char* x; ++ for (x = str; *x; ++x) + *x = toupper(*x); + } + +@@ -51,12 +52,13 @@ + { + char envstrupper[BUFLEN]; + char buf[BUFLEN]; ++ size_t i; + + /* Convert env str to all uppercase */ + OPENSSL_strlcpy(envstrupper, envstr, sizeof(envstrupper)); + strtoupper(envstrupper); + +- for (size_t i = 0; i < kRISCVNumCaps; ++i) { ++ for (i = 0; i < kRISCVNumCaps; ++i) { + /* Prefix capability with underscore in preparation for search */ + BIO_snprintf(buf, BUFLEN, "_%s", RISCV_capabilities[i].name); + if (strstr(envstrupper, buf) != NULL) { +diff -urEb openssl-3.1.4.orig/providers/implementations/rands/seeding/rand_unix.c openssl-3.1.4/providers/implementations/rands/seeding/rand_unix.c +--- openssl-3.1.4.orig/providers/implementations/rands/seeding/rand_unix.c 2024-01-24 16:58:48.332108547 +0100 ++++ openssl-3.1.4/providers/implementations/rands/seeding/rand_unix.c 2024-01-24 17:01:30.182683539 +0100 +@@ -452,6 +452,7 @@ + * system call and this should always succeed which renders + * this alternative but essentially identical source moot. + */ ++#if !defined(__LSB_VERSION__) // "syscall()" is not available in LSB + if (uname(&un) == 0) { + kernel[0] = atoi(un.release); + p = strchr(un.release, '.'); +@@ -462,6 +463,7 @@ + return 0; + } + } ++#endif + /* Open /dev/random and wait for it to be readable */ + if ((fd = open(DEVRANDOM_WAIT, O_RDONLY)) != -1) { + if (DEVRANDM_WAIT_USE_SELECT && fd < FD_SETSIZE) { diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Patches/protobuf-3.5.1.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/Patches/protobuf-3.5.1.patch Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,30 @@ +diff -urEb protobuf-3.5.1.orig/src/google/protobuf/stubs/io_win32.cc protobuf-3.5.1/src/google/protobuf/stubs/io_win32.cc +--- protobuf-3.5.1.orig/src/google/protobuf/stubs/io_win32.cc 2023-03-26 20:13:45.095021011 +0200 ++++ protobuf-3.5.1/src/google/protobuf/stubs/io_win32.cc 2023-03-26 20:19:19.932920102 +0200 +@@ -91,7 +91,12 @@ + + template + bool null_or_empty(const char_type* s) { +- return s == nullptr || *s == 0; ++ /** ++ * "nullptr" is not known to Visual Studio 2008, because this is a ++ * C++11 construction, which shouldn't be present in protobuf 3.5.1 ++ * that is supposed to comply with C++98. ++ **/ ++ return s == NULL || *s == 0; + } + + // Returns true if the path starts with a drive letter, e.g. "c:". +diff -urEb protobuf-3.5.1.orig/src/google/protobuf/stubs/hash.h protobuf-3.5.1/src/google/protobuf/stubs/hash.h +--- protobuf-3.5.1.orig/src/google/protobuf/stubs/hash.h 2023-03-26 20:13:45.095021011 +0200 ++++ protobuf-3.5.1/src/google/protobuf/stubs/hash.h 2023-03-26 20:19:19.932920102 +0200 +@@ -1,3 +1,9 @@ ++#if _MSC_VER >= 1930 // Since Visual Studio 2022 ++#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS ++#include ++#include ++#endif ++ + // Protocol Buffers - Google's data interchange format + // Copyright 2008 Google Inc. All rights reserved. + // https://developers.google.com/protocol-buffers/ \ No newline at end of file diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ProtocolBuffers/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/ProtocolBuffers/CMakeLists.txt Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,150 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + +cmake_minimum_required(VERSION 2.8.3) + +project(ProtocolBuffers) + +set(ALLOW_DOWNLOADS ON) + +include(${CMAKE_SOURCE_DIR}/../CMake/DownloadPackage.cmake) +include(${CMAKE_SOURCE_DIR}/../CMake/Compiler.cmake) + +include(${CMAKE_SOURCE_DIR}/ProtobufLibrary.cmake) + +set(PROTOBUF_COMPILER_SOURCES + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_enum.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_enum_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_extension.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_file.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_generator.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_helpers.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_map_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_message.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_message_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_service.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_string_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_enum.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_enum_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_field_base.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_generator.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_helpers.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_map_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_message.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_message_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/importer.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_context.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_doc_comment.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_enum.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_enum_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_enum_field_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_enum_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_extension.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_extension_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_file.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_generator.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_generator_factory.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_helpers.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_lazy_message_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_map_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_map_field_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_message.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_message_builder.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_message_builder_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_message_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_message_field_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_message_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_name_resolver.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_primitive_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_primitive_field_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_service.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_shared_code_generator.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_string_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/java/java_string_field_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_enum.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_enum_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_extension.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_file.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_generator.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_helpers.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_map_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_message.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_message_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc + #${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/js/embed.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/js/js_generator.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/js/well_known_types_embed.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/main.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_extension.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_file.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_generator.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/parser.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/php/php_generator.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/plugin.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/python/python_generator.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/subprocess.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/compiler/zip_writer.cc + ) + +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + set_property( + SOURCE ${PROTOBUF_COMPILER_SOURCES} APPEND + PROPERTY COMPILE_DEFINITIONS "HAVE_PTHREAD=1" + ) +endif() + +add_executable(protoc + ${PROTOBUF_LIBRARY_SOURCES} + ${PROTOBUF_COMPILER_SOURCES} + ) + +install( + TARGETS protoc + RUNTIME DESTINATION . + ) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ProtocolBuffers/NOTES.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/ProtocolBuffers/NOTES.txt Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,29 @@ + +Version +======= + +We use Google's Protocol Buffers version 3.5.1, as this is the last +release to be compatible with C++98, which is mandatory for Visual +Studio 2008 and Linux Standard Base. + +References: +https://github.com/protocolbuffers/protobuf/releases/tag/v3.5.1 +https://github.com/protocolbuffers/protobuf/issues/2780 + + +Linux Standard Base +=================== + +$ mkdir lsb +$ cd lsb +$ LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Release -DALLOW_DOWNLOADS=ON -DCMAKE_TOOLCHAIN_FILE=../../Toolchains/LinuxStandardBaseToolchain.cmake -G Ninja +$ ninja + + +MinGW for 32bits +================ + +$ mkdir w32 +$ cd w32 +$ LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Release -DALLOW_DOWNLOADS=ON -DCMAKE_TOOLCHAIN_FILE=../../Toolchains/MinGW-W64-Toolchain32.cmake -G Ninja +$ ninja diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ProtocolBuffers/ProtobufLibrary.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Resources/ProtocolBuffers/ProtobufLibrary.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,145 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + +set(PROTOBUF_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/protobuf-3.5.1) + +if (IS_DIRECTORY "${PROTOBUF_SOURCE_DIR}") + set(FirstRun OFF) +else() + set(FirstRun ON) +endif() + +DownloadPackage( + "ca0d9b243e649d398a6b419acd35103a" + "https://orthanc.uclouvain.be/downloads/third-party-downloads/protobuf-cpp-3.5.1.tar.gz" + "${CMAKE_CURRENT_BINARY_DIR}/protobuf-3.5.1") + +if (FirstRun) + # Apply the patches + execute_process( + COMMAND ${PATCH_EXECUTABLE} -p0 -N -i + ${CMAKE_CURRENT_LIST_DIR}/../Patches/protobuf-3.5.1.patch + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + + if (Failure) + message(FATAL_ERROR "Error while patching a file") + endif() +endif() + +include_directories( + ${PROTOBUF_SOURCE_DIR}/src + ) + +set(PROTOBUF_LIBRARY_SOURCES + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/any.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/any.pb.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/api.pb.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/arena.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/arenastring.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/descriptor.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/descriptor.pb.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/descriptor_database.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/duration.pb.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/dynamic_message.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/empty.pb.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/extension_set.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/extension_set_heavy.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/field_mask.pb.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/generated_message_reflection.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/generated_message_table_driven.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/generated_message_table_driven_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/generated_message_util.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/coded_stream.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/gzip_stream.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/printer.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/strtod.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/tokenizer.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/map_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/message.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/message_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/reflection_ops.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/repeated_field.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/service.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/source_context.pb.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/struct.pb.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_arm64_gcc.h + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_arm_gcc.h + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_mips_gcc.h + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_ppc_gcc.h + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/common.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/int128.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/io_win32.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/mathlimits.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/once.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/status.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/statusor.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/stringpiece.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/stringprintf.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/structurally_valid.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/strutil.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/substitute.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/time.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/stubs/bytestream.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/text_format.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/timestamp.pb.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/type.pb.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/unknown_field_set.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/field_comparator.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/field_mask_util.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/datapiece.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/default_value_objectwriter.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/error_listener.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/field_mask_utility.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/json_escaping.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/json_objectwriter.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/json_stream_parser.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/object_writer.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/proto_writer.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectsource.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectwriter.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/type_info.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/internal/utility.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/json_util.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/message_differencer.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/time_util.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/util/type_resolver_util.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/wire_format.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/wire_format_lite.cc + ${PROTOBUF_SOURCE_DIR}/src/google/protobuf/wrappers.pb.cc + ) + +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + set_property( + SOURCE ${PROTOBUF_LIBRARY_SOURCES} APPEND + PROPERTY COMPILE_DEFINITIONS "HAVE_PTHREAD=1" + ) +endif() diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/RetrieveCACertificates.py --- a/OrthancFramework/Resources/RetrieveCACertificates.py Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/RetrieveCACertificates.py Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -31,7 +32,7 @@ print('Download a set of CA certificates, convert them to PEM, then format them as a C macro') print('Usage: %s [Macro] [Certificate1] ...' % sys.argv[0]) print('') - print('Example: %s BITBUCKET_CERTIFICATES https://cacerts.digicert.com/DigiCertSHA2HighAssuranceServerCA.crt' % sys.argv[0]) + print('Example: %s GITHUB_CERTIFICATES https://cacerts.digicert.com/DigiCertSHA2HighAssuranceServerCA.crt' % sys.argv[0]) print('') sys.exit(-1) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Samples/MicroService/CMakeLists.txt --- a/OrthancFramework/Resources/Samples/MicroService/CMakeLists.txt Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Samples/MicroService/CMakeLists.txt Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Samples/MicroService/Sample.cpp --- a/OrthancFramework/Resources/Samples/MicroService/Sample.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Samples/MicroService/Sample.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ThirdParty/icu/CMakeLists.txt --- a/OrthancFramework/Resources/ThirdParty/icu/CMakeLists.txt Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/ThirdParty/icu/CMakeLists.txt Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ThirdParty/icu/Version.cmake --- a/OrthancFramework/Resources/ThirdParty/icu/Version.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/ThirdParty/icu/Version.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -32,7 +33,7 @@ set(LIBICU_SUFFIX "l") endif() -set(LIBICU_BASE_URL "http://orthanc.osimis.io/ThirdPartyDownloads") +set(LIBICU_BASE_URL "https://orthanc.uclouvain.be/downloads/third-party-downloads") if (USE_LEGACY_LIBICU) # This is the latest version of icu that compiles without C++11 diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ThirdParty/minizip/NOTES --- a/OrthancFramework/Resources/ThirdParty/minizip/NOTES Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/ThirdParty/minizip/NOTES Tue Sep 24 11:39:52 2024 +0200 @@ -1,1 +1,2 @@ -These files come from the "contrib/minizip" directory in zlib 1.2.11. +These files come from the "contrib/minizip" directory in zlib 1.3+. +It was last synced on this commit: https://github.com/madler/zlib/commit/73331a6a0481067628f065ffe87bb1d8f787d10c. diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ThirdParty/minizip/crypt.h --- a/OrthancFramework/Resources/ThirdParty/minizip/crypt.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/ThirdParty/minizip/crypt.h Tue Sep 24 11:39:52 2024 +0200 @@ -32,12 +32,12 @@ /*********************************************************************** * Return the next byte in the pseudo-random sequence */ -static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) -{ +static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) { unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem * with any known compiler so far, though */ + (void)pcrc_32_tab; temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); } @@ -45,8 +45,7 @@ /*********************************************************************** * Update the encryption keys with the next byte of plain text */ -static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c) -{ +static int update_keys(unsigned long* pkeys, const z_crc_t* pcrc_32_tab, int c) { (*(pkeys+0)) = CRC32((*(pkeys+0)), c); (*(pkeys+1)) += (*(pkeys+0)) & 0xff; (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; @@ -62,8 +61,7 @@ * Initialize the encryption keys and the random header according to * the given password. */ -static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab) -{ +static void init_keys(const char* passwd, unsigned long* pkeys, const z_crc_t* pcrc_32_tab) { *(pkeys+0) = 305419896L; *(pkeys+1) = 591751049L; *(pkeys+2) = 878082192L; @@ -77,24 +75,23 @@ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) #define zencode(pkeys,pcrc_32_tab,c,t) \ - (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), (Byte)t^(c)) #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED #define RAND_HEAD_LEN 12 /* "last resort" source for second part of crypt seed pattern */ # ifndef ZCR_SEED2 -# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ # endif -static int crypthead(const char* passwd, /* password string */ - unsigned char* buf, /* where to write header */ - int bufSize, - unsigned long* pkeys, - const z_crc_t* pcrc_32_tab, - unsigned long crcForCrypting) -{ - int n; /* index in random header */ +static unsigned crypthead(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned long* pkeys, + const z_crc_t* pcrc_32_tab, + unsigned long crcForCrypting) { + unsigned n; /* index in random header */ int t; /* temporary */ int c; /* random byte */ unsigned char header[RAND_HEAD_LEN-2]; /* random header */ diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ThirdParty/minizip/ioapi.c --- a/OrthancFramework/Resources/ThirdParty/minizip/ioapi.c Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/ThirdParty/minizip/ioapi.c Tue Sep 24 11:39:52 2024 +0200 @@ -14,7 +14,7 @@ #define _CRT_SECURE_NO_WARNINGS #endif -#if defined(__APPLE__) || defined(IOAPI_NO_64) +#if defined(__APPLE__) || defined(IOAPI_NO_64) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64) // In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions #define FOPEN_FUNC(filename, mode) fopen(filename, mode) #define FTELLO_FUNC(stream) ftello(stream) @@ -28,8 +28,7 @@ #include "ioapi.h" -voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) -{ +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc, const void*filename, int mode) { if (pfilefunc->zfile_func64.zopen64_file != NULL) return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); else @@ -38,8 +37,7 @@ } } -long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) -{ +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); else @@ -52,13 +50,12 @@ } } -ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) -{ +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc, voidpf filestream) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); else { - uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + uLong tell_uLong = (uLong)(*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); if ((tell_uLong) == MAXU32) return (ZPOS64_T)-1; else @@ -66,11 +63,9 @@ } } -void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) -{ +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32, const zlib_filefunc_def* p_filefunc32) { p_filefunc64_32->zfile_func64.zopen64_file = NULL; p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; - p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; p_filefunc64_32->zfile_func64.ztell64_file = NULL; @@ -84,18 +79,10 @@ -static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); -static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); -static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); -static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); -static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); - -static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) -{ +static voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; + (void)opaque; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else @@ -110,10 +97,10 @@ return file; } -static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) -{ +static voidpf ZCALLBACK fopen64_file_func(voidpf opaque, const void* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; + (void)opaque; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else @@ -129,39 +116,39 @@ } -static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) -{ +static uLong ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uLong size) { uLong ret; + (void)opaque; ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); return ret; } -static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) -{ +static uLong ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void* buf, uLong size) { uLong ret; + (void)opaque; ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); return ret; } -static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) -{ +static long ZCALLBACK ftell_file_func(voidpf opaque, voidpf stream) { long ret; + (void)opaque; ret = ftell((FILE *)stream); return ret; } -static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) -{ +static ZPOS64_T ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream) { ZPOS64_T ret; - ret = FTELLO_FUNC((FILE *)stream); + (void)opaque; + ret = (ZPOS64_T)FTELLO_FUNC((FILE *)stream); return ret; } -static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) -{ +static long ZCALLBACK fseek_file_func(voidpf opaque, voidpf stream, uLong offset, int origin) { int fseek_origin=0; long ret; + (void)opaque; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : @@ -176,15 +163,15 @@ default: return -1; } ret = 0; - if (fseek((FILE *)stream, offset, fseek_origin) != 0) + if (fseek((FILE *)stream, (long)offset, fseek_origin) != 0) ret = -1; return ret; } -static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) -{ +static long ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) { int fseek_origin=0; long ret; + (void)opaque; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : @@ -200,30 +187,28 @@ } ret = 0; - if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0) + if(FSEEKO_FUNC((FILE *)stream, (z_off64_t)offset, fseek_origin) != 0) ret = -1; return ret; } -static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) -{ +static int ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream) { int ret; + (void)opaque; ret = fclose((FILE *)stream); return ret; } -static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) -{ +static int ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream) { int ret; + (void)opaque; ret = ferror((FILE *)stream); return ret; } -void fill_fopen_filefunc (pzlib_filefunc_def) - zlib_filefunc_def* pzlib_filefunc_def; -{ +void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen_file = fopen_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; @@ -234,8 +219,7 @@ pzlib_filefunc_def->opaque = NULL; } -void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) -{ +void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen64_file = fopen64_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ThirdParty/minizip/ioapi.h --- a/OrthancFramework/Resources/ThirdParty/minizip/ioapi.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/ThirdParty/minizip/ioapi.h Tue Sep 24 11:39:52 2024 +0200 @@ -50,7 +50,7 @@ #define ftello64 ftell #define fseeko64 fseek #else -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64) #define fopen64 fopen #define ftello64 ftello #define fseeko64 fseeko @@ -82,7 +82,7 @@ #include "mz64conf.h" #endif -/* a type choosen by DEFINE */ +/* a type chosen by DEFINE */ #ifdef HAVE_64BIT_INT_CUSTOM typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; #else @@ -91,8 +91,7 @@ typedef uint64_t ZPOS64_T; #else -/* Maximum unsigned 32-bit value used as placeholder for zip64 */ -#define MAXU32 0xffffffff + #if defined(_MSC_VER) || defined(__BORLANDC__) typedef unsigned __int64 ZPOS64_T; @@ -102,7 +101,10 @@ #endif #endif - +/* Maximum unsigned 32-bit value used as placeholder for zip64 */ +#ifndef MAXU32 +#define MAXU32 (0xffffffff) +#endif #ifdef __cplusplus extern "C" { @@ -132,17 +134,17 @@ -typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); -typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); -typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); -typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); +typedef voidpf (ZCALLBACK *open_file_func) (voidpf opaque, const char* filename, int mode); +typedef uLong (ZCALLBACK *read_file_func) (voidpf opaque, voidpf stream, void* buf, uLong size); +typedef uLong (ZCALLBACK *write_file_func) (voidpf opaque, voidpf stream, const void* buf, uLong size); +typedef int (ZCALLBACK *close_file_func) (voidpf opaque, voidpf stream); +typedef int (ZCALLBACK *testerror_file_func) (voidpf opaque, voidpf stream); -typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); -typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); +typedef long (ZCALLBACK *tell_file_func) (voidpf opaque, voidpf stream); +typedef long (ZCALLBACK *seek_file_func) (voidpf opaque, voidpf stream, uLong offset, int origin); -/* here is the "old" 32 bits structure structure */ +/* here is the "old" 32 bits structure */ typedef struct zlib_filefunc_def_s { open_file_func zopen_file; @@ -155,9 +157,9 @@ voidpf opaque; } zlib_filefunc_def; -typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); -typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) (voidpf opaque, voidpf stream); +typedef long (ZCALLBACK *seek64_file_func) (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin); +typedef voidpf (ZCALLBACK *open64_file_func) (voidpf opaque, const void* filename, int mode); typedef struct zlib_filefunc64_def_s { @@ -171,8 +173,8 @@ voidpf opaque; } zlib_filefunc64_def; -void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); -void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); +void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def); +void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def); /* now internal definition, only for zip.c and unzip.h */ typedef struct zlib_filefunc64_32_def_s @@ -191,11 +193,11 @@ #define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) #define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) -voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); -long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); -ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); +voidpf call_zopen64(const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode); +long call_zseek64(const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin); +ZPOS64_T call_ztell64(const zlib_filefunc64_32_def* pfilefunc,voidpf filestream); -void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); #define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) #define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ThirdParty/minizip/unzip.c --- a/OrthancFramework/Resources/ThirdParty/minizip/unzip.c Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/ThirdParty/minizip/unzip.c Tue Sep 24 11:39:52 2024 +0200 @@ -49,12 +49,12 @@ Copyright (C) 2007-2008 Even Rouault - Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G should only read the compressed/uncompressed size from the Zip64 format if the size from normal header was 0xFFFFFFFF - Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant - Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Oct-2009 - Mathias Svensson - Applied some bug fixes from patches received from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression method BZIP2 (bzip2 lib is required) Patch created by Daniel Borca Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer @@ -77,8 +77,6 @@ #ifdef STDC # include -# include -# include #endif #ifdef NO_ERRNO_H extern int errno; @@ -111,9 +109,6 @@ #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) @@ -153,7 +148,7 @@ ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ zlib_filefunc64_32_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ + voidpf filestream; /* io structure of the zipfile */ uLong compression_method; /* compression method (0==store) */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ int raw; @@ -166,7 +161,7 @@ { zlib_filefunc64_32_def z_filefunc; int is64bitOpenFunction; - voidpf filestream; /* io structore of the zipfile */ + voidpf filestream; /* io structure of the zipfile */ unz_global_info64 gi; /* public global information */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T num_file; /* number of the current file in the zipfile*/ @@ -197,29 +192,44 @@ #include "crypt.h" #endif + /* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been successfully opened for reading. + Reads a long in LSB order from the given gz_stream. Sets */ - -local int unz64local_getByte OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - int *pi)); - -local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) -{ - unsigned char c; - int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); - if (err==1) +local int unz64local_getShort(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) { + unsigned char c[2]; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,2); + if (err==2) { - *pi = (int)c; + *pX = c[0] | ((uLong)c[1] << 8); return UNZ_OK; } else { + *pX = 0; + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + +local int unz64local_getLong(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) { + unsigned char c[4]; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,4); + if (err==4) + { + *pX = c[0] | ((uLong)c[1] << 8) | ((uLong)c[2] << 16) | ((uLong)c[3] << 24); + return UNZ_OK; + } + else + { + *pX = 0; if (ZERROR64(*pzlib_filefunc_def,filestream)) return UNZ_ERRNO; else @@ -228,126 +238,29 @@ } -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -local int unz64local_getShort OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX) -{ - uLong x ; - int i = 0; - int err; - - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((uLong)i)<<8; - - if (err==UNZ_OK) - *pX = x; +local int unz64local_getLong64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) { + unsigned char c[8]; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,8); + if (err==8) + { + *pX = c[0] | ((ZPOS64_T)c[1] << 8) | ((ZPOS64_T)c[2] << 16) | ((ZPOS64_T)c[3] << 24) + | ((ZPOS64_T)c[4] << 32) | ((ZPOS64_T)c[5] << 40) | ((ZPOS64_T)c[6] << 48) | ((ZPOS64_T)c[7] << 56); + return UNZ_OK; + } else + { *pX = 0; - return err; -} - -local int unz64local_getLong OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX) -{ - uLong x ; - int i = 0; - int err; - - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((uLong)i)<<8; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((uLong)i)<<16; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<24; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int unz64local_getLong64 OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - ZPOS64_T *pX)); - - -local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - ZPOS64_T *pX) -{ - ZPOS64_T x ; - int i = 0; - int err; - - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (ZPOS64_T)i; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<8; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<16; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<24; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<32; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<40; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<48; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<56; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } } /* My own strcmpi / strcasecmp */ -local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) -{ +local int strcmpcasenosensitive_internal(const char* fileName1, const char* fileName2) { for (;;) { char c1=*(fileName1++); @@ -379,19 +292,17 @@ #endif /* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + Compare two filenames (fileName1,fileName2). + If iCaseSensitivity = 1, comparison is case sensitive (like strcmp) + If iCaseSensitivity = 2, comparison is not case sensitive (like strcmpi or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + If iCaseSensitivity = 0, case sensitivity is default of your operating system (like 1 on Unix, 2 on Windows) */ extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, - const char* fileName2, - int iCaseSensitivity) - -{ + const char* fileName2, + int iCaseSensitivity) { if (iCaseSensitivity==0) iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; @@ -405,21 +316,23 @@ #define BUFREADCOMMENT (0x400) #endif +#ifndef CENTRALDIRINVALID +#define CENTRALDIRINVALID ((ZPOS64_T)(-1)) +#endif + /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ -local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); -local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) -{ +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ - ZPOS64_T uPosFound=0; + ZPOS64_T uPosFound=CENTRALDIRINVALID; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; + return CENTRALDIRINVALID; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); @@ -429,7 +342,7 @@ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) - return 0; + return CENTRALDIRINVALID; uBackRead = 4; while (uBackReadz_filefunc, s->filestream); - TRYFREE(s); + free(s); return UNZ_OK; } @@ -825,8 +727,7 @@ Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) -{ +extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64* pglobal_info) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; @@ -835,8 +736,7 @@ return UNZ_OK; } -extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) -{ +extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; @@ -847,46 +747,33 @@ return UNZ_OK; } /* - Translate date/time from Dos format to tm_unz (readable more easilty) + Translate date/time from Dos format to tm_unz (readable more easily) */ -local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) -{ +local void unz64local_DosDateToTmuDate(ZPOS64_T ulDosDate, tm_unz* ptm) { ZPOS64_T uDate; uDate = (ZPOS64_T)(ulDosDate>>16); - ptm->tm_mday = (uInt)(uDate&0x1f) ; - ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; - ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + ptm->tm_mday = (int)(uDate&0x1f) ; + ptm->tm_mon = (int)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (int)(((uDate&0x0FE00)/0x0200)+1980) ; - ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); - ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; - ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; + ptm->tm_hour = (int) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (int) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (int) (2*(ulDosDate&0x1f)) ; } /* Get Info about the current file in the zipfile, with internal only info */ -local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, - unz_file_info64 *pfile_info, - unz_file_info64_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); - -local int unz64local_GetCurrentFileInfoInternal (unzFile file, - unz_file_info64 *pfile_info, - unz_file_info64_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize) -{ +local int unz64local_GetCurrentFileInfoInternal(unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) { unz64_s* s; unz_file_info64 file_info; unz_file_info64_internal file_info_internal; @@ -993,7 +880,7 @@ if (lSeek!=0) { - if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + if (ZSEEK64(s->z_filefunc, s->filestream,(ZPOS64_T)lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; @@ -1018,7 +905,7 @@ if (lSeek!=0) { - if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + if (ZSEEK64(s->z_filefunc, s->filestream,(ZPOS64_T)lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; @@ -1038,33 +925,31 @@ /* ZIP64 extra fields */ if (headerId == 0x0001) { - uLong uL; + if(file_info.uncompressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } - if(file_info.uncompressed_size == MAXU32) - { - if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) - err=UNZ_ERRNO; - } - - if(file_info.compressed_size == MAXU32) - { - if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) - err=UNZ_ERRNO; - } + if(file_info.compressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } - if(file_info_internal.offset_curfile == MAXU32) - { - /* Relative Header offset */ - if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) - err=UNZ_ERRNO; - } + if(file_info_internal.offset_curfile == MAXU32) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } - if(file_info.disk_num_start == MAXU32) - { - /* Disk Start Number */ - if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) - err=UNZ_ERRNO; - } + if(file_info.disk_num_start == 0xffff) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + } } else @@ -1090,7 +975,7 @@ if (lSeek!=0) { - if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + if (ZSEEK64(s->z_filefunc, s->filestream,(ZPOS64_T)lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; @@ -1121,24 +1006,22 @@ No preparation of the structure is needed return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, - unz_file_info64 * pfile_info, - char * szFileName, uLong fileNameBufferSize, - void *extraField, uLong extraFieldBufferSize, - char* szComment, uLong commentBufferSize) -{ +extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) { return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, - szFileName,fileNameBufferSize, - extraField,extraFieldBufferSize, - szComment,commentBufferSize); + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); } -extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, - unz_file_info * pfile_info, - char * szFileName, uLong fileNameBufferSize, - void *extraField, uLong extraFieldBufferSize, - char* szComment, uLong commentBufferSize) -{ +extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) { int err; unz_file_info64 file_info64; err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, @@ -1162,7 +1045,7 @@ pfile_info->internal_fa = file_info64.internal_fa; pfile_info->external_fa = file_info64.external_fa; - pfile_info->tmu_date = file_info64.tmu_date, + pfile_info->tmu_date = file_info64.tmu_date; pfile_info->compressed_size = (uLong)file_info64.compressed_size; @@ -1175,8 +1058,7 @@ Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ -extern int ZEXPORT unzGoToFirstFile (unzFile file) -{ +extern int ZEXPORT unzGoToFirstFile(unzFile file) { int err=UNZ_OK; unz64_s* s; if (file==NULL) @@ -1196,8 +1078,7 @@ return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ -extern int ZEXPORT unzGoToNextFile (unzFile file) -{ +extern int ZEXPORT unzGoToNextFile(unzFile file) { unz64_s* s; int err; @@ -1229,8 +1110,7 @@ UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ -extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) -{ +extern int ZEXPORT unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity) { unz64_s* s; int err; @@ -1305,8 +1185,7 @@ } unz_file_pos; */ -extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) -{ +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) { unz64_s* s; if (file==NULL || file_pos==NULL) @@ -1321,10 +1200,7 @@ return UNZ_OK; } -extern int ZEXPORT unzGetFilePos( - unzFile file, - unz_file_pos* file_pos) -{ +extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; int err = unzGetFilePos64(file,&file_pos64); if (err==UNZ_OK) @@ -1335,8 +1211,7 @@ return err; } -extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) -{ +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) { unz64_s* s; int err; @@ -1357,10 +1232,7 @@ return err; } -extern int ZEXPORT unzGoToFilePos( - unzFile file, - unz_file_pos* file_pos) -{ +extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; if (file_pos == NULL) return UNZ_PARAMERROR; @@ -1382,10 +1254,9 @@ store in *piSizeVar the size of extra info in local header (filename and size of extra field data) */ -local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, - ZPOS64_T * poffset_local_extrafield, - uInt * psize_local_extrafield) -{ +local int unz64local_CheckCurrentFileCoherencyHeader(unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) { uLong uMagic,uData,uFlags; uLong size_filename; uLong size_extra_field; @@ -1469,9 +1340,8 @@ Open for reading data the current file in the zipfile. If there is no error and the file is opened, the return value is UNZ_OK. */ -extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, - int* level, int raw, const char* password) -{ +extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int* method, + int* level, int raw, const char* password) { int err=UNZ_OK; uInt iSizeVar; unz64_s* s; @@ -1509,7 +1379,7 @@ if (pfile_in_zip_read_info->read_buffer==NULL) { - TRYFREE(pfile_in_zip_read_info); + free(pfile_in_zip_read_info); return UNZ_INTERNALERROR; } @@ -1566,7 +1436,8 @@ pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; else { - TRYFREE(pfile_in_zip_read_info); + free(pfile_in_zip_read_info->read_buffer); + free(pfile_in_zip_read_info); return err; } #else @@ -1586,7 +1457,8 @@ pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; else { - TRYFREE(pfile_in_zip_read_info); + free(pfile_in_zip_read_info->read_buffer); + free(pfile_in_zip_read_info); return err; } /* windowBits is passed < 0 to tell that there is no zlib header. @@ -1638,25 +1510,21 @@ return UNZ_OK; } -extern int ZEXPORT unzOpenCurrentFile (unzFile file) -{ +extern int ZEXPORT unzOpenCurrentFile(unzFile file) { return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); } -extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) -{ +extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char* password) { return unzOpenCurrentFile3(file, NULL, NULL, 0, password); } -extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) -{ +extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int* method, int* level, int raw) { return unzOpenCurrentFile3(file, method, level, raw, NULL); } /** Addition for GDAL : START */ -extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) -{ +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; s=(unz64_s*)file; @@ -1676,13 +1544,12 @@ buf contain buffer where data must be copied len the size of buf. - return the number of byte copied if somes bytes are copied + return the number of byte copied if some bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ -extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) -{ +extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len) { int err=UNZ_OK; uInt iRead = 0; unz64_s* s; @@ -1767,7 +1634,7 @@ if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed == 0)) - return (iRead==0) ? UNZ_EOF : iRead; + return (iRead==0) ? UNZ_EOF : (int)iRead; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) @@ -1857,6 +1724,9 @@ err = Z_DATA_ERROR; uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + /* Detect overflow, because z_stream.total_out is uLong (32 bits) */ + if (uTotalOutAftertotal_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; @@ -1871,14 +1741,14 @@ iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); if (err==Z_STREAM_END) - return (iRead==0) ? UNZ_EOF : iRead; + return (iRead==0) ? UNZ_EOF : (int)iRead; if (err!=Z_OK) break; } } if (err==Z_OK) - return iRead; + return (int)iRead; return err; } @@ -1886,8 +1756,7 @@ /* Give the current position in uncompressed data */ -extern z_off_t ZEXPORT unztell (unzFile file) -{ +extern z_off_t ZEXPORT unztell(unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) @@ -1901,8 +1770,7 @@ return (z_off_t)pfile_in_zip_read_info->stream.total_out; } -extern ZPOS64_T ZEXPORT unztell64 (unzFile file) -{ +extern ZPOS64_T ZEXPORT unztell64(unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; @@ -1921,8 +1789,7 @@ /* return 1 if the end of file was reached, 0 elsewhere */ -extern int ZEXPORT unzeof (unzFile file) -{ +extern int ZEXPORT unzeof(unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) @@ -1953,8 +1820,7 @@ the return value is the number of bytes copied in buf, or (if <0) the error code */ -extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) -{ +extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; uInt read_now; @@ -2001,8 +1867,7 @@ Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ -extern int ZEXPORT unzCloseCurrentFile (unzFile file) -{ +extern int ZEXPORT unzCloseCurrentFile(unzFile file) { int err=UNZ_OK; unz64_s* s; @@ -2024,7 +1889,7 @@ } - TRYFREE(pfile_in_zip_read_info->read_buffer); + free(pfile_in_zip_read_info->read_buffer); pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) inflateEnd(&pfile_in_zip_read_info->stream); @@ -2035,7 +1900,7 @@ pfile_in_zip_read_info->stream_initialised = 0; - TRYFREE(pfile_in_zip_read_info); + free(pfile_in_zip_read_info); s->pfile_in_zip_read=NULL; @@ -2048,8 +1913,7 @@ uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ -extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) -{ +extern int ZEXPORT unzGetGlobalComment(unzFile file, char * szComment, uLong uSizeBuf) { unz64_s* s; uLong uReadThis ; if (file==NULL) @@ -2076,8 +1940,7 @@ } /* Additions by RX '2004 */ -extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) -{ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) { unz64_s* s; if (file==NULL) @@ -2091,8 +1954,7 @@ return s->pos_in_central_dir; } -extern uLong ZEXPORT unzGetOffset (unzFile file) -{ +extern uLong ZEXPORT unzGetOffset(unzFile file) { ZPOS64_T offset64; if (file==NULL) @@ -2101,8 +1963,7 @@ return (uLong)offset64; } -extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) -{ +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) { unz64_s* s; int err; @@ -2119,7 +1980,6 @@ return err; } -extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) -{ +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) { return unzSetOffset64(file,pos); } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ThirdParty/minizip/unzip.h --- a/OrthancFramework/Resources/ThirdParty/minizip/unzip.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/ThirdParty/minizip/unzip.h Tue Sep 24 11:39:52 2024 +0200 @@ -83,12 +83,12 @@ /* tm_unz contain date/time info */ typedef struct tm_unz_s { - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt tm_year; /* years - [1980..2044] */ + int tm_sec; /* seconds after the minute - [0,59] */ + int tm_min; /* minutes after the hour - [0,59] */ + int tm_hour; /* hours since midnight - [0,23] */ + int tm_mday; /* day of the month - [1,31] */ + int tm_mon; /* months since January - [0,11] */ + int tm_year; /* years - [1980..2044] */ } tm_unz; /* unz_global_info structure contain global data about the ZIPfile @@ -150,21 +150,21 @@ tm_unz tmu_date; } unz_file_info; -extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, - const char* fileName2, - int iCaseSensitivity)); +extern int ZEXPORT unzStringFileNameCompare(const char* fileName1, + const char* fileName2, + int iCaseSensitivity); /* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + Compare two filenames (fileName1,fileName2). + If iCaseSensitivity = 1, comparison is case sensitive (like strcmp) + If iCaseSensitivity = 2, comparison is not case sensitive (like strcmpi or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + If iCaseSensitivity = 0, case sensitivity is default of your operating system (like 1 on Unix, 2 on Windows) */ -extern unzFile ZEXPORT unzOpen OF((const char *path)); -extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +extern unzFile ZEXPORT unzOpen(const char *path); +extern unzFile ZEXPORT unzOpen64(const void *path); /* Open a Zip file. path contain the full pathname (by example, on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer @@ -181,41 +181,41 @@ */ -extern unzFile ZEXPORT unzOpen2 OF((const char *path, - zlib_filefunc_def* pzlib_filefunc_def)); +extern unzFile ZEXPORT unzOpen2(const char *path, + zlib_filefunc_def* pzlib_filefunc_def); /* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ -extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, - zlib_filefunc64_def* pzlib_filefunc_def)); +extern unzFile ZEXPORT unzOpen2_64(const void *path, + zlib_filefunc64_def* pzlib_filefunc_def); /* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ -extern int ZEXPORT unzClose OF((unzFile file)); +extern int ZEXPORT unzClose(unzFile file); /* Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), these files MUST be closed with unzCloseCurrentFile before call unzClose. return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, - unz_global_info *pglobal_info)); +extern int ZEXPORT unzGetGlobalInfo(unzFile file, + unz_global_info *pglobal_info); -extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, - unz_global_info64 *pglobal_info)); +extern int ZEXPORT unzGetGlobalInfo64(unzFile file, + unz_global_info64 *pglobal_info); /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalComment OF((unzFile file, - char *szComment, - uLong uSizeBuf)); +extern int ZEXPORT unzGetGlobalComment(unzFile file, + char *szComment, + uLong uSizeBuf); /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. @@ -226,22 +226,22 @@ /***************************************************************************/ /* Unzip package allow you browse the directory of the zipfile */ -extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +extern int ZEXPORT unzGoToFirstFile(unzFile file); /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ -extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +extern int ZEXPORT unzGoToNextFile(unzFile file); /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ -extern int ZEXPORT unzLocateFile OF((unzFile file, - const char *szFileName, - int iCaseSensitivity)); +extern int ZEXPORT unzLocateFile(unzFile file, + const char *szFileName, + int iCaseSensitivity); /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare @@ -285,26 +285,26 @@ /* ****************************************** */ -extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, - unz_file_info64 *pfile_info, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); +extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize); -extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, - unz_file_info *pfile_info, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); +extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize); /* Get Info about the current file - if pfile_info!=NULL, the *pfile_info structure will contain somes info about + if pfile_info!=NULL, the *pfile_info structure will contain some info about the current file if szFileName!=NULL, the filemane string will be copied in szFileName (fileNameBufferSize is the size of the buffer) @@ -318,7 +318,7 @@ /** Addition for GDAL : START */ -extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file); /** Addition for GDAL : END */ @@ -328,24 +328,24 @@ from it, and close it (you can close it before reading all the file) */ -extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +extern int ZEXPORT unzOpenCurrentFile(unzFile file); /* Open for reading data the current file in the zipfile. If there is no error, the return value is UNZ_OK. */ -extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, - const char* password)); +extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, + const char* password); /* Open for reading data the current file in the zipfile. password is a crypting password If there is no error, the return value is UNZ_OK. */ -extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, - int* method, - int* level, - int raw)); +extern int ZEXPORT unzOpenCurrentFile2(unzFile file, + int* method, + int* level, + int raw); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 @@ -355,11 +355,11 @@ but you CANNOT set method parameter as NULL */ -extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, - int* method, - int* level, - int raw, - const char* password)); +extern int ZEXPORT unzOpenCurrentFile3(unzFile file, + int* method, + int* level, + int raw, + const char* password); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 @@ -370,41 +370,41 @@ */ -extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +extern int ZEXPORT unzCloseCurrentFile(unzFile file); /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ -extern int ZEXPORT unzReadCurrentFile OF((unzFile file, - voidp buf, - unsigned len)); +extern int ZEXPORT unzReadCurrentFile(unzFile file, + voidp buf, + unsigned len); /* Read bytes from the current file (opened by unzOpenCurrentFile) buf contain buffer where data must be copied len the size of buf. - return the number of byte copied if somes bytes are copied + return the number of byte copied if some bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ -extern z_off_t ZEXPORT unztell OF((unzFile file)); +extern z_off_t ZEXPORT unztell(unzFile file); -extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +extern ZPOS64_T ZEXPORT unztell64(unzFile file); /* Give the current position in uncompressed data */ -extern int ZEXPORT unzeof OF((unzFile file)); +extern int ZEXPORT unzeof(unzFile file); /* return 1 if the end of file was reached, 0 elsewhere */ -extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, - voidp buf, - unsigned len)); +extern int ZEXPORT unzGetLocalExtrafield(unzFile file, + voidp buf, + unsigned len); /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ThirdParty/minizip/zip.c --- a/OrthancFramework/Resources/ThirdParty/minizip/zip.c Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/ThirdParty/minizip/zip.c Tue Sep 24 11:39:52 2024 +0200 @@ -14,7 +14,7 @@ Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data - It is used when recreting zip archive with RAW when deleting items from a zip. + It is used when recreating zip archive with RAW when deleting items from a zip. ZIP64 data is automatically added to items that needs it, and existing ZIP64 data need to be removed. Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer @@ -25,14 +25,13 @@ #include #include #include +#include #include #include "zlib.h" #include "zip.h" #ifdef STDC # include -# include -# include #endif #ifdef NO_ERRNO_H extern int errno; @@ -47,7 +46,7 @@ /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef VERSIONMADEBY -# define VERSIONMADEBY (0x0) /* platform depedent */ +# define VERSIONMADEBY (0x0) /* platform dependent */ #endif #ifndef Z_BUFSIZE @@ -61,9 +60,6 @@ #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif /* #define SIZECENTRALDIRITEM (0x2e) @@ -138,37 +134,37 @@ uInt pos_in_buffered_data; /* last written byte in buffered_data */ ZPOS64_T pos_local_header; /* offset of the local header of the file - currenty writing */ + currently writing */ char* central_header; /* central header data for the current file */ uLong size_centralExtra; uLong size_centralheader; /* size of the central header for cur file */ uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ uLong flag; /* flag of the file currently writing */ - int method; /* compression method of file currenty wr.*/ + int method; /* compression method of file currently wr.*/ int raw; /* 1 for directly writing raw data */ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ uLong dosDate; uLong crc32; int encrypt; - int zip64; /* Add ZIP64 extened information in the extra field */ + int zip64; /* Add ZIP64 extended information in the extra field */ ZPOS64_T pos_zip64extrainfo; ZPOS64_T totalCompressedData; ZPOS64_T totalUncompressedData; #ifndef NOCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const z_crc_t* pcrc_32_tab; - int crypt_header_size; + unsigned crypt_header_size; #endif } curfile64_info; typedef struct { zlib_filefunc64_32_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ + voidpf filestream; /* io structure of the zipfile */ linkedlist_data central_dir;/* datablock with central dir in construction*/ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ - curfile64_info ci; /* info on the file curretly writing */ + curfile64_info ci; /* info on the file currently writing */ ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ ZPOS64_T add_position_when_writing_offset; @@ -186,8 +182,7 @@ #include "crypt.h" #endif -local linkedlist_datablock_internal* allocate_new_datablock() -{ +local linkedlist_datablock_internal* allocate_new_datablock(void) { linkedlist_datablock_internal* ldi; ldi = (linkedlist_datablock_internal*) ALLOC(sizeof(linkedlist_datablock_internal)); @@ -200,30 +195,26 @@ return ldi; } -local void free_datablock(linkedlist_datablock_internal* ldi) -{ +local void free_datablock(linkedlist_datablock_internal* ldi) { while (ldi!=NULL) { linkedlist_datablock_internal* ldinext = ldi->next_datablock; - TRYFREE(ldi); + free(ldi); ldi = ldinext; } } -local void init_linkedlist(linkedlist_data* ll) -{ +local void init_linkedlist(linkedlist_data* ll) { ll->first_block = ll->last_block = NULL; } -local void free_linkedlist(linkedlist_data* ll) -{ +local void free_linkedlist(linkedlist_data* ll) { free_datablock(ll->first_block); ll->first_block = ll->last_block = NULL; } -local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) -{ +local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) { linkedlist_datablock_internal* ldi; const unsigned char* from_copy; @@ -238,7 +229,7 @@ } ldi = ll->last_block; - from_copy = (unsigned char*)buf; + from_copy = (const unsigned char*)buf; while (len>0) { @@ -283,9 +274,7 @@ nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) */ -local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); -local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) -{ +local int zip64local_putValue(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) { unsigned char buf[8]; int n; for (n = 0; n < nbByte; n++) @@ -301,15 +290,13 @@ } } - if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,(uLong)nbByte)!=(uLong)nbByte) return ZIP_ERRNO; else return ZIP_OK; } -local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); -local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) -{ +local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) { unsigned char* buf=(unsigned char*)dest; int n; for (n = 0; n < nbByte; n++) { @@ -329,25 +316,21 @@ /****************************************************************************/ -local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) -{ +local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) { uLong year = (uLong)ptm->tm_year; if (year>=1980) year-=1980; else if (year>=80) year-=80; return - (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | - ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); + (uLong) (((uLong)(ptm->tm_mday) + (32 * (uLong)(ptm->tm_mon+1)) + (512 * year)) << 16) | + (((uLong)ptm->tm_sec/2) + (32 * (uLong)ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); } /****************************************************************************/ -local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); - -local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) -{ +local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int* pi) { unsigned char c; int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); if (err==1) @@ -368,10 +351,7 @@ /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ -local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); - -local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) -{ +local int zip64local_getShort(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) { uLong x ; int i = 0; int err; @@ -390,10 +370,7 @@ return err; } -local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); - -local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) -{ +local int zip64local_getLong(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) { uLong x ; int i = 0; int err; @@ -420,11 +397,8 @@ return err; } -local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); - -local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) -{ +local int zip64local_getLong64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) { ZPOS64_T x; int i = 0; int err; @@ -475,10 +449,7 @@ Locate the Central directory of a zipfile (at the end, just before the global comment) */ -local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); - -local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) -{ +local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; @@ -522,14 +493,14 @@ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { - uPosFound = uReadPos+i; + uPosFound = uReadPos+(unsigned)i; break; } if (uPosFound!=0) break; } - TRYFREE(buf); + free(buf); return uPosFound; } @@ -537,10 +508,7 @@ Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before the global comment) */ -local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); - -local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) -{ +local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; @@ -586,7 +554,7 @@ // Signature "0x07064b50" Zip64 end of central directory locater if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) { - uPosFound = uReadPos+i; + uPosFound = uReadPos+(unsigned)i; break; } } @@ -595,7 +563,7 @@ break; } - TRYFREE(buf); + free(buf); if (uPosFound == 0) return 0; @@ -637,8 +605,7 @@ return relativeOffset; } -int LoadCentralDirectoryRecord(zip64_internal* pziinit) -{ +local int LoadCentralDirectoryRecord(zip64_internal* pziinit) { int err=ZIP_OK; ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ @@ -647,10 +614,10 @@ ZPOS64_T central_pos; uLong uL; - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ + uLong number_disk; /* number of the current disk, used for + spanning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number of the disk with central dir, used + for spanning ZIP, unsupported, always 0*/ ZPOS64_T number_entry; ZPOS64_T number_entry_CD; /* total number of entries in the central dir @@ -830,7 +797,7 @@ size_central_dir_to_read-=read_this; } - TRYFREE(buf_read); + free(buf_read); } pziinit->begin_pos = byte_before_the_zipfile; pziinit->number_entry = number_entry_CD; @@ -846,8 +813,7 @@ /************************************************************/ -extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) -{ +extern zipFile ZEXPORT zipOpen3(const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) { zip64_internal ziinit; zip64_internal* zi; int err=ZIP_OK; @@ -905,9 +871,9 @@ if (err != ZIP_OK) { # ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(ziinit.globalcomment); + free(ziinit.globalcomment); # endif /* !NO_ADDFILEINEXISTINGZIP*/ - TRYFREE(zi); + free(zi); return NULL; } else @@ -917,8 +883,7 @@ } } -extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) -{ +extern zipFile ZEXPORT zipOpen2(const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) { if (pzlib_filefunc32_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; @@ -929,8 +894,7 @@ return zipOpen3(pathname, append, globalcomment, NULL); } -extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) -{ +extern zipFile ZEXPORT zipOpen2_64(const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) { if (pzlib_filefunc_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; @@ -945,18 +909,15 @@ -extern zipFile ZEXPORT zipOpen (const char* pathname, int append) -{ +extern zipFile ZEXPORT zipOpen(const char* pathname, int append) { return zipOpen3((const void*)pathname,append,NULL,NULL); } -extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) -{ +extern zipFile ZEXPORT zipOpen64(const void* pathname, int append) { return zipOpen3(pathname,append,NULL,NULL); } -int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) -{ +local int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) { /* write the local header */ int err; uInt size_filename = (uInt)strlen(filename); @@ -1034,8 +995,8 @@ // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)HeaderID,2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)DataSize,2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); @@ -1052,14 +1013,13 @@ It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize unnecessary allocations. */ -extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, - int windowBits,int memLevel, int strategy, - const char* password, uLong crcForCrypting, - uLong versionMadeBy, uLong flagBase, int zip64) -{ +extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase, int zip64) { zip64_internal* zi; uInt size_filename; uInt size_comment; @@ -1083,6 +1043,17 @@ return ZIP_PARAMERROR; #endif + // The filename and comment length must fit in 16 bits. + if ((filename!=NULL) && (strlen(filename)>0xffff)) + return ZIP_PARAMERROR; + if ((comment!=NULL) && (strlen(comment)>0xffff)) + return ZIP_PARAMERROR; + // The extra field length must fit in 16 bits. If the member also requires + // a Zip64 extra block, that will also need to fit within that 16-bit + // length, but that will be checked for later. + if ((size_extrafield_local>0xffff) || (size_extrafield_global>0xffff)) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 1) @@ -1262,35 +1233,33 @@ return err; } -extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, - int windowBits,int memLevel, int strategy, - const char* password, uLong crcForCrypting, - uLong versionMadeBy, uLong flagBase) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - windowBits, memLevel, strategy, - password, crcForCrypting, versionMadeBy, flagBase, 0); +extern int ZEXPORT zipOpenNewFileInZip4(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase) { + return zipOpenNewFileInZip4_64(file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase, 0); } -extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, - int windowBits,int memLevel, int strategy, - const char* password, uLong crcForCrypting) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - windowBits, memLevel, strategy, - password, crcForCrypting, VERSIONMADEBY, 0, 0); +extern int ZEXPORT zipOpenNewFileInZip3(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting) { + return zipOpenNewFileInZip4_64(file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, 0); } extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, @@ -1298,70 +1267,64 @@ const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, - const char* password, uLong crcForCrypting, int zip64) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - windowBits, memLevel, strategy, - password, crcForCrypting, VERSIONMADEBY, 0, zip64); + const char* password, uLong crcForCrypting, int zip64) { + return zipOpenNewFileInZip4_64(file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0, VERSIONMADEBY, 0, 0); + const char* comment, int method, int level, int raw) { + return zipOpenNewFileInZip4_64(file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); } extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, int zip64) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0, VERSIONMADEBY, 0, zip64); + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, int zip64) { + return zipOpenNewFileInZip4_64(file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); } -extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void*extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int zip64) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, 0, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0, VERSIONMADEBY, 0, zip64); +extern int ZEXPORT zipOpenNewFileInZip64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int zip64) { + return zipOpenNewFileInZip4_64(file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); } -extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void*extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, 0, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0, VERSIONMADEBY, 0, 0); +extern int ZEXPORT zipOpenNewFileInZip(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level) { + return zipOpenNewFileInZip4_64(file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); } -local int zip64FlushWriteBuffer(zip64_internal* zi) -{ +local int zip64FlushWriteBuffer(zip64_internal* zi) { int err=ZIP_OK; if (zi->ci.encrypt != 0) @@ -1399,8 +1362,7 @@ return err; } -extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) -{ +extern int ZEXPORT zipWriteInFileInZip(zipFile file, const void* buf, unsigned int len) { zip64_internal* zi; int err=ZIP_OK; @@ -1450,7 +1412,7 @@ else #endif { - zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.next_in = (Bytef*)(uintptr_t)buf; zi->ci.stream.avail_in = len; while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) @@ -1471,11 +1433,6 @@ { uLong uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_NO_FLUSH); - if(uTotalOutBefore > zi->ci.stream.total_out) - { - int bBreak = 0; - bBreak++; - } zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } @@ -1506,17 +1463,15 @@ return err; } -extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) -{ +extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, uLong uncompressed_size, uLong crc32) { return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); } -extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) -{ +extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, ZPOS64_T uncompressed_size, uLong crc32) { zip64_internal* zi; ZPOS64_T compressed_size; uLong invalidValue = 0xffffffff; - short datasize = 0; + unsigned datasize = 0; int err=ZIP_OK; if (file == NULL) @@ -1747,13 +1702,11 @@ return err; } -extern int ZEXPORT zipCloseFileInZip (zipFile file) -{ +extern int ZEXPORT zipCloseFileInZip(zipFile file) { return zipCloseFileInZipRaw (file,0,0); } -int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) -{ +local int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) { int err = ZIP_OK; ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writing_offset; @@ -1774,8 +1727,7 @@ return err; } -int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) -{ +local int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) { int err = ZIP_OK; uLong Zip64DataSize = 44; @@ -1813,8 +1765,8 @@ } return err; } -int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) -{ + +local int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) { int err = ZIP_OK; /*signature*/ @@ -1861,8 +1813,7 @@ return err; } -int Write_GlobalComment(zip64_internal* zi, const char* global_comment) -{ +local int Write_GlobalComment(zip64_internal* zi, const char* global_comment) { int err = ZIP_OK; uInt size_global_comment = 0; @@ -1879,8 +1830,7 @@ return err; } -extern int ZEXPORT zipClose (zipFile file, const char* global_comment) -{ +extern int ZEXPORT zipClose(zipFile file, const char* global_comment) { zip64_internal* zi; int err = 0; uLong size_centraldir = 0; @@ -1922,7 +1872,7 @@ free_linkedlist(&(zi->central_dir)); pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; - if(pos >= 0xffffffff || zi->number_entry > 0xFFFF) + if(pos >= 0xffffffff || zi->number_entry >= 0xFFFF) { ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); @@ -1941,15 +1891,14 @@ err = ZIP_ERRNO; #ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(zi->globalcomment); + free(zi->globalcomment); #endif - TRYFREE(zi); + free(zi); return err; } -extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) -{ +extern int ZEXPORT zipRemoveExtraInfoBlock(char* pData, int* dataLen, short sHeader) { char* p = pData; int size = 0; char* pNewHeader; @@ -1959,10 +1908,10 @@ int retVal = ZIP_OK; - if(pData == NULL || *dataLen < 4) + if(pData == NULL || dataLen == NULL || *dataLen < 4) return ZIP_PARAMERROR; - pNewHeader = (char*)ALLOC(*dataLen); + pNewHeader = (char*)ALLOC((unsigned)*dataLen); pTmp = pNewHeader; while(p < (pData + *dataLen)) @@ -2001,7 +1950,7 @@ else retVal = ZIP_ERRNO; - TRYFREE(pNewHeader); + free(pNewHeader); return retVal; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/ThirdParty/minizip/zip.h --- a/OrthancFramework/Resources/ThirdParty/minizip/zip.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/ThirdParty/minizip/zip.h Tue Sep 24 11:39:52 2024 +0200 @@ -88,12 +88,12 @@ /* tm_zip contain date/time info */ typedef struct tm_zip_s { - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt tm_year; /* years - [1980..2044] */ + int tm_sec; /* seconds after the minute - [0,59] */ + int tm_min; /* minutes after the hour - [0,59] */ + int tm_hour; /* hours since midnight - [0,23] */ + int tm_mday; /* day of the month - [1,31] */ + int tm_mon; /* months since January - [0,11] */ + int tm_year; /* years - [1980..2044] */ } tm_zip; typedef struct @@ -113,8 +113,8 @@ #define APPEND_STATUS_CREATEAFTER (1) #define APPEND_STATUS_ADDINZIP (2) -extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); -extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); +extern zipFile ZEXPORT zipOpen(const char *pathname, int append); +extern zipFile ZEXPORT zipOpen64(const void *pathname, int append); /* Create a zipfile. pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on @@ -131,50 +131,55 @@ /* Note : there is no delete function into a zipfile. If you want delete file into a zipfile, you must open a zipfile, and create another - Of couse, you can use RAW reading and writing to copy the file you did not want delte + Of course, you can use RAW reading and writing to copy the file you did not want delete */ -extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, - int append, - zipcharpc* globalcomment, - zlib_filefunc_def* pzlib_filefunc_def)); +extern zipFile ZEXPORT zipOpen2(const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def); -extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, +extern zipFile ZEXPORT zipOpen2_64(const void *pathname, int append, zipcharpc* globalcomment, - zlib_filefunc64_def* pzlib_filefunc_def)); + zlib_filefunc64_def* pzlib_filefunc_def); + +extern zipFile ZEXPORT zipOpen3(const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def); -extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level)); +extern int ZEXPORT zipOpenNewFileInZip(zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level); -extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int zip64)); +extern int ZEXPORT zipOpenNewFileInZip64(zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64); /* Open a file in the ZIP for writing. filename : the filename in zip (if NULL, '-' without quote will be used *zipfi contain supplemental information if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local - contains the extrafield data the the local header + contains the extrafield data for the local header if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global - contains the extrafield data the the local header + contains the extrafield data for the global header if comment != NULL, comment contain the comment string method contain the compression method (0 for store, Z_DEFLATED for deflate) level contain the level of compression (can be Z_DEFAULT_COMPRESSION) @@ -184,70 +189,69 @@ */ -extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw)); +extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw); -extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int zip64)); +extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64); /* Same than zipOpenNewFileInZip, except if raw=1, we write raw file */ -extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCrypting)); +extern int ZEXPORT zipOpenNewFileInZip3(zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting); -extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCrypting, - int zip64 - )); +extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64); /* Same than zipOpenNewFileInZip2, except @@ -256,47 +260,45 @@ crcForCrypting : crc of file to compress (needed for crypting) */ -extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCrypting, - uLong versionMadeBy, - uLong flagBase - )); +extern int ZEXPORT zipOpenNewFileInZip4(zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase); -extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCrypting, - uLong versionMadeBy, - uLong flagBase, - int zip64 - )); +extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64); /* Same than zipOpenNewFileInZip4, except versionMadeBy : value for Version made by field @@ -304,25 +306,25 @@ */ -extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, - const void* buf, - unsigned len)); +extern int ZEXPORT zipWriteInFileInZip(zipFile file, + const void* buf, + unsigned len); /* Write data in the zipfile */ -extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +extern int ZEXPORT zipCloseFileInZip(zipFile file); /* Close the current file in the zipfile */ -extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, - uLong uncompressed_size, - uLong crc32)); +extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, + uLong uncompressed_size, + uLong crc32); -extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, - ZPOS64_T uncompressed_size, - uLong crc32)); +extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32); /* Close the current file in the zipfile, for file opened with @@ -330,14 +332,14 @@ uncompressed_size and crc32 are value for the uncompressed size */ -extern int ZEXPORT zipClose OF((zipFile file, - const char* global_comment)); +extern int ZEXPORT zipClose(zipFile file, + const char* global_comment); /* Close the zipfile */ -extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +extern int ZEXPORT zipRemoveExtraInfoBlock(char* pData, int* dataLen, short sHeader); /* zipRemoveExtraInfoBlock - Added by Mathias Svensson diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Toolchains/CrossToolchain.cmake --- a/OrthancFramework/Resources/Toolchains/CrossToolchain.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Toolchains/CrossToolchain.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Toolchains/LinuxStandardBaseToolchain.cmake --- a/OrthancFramework/Resources/Toolchains/LinuxStandardBaseToolchain.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Toolchains/LinuxStandardBaseToolchain.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain32.cmake --- a/OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain32.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain32.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain64.cmake --- a/OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain64.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain64.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/Toolchains/MinGWToolchain.cmake --- a/OrthancFramework/Resources/Toolchains/MinGWToolchain.cmake Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/Toolchains/MinGWToolchain.cmake Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/WindowsResources.py --- a/OrthancFramework/Resources/WindowsResources.py Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/WindowsResources.py Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Resources/WindowsResources.rc --- a/OrthancFramework/Resources/WindowsResources.rc Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Resources/WindowsResources.rc Tue Sep 24 11:39:52 2024 +0200 @@ -15,8 +15,8 @@ VALUE "FileDescription", "${DESCRIPTION}" VALUE "FileVersion", "${VERSION_MAJOR}.${VERSION_MINOR}.0.${VERSION_PATCH}" VALUE "InternalName", "${PRODUCT}" - VALUE "LegalCopyright", "(c) 2012-${YEAR}, Sebastien Jodogne, University Hospital of Liege, Osimis S.A., and ICTEAM UCLouvain" - VALUE "LegalTrademarks", "Licensing information is available at http://www.orthanc-server.com/" + VALUE "LegalCopyright", "(c) 2012-${YEAR}, Sebastien Jodogne, University Hospital of Liege, Osimis S.A., Orthanc Team SRL, and ICTEAM UCLouvain" + VALUE "LegalTrademarks", "Licensing information is available at https://orthanc.uclouvain.be/book/faq/licensing.html" VALUE "OriginalFilename", "${FILENAME}" VALUE "ProductName", "${PRODUCT}" VALUE "ProductVersion", "${VERSION_MAJOR}.${VERSION_MINOR}" diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/SharedLibrary/CMakeLists.txt --- a/OrthancFramework/SharedLibrary/CMakeLists.txt Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/SharedLibrary/CMakeLists.txt Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -257,6 +258,8 @@ ${ORTHANC_DICOM_SOURCES} ) + DefineSourceBasenameForTarget(OrthancFramework) + # CMake does not natively handle SIDE_MODULE, and believes that # Emscripten produces a ".js" file (whereas it creates only the # ".wasm"). Create a dummy ".js" for target to work. @@ -273,6 +276,8 @@ DllMain.cpp ) + DefineSourceBasenameForTarget(OrthancFramework) + # By default, hide all the symbols set_target_properties(OrthancFramework PROPERTIES C_VISIBILITY_PRESET hidden) set_target_properties(OrthancFramework PROPERTIES CXX_VISIBILITY_PRESET hidden) @@ -301,10 +306,14 @@ ${ORTHANC_DICOM_SOURCES} ) + DefineSourceBasenameForTarget(OrthancFramework) + # Add the "-fPIC" option to use the static library from Orthanc # plugins (the latter being shared libraries) set_property(TARGET OrthancFramework PROPERTY POSITION_INDEPENDENT_CODE ON) endif() + + DefineSourceBasenameForTarget(OrthancFramework) endif() diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/SharedLibrary/DllMain.cpp --- a/OrthancFramework/SharedLibrary/DllMain.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/SharedLibrary/DllMain.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -27,35 +28,55 @@ ${BOOST_SOURCES_DIR}/libs/thread/src/win32/tss_dll.cpp ${OPENSSL_SOURCES_DIR}/crypto/dllmain.c - **/ +**/ #if defined(_WIN32) || defined(__CYGWIN__) -# ifdef __CYGWIN__ -# include -# endif + +#include + +#include + +#include -#include "e_os.h" -#include "crypto/cryptlib.h" - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +#if defined(__BORLANDC__) +extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/) +#elif defined(_WIN32_WCE) + extern "C" BOOL WINAPI DllMain(HANDLE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/) +#else + extern "C" BOOL WINAPI DllMain(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/) +#endif { - switch (fdwReason) + switch(dwReason) { case DLL_PROCESS_ATTACH: + { //OPENSSL_cpuid_setup(); // TODO - Is this necessary? + boost::on_process_enter(); + boost::on_thread_enter(); break; - + } + case DLL_THREAD_ATTACH: + { + boost::on_thread_enter(); break; - + } + case DLL_THREAD_DETACH: + { OPENSSL_thread_stop(); + boost::on_thread_exit(); break; - + } + case DLL_PROCESS_DETACH: + { + boost::on_thread_exit(); + boost::on_process_exit(); break; + } } - + return TRUE; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/SharedLibrary/OrthancFramework.h.in --- a/OrthancFramework/SharedLibrary/OrthancFramework.h.in Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/SharedLibrary/OrthancFramework.h.in Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Cache/ICachePageProvider.h --- a/OrthancFramework/Sources/Cache/ICachePageProvider.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Cache/ICachePageProvider.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Cache/ICacheable.h --- a/OrthancFramework/Sources/Cache/ICacheable.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Cache/ICacheable.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Cache/LeastRecentlyUsedIndex.h --- a/OrthancFramework/Sources/Cache/LeastRecentlyUsedIndex.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Cache/LeastRecentlyUsedIndex.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Cache/MemoryCache.cpp --- a/OrthancFramework/Sources/Cache/MemoryCache.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryCache.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Cache/MemoryCache.h --- a/OrthancFramework/Sources/Cache/MemoryCache.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryCache.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Cache/MemoryObjectCache.cpp --- a/OrthancFramework/Sources/Cache/MemoryObjectCache.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryObjectCache.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Cache/MemoryObjectCache.h --- a/OrthancFramework/Sources/Cache/MemoryObjectCache.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryObjectCache.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Cache/MemoryStringCache.cpp --- a/OrthancFramework/Sources/Cache/MemoryStringCache.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryStringCache.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -53,47 +54,235 @@ } }; + + MemoryStringCache::Accessor::Accessor(MemoryStringCache& cache) + : cache_(cache), + shouldAdd_(false) + { + } + + + MemoryStringCache::Accessor::~Accessor() + { + // if this accessor was the one in charge of loading and adding the data into the cache + // and it failed to add, remove the key from the list to make sure others accessor + // stop waiting for it. + if (shouldAdd_) + { + cache_.RemoveFromItemsBeingLoaded(keyToAdd_); + } + } + + + bool MemoryStringCache::Accessor::Fetch(std::string& value, const std::string& key) + { + // if multiple accessors are fetching at the same time: + // the first one will return false and will be in charge of adding to the cache. + // others will wait. + // if the first one fails to add, or, if the content was too large to fit in the cache, + // the next one will be in charge of adding ... + if (!cache_.Fetch(value, key)) + { + shouldAdd_ = true; + keyToAdd_ = key; + return false; + } + + shouldAdd_ = false; + keyToAdd_.clear(); + + return true; + } + + + void MemoryStringCache::Accessor::Add(const std::string& key, const std::string& value) + { + cache_.Add(key, value); + shouldAdd_ = false; + } + + + void MemoryStringCache::Accessor::Add(const std::string& key, const char* buffer, size_t size) + { + cache_.Add(key, buffer, size); + shouldAdd_ = false; + } + + + MemoryStringCache::MemoryStringCache() : + currentSize_(0), + maxSize_(100 * 1024 * 1024) // 100 MB + { + } + + + MemoryStringCache::~MemoryStringCache() + { + Recycle(0); + assert(content_.IsEmpty()); + } + + size_t MemoryStringCache::GetMaximumSize() { - return cache_.GetMaximumSize(); + return maxSize_; } + void MemoryStringCache::SetMaximumSize(size_t size) { - cache_.SetMaximumSize(size); + if (size == 0) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + // // Make sure no accessor is currently open (as its data may be + // // removed if recycling is needed) + // WriterLock contentLock(contentMutex_); + + // Lock the global structure of the cache + boost::mutex::scoped_lock cacheLock(cacheMutex_); + + Recycle(size); + maxSize_ = size; } + void MemoryStringCache::Add(const std::string& key, - const std::string& value) + const std::string& value) { - cache_.Acquire(key, new StringValue(value)); + std::unique_ptr item(new StringValue(value)); + size_t size = value.size(); + + boost::mutex::scoped_lock cacheLock(cacheMutex_); + + if (size > maxSize_) + { + // This object is too large to be stored in the cache, discard it + } + else if (content_.Contains(key)) + { + // Value already stored, don't overwrite the old value but put it on top of the cache + content_.MakeMostRecent(key); + } + else + { + Recycle(maxSize_ - size); // Post-condition: currentSize_ <= maxSize_ - size + assert(currentSize_ + size <= maxSize_); + + content_.Add(key, item.release()); + currentSize_ += size; + } + + RemoveFromItemsBeingLoadedInternal(key); } + void MemoryStringCache::Add(const std::string& key, const void* buffer, size_t size) { - cache_.Acquire(key, new StringValue(reinterpret_cast(buffer), size)); + Add(key, std::string(reinterpret_cast(buffer), size)); } + void MemoryStringCache::Invalidate(const std::string &key) { - cache_.Invalidate(key); + boost::mutex::scoped_lock cacheLock(cacheMutex_); + + StringValue* item = NULL; + if (content_.Contains(key, item)) + { + assert(item != NULL); + const size_t size = item->GetMemoryUsage(); + delete item; + + content_.Invalidate(key); + + assert(currentSize_ >= size); + currentSize_ -= size; + } + + RemoveFromItemsBeingLoadedInternal(key); } - + + bool MemoryStringCache::Fetch(std::string& value, const std::string& key) { - MemoryObjectCache::Accessor reader(cache_, key, false /* multiple readers are allowed */); + boost::mutex::scoped_lock cacheLock(cacheMutex_); + + StringValue* item; - if (reader.IsValid()) + // if another client is currently loading the item, wait for it. + while (itemsBeingLoaded_.find(key) != itemsBeingLoaded_.end() && !content_.Contains(key, item)) { - value = dynamic_cast(reader.GetValue()).GetContent(); + cacheCond_.wait(cacheLock); + } + + if (content_.Contains(key, item)) + { + value = dynamic_cast(*item).GetContent(); + content_.MakeMostRecent(key); + return true; } else { + // note that this accessor will be in charge of loading and adding. + itemsBeingLoaded_.insert(key); return false; } } + + + void MemoryStringCache::RemoveFromItemsBeingLoaded(const std::string& key) + { + boost::mutex::scoped_lock cacheLock(cacheMutex_); + RemoveFromItemsBeingLoadedInternal(key); + } + + + void MemoryStringCache::RemoveFromItemsBeingLoadedInternal(const std::string& key) + { + // notify all waiting users, some of them potentially waiting for this item + itemsBeingLoaded_.erase(key); + cacheCond_.notify_all(); + } + + void MemoryStringCache::Recycle(size_t targetSize) + { + // WARNING: "cacheMutex_" must be locked + while (currentSize_ > targetSize) + { + assert(!content_.IsEmpty()); + + StringValue* item = NULL; + content_.RemoveOldest(item); + + assert(item != NULL); + const size_t size = item->GetMemoryUsage(); + delete item; + + assert(currentSize_ >= size); + currentSize_ -= size; + } + + // Post-condition: "currentSize_ <= targetSize" + } + + size_t MemoryStringCache::GetCurrentSize() const + { + boost::mutex::scoped_lock cacheLock(cacheMutex_); + + return currentSize_; + } + + size_t MemoryStringCache::GetNumberOfItems() const + { + boost::mutex::scoped_lock cacheLock(cacheMutex_); + return content_.GetSize(); + + } + } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Cache/MemoryStringCache.h --- a/OrthancFramework/Sources/Cache/MemoryStringCache.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Cache/MemoryStringCache.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -23,28 +24,79 @@ #pragma once -#include "MemoryObjectCache.h" +#include "../OrthancFramework.h" +#include "ICacheable.h" +#include "LeastRecentlyUsedIndex.h" + +#include +#include + namespace Orthanc { /** - * Facade object around "MemoryObjectCache" that caches a dictionary + * Class that caches a dictionary * of strings, using the "fetch/add" paradigm of memcached. * + * Starting from 1.12.2, if multiple clients are trying to access + * an inexistent item at the same time, only one of them will load it + * and the others will wait until the first one has loaded the data. + * + * The MemoryStringCache is only accessible through an Accessor. + * * Note: this class is thread safe **/ class ORTHANC_PUBLIC MemoryStringCache : public boost::noncopyable { + public: + class ORTHANC_PUBLIC Accessor : public boost::noncopyable + { + protected: + MemoryStringCache& cache_; + + private: + bool shouldAdd_; // when this accessor is the one who should load and add the data + std::string keyToAdd_; + + + public: + explicit Accessor(MemoryStringCache& cache); + ~Accessor(); + + bool Fetch(std::string& value, const std::string& key); + void Add(const std::string& key, const std::string& value); + void Add(const std::string& key,const char* buffer, size_t size); + }; + private: class StringValue; - MemoryObjectCache cache_; + mutable boost::mutex cacheMutex_; // note: we can not use recursive_mutex with condition_variable + boost::condition_variable cacheCond_; + std::set itemsBeingLoaded_; + + size_t currentSize_; + size_t maxSize_; + LeastRecentlyUsedIndex content_; + + void Recycle(size_t targetSize); public: + MemoryStringCache(); + + ~MemoryStringCache(); + size_t GetMaximumSize(); void SetMaximumSize(size_t size); + void Invalidate(const std::string& key); + + size_t GetCurrentSize() const; + + size_t GetNumberOfItems() const; + + private: void Add(const std::string& key, const std::string& value); @@ -52,9 +104,12 @@ const void* buffer, size_t size); - void Invalidate(const std::string& key); - bool Fetch(std::string& value, const std::string& key); + + void RemoveFromItemsBeingLoaded(const std::string& key); + void RemoveFromItemsBeingLoadedInternal(const std::string& key); + + void AddToItemsBeingLoadedInternal(const std::string& key); }; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Cache/SharedArchive.cpp --- a/OrthancFramework/Sources/Cache/SharedArchive.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Cache/SharedArchive.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -102,7 +103,7 @@ std::string SharedArchive::Add(IDynamicObject* obj) { - boost::mutex::scoped_lock lock(mutex_); + boost::recursive_mutex::scoped_lock lock(mutex_); if (archive_.size() == maxSize_) { @@ -122,7 +123,7 @@ void SharedArchive::Remove(const std::string& id) { - boost::mutex::scoped_lock lock(mutex_); + boost::recursive_mutex::scoped_lock lock(mutex_); RemoveInternal(id); } @@ -132,7 +133,7 @@ items.clear(); { - boost::mutex::scoped_lock lock(mutex_); + boost::recursive_mutex::scoped_lock lock(mutex_); for (Archive::const_iterator it = archive_.begin(); it != archive_.end(); ++it) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Cache/SharedArchive.h --- a/OrthancFramework/Sources/Cache/SharedArchive.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Cache/SharedArchive.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -44,9 +45,9 @@ private: typedef std::map Archive; - size_t maxSize_; - boost::mutex mutex_; - Archive archive_; + size_t maxSize_; + boost::recursive_mutex mutex_; + Archive archive_; LeastRecentlyUsedIndex lru_; void RemoveInternal(const std::string& id); @@ -55,8 +56,8 @@ class ORTHANC_PUBLIC Accessor : public boost::noncopyable { private: - boost::mutex::scoped_lock lock_; - IDynamicObject* item_; + boost::recursive_mutex::scoped_lock lock_; + IDynamicObject* item_; public: Accessor(SharedArchive& that, diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/ChunkedBuffer.cpp --- a/OrthancFramework/Sources/ChunkedBuffer.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/ChunkedBuffer.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/ChunkedBuffer.h --- a/OrthancFramework/Sources/ChunkedBuffer.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/ChunkedBuffer.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compatibility.h --- a/OrthancFramework/Sources/Compatibility.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compatibility.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/DeflateBaseCompressor.cpp --- a/OrthancFramework/Sources/Compression/DeflateBaseCompressor.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/DeflateBaseCompressor.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/DeflateBaseCompressor.h --- a/OrthancFramework/Sources/Compression/DeflateBaseCompressor.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/DeflateBaseCompressor.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/GzipCompressor.cpp --- a/OrthancFramework/Sources/Compression/GzipCompressor.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/GzipCompressor.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/GzipCompressor.h --- a/OrthancFramework/Sources/Compression/GzipCompressor.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/GzipCompressor.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/HierarchicalZipWriter.cpp --- a/OrthancFramework/Sources/Compression/HierarchicalZipWriter.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/HierarchicalZipWriter.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/HierarchicalZipWriter.h --- a/OrthancFramework/Sources/Compression/HierarchicalZipWriter.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/HierarchicalZipWriter.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/IBufferCompressor.cpp --- a/OrthancFramework/Sources/Compression/IBufferCompressor.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/IBufferCompressor.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/IBufferCompressor.h --- a/OrthancFramework/Sources/Compression/IBufferCompressor.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/IBufferCompressor.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/ZipReader.cpp --- a/OrthancFramework/Sources/Compression/ZipReader.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/ZipReader.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/ZipReader.h --- a/OrthancFramework/Sources/Compression/ZipReader.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/ZipReader.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/ZipWriter.cpp --- a/OrthancFramework/Sources/Compression/ZipWriter.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/ZipWriter.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -553,7 +554,7 @@ if (!pimpl_->file_) { throw OrthancException(ErrorCode_CannotWriteFile, - "Cannot create new ZIP archive: " + path_); + "Cannot create new ZIP archive"); // we do not log the path anymore since it can contain PHI } } } @@ -632,10 +633,10 @@ compressionLevel_); } - if (result != 0) + if (result != ZIP_OK) { throw OrthancException(ErrorCode_CannotWriteFile, - "Cannot add new file inside ZIP archive: " + std::string(path)); + "Cannot add new file inside ZIP archive - error code = " + boost::lexical_cast(result)); // we do not log the path anymore since it can contain PHI } hasFileInZip_ = true; @@ -666,10 +667,11 @@ { int bytes = static_cast(length <= maxBytesInAStep ? length : maxBytesInAStep); - if (zipWriteInFileInZip(pimpl_->file_, p, bytes)) + int result = zipWriteInFileInZip(pimpl_->file_, p, bytes); + if (result != ZIP_OK) { throw OrthancException(ErrorCode_CannotWriteFile, - "Cannot write data to ZIP archive: " + path_); + "Cannot write data to ZIP archive - error code =" + boost::lexical_cast(result)); // we do not log the path anymore since it can contain PHI } p += bytes; diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/ZipWriter.h --- a/OrthancFramework/Sources/Compression/ZipWriter.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/ZipWriter.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/ZlibCompressor.cpp --- a/OrthancFramework/Sources/Compression/ZlibCompressor.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/ZlibCompressor.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Compression/ZlibCompressor.h --- a/OrthancFramework/Sources/Compression/ZlibCompressor.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Compression/ZlibCompressor.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomArray.cpp --- a/OrthancFramework/Sources/DicomFormat/DicomArray.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomArray.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -86,7 +87,21 @@ { DicomTag t = elements_[i]->GetTag(); const DicomValue& v = elements_[i]->GetValue(); - std::string s = v.IsNull() ? "(null)" : v.GetContent(); + + std::string s; + if (v.IsNull()) + { + s = "(null)"; + } + else if (v.IsSequence()) + { + s = "(sequence)"; + } + else + { + s = v.GetContent(); + } + printf("0x%04x 0x%04x [%s]\n", t.GetGroup(), t.GetElement(), s.c_str()); } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomArray.h --- a/OrthancFramework/Sources/DicomFormat/DicomArray.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomArray.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomElement.cpp --- a/OrthancFramework/Sources/DicomFormat/DicomElement.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomElement.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomElement.h --- a/OrthancFramework/Sources/DicomFormat/DicomElement.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomElement.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomImageInformation.cpp --- a/OrthancFramework/Sources/DicomFormat/DicomImageInformation.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomImageInformation.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -59,60 +60,66 @@ try { - std::string p = values.GetValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION).GetContent(); - Toolbox::ToUpperCase(p); + std::string p; + if (values.LookupStringValue(p, DICOM_TAG_PHOTOMETRIC_INTERPRETATION, false)) { + Toolbox::ToUpperCase(p); - if (p == "RGB") - { - photometric_ = PhotometricInterpretation_RGB; - } - else if (p == "MONOCHROME1") - { - photometric_ = PhotometricInterpretation_Monochrome1; - } - else if (p == "MONOCHROME2") - { - photometric_ = PhotometricInterpretation_Monochrome2; - } - else if (p == "PALETTE COLOR") - { - photometric_ = PhotometricInterpretation_Palette; - } - else if (p == "HSV") - { - photometric_ = PhotometricInterpretation_HSV; - } - else if (p == "ARGB") - { - photometric_ = PhotometricInterpretation_ARGB; - } - else if (p == "CMYK") - { - photometric_ = PhotometricInterpretation_CMYK; - } - else if (p == "YBR_FULL") - { - photometric_ = PhotometricInterpretation_YBRFull; - } - else if (p == "YBR_FULL_422") - { - photometric_ = PhotometricInterpretation_YBRFull422; - } - else if (p == "YBR_PARTIAL_420") - { - photometric_ = PhotometricInterpretation_YBRPartial420; - } - else if (p == "YBR_PARTIAL_422") - { - photometric_ = PhotometricInterpretation_YBRPartial422; - } - else if (p == "YBR_ICT") - { - photometric_ = PhotometricInterpretation_YBR_ICT; - } - else if (p == "YBR_RCT") - { - photometric_ = PhotometricInterpretation_YBR_RCT; + if (p == "RGB") + { + photometric_ = PhotometricInterpretation_RGB; + } + else if (p == "MONOCHROME1") + { + photometric_ = PhotometricInterpretation_Monochrome1; + } + else if (p == "MONOCHROME2") + { + photometric_ = PhotometricInterpretation_Monochrome2; + } + else if (p == "PALETTE COLOR") + { + photometric_ = PhotometricInterpretation_Palette; + } + else if (p == "HSV") + { + photometric_ = PhotometricInterpretation_HSV; + } + else if (p == "ARGB") + { + photometric_ = PhotometricInterpretation_ARGB; + } + else if (p == "CMYK") + { + photometric_ = PhotometricInterpretation_CMYK; + } + else if (p == "YBR_FULL") + { + photometric_ = PhotometricInterpretation_YBRFull; + } + else if (p == "YBR_FULL_422") + { + photometric_ = PhotometricInterpretation_YBRFull422; + } + else if (p == "YBR_PARTIAL_420") + { + photometric_ = PhotometricInterpretation_YBRPartial420; + } + else if (p == "YBR_PARTIAL_422") + { + photometric_ = PhotometricInterpretation_YBRPartial422; + } + else if (p == "YBR_ICT") + { + photometric_ = PhotometricInterpretation_YBR_ICT; + } + else if (p == "YBR_RCT") + { + photometric_ = PhotometricInterpretation_YBR_RCT; + } + else + { + photometric_ = PhotometricInterpretation_Unknown; + } } else { @@ -423,4 +430,46 @@ { return 256; } + + + ValueRepresentation DicomImageInformation::GuessPixelDataValueRepresentation(const DicomTransferSyntax& transferSyntax, + unsigned int bitsAllocated) + { + /** + * This approach is validated in "Tests/GuessPixelDataVR.py": + * https://orthanc.uclouvain.be/hg/orthanc-tests/file/default/Tests/GuessPixelDataVR.py + **/ + + if (transferSyntax == DicomTransferSyntax_LittleEndianExplicit || + transferSyntax == DicomTransferSyntax_BigEndianExplicit) + { + /** + * Same rules apply to Little Endian Explicit and Big Endian + * Explicit (now retired). The VR of the pixel data directly + * depends upon the "Bits Allocated (0028,0100)" tag: + * https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_A.2.html + * https://dicom.nema.org/medical/dicom/2016b/output/chtml/part05/sect_A.3.html + **/ + if (bitsAllocated > 8) + { + return ValueRepresentation_OtherWord; + } + else + { + return ValueRepresentation_OtherByte; + } + } + else if (transferSyntax == DicomTransferSyntax_LittleEndianImplicit) + { + // Assume "OW" for DICOM Implicit VR Little Endian Transfer Syntax + // https://dicom.nema.org/medical/dicom/current/output/chtml/part05/chapter_A.html#sect_A.1 + return ValueRepresentation_OtherWord; + } + else + { + // Assume "OB" for all the compressed transfer syntaxes + // https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_A.4.html + return ValueRepresentation_OtherByte; + } + } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomImageInformation.h --- a/OrthancFramework/Sources/DicomFormat/DicomImageInformation.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomImageInformation.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -95,5 +96,8 @@ * was implicitly used in Orthanc <= 1.7.2. **/ static unsigned int GetUsefulTagLength(); + + static ValueRepresentation GuessPixelDataValueRepresentation(const DicomTransferSyntax& transferSyntax, + unsigned int bitsAllocated); }; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomInstanceHasher.cpp --- a/OrthancFramework/Sources/DicomFormat/DicomInstanceHasher.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomInstanceHasher.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomInstanceHasher.h --- a/OrthancFramework/Sources/DicomFormat/DicomInstanceHasher.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomInstanceHasher.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomIntegerPixelAccessor.cpp --- a/OrthancFramework/Sources/DicomFormat/DicomIntegerPixelAccessor.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomIntegerPixelAccessor.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomIntegerPixelAccessor.h --- a/OrthancFramework/Sources/DicomFormat/DicomIntegerPixelAccessor.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomIntegerPixelAccessor.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomMap.cpp --- a/OrthancFramework/Sources/DicomFormat/DicomMap.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomMap.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -34,11 +35,17 @@ #include "../OrthancException.h" #include "../Toolbox.h" #include "DicomArray.h" +#include "DicomImageInformation.h" #if ORTHANC_ENABLE_DCMTK == 1 #include "../DicomParsing/FromDcmtkBridge.h" #endif +#if !defined(__EMSCRIPTEN__) +// Multithreading is not supported in WebAssembly +# include +#endif + namespace Orthanc { // WARNING: the DEFAULT list of main dicom tags below are the list as they @@ -58,8 +65,7 @@ DICOM_TAG_PATIENT_BIRTH_DATE, DICOM_TAG_PATIENT_SEX, DICOM_TAG_OTHER_PATIENT_IDS, - DICOM_TAG_PATIENT_ID, - + DICOM_TAG_PATIENT_ID }; static const DicomTag DEFAULT_STUDY_MAIN_DICOM_TAGS[] = @@ -72,7 +78,8 @@ DICOM_TAG_STUDY_DESCRIPTION, DICOM_TAG_ACCESSION_NUMBER, DICOM_TAG_STUDY_INSTANCE_UID, - // New in db v6 + + // New in db v6 (Orthanc 0.9.5) DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION, DICOM_TAG_INSTITUTION_NAME, DICOM_TAG_REQUESTING_PHYSICIAN, @@ -99,7 +106,7 @@ DICOM_TAG_NUMBER_OF_TIME_SLICES, DICOM_TAG_SERIES_INSTANCE_UID, - // New in db v6 + // New in db v6 (Orthanc 0.9.5) DICOM_TAG_IMAGE_ORIENTATION_PATIENT, DICOM_TAG_SERIES_TYPE, DICOM_TAG_OPERATOR_NAME, @@ -119,7 +126,7 @@ DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER, DICOM_TAG_SOP_INSTANCE_UID, - // New in db v6 + // New in db v6 (Orthanc 0.9.5) DICOM_TAG_IMAGE_POSITION_PATIENT, DICOM_TAG_IMAGE_COMMENTS, @@ -133,18 +140,20 @@ DICOM_TAG_IMAGE_ORIENTATION_PATIENT // New in Orthanc 1.4.2 }; - - - - class DicomMap::MainDicomTagsConfiguration + class DicomMap::MainDicomTagsConfiguration : public boost::noncopyable { private: - friend DicomMap; +#if !defined(__EMSCRIPTEN__) + typedef boost::unique_lock WriterLock; + typedef boost::shared_lock ReaderLock; - std::set patientsMainDicomTagsByLevel_; - std::set studiesMainDicomTagsByLevel_; - std::set seriesMainDicomTagsByLevel_; - std::set instancesMainDicomTagsByLevel_; + boost::shared_mutex mutex_; +#endif + + std::set patientsMainDicomTagsByLevel_; + std::set studiesMainDicomTagsByLevel_; + std::set seriesMainDicomTagsByLevel_; + std::set instancesMainDicomTagsByLevel_; std::set allMainDicomTags_; @@ -156,27 +165,6 @@ ResetDefaultMainDicomTags(); } - void ResetDefaultMainDicomTags() - { - patientsMainDicomTagsByLevel_.clear(); - studiesMainDicomTagsByLevel_.clear(); - seriesMainDicomTagsByLevel_.clear(); - instancesMainDicomTagsByLevel_.clear(); - - allMainDicomTags_.clear(); - - // by default, initialize with the previous static list (up to 1.10.0) - LoadDefaultMainDicomTags(ResourceType_Patient); - LoadDefaultMainDicomTags(ResourceType_Study); - LoadDefaultMainDicomTags(ResourceType_Series); - LoadDefaultMainDicomTags(ResourceType_Instance); - - defaultSignatures_[ResourceType_Patient] = signatures_[ResourceType_Patient]; - defaultSignatures_[ResourceType_Study] = signatures_[ResourceType_Study]; - defaultSignatures_[ResourceType_Series] = signatures_[ResourceType_Series]; - defaultSignatures_[ResourceType_Instance] = signatures_[ResourceType_Instance]; - } - std::string ComputeSignature(const std::set& tags) { // std::set are sorted by default (which is important for us !) @@ -227,13 +215,11 @@ for (size_t i = 0; i < size; i++) { - AddMainDicomTag(tags[i], level); + AddMainDicomTagInternal(tags[i], level); } - } - - std::set& GetMainDicomTagsByLevel(ResourceType level) + std::set& GetMainDicomTagsByLevelInternal(ResourceType level) { switch (level) { @@ -254,6 +240,22 @@ } } + void AddMainDicomTagInternal(const DicomTag& tag, + ResourceType level) + { + std::set& existingLevelTags = GetMainDicomTagsByLevelInternal(level); + + if (existingLevelTags.find(tag) != existingLevelTags.end()) + { + throw OrthancException(ErrorCode_MainDicomTagsMultiplyDefined, tag.Format() + " is already defined"); + } + + existingLevelTags.insert(tag); + allMainDicomTags_.insert(tag); + + signatures_[level] = ComputeSignature(GetMainDicomTagsByLevelInternal(level)); + } + public: // Singleton pattern static MainDicomTagsConfiguration& GetInstance() @@ -262,40 +264,99 @@ return parameters; } - void AddMainDicomTag(const DicomTag& tag, ResourceType level) + void ResetDefaultMainDicomTags() { - const std::set& existingLevelTags = GetMainDicomTagsByLevel(level); +#if !defined(__EMSCRIPTEN__) + WriterLock lock(mutex_); +#endif - if (existingLevelTags.find(tag) != existingLevelTags.end()) - { - throw OrthancException(ErrorCode_MainDicomTagsMultiplyDefined, tag.Format() + " is already defined"); - } + patientsMainDicomTagsByLevel_.clear(); + studiesMainDicomTagsByLevel_.clear(); + seriesMainDicomTagsByLevel_.clear(); + instancesMainDicomTagsByLevel_.clear(); + + allMainDicomTags_.clear(); + // by default, initialize with the previous static list (up to 1.10.0) + LoadDefaultMainDicomTags(ResourceType_Patient); + LoadDefaultMainDicomTags(ResourceType_Study); + LoadDefaultMainDicomTags(ResourceType_Series); + LoadDefaultMainDicomTags(ResourceType_Instance); - GetMainDicomTagsByLevel(level).insert(tag); - allMainDicomTags_.insert(tag); - signatures_[level] = ComputeSignature(GetMainDicomTagsByLevel(level)); + defaultSignatures_[ResourceType_Patient] = signatures_[ResourceType_Patient]; + defaultSignatures_[ResourceType_Study] = signatures_[ResourceType_Study]; + defaultSignatures_[ResourceType_Series] = signatures_[ResourceType_Series]; + defaultSignatures_[ResourceType_Instance] = signatures_[ResourceType_Instance]; } - const std::set& GetAllMainDicomTags() const + void AddMainDicomTag(const DicomTag& tag, + ResourceType level) { - return allMainDicomTags_; +#if !defined(__EMSCRIPTEN__) + WriterLock lock(mutex_); +#endif + + AddMainDicomTagInternal(tag, level); } - const std::string& GetMainDicomTagsSignature(ResourceType level) + void GetAllMainDicomTags(std::set& target) + { +#if !defined(__EMSCRIPTEN__) + ReaderLock lock(mutex_); +#endif + + target = allMainDicomTags_; + } + + void GetMainDicomTagsByLevel(std::set& target, + ResourceType level) { +#if !defined(__EMSCRIPTEN__) + ReaderLock lock(mutex_); +#endif + + target = GetMainDicomTagsByLevelInternal(level); + } + + std::string GetMainDicomTagsSignature(ResourceType level) + { +#if !defined(__EMSCRIPTEN__) + ReaderLock lock(mutex_); +#endif + assert(signatures_.find(level) != signatures_.end()); - return signatures_[level]; } - const std::string& GetDefaultMainDicomTagsSignature(ResourceType level) + std::string GetDefaultMainDicomTagsSignature(ResourceType level) { +#if !defined(__EMSCRIPTEN__) + ReaderLock lock(mutex_); +#endif + assert(defaultSignatures_.find(level) != defaultSignatures_.end()); - return defaultSignatures_[level]; } + bool IsMainDicomTag(const DicomTag& tag) + { +#if !defined(__EMSCRIPTEN__) + ReaderLock lock(mutex_); +#endif + + return allMainDicomTags_.find(tag) != allMainDicomTags_.end(); + } + + bool IsMainDicomTag(const DicomTag& tag, + ResourceType level) + { +#if !defined(__EMSCRIPTEN__) + ReaderLock lock(mutex_); +#endif + + const std::set& mainDicomTags = GetMainDicomTagsByLevelInternal(level); + return mainDicomTags.find(tag) != mainDicomTags.end(); + } }; @@ -359,7 +420,7 @@ SetValueInternal(group, element, new DicomValue(str, isBinary)); } - void DicomMap::SetValue(const DicomTag& tag, const Json::Value& value) + void DicomMap::SetSequenceValue(const DicomTag& tag, const Json::Value& value) { SetValueInternal(tag.GetGroup(), tag.GetElement(), new DicomValue(value)); } @@ -414,7 +475,8 @@ void DicomMap::ExtractResourceInformation(DicomMap& result, ResourceType level) const { - const std::set& mainDicomTags = DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(level); + std::set mainDicomTags; + DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(mainDicomTags, level); ExtractTagsInternal(result, content_, mainDicomTags); } @@ -527,69 +589,81 @@ } } - static void SetupFindTemplate(DicomMap& result, - const std::set& mainDicomTags) + void DicomMap::SetupFindPatientTemplate(DicomMap& result) { result.Clear(); - for (std::set::const_iterator itmt = mainDicomTags.begin(); - itmt != mainDicomTags.end(); ++itmt) - { - result.SetValue(*itmt, "", false); - } - } + // Identifying tags + result.SetValue(DICOM_TAG_PATIENT_ID, "", false); - void DicomMap::SetupFindPatientTemplate(DicomMap& result) - { - const std::set& mainDicomTags = DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(ResourceType_Patient); - SetupFindTemplate(result, mainDicomTags); + // Other tags in the "Patient" module + result.SetValue(DICOM_TAG_OTHER_PATIENT_IDS, "", false); + result.SetValue(DICOM_TAG_PATIENT_BIRTH_DATE, "", false); + result.SetValue(DICOM_TAG_PATIENT_NAME, "", false); + result.SetValue(DICOM_TAG_PATIENT_SEX, "", false); } void DicomMap::SetupFindStudyTemplate(DicomMap& result) { - const std::set& mainDicomTags = DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(ResourceType_Study); - SetupFindTemplate(result, mainDicomTags); + result.Clear(); + + // Identifying tags + result.SetValue(DICOM_TAG_PATIENT_ID, "", false); result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); - result.SetValue(DICOM_TAG_PATIENT_ID, "", false); + result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); - // These main DICOM tags are only indirectly related to the - // General Study Module, remove them - result.Remove(DICOM_TAG_INSTITUTION_NAME); - result.Remove(DICOM_TAG_REQUESTING_PHYSICIAN); - result.Remove(DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION); + // Other tags in the "General Study" module + result.SetValue(DICOM_TAG_REFERRING_PHYSICIAN_NAME, "", false); + result.SetValue(DICOM_TAG_STUDY_DATE, "", false); + result.SetValue(DICOM_TAG_STUDY_DESCRIPTION, "", false); + result.SetValue(DICOM_TAG_STUDY_ID, "", false); + result.SetValue(DICOM_TAG_STUDY_TIME, "", false); } void DicomMap::SetupFindSeriesTemplate(DicomMap& result) { - const std::set& mainDicomTags = DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(ResourceType_Series); - SetupFindTemplate(result, mainDicomTags); + result.Clear(); + + // Identifying tags + result.SetValue(DICOM_TAG_PATIENT_ID, "", false); result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); - result.SetValue(DICOM_TAG_PATIENT_ID, "", false); result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); + result.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "", false); - // These tags are considered as "main" by Orthanc, but are not in the Series module - result.Remove(DicomTag(0x0008, 0x0070)); // Manufacturer - result.Remove(DicomTag(0x0008, 0x1010)); // Station name - result.Remove(DicomTag(0x0018, 0x0024)); // Sequence name - result.Remove(DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES); - result.Remove(DICOM_TAG_IMAGES_IN_ACQUISITION); - result.Remove(DICOM_TAG_NUMBER_OF_SLICES); - result.Remove(DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS); - result.Remove(DICOM_TAG_NUMBER_OF_TIME_SLICES); - result.Remove(DICOM_TAG_IMAGE_ORIENTATION_PATIENT); - result.Remove(DICOM_TAG_SERIES_TYPE); - result.Remove(DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION); - result.Remove(DICOM_TAG_CONTRAST_BOLUS_AGENT); + // Other tags in the "General Series" module + result.SetValue(DICOM_TAG_BODY_PART_EXAMINED, "", false); + result.SetValue(DICOM_TAG_MODALITY, "", false); + result.SetValue(DICOM_TAG_OPERATOR_NAME, "", false); + result.SetValue(DICOM_TAG_PERFORMED_PROCEDURE_STEP_DESCRIPTION, "", false); + result.SetValue(DICOM_TAG_PROTOCOL_NAME, "", false); + result.SetValue(DICOM_TAG_SERIES_DATE, "", false); + result.SetValue(DICOM_TAG_SERIES_DESCRIPTION, "", false); + result.SetValue(DICOM_TAG_SERIES_NUMBER, "", false); + result.SetValue(DICOM_TAG_SERIES_TIME, "", false); } void DicomMap::SetupFindInstanceTemplate(DicomMap& result) { - const std::set& mainDicomTags = DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(ResourceType_Instance); - SetupFindTemplate(result, mainDicomTags); + result.Clear(); + + // Identifying tags + result.SetValue(DICOM_TAG_PATIENT_ID, "", false); result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); - result.SetValue(DICOM_TAG_PATIENT_ID, "", false); result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); result.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "", false); + result.SetValue(DICOM_TAG_SOP_INSTANCE_UID, "", false); + + // Other tags in the "SOP Common" module + result.SetValue(DICOM_TAG_ACQUISITION_NUMBER, "", false); + result.SetValue(DICOM_TAG_IMAGE_COMMENTS, "", false); + result.SetValue(DICOM_TAG_IMAGE_INDEX, "", false); + result.SetValue(DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "", false); + result.SetValue(DICOM_TAG_IMAGE_POSITION_PATIENT, "", false); + result.SetValue(DICOM_TAG_INSTANCE_CREATION_DATE, "", false); + result.SetValue(DICOM_TAG_INSTANCE_CREATION_TIME, "", false); + result.SetValue(DICOM_TAG_INSTANCE_NUMBER, "", false); + result.SetValue(DICOM_TAG_NUMBER_OF_FRAMES, "", false); + result.SetValue(DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER, "", false); } @@ -605,8 +679,7 @@ bool DicomMap::IsMainDicomTag(const DicomTag& tag, ResourceType level) { - const std::set& mainDicomTags = DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(level); - return mainDicomTags.find(tag) != mainDicomTags.end(); + return DicomMap::MainDicomTagsConfiguration::GetInstance().IsMainDicomTag(tag, level); } bool DicomMap::IsMainDicomTag(const DicomTag& tag) @@ -706,14 +779,15 @@ } - const std::set& DicomMap::GetMainDicomTags(ResourceType level) + void DicomMap::GetMainDicomTags(std::set& target, + ResourceType level) { - return DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(level); + DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(target, level); } - const std::set& DicomMap::GetAllMainDicomTags() + void DicomMap::GetAllMainDicomTags(std::set& target) { - return DicomMap::MainDicomTagsConfiguration::GetInstance().GetAllMainDicomTags(); + DicomMap::MainDicomTagsConfiguration::GetInstance().GetAllMainDicomTags(target); } void DicomMap::AddMainDicomTag(const DicomTag& tag, ResourceType level) @@ -726,12 +800,12 @@ DicomMap::MainDicomTagsConfiguration::GetInstance().ResetDefaultMainDicomTags(); } - const std::string& DicomMap::GetMainDicomTagsSignature(ResourceType level) + std::string DicomMap::GetMainDicomTagsSignature(ResourceType level) { return DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsSignature(level); } - const std::string& DicomMap::GetDefaultMainDicomTagsSignature(ResourceType level) + std::string DicomMap::GetDefaultMainDicomTagsSignature(ResourceType level) { return DicomMap::MainDicomTagsConfiguration::GetInstance().GetDefaultMainDicomTagsSignature(level); } @@ -1384,7 +1458,7 @@ } else { - SetValue(tag, value["Value"]); + SetSequenceValue(tag, value["Value"]); } } } @@ -1409,7 +1483,8 @@ void DicomMap::MergeMainDicomTags(const DicomMap& other, ResourceType level) { - const std::set& mainDicomTags = DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(level); + std::set mainDicomTags; + DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(mainDicomTags, level); for (std::set::const_iterator itmt = mainDicomTags.begin(); itmt != mainDicomTags.end(); ++itmt) @@ -1438,11 +1513,9 @@ bool DicomMap::HasOnlyMainDicomTags() const { - const std::set& allMainDicomTags = DicomMap::MainDicomTagsConfiguration::GetInstance().GetAllMainDicomTags(); - for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) { - if (allMainDicomTags.find(it->first) == allMainDicomTags.end()) + if (!DicomMap::MainDicomTagsConfiguration::GetInstance().IsMainDicomTag(it->first)) { return false; } @@ -1459,7 +1532,7 @@ { if (it->second->IsSequence()) { - result.SetValue(it->first, it->second->GetSequenceContent()); + result.SetSequenceValue(it->first, it->second->GetSequenceContent()); } } } @@ -1710,7 +1783,8 @@ void DicomMap::DumpMainDicomTags(Json::Value& target, ResourceType level) const { - const std::set& mainDicomTags = DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(level); + std::set mainDicomTags; + DicomMap::MainDicomTagsConfiguration::GetInstance().GetMainDicomTagsByLevel(mainDicomTags, level); target = Json::objectValue; @@ -1736,6 +1810,19 @@ } + ValueRepresentation DicomMap::GuessPixelDataValueRepresentation(DicomTransferSyntax transferSyntax) const + { + const DicomValue* value = TestAndGetValue(DICOM_TAG_BITS_ALLOCATED); + + uint32_t bitsAllocated; + if (value == NULL || + !value->ParseUnsignedInteger32(bitsAllocated)) + { + bitsAllocated = 8; + } + + return DicomImageInformation::GuessPixelDataValueRepresentation(transferSyntax, bitsAllocated); + } void DicomMap::Print(FILE* fp) const diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomMap.h --- a/OrthancFramework/Sources/DicomFormat/DicomMap.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomMap.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -31,10 +32,6 @@ #include #include -#if ORTHANC_BUILD_UNIT_TESTS == 1 -# include -#endif - namespace Orthanc { class ORTHANC_PUBLIC DicomMap : public boost::noncopyable @@ -48,10 +45,6 @@ friend class FromDcmtkBridge; friend class ParsedDicomFile; -#if ORTHANC_BUILD_UNIT_TESTS == 1 - friend class DicomMapMainTagsTests; -#endif - Content content_; // Warning: This takes the ownership of "value" @@ -59,12 +52,11 @@ uint16_t element, DicomValue* value); - // used for unit tests only - static void ResetDefaultMainDicomTags(); - public: ~DicomMap(); + static void ResetDefaultMainDicomTags(); + size_t GetSize() const; DicomMap* Clone() const; @@ -94,8 +86,8 @@ const std::string& str, bool isBinary); - void SetValue(const DicomTag& tag, - const Json::Value& value); + void SetSequenceValue(const DicomTag& tag, + const Json::Value& value); bool HasTag(uint16_t group, uint16_t element) const; @@ -154,14 +146,15 @@ static bool HasComputedTags(const std::set& tags); - static const std::set& GetMainDicomTags(ResourceType level); + static void GetMainDicomTags(std::set& target, + ResourceType level); // returns a string uniquely identifying the list of main dicom tags for a level - static const std::string& GetMainDicomTagsSignature(ResourceType level); + static std::string GetMainDicomTagsSignature(ResourceType level); - static const std::string& GetDefaultMainDicomTagsSignature(ResourceType level); + static std::string GetDefaultMainDicomTagsSignature(ResourceType level); - static const std::set& GetAllMainDicomTags(); + static void GetAllMainDicomTags(std::set& target); // adds a main dicom tag to the definition of main dicom tags for each level. // this should be done once at startup before you use MainDicomTags methods @@ -238,6 +231,8 @@ void DumpMainDicomTags(Json::Value& target, ResourceType level) const; + ValueRepresentation GuessPixelDataValueRepresentation(DicomTransferSyntax transferSyntax) const; + void Print(FILE* fp) const; // For debugging only }; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomPath.cpp --- a/OrthancFramework/Sources/DicomFormat/DicomPath.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomPath.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomPath.h --- a/OrthancFramework/Sources/DicomFormat/DicomPath.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomPath.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomStreamReader.cpp --- a/OrthancFramework/Sources/DicomFormat/DicomStreamReader.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomStreamReader.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -579,13 +580,17 @@ class DicomStreamReader::PixelDataVisitor : public DicomStreamReader::IVisitor { private: - bool hasPixelData_; - uint64_t pixelDataOffset_; + bool hasPixelData_; + uint64_t pixelDataOffset_; + ValueRepresentation pixelDataVR_; + DicomTransferSyntax transferSyntax_; public: PixelDataVisitor() : hasPixelData_(false), - pixelDataOffset_(0) + pixelDataOffset_(0), + pixelDataVR_(ValueRepresentation_Unknown), + transferSyntax_(DicomTransferSyntax_LittleEndianImplicit) // Default DICOM transfer syntax { } @@ -597,6 +602,7 @@ virtual void VisitTransferSyntax(DicomTransferSyntax transferSyntax) ORTHANC_OVERRIDE { + transferSyntax_ = transferSyntax; } virtual bool VisitDatasetTag(const DicomTag& tag, @@ -609,6 +615,23 @@ { hasPixelData_ = true; pixelDataOffset_ = fileOffset; + + if (transferSyntax_ == DicomTransferSyntax_LittleEndianImplicit) + { + // Implicit Little Endian has always "OW" VR for pixel data + // https://dicom.nema.org/medical/dicom/current/output/chtml/part05/chapter_A.html + pixelDataVR_ = ValueRepresentation_OtherWord; + } + else if (transferSyntax_ == DicomTransferSyntax_LittleEndianExplicit || + transferSyntax_ == DicomTransferSyntax_BigEndianExplicit) + { + pixelDataVR_ = vr; + } + else + { + // Compressed transfer syntaxes must always be OB + pixelDataVR_ = ValueRepresentation_OtherByte; + } } // Stop processing once pixel data has been passed @@ -625,7 +648,13 @@ return pixelDataOffset_; } + ValueRepresentation GetPixelDataVR() const + { + return pixelDataVR_; + } + static bool LookupPixelDataOffset(uint64_t& offset, + ValueRepresentation& vr, std::istream& stream) { PixelDataVisitor visitor; @@ -672,6 +701,7 @@ s[3] == char(0x00)) { offset = visitor.GetPixelDataOffset(); + vr = visitor.GetPixelDataVR(); return true; } else @@ -688,20 +718,22 @@ bool DicomStreamReader::LookupPixelDataOffset(uint64_t& offset, + ValueRepresentation& vr, const std::string& dicom) { std::stringstream stream(dicom); - return PixelDataVisitor::LookupPixelDataOffset(offset, stream); + return PixelDataVisitor::LookupPixelDataOffset(offset, vr, stream); } bool DicomStreamReader::LookupPixelDataOffset(uint64_t& offset, + ValueRepresentation& vr, const void* buffer, size_t size) { boost::iostreams::array_source source(reinterpret_cast(buffer), size); boost::iostreams::stream stream(source); - return PixelDataVisitor::LookupPixelDataOffset(offset, stream); + return PixelDataVisitor::LookupPixelDataOffset(offset, vr, stream); } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomStreamReader.h --- a/OrthancFramework/Sources/DicomFormat/DicomStreamReader.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomStreamReader.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -128,10 +129,12 @@ uint64_t GetProcessedBytes() const; - static bool LookupPixelDataOffset(uint64_t& offset, + static bool LookupPixelDataOffset(uint64_t& offset /* out */, + ValueRepresentation& vr /* out */, const std::string& dicom); - static bool LookupPixelDataOffset(uint64_t& offset, + static bool LookupPixelDataOffset(uint64_t& offset /* out */, + ValueRepresentation& vr /* out */, const void* buffer, size_t size); }; diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomTag.cpp --- a/OrthancFramework/Sources/DicomFormat/DicomTag.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomTag.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomTag.h --- a/OrthancFramework/Sources/DicomFormat/DicomTag.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomTag.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -147,6 +148,7 @@ static const DicomTag DICOM_TAG_SERIES_TIME(0x0008, 0x0031); static const DicomTag DICOM_TAG_STUDY_DATE(0x0008, 0x0020); static const DicomTag DICOM_TAG_STUDY_TIME(0x0008, 0x0030); + static const DicomTag DICOM_TAG_TIMEZONE_OFFSET_FROM_UTC(0x0008, 0x0201); // Various tags static const DicomTag DICOM_TAG_SERIES_TYPE(0x0054, 0x1000); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomValue.cpp --- a/OrthancFramework/Sources/DicomFormat/DicomValue.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomValue.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -66,6 +67,10 @@ type_(Type_SequenceAsJson), sequenceJson_(value) { + if (value.type() != Json::arrayValue) + { + throw OrthancException(ErrorCode_BadParameterType); + } } const std::string& DicomValue::GetContent() const diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/DicomValue.h --- a/OrthancFramework/Sources/DicomFormat/DicomValue.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomValue.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/StreamBlockReader.cpp --- a/OrthancFramework/Sources/DicomFormat/StreamBlockReader.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/StreamBlockReader.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomFormat/StreamBlockReader.h --- a/OrthancFramework/Sources/DicomFormat/StreamBlockReader.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomFormat/StreamBlockReader.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/DicomAssociation.cpp --- a/OrthancFramework/Sources/DicomNetworking/DicomAssociation.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociation.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -33,6 +34,10 @@ #include "../OrthancException.h" #include "NetworkingCompatibility.h" +#ifdef _WIN32 +# include +#endif + #include // For dcmConnectionTimeout() #include @@ -104,6 +109,8 @@ void DicomAssociation::CloseInternal() { + CLOG(INFO, DICOM) << "Closing DICOM association"; + #if ORTHANC_ENABLE_SSL == 1 tls_.reset(NULL); // Transport layer must be destroyed before the association itself #endif @@ -293,11 +300,12 @@ { assert(net_ != NULL && params_ != NULL); - tls_.reset(Internals::InitializeDicomTls(net_, NET_REQUESTOR, parameters.GetOwnPrivateKeyPath(), parameters.GetOwnCertificatePath(), parameters.GetTrustedCertificatesPath(), - parameters.IsRemoteCertificateRequired())); + parameters.IsRemoteCertificateRequired(), + parameters.GetMinimumTlsVersion(), + parameters.GetAcceptedCiphers())); } catch (OrthancException&) { @@ -389,8 +397,10 @@ LST_Position(l, (LST_NODE*)pc); while (pc) { - if (pc->result == ASC_P_ACCEPTANCE) + if (pc->result == ASC_P_ACCEPTANCE && strlen(pc->abstractSyntax) > 0) { + CLOG(TRACE, DICOM) << "DicomAssociation::Open, adding SOPClassUID " << pc->abstractSyntax << " - TS " << pc->acceptedTransferSyntax << " - PC ID " << boost::lexical_cast(static_cast(pc->presentationContextID)); + DicomTransferSyntax transferSyntax; if (LookupTransferSyntax(transferSyntax, pc->acceptedTransferSyntax)) { diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/DicomAssociation.h --- a/OrthancFramework/Sources/DicomNetworking/DicomAssociation.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociation.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.cpp --- a/OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -43,7 +44,8 @@ static std::string defaultTrustedCertificatesPath_; static unsigned int defaultMaximumPduLength_ = ASC_DEFAULTMAXPDU; static bool defaultRemoteCertificateRequired_ = true; - +static unsigned int minimumTlsVersion_ = 0; +static std::set acceptedCiphers_; namespace Orthanc { @@ -193,7 +195,7 @@ throw OrthancException(ErrorCode_BadSequenceOfCalls, "DICOM TLS - No path to the local certificate was provided"); } - else if (trustedCertificatesPath_.empty()) + else if (remoteCertificateRequired_ && trustedCertificatesPath_.empty()) { throw OrthancException(ErrorCode_BadSequenceOfCalls, "DICOM TLS - No path to the trusted remote certificates was provided"); @@ -251,7 +253,26 @@ return remoteCertificateRequired_; } + unsigned int DicomAssociationParameters::GetMinimumTlsVersion() + { + return minimumTlsVersion_; + } + void DicomAssociationParameters::SetMinimumTlsVersion(unsigned int version) + { + minimumTlsVersion_ = version; + } + + void DicomAssociationParameters::SetAcceptedCiphers(const std::set& acceptedCiphers) + { + acceptedCiphers_ = acceptedCiphers; + } + + const std::set& DicomAssociationParameters::GetAcceptedCiphers() + { + return acceptedCiphers_; + } + static const char* const LOCAL_AET = "LocalAet"; static const char* const REMOTE = "Remote"; diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.h --- a/OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -127,5 +128,13 @@ static void SetDefaultRemoteCertificateRequired(bool required); static bool GetDefaultRemoteCertificateRequired(); + + static void SetMinimumTlsVersion(unsigned int version); + + static unsigned int GetMinimumTlsVersion(); + + static void SetAcceptedCiphers(const std::set& acceptedCiphers); + + static const std::set& GetAcceptedCiphers(); }; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.cpp --- a/OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -189,7 +190,7 @@ // same fix is required for Agfa Impax. This was generalized for // generic manufacturer since it seems to affect PhilipsADW, // GEWAServer as well: - // https://bugs.orthanc-server.com/show_bug.cgi?id=31 + // https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=31 switch (manufacturer) { diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.h --- a/OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomControlUserConnection.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.cpp --- a/OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.h --- a/OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomFindAnswers.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/DicomServer.cpp --- a/OrthancFramework/Sources/DicomNetworking/DicomServer.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomServer.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -61,6 +62,7 @@ unsigned int maximumPduLength, bool useDicomTls) { + Logging::SetCurrentThreadName("DICOM-SERVER"); CLOG(INFO, DICOM) << "DICOM server started"; while (server->continue_) @@ -105,7 +107,8 @@ applicationEntityFilter_(NULL), useDicomTls_(false), maximumPduLength_(ASC_DEFAULTMAXPDU), - remoteCertificateRequired_(true) + remoteCertificateRequired_(true), + minimumTlsVersion_(0) { } @@ -409,7 +412,7 @@ { pimpl_->tls_.reset(Internals::InitializeDicomTls( pimpl_->network_, NET_ACCEPTOR, ownPrivateKeyPath_, ownCertificatePath_, - trustedCertificatesPath_, remoteCertificateRequired_)); + trustedCertificatesPath_, remoteCertificateRequired_, minimumTlsVersion_, acceptedCiphers_)); } catch (OrthancException&) { @@ -429,7 +432,7 @@ CLOG(INFO, DICOM) << "The embedded DICOM server will use " << threadsCount_ << " threads"; - pimpl_->workers_.reset(new RunnableWorkersPool(threadsCount_)); + pimpl_->workers_.reset(new RunnableWorkersPool(threadsCount_, "DICOM-")); pimpl_->thread_ = boost::thread(ServerThread, this, maximumPduLength_, useDicomTls_); } @@ -492,6 +495,18 @@ return useDicomTls_; } + void DicomServer::SetMinimumTlsVersion(unsigned int version) + { + minimumTlsVersion_ = version; + DicomAssociationParameters::SetMinimumTlsVersion(version); + } + + void DicomServer::SetAcceptedCiphers(const std::set& ciphers) + { + acceptedCiphers_ = ciphers; + DicomAssociationParameters::SetAcceptedCiphers(ciphers); + } + void DicomServer::SetOwnCertificatePath(const std::string& privateKeyPath, const std::string& certificatePath) { diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/DicomServer.h --- a/OrthancFramework/Sources/DicomNetworking/DicomServer.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomServer.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -90,6 +91,8 @@ std::string trustedCertificatesPath_; unsigned int maximumPduLength_; bool remoteCertificateRequired_; // New in 1.9.3 + unsigned int minimumTlsVersion_; // New in 1.12.4 + std::set acceptedCiphers_; // New in 1.12.4 static void ServerThread(DicomServer* server, @@ -153,6 +156,9 @@ void SetDicomTlsEnabled(bool enabled); bool IsDicomTlsEnabled() const; + void SetMinimumTlsVersion(unsigned int version); + void SetAcceptedCiphers(const std::set& ciphers); + void SetOwnCertificatePath(const std::string& privateKeyPath, const std::string& certificatePath); const std::string& GetOwnPrivateKeyPath() const; diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.cpp --- a/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -262,26 +263,33 @@ if (LookupPresentationContext(presentationContextId, sopClassUid, transferSyntax)) { + CLOG(INFO, DICOM) << "Found an accepted presentation context for SOPClassUID " << sopClassUid << " and transfer syntax " << GetTransferSyntaxUid(transferSyntax); return true; } // The association must be re-negotiated if (association_->IsOpen()) { - CLOG(INFO, DICOM) << "Re-negotiating DICOM association with " - << parameters_.GetRemoteModality().GetApplicationEntityTitle(); + CLOG(INFO, DICOM) << "No accepted presentation context found, re-negotiating DICOM association with " + << parameters_.GetRemoteModality().GetApplicationEntityTitle() + << " for SOPClassUID " << sopClassUid << " TransferSyntax =" << GetTransferSyntaxUid(transferSyntax); - // Don't renegociate if we know that the remote modality was + // Check if we know that the remote modality was // already proposed this individual transfer syntax (**) - if (proposedOriginalClasses_.find(std::make_pair(sopClassUid, transferSyntax)) != - proposedOriginalClasses_.end()) + if (proposedOriginalClasses_.find(std::make_pair(sopClassUid, transferSyntax)) != proposedOriginalClasses_.end()) { CLOG(INFO, DICOM) << "The remote modality has already rejected SOP class UID \"" << sopClassUid << "\" with transfer syntax \"" - << GetTransferSyntaxUid(transferSyntax) << "\", don't renegotiate"; - return false; + << GetTransferSyntaxUid(transferSyntax) << "\", but we will renegotiate anyway"; + // always renegotiating since 1.12.2 // return false; } } + else + { + CLOG(INFO, DICOM) << "Negotiating DICOM association with " + << parameters_.GetRemoteModality().GetApplicationEntityTitle() + << " for SOPClassUID " << sopClassUid << " TransferSyntax =" << GetTransferSyntaxUid(transferSyntax); + } association_->ClearPresentationContexts(); proposedOriginalClasses_.clear(); @@ -374,6 +382,8 @@ DicomTransferSyntax transferSyntax; LookupParameters(sopClassUid, sopInstanceUid, transferSyntax, dicom); + LOG(INFO) << "Performing C-Store on instance of SOPClassUID '" << sopClassUid << "'"; + uint8_t presID; if (!NegotiatePresentationContext(presID, sopClassUid, transferSyntax, proposeUncompressedSyntaxes_, DicomTransferSyntax_LittleEndianExplicit)) @@ -440,7 +450,8 @@ if (response.DimseStatus != 0x0000 && // Success response.DimseStatus != 0xB000 && // Warning - Coercion of Data Elements response.DimseStatus != 0xB007 && // Warning - Data Set does not match SOP Class - response.DimseStatus != 0xB006) // Warning - Elements Discarded + response.DimseStatus != 0xB006 && // Warning - Elements Discarded + response.DimseStatus != 0x0111) // Warning - Duplicate SOPInstanceUID (https://discourse.orthanc-server.org/t/ignore-dimse-status-0x0111-when-sending-partial-duplicate-studies/4555/3) { char buf[16]; sprintf(buf, "%04X", response.DimseStatus); @@ -472,6 +483,7 @@ } +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 void DicomStoreUserConnection::LookupTranscoding(std::set& acceptedSyntaxes, const std::string& sopClassUid, DicomTransferSyntax sourceSyntax, @@ -479,14 +491,17 @@ DicomTransferSyntax preferred) { acceptedSyntaxes.clear(); + std::map contexts; // Make sure a negotiation has already occurred for this transfer - // syntax. We don't use the return code: Transcoding is possible - // even if the "sourceSyntax" is not supported. - uint8_t presID; - NegotiatePresentationContext(presID, sopClassUid, sourceSyntax, hasPreferred, preferred); + // syntax if we have not negotiated yet. + // We don't use the return code: Transcoding is possible even if the "sourceSyntax" is not supported. + if (!association_->IsOpen() || !association_->LookupAcceptedPresentationContext(contexts, sopClassUid)) + { + uint8_t presID; + NegotiatePresentationContext(presID, sopClassUid, sourceSyntax, hasPreferred, preferred); + } - std::map contexts; if (association_->LookupAcceptedPresentationContext(contexts, sopClassUid)) { for (std::map::const_iterator @@ -496,8 +511,10 @@ } } } +#endif + - +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 void DicomStoreUserConnection::Transcode(std::string& sopClassUid /* out */, std::string& sopInstanceUid /* out */, IDicomTranscoder& transcoder, @@ -521,6 +538,12 @@ std::set accepted; LookupTranscoding(accepted, sopClassUid, sourceSyntax, true, preferredTransferSyntax); + if (accepted.size() == 0) + { + throw OrthancException(ErrorCode_NoPresentationContext, "Cannot C-Store an instance of SOPClassUID " + + sopClassUid + ", the destination has not accepted any TransferSyntax for this SOPClassUID."); + } + if (accepted.find(sourceSyntax) != accepted.end()) { // No need for transcoding @@ -541,6 +564,8 @@ bool isDestructiveCompressionAllowed = false; std::set attemptedSyntaxes; + LOG(INFO) << "Transcoding is required to C-Store an instance of SOPClassUID '" << sopClassUid << "', preferredTransferSyntax is " << GetTransferSyntaxUid(preferredTransferSyntax); + if (accepted.find(preferredTransferSyntax) != accepted.end()) { // New in Orthanc 1.9.0: The preferred transfer syntax is @@ -626,14 +651,17 @@ s += " " + std::string(GetTransferSyntaxUid(*it)); } - throw OrthancException(ErrorCode_NotImplemented, "Cannot transcode from " + + throw OrthancException(ErrorCode_NotImplemented, "Cannot transcode instance of SOPClassUID " + + sopClassUid + " from " + std::string(GetTransferSyntaxUid(sourceSyntax)) + " to one of [" + s + " ]"); } } } - +#endif + +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 void DicomStoreUserConnection::Transcode(std::string& sopClassUid /* out */, std::string& sopInstanceUid /* out */, IDicomTranscoder& transcoder, @@ -646,4 +674,5 @@ Transcode(sopClassUid, sopInstanceUid, transcoder, buffer, size, DicomTransferSyntax_LittleEndianExplicit, hasMoveOriginator, moveOriginatorAET, moveOriginatorID); } +#endif } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.h --- a/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/DicomStoreUserConnection.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -96,11 +97,13 @@ bool hasPreferred, DicomTransferSyntax preferred); +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 void LookupTranscoding(std::set& acceptedSyntaxes, const std::string& sopClassUid, DicomTransferSyntax sourceSyntax, bool hasPreferred, DicomTransferSyntax preferred); +#endif public: explicit DicomStoreUserConnection(const DicomAssociationParameters& params); @@ -142,6 +145,7 @@ DicomTransferSyntax& transferSyntax, DcmFileFormat& dicom); +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 void Transcode(std::string& sopClassUid /* out */, std::string& sopInstanceUid /* out */, IDicomTranscoder& transcoder, @@ -151,7 +155,9 @@ bool hasMoveOriginator, const std::string& moveOriginatorAET, uint16_t moveOriginatorID); - +#endif + +#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 void Transcode(std::string& sopClassUid /* out */, std::string& sopInstanceUid /* out */, IDicomTranscoder& transcoder, @@ -160,5 +166,6 @@ bool hasMoveOriginator, const std::string& moveOriginatorAET, uint16_t moveOriginatorID); +#endif }; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IApplicationEntityFilter.h --- a/OrthancFramework/Sources/DicomNetworking/IApplicationEntityFilter.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IApplicationEntityFilter.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -25,6 +26,7 @@ #include "../Enumerations.h" +#include #include namespace Orthanc diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IFindRequestHandler.h --- a/OrthancFramework/Sources/DicomNetworking/IFindRequestHandler.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IFindRequestHandler.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IFindRequestHandlerFactory.h --- a/OrthancFramework/Sources/DicomNetworking/IFindRequestHandlerFactory.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IFindRequestHandlerFactory.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IGetRequestHandler.h --- a/OrthancFramework/Sources/DicomNetworking/IGetRequestHandler.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IGetRequestHandler.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IGetRequestHandlerFactory.h --- a/OrthancFramework/Sources/DicomNetworking/IGetRequestHandlerFactory.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IGetRequestHandlerFactory.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IMoveRequestHandler.h --- a/OrthancFramework/Sources/DicomNetworking/IMoveRequestHandler.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IMoveRequestHandler.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IMoveRequestHandlerFactory.h --- a/OrthancFramework/Sources/DicomNetworking/IMoveRequestHandlerFactory.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IMoveRequestHandlerFactory.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IStorageCommitmentRequestHandler.h --- a/OrthancFramework/Sources/DicomNetworking/IStorageCommitmentRequestHandler.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IStorageCommitmentRequestHandler.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IStorageCommitmentRequestHandlerFactory.h --- a/OrthancFramework/Sources/DicomNetworking/IStorageCommitmentRequestHandlerFactory.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IStorageCommitmentRequestHandlerFactory.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IStoreRequestHandler.h --- a/OrthancFramework/Sources/DicomNetworking/IStoreRequestHandler.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IStoreRequestHandler.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IStoreRequestHandlerFactory.h --- a/OrthancFramework/Sources/DicomNetworking/IStoreRequestHandlerFactory.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IStoreRequestHandlerFactory.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IWorklistRequestHandler.h --- a/OrthancFramework/Sources/DicomNetworking/IWorklistRequestHandler.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IWorklistRequestHandler.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/IWorklistRequestHandlerFactory.h --- a/OrthancFramework/Sources/DicomNetworking/IWorklistRequestHandlerFactory.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/IWorklistRequestHandlerFactory.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/Internals/CommandDispatcher.cpp --- a/OrthancFramework/Sources/DicomNetworking/Internals/CommandDispatcher.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/CommandDispatcher.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -481,7 +482,7 @@ #if DCMTK_VERSION_NUMBER >= 362 // The global variable "numberOfDcmAllStorageSOPClassUIDs" is // only published if DCMTK >= 3.6.2: - // https://bugs.orthanc-server.com/show_bug.cgi?id=137 + // https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=137 assert(static_cast(count) == numberOfDcmAllStorageSOPClassUIDs); #endif @@ -521,10 +522,12 @@ * Accept in the order "least wanted" to "most wanted" * transfer syntax. Accepting a transfer syntax will * override previously accepted transfer syntaxes. + * Since Orthanc 1.11.2+, we give priority to the transfer + * syntaxes proposed in the presentation context. **/ - for (int k = static_cast(storageTransferSyntaxesC.size()) - 1; k >= 0; k--) + for (int j = static_cast(pc.transferSyntaxCount)-1; j >=0; j--) { - for (int j = 0; j < static_cast(pc.transferSyntaxCount); j++) + for (int k = static_cast(storageTransferSyntaxesC.size()) - 1; k >= 0; k--) { /** * If the transfer syntax was proposed then we can accept it diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/Internals/CommandDispatcher.h --- a/OrthancFramework/Sources/DicomNetworking/Internals/CommandDispatcher.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/CommandDispatcher.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.cpp --- a/OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -27,7 +28,9 @@ #include "../../Logging.h" #include "../../OrthancException.h" #include "../../SystemToolbox.h" - +#include "../../Toolbox.h" +#include +#include #if DCMTK_VERSION_NUMBER < 364 # define DCF_Filetype_PEM SSL_FILETYPE_PEM @@ -58,12 +61,47 @@ #endif +#if DCMTK_VERSION_NUMBER >= 367 + static OFCondition MyConvertOpenSSLError(unsigned long errorCode, OFBool logAsError) + { + return DcmTLSTransportLayer::convertOpenSSLError(errorCode, logAsError); + } +#else + static OFCondition MyConvertOpenSSLError(unsigned long errorCode, OFBool logAsError) + { + if (errorCode == 0) + { + return EC_Normal; + } + else + { + const char *err = ERR_reason_error_string(errorCode); + if (err == NULL) + { + err = "OpenSSL error"; + } + + if (logAsError) + { + DCMTLS_ERROR("OpenSSL error " << STD_NAMESPACE hex << STD_NAMESPACE setfill('0') + << STD_NAMESPACE setw(8) << errorCode << ": " << err); + } + + // The "2" below corresponds to the same error code as "DCMTLS_EC_FailedToSetCiphersuites" + return OFCondition(OFM_dcmtls, 2, OF_error, err); + } + } +#endif + + DcmTLSTransportLayer* InitializeDicomTls(T_ASC_Network *network, T_ASC_NetworkRole role, const std::string& ownPrivateKeyPath, const std::string& ownCertificatePath, const std::string& trustedCertificatesPath, - bool requireRemoteCertificate) + bool requireRemoteCertificate, + unsigned int minimalTlsVersion, + const std::set& ciphers) { if (network == NULL) { @@ -76,7 +114,7 @@ throw OrthancException(ErrorCode_ParameterOutOfRange, "Unknown role"); } - if (!SystemToolbox::IsRegularFile(trustedCertificatesPath)) + if (requireRemoteCertificate && !SystemToolbox::IsRegularFile(trustedCertificatesPath)) { throw OrthancException(ErrorCode_InexistentFile, "Cannot read file with trusted certificates for DICOM TLS: " + trustedCertificatesPath); @@ -120,7 +158,7 @@ new DcmTLSTransportLayer(tmpRole /*opt_networkRole*/, NULL /*opt_readSeedFile*/, OFFalse /*initializeOpenSSL, done by Orthanc::Toolbox::InitializeOpenSsl()*/)); - if (IsFailure(tls->addTrustedCertificateFile(trustedCertificatesPath.c_str(), DCF_Filetype_PEM /*opt_keyFileFormat*/))) + if (requireRemoteCertificate && IsFailure(tls->addTrustedCertificateFile(trustedCertificatesPath.c_str(), DCF_Filetype_PEM /*opt_keyFileFormat*/))) { throw OrthancException(ErrorCode_BadFileFormat, "Cannot parse PEM file with trusted certificates for DICOM TLS: " + trustedCertificatesPath); @@ -132,7 +170,18 @@ ownPrivateKeyPath); } - if (IsFailure(tls->setCertificateFile(ownCertificatePath.c_str(), DCF_Filetype_PEM /*opt_keyFileFormat*/))) + if (IsFailure(tls->setCertificateFile( + ownCertificatePath.c_str(), DCF_Filetype_PEM /*opt_keyFileFormat*/ +#if DCMTK_VERSION_NUMBER >= 368 + /** + * DICOM BCP 195 RFC 8996 TLS Profile, based on RFC 8996 and RFC 9325. + * This profile only negotiates TLS 1.2 or newer, and will not fall back to + * previous TLS versions. It provides the higher security level offered by the + * 2021 revised edition of BCP 195. + **/ + , TSP_Profile_BCP_195_RFC_8996 +#endif + ))) { throw OrthancException(ErrorCode_BadFileFormat, "Cannot parse PEM file with own certificate for DICOM TLS: " + ownCertificatePath); @@ -145,14 +194,94 @@ } #if DCMTK_VERSION_NUMBER >= 364 - if (IsFailure(tls->setTLSProfile(TSP_Profile_BCP195 /*opt_tlsProfile*/))) + if (minimalTlsVersion == 0) // use the default values (same behavior as before 1.12.4) { - throw OrthancException(ErrorCode_InternalError, "Cannot set the DICOM TLS profile"); + if (ciphers.size() > 0) + { + throw OrthancException(ErrorCode_BadFileFormat, "The cipher suites can not be specified when using the default BCP profile"); + } + + if (IsFailure(tls->setTLSProfile(TSP_Profile_BCP195 /*opt_tlsProfile*/))) + { + throw OrthancException(ErrorCode_InternalError, "Cannot set the DICOM TLS profile"); + } + + if (IsFailure(tls->activateCipherSuites())) + { + throw OrthancException(ErrorCode_InternalError, "Cannot activate the cipher suites for DICOM TLS"); + } } - - if (IsFailure(tls->activateCipherSuites())) + else { - throw OrthancException(ErrorCode_InternalError, "Cannot activate the cipher suites for DICOM TLS"); + // Fine tune the SSL context + if (IsFailure(tls->setTLSProfile(TSP_Profile_None))) + { + throw OrthancException(ErrorCode_InternalError, "Cannot set the DICOM TLS profile"); + } + + DcmTLSTransportLayer::native_handle_type sslNativeHandle = tls->getNativeHandle(); + SSL_CTX_clear_options(sslNativeHandle, SSL_OP_NO_SSL_MASK); + if (minimalTlsVersion > 1) + { + SSL_CTX_set_options(sslNativeHandle, SSL_OP_NO_SSLv3); + } + if (minimalTlsVersion > 2) + { + SSL_CTX_set_options(sslNativeHandle, SSL_OP_NO_TLSv1); + } + if (minimalTlsVersion > 3) + { + SSL_CTX_set_options(sslNativeHandle, SSL_OP_NO_TLSv1_1); + } + if (minimalTlsVersion > 4) + { + SSL_CTX_set_options(sslNativeHandle, SSL_OP_NO_TLSv1_2); + } + + std::set ciphersTls; + std::set ciphersTls13; + + // DCMTK 3.8 is missing a method to add TLS13 cipher suite in the DcmTLSTransportLayer interface. + // And, anyway, since we do not run dcmtkPrepare.cmake, DCMTK is not aware of TLS v1.3 cipher suite names. + for (std::set::const_iterator it = ciphers.begin(); it != ciphers.end(); ++it) + { + bool isValid = false; + if (DcmTLSCiphersuiteHandler::lookupCiphersuiteByOpenSSLName(it->c_str()) != DcmTLSCiphersuiteHandler::unknownCipherSuiteIndex) + { + ciphersTls.insert(it->c_str()); + isValid = true; + } + + // list of TLS v1.3 ciphers according to https://www.openssl.org/docs/man3.3/man1/openssl-ciphers.html + if (strstr("TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256", it->c_str()) != NULL) + { + ciphersTls13.insert(it->c_str()); + isValid = true; + } + + if (!isValid) + { + throw OrthancException(ErrorCode_BadFileFormat, "The cipher suite " + *it + " is not recognized as valid cipher suite by OpenSSL "); + } + } + + std::string joinedCiphersTls; + std::string joinedCiphersTls13; + Toolbox::JoinStrings(joinedCiphersTls, ciphersTls, ":"); + Toolbox::JoinStrings(joinedCiphersTls13, ciphersTls13, ":"); + + if (joinedCiphersTls.size() > 0 && SSL_CTX_set_cipher_list(sslNativeHandle, joinedCiphersTls.c_str()) != 1) + { + OFCondition cond = MyConvertOpenSSLError(ERR_get_error(), OFTrue); + throw OrthancException(ErrorCode_InternalError, "Unable to configure cipher suite. OpenSSL error: " + boost::lexical_cast(cond.code()) + " - " + cond.text()); + } + + if (joinedCiphersTls13.size() > 0 && SSL_CTX_set_ciphersuites(sslNativeHandle, joinedCiphersTls13.c_str()) != 1) + { + OFCondition cond = MyConvertOpenSSLError(ERR_get_error(), OFTrue); + throw OrthancException(ErrorCode_InternalError, "Unable to configure cipher suite for TLS 1.3. OpenSSL error: " + boost::lexical_cast(cond.code()) + " - " + cond.text()); + } + } #else CLOG(INFO, DICOM) << "Using the following cipher suites for DICOM TLS: " << opt_ciphersuites; @@ -169,8 +298,8 @@ } else { - // Check remote certificate if present, succeed if no certificate is present - tls->setCertificateVerification(DCV_checkCertificate /*opt_certVerification*/); + // From 1.12.4, do not even request remote certificate (prior to 1.12.4, we were requesting a certificates, checking it if present and succeeding if not present) + tls->setCertificateVerification(DCV_ignoreCertificate /*opt_certVerification*/); } if (ASC_setTransportLayer(network, tls.get(), 0).bad()) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.h --- a/OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -38,7 +39,7 @@ #include #include - +#include namespace Orthanc { @@ -50,6 +51,9 @@ const std::string& ownPrivateKeyPath, // This is the first argument of "+tls" option from DCMTK command-line tools const std::string& ownCertificatePath, // This is the second argument of "+tls" option const std::string& trustedCertificatesPath, // This is the "--add-cert-file" ("+cf") option - bool requireRemoteCertificate); // "true" means "--require-peer-cert", "false" means "--verify-peer-cert" + bool requireRemoteCertificate, // "true" means "--require-peer-cert", "false" means "--ignore-peer-cert" + unsigned int minimalTlsVersion, // 0 = default BCP195, 5 = TLS1.3 only + const std::set& acceptedCiphers + ); } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/Internals/FindScp.cpp --- a/OrthancFramework/Sources/DicomNetworking/Internals/FindScp.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/FindScp.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -174,11 +175,15 @@ // http://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_C.4.html#sect_C.4.1.1.3 // https://groups.google.com/d/msg/orthanc-users/D3kpPuX8yV0/_zgHOzkMEQAJ + // GroupLength are removed as well since they make no sense in the filtering as well as in the response. + // Note that it seems that only some GE devices include them. + DicomArray a(source); for (size_t i = 0; i < a.GetSize(); i++) { - if (a.GetElement(i).GetTag().GetGroup() >= 0x0008) + if (a.GetElement(i).GetTag().GetGroup() >= 0x0008 + && a.GetElement(i).GetTag().GetElement() != 0x0000) { target.SetValue(a.GetElement(i).GetTag(), a.GetElement(i).GetValue()); } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/Internals/FindScp.h --- a/OrthancFramework/Sources/DicomNetworking/Internals/FindScp.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/FindScp.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/Internals/GetScp.cpp --- a/OrthancFramework/Sources/DicomNetworking/Internals/GetScp.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/GetScp.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/Internals/GetScp.h --- a/OrthancFramework/Sources/DicomNetworking/Internals/GetScp.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/GetScp.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/Internals/MoveScp.cpp --- a/OrthancFramework/Sources/DicomNetworking/Internals/MoveScp.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/MoveScp.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -86,7 +87,7 @@ /** * Macro specifying whether to apply the patch suggested in issue 66: * "Orthanc responses C-MOVE with zero Move Originator Message ID" - * https://bugs.orthanc-server.com/show_bug.cgi?id=66 + * https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=66 **/ #define APPLY_FIX_ISSUE_66 1 diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/Internals/MoveScp.h --- a/OrthancFramework/Sources/DicomNetworking/Internals/MoveScp.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/MoveScp.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.cpp --- a/OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.h --- a/OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/StoreScp.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/NetworkingCompatibility.h --- a/OrthancFramework/Sources/DicomNetworking/NetworkingCompatibility.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/NetworkingCompatibility.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -32,7 +33,6 @@ * http://msdn.microsoft.com/en-us/library/windows/desktop/ms738527(v=vs.85).aspx **/ # define HOST_NAME_MAX 256 -# include #endif diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.cpp --- a/OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -186,7 +187,6 @@ manufacturer_ = StringToModalityManufacturer(manufacturer); } - void RemoteModalityParameters::UnserializeArray(const Json::Value& serialized) { assert(serialized.type() == Json::arrayValue); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.h --- a/OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/TimeoutDicomConnectionManager.cpp --- a/OrthancFramework/Sources/DicomNetworking/TimeoutDicomConnectionManager.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/TimeoutDicomConnectionManager.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomNetworking/TimeoutDicomConnectionManager.h --- a/OrthancFramework/Sources/DicomNetworking/TimeoutDicomConnectionManager.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/TimeoutDicomConnectionManager.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.cpp --- a/OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -37,6 +38,7 @@ #include "FromDcmtkBridge.h" #include "../Logging.h" #include "../OrthancException.h" +#include "../Toolbox.h" #include #include // for DJ_RPLossy @@ -83,12 +85,33 @@ return lossyQuality_; } + bool TryTranscode(std::vector& failureReasons, /* out */ + DicomTransferSyntax& selectedSyntax, /* out*/ + DcmFileFormat& dicom, /* in/out */ + const std::set& allowedSyntaxes, + DicomTransferSyntax trySyntax) + { + if (allowedSyntaxes.find(trySyntax) != allowedSyntaxes.end()) + { + if (FromDcmtkBridge::Transcode(dicom, trySyntax, NULL)) + { + selectedSyntax = trySyntax; + return true; + } + + failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(trySyntax)); + } + return false; + } bool DcmtkTranscoder::InplaceTranscode(DicomTransferSyntax& selectedSyntax /* out */, - DcmFileFormat& dicom, + std::string& failureReason /* out */, + DcmFileFormat& dicom, /* in/out */ const std::set& allowedSyntaxes, bool allowNewSopInstanceUid) { + std::vector failureReasons; + if (dicom.getDataset() == NULL) { throw OrthancException(ErrorCode_InternalError); @@ -109,62 +132,75 @@ // No transcoding is needed return true; } - - if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianImplicit) != allowedSyntaxes.end() && - FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianImplicit, NULL)) + + if (TryTranscode(failureReasons, selectedSyntax, dicom, allowedSyntaxes, DicomTransferSyntax_LittleEndianImplicit)) + { + return true; + } + + if (TryTranscode(failureReasons, selectedSyntax, dicom, allowedSyntaxes, DicomTransferSyntax_LittleEndianExplicit)) { - selectedSyntax = DicomTransferSyntax_LittleEndianImplicit; + return true; + } + + if (TryTranscode(failureReasons, selectedSyntax, dicom, allowedSyntaxes, DicomTransferSyntax_BigEndianExplicit)) + { + return true; + } + + if (TryTranscode(failureReasons, selectedSyntax, dicom, allowedSyntaxes, DicomTransferSyntax_DeflatedLittleEndianExplicit)) + { return true; } - if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianExplicit) != allowedSyntaxes.end() && - FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianExplicit, NULL)) - { - selectedSyntax = DicomTransferSyntax_LittleEndianExplicit; - return true; - } - - if (allowedSyntaxes.find(DicomTransferSyntax_BigEndianExplicit) != allowedSyntaxes.end() && - FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_BigEndianExplicit, NULL)) - { - selectedSyntax = DicomTransferSyntax_BigEndianExplicit; - return true; - } - - if (allowedSyntaxes.find(DicomTransferSyntax_DeflatedLittleEndianExplicit) != allowedSyntaxes.end() && - FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL)) - { - selectedSyntax = DicomTransferSyntax_DeflatedLittleEndianExplicit; - return true; - } #if ORTHANC_ENABLE_DCMTK_JPEG == 1 - if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess1) != allowedSyntaxes.end() && - allowNewSopInstanceUid && - (!hasBitsStored || bitsStored == 8)) + if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess1) != allowedSyntaxes.end()) { - // Check out "dcmjpeg/apps/dcmcjpeg.cc" - DJ_RPLossy parameters(lossyQuality_); - - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess1, ¶meters)) + if (!allowNewSopInstanceUid) + { + failureReasons.push_back(std::string("Can not transcode to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess1) + " without generating new SOPInstanceUID"); + } + else if (hasBitsStored && bitsStored != 8) + { + failureReasons.push_back(std::string("Can not transcode to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess1) + " if BitsStored != 8"); + } + else { - selectedSyntax = DicomTransferSyntax_JPEGProcess1; - return true; + // Check out "dcmjpeg/apps/dcmcjpeg.cc" + DJ_RPLossy parameters(lossyQuality_); + + if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess1, ¶meters)) + { + selectedSyntax = DicomTransferSyntax_JPEGProcess1; + return true; + } + failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess1)); } } #endif #if ORTHANC_ENABLE_DCMTK_JPEG == 1 - if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess2_4) != allowedSyntaxes.end() && - allowNewSopInstanceUid && - (!hasBitsStored || bitsStored <= 12)) + if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess2_4) != allowedSyntaxes.end()) { - // Check out "dcmjpeg/apps/dcmcjpeg.cc" - DJ_RPLossy parameters(lossyQuality_); - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess2_4, ¶meters)) + if (!allowNewSopInstanceUid) + { + failureReasons.push_back(std::string("Can not transcode to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess2_4) + " without generating new SOPInstanceUID"); + } + else if (hasBitsStored && bitsStored > 12) { - selectedSyntax = DicomTransferSyntax_JPEGProcess2_4; - return true; + failureReasons.push_back(std::string("Can not transcode to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess2_4) + " if BitsStored != 8"); + } + else + { + // Check out "dcmjpeg/apps/dcmcjpeg.cc" + DJ_RPLossy parameters(lossyQuality_); + if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess2_4, ¶meters)) + { + selectedSyntax = DicomTransferSyntax_JPEGProcess2_4; + return true; + } + failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess2_4)); } } #endif @@ -180,6 +216,7 @@ selectedSyntax = DicomTransferSyntax_JPEGProcess14; return true; } + failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess14)); } #endif @@ -194,6 +231,7 @@ selectedSyntax = DicomTransferSyntax_JPEGProcess14SV1; return true; } + failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGProcess14SV1)); } #endif @@ -213,6 +251,7 @@ selectedSyntax = DicomTransferSyntax_JPEGLSLossless; return true; } + failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGLSLossless)); } #endif @@ -233,9 +272,11 @@ selectedSyntax = DicomTransferSyntax_JPEGLSLossy; return true; } + failureReasons.push_back(std::string("Internal error while transcoding to ") + GetTransferSyntaxUid(DicomTransferSyntax_JPEGLSLossy)); } #endif + Orthanc::Toolbox::JoinStrings(failureReason, failureReasons, ", "); return false; } @@ -285,28 +326,27 @@ return false; } + std::string failureReason; + std::string s; + for (std::set::const_iterator + it = allowedSyntaxes.begin(); it != allowedSyntaxes.end(); ++it) { - std::string s; - for (std::set::const_iterator - it = allowedSyntaxes.begin(); it != allowedSyntaxes.end(); ++it) + if (!s.empty()) { - if (!s.empty()) - { - s += ", "; - } - - s += GetTransferSyntaxUid(*it); + s += ", "; } - if (s.empty()) - { - s = ""; - } - - LOG(INFO) << "DCMTK transcoding from " << GetTransferSyntaxUid(sourceSyntax) - << " to one of: " << s; + s += GetTransferSyntaxUid(*it); } + if (s.empty()) + { + s = ""; + } + + LOG(INFO) << "DCMTK transcoding from " << GetTransferSyntaxUid(sourceSyntax) + << " to one of: " << s; + #if !defined(NDEBUG) const std::string sourceSopInstanceUid = GetSopInstanceUid(source.GetParsed()); #endif @@ -319,7 +359,7 @@ target.AcquireBuffer(source); return true; } - else if (InplaceTranscode(targetSyntax, source.GetParsed(), + else if (InplaceTranscode(targetSyntax, failureReason, source.GetParsed(), allowedSyntaxes, allowNewSopInstanceUid)) { // Sanity check @@ -347,6 +387,8 @@ else { // Cannot transcode + LOG(WARNING) << "DCMTK was unable to transcode from " << GetTransferSyntaxUid(sourceSyntax) + << " to one of: " << s << " " << failureReason; return false; } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.h --- a/OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DcmtkTranscoder.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -41,6 +42,7 @@ unsigned int lossyQuality_; bool InplaceTranscode(DicomTransferSyntax& selectedSyntax /* out */, + std::string& failureReason /* out */, DcmFileFormat& dicom, const std::set& allowedSyntaxes, bool allowNewSopInstanceUid); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/DicomDirWriter.cpp --- a/OrthancFramework/Sources/DicomParsing/DicomDirWriter.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomDirWriter.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/DicomDirWriter.h --- a/OrthancFramework/Sources/DicomParsing/DicomDirWriter.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomDirWriter.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/DicomModification.cpp --- a/OrthancFramework/Sources/DicomParsing/DicomModification.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -43,6 +44,9 @@ static const std::string ORTHANC_DEIDENTIFICATION_METHOD_2021b = "Orthanc " ORTHANC_VERSION " - PS 3.15-2021b Table E.1-1 Basic Profile"; +static const std::string ORTHANC_DEIDENTIFICATION_METHOD_2023b = + "Orthanc " ORTHANC_VERSION " - PS 3.15-2023b Table E.1-1 Basic Profile"; + namespace Orthanc { namespace @@ -314,7 +318,7 @@ * data sets including: * https://wiki.cancerimagingarchive.net/display/Public/Lung+CT+Segmentation+Challenge+2017) * Tested in "test_anonymize_relationships_5". Introduced - * in: https://hg.orthanc-server.com/orthanc/rev/3513 + * in: https://orthanc.uclouvain.be/hg/orthanc/rev/3513 **/ newValue = that_.MapDicomIdentifier(value, ResourceType_Study); } @@ -427,7 +431,8 @@ if (it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2008 || it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2017c || - it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2021b) + it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2021b || + it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2023b) { delete it->second; replacements_.erase(it); @@ -521,6 +526,7 @@ DicomModification::DicomModification() : removePrivateTags_(false), + keepLabels_(false), level_(ResourceType_Instance), allowManualIdentifiers_(true), keepStudyInstanceUid_(false), @@ -540,6 +546,7 @@ void DicomModification::Keep(const DicomTag& tag) { + keep_.insert(tag); removals_.erase(tag); clearings_.erase(tag); uids_.erase(tag); @@ -636,6 +643,11 @@ return replacements_.find(tag) != replacements_.end(); } + bool DicomModification::IsKept(const DicomTag& tag) const + { + return keep_.find(tag) != keep_.end(); + } + const Json::Value& DicomModification::GetReplacement(const DicomTag& tag) const { Replacements::const_iterator it = replacements_.find(tag); @@ -682,6 +694,16 @@ return removePrivateTags_; } + void DicomModification::SetKeepLabels(bool keep) + { + keepLabels_ = keep; + } + + bool DicomModification::AreLabelsKept() const + { + return keepLabels_; + } + void DicomModification::SetLevel(ResourceType level) { uidMap_.clear(); @@ -714,7 +736,7 @@ * Values below come from the hardcoded UID of Orthanc 1.9.3 * in DicomModification::RelationshipsVisitor::VisitString() and * DicomModification::RelationshipsVisitor::RemoveRelationships() - * https://hg.orthanc-server.com/orthanc/file/Orthanc-1.9.3/OrthancFramework/Sources/DicomParsing/DicomModification.cpp#l117 + * https://orthanc.uclouvain.be/hg/orthanc/file/Orthanc-1.9.3/OrthancFramework/Sources/DicomParsing/DicomModification.cpp#l117 **/ uids_.clear(); @@ -825,9 +847,6 @@ * generated automatically by calling: * "../../../OrthancServer/Resources/GenerateAnonymizationProfile.py * https://raw.githubusercontent.com/jodogne/dicom-specification/master/2021b/part15.xml" - * - * http://dicom.nema.org/medical/dicom/2021b/output/chtml/part15/chapter_E.html#table_E.1-1a - * http://dicom.nema.org/medical/dicom/2021b/output/chtml/part15/chapter_E.html#table_E.1-1 **/ #include "DicomModification_Anonymization2021b.impl.h" @@ -837,10 +856,31 @@ } + void DicomModification::SetupAnonymization2023b() + { + /** + * This is Table E.1-1 from PS 3.15-2023b (DICOM Part 15: Security + * and System Management Profiles), "basic profile" column. It was + * generated automatically by calling: + * "../../../OrthancServer/Resources/GenerateAnonymizationProfile.py + * https://raw.githubusercontent.com/jodogne/dicom-specification/master/2023b/part15.xml" + * + * http://dicom.nema.org/medical/dicom/current/output/chtml/part15/chapter_E.html#table_E.1-1a + * http://dicom.nema.org/medical/dicom/current/output/chtml/part15/chapter_E.html#table_E.1-1 + **/ + +#include "DicomModification_Anonymization2023b.impl.h" + + // Set the DeidentificationMethod tag + ReplaceInternal(DICOM_TAG_DEIDENTIFICATION_METHOD, ORTHANC_DEIDENTIFICATION_METHOD_2023b); + } + + void DicomModification::SetupAnonymization(DicomVersion version) { isAnonymization_ = true; + keep_.clear(); removals_.clear(); clearings_.clear(); removedRanges_.clear(); @@ -867,6 +907,10 @@ SetupAnonymization2021b(); break; + case DicomVersion_2023b: + SetupAnonymization2023b(); + break; + default: throw OrthancException(ErrorCode_ParameterOutOfRange); } @@ -918,22 +962,12 @@ IsRemoved(DICOM_TAG_SERIES_INSTANCE_UID) || IsRemoved(DICOM_TAG_SOP_INSTANCE_UID)) { - throw OrthancException(ErrorCode_BadRequest); + throw OrthancException(ErrorCode_BadRequest, "It is forbidden to remove one of the main Dicom identifiers"); } - - // Sanity checks at the patient level - bool isReplacedPatientId = (IsReplaced(DICOM_TAG_PATIENT_ID) || - uids_.find(DICOM_TAG_PATIENT_ID) != uids_.end()); - - if (level_ == ResourceType_Patient && !isReplacedPatientId) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a patient, her PatientID is required to be modified"); - } - if (!allowManualIdentifiers_) { + // Sanity checks at the patient level if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) { throw OrthancException(ErrorCode_BadRequest, @@ -951,18 +985,8 @@ throw OrthancException(ErrorCode_BadRequest, "When modifying a patient, the SopInstanceUID cannot be manually modified"); } - } - - // Sanity checks at the study level - if (level_ == ResourceType_Study && isReplacedPatientId) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a study, the parent PatientID cannot be manually modified"); - } - - if (!allowManualIdentifiers_) - { + // Sanity checks at the study level if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) { throw OrthancException(ErrorCode_BadRequest, @@ -974,24 +998,8 @@ throw OrthancException(ErrorCode_BadRequest, "When modifying a study, the SopInstanceUID cannot be manually modified"); } - } - - // Sanity checks at the series level - if (level_ == ResourceType_Series && isReplacedPatientId) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a series, the parent PatientID cannot be manually modified"); - } - - if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a series, the parent StudyInstanceUID cannot be manually modified"); - } - - if (!allowManualIdentifiers_) - { + // Sanity checks at the series level if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) { throw OrthancException(ErrorCode_BadRequest, @@ -1000,25 +1008,6 @@ } - // Sanity checks at the instance level - if (level_ == ResourceType_Instance && isReplacedPatientId) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying an instance, the parent PatientID cannot be manually modified"); - } - - if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying an instance, the parent StudyInstanceUID cannot be manually modified"); - } - - if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying an instance, the parent SeriesInstanceUID cannot be manually modified"); - } - // (0) Create a summary of the source file, if a custom generator // is provided if (identifierGenerator_ != NULL) @@ -1296,6 +1285,11 @@ SetRemovePrivateTags(true); } + if (GetBooleanValue("KeepLabels", request, false)) + { + SetKeepLabels(true); + } + if (request.isMember("Remove")) { ParseListOfTags(*this, request["Remove"], TagOperation_Remove, force); @@ -1321,6 +1315,62 @@ { privateCreator_ = SerializationToolbox::ReadString(request, "PrivateCreator"); } + + if (!force) + { + /** + * Sanity checks about the manual replacement of DICOM + * identifiers. Those checks were part of + * "DicomModification::Apply()" in Orthanc <= 1.11.2, and + * couldn't be disabled even if using the "Force" flag. Check + * out: + * https://groups.google.com/g/orthanc-users/c/xMUUZAnBa5g/m/WCEu-U2NBQAJ + **/ + bool isReplacedPatientId = (IsReplaced(DICOM_TAG_PATIENT_ID) || + uids_.find(DICOM_TAG_PATIENT_ID) != uids_.end()); + + if (level_ == ResourceType_Patient && !isReplacedPatientId) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying a patient, her PatientID is required to be modified."); + } + + if (level_ == ResourceType_Study && isReplacedPatientId) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying a study, the parent PatientID cannot be manually modified"); + } + + if (level_ == ResourceType_Series && isReplacedPatientId) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying a series, the parent PatientID cannot be manually modified"); + } + + if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying a series, the parent StudyInstanceUID cannot be manually modified"); + } + + if (level_ == ResourceType_Instance && isReplacedPatientId) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying an instance, the parent PatientID cannot be manually modified"); + } + + if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying an instance, the parent StudyInstanceUID cannot be manually modified"); + } + + if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying an instance, the parent SeriesInstanceUID cannot be manually modified"); + } + } } @@ -1336,7 +1386,9 @@ // DicomVersion version = DicomVersion_2008; // For Orthanc <= 1.2.0 // DicomVersion version = DicomVersion_2017c; // For Orthanc between 1.3.0 and 1.9.3 - DicomVersion version = DicomVersion_2021b; // For Orthanc >= 1.9.4 + // DicomVersion version = DicomVersion_2021b; // For Orthanc >= 1.9.4 + DicomVersion version = DicomVersion_2023b; // For Orthanc >= 1.12.1 + if (request.isMember("DicomVersion")) { if (request["DicomVersion"].type() != Json::stringValue) @@ -1356,6 +1408,11 @@ SetRemovePrivateTags(false); } + if (GetBooleanValue("KeepLabels", request, false)) + { + SetKeepLabels(true); + } + if (request.isMember("Remove")) { ParseListOfTags(*this, request["Remove"], TagOperation_Remove, force); @@ -1585,7 +1642,7 @@ * 1.5.0 and 1.6.1. This compatibility was broken between 1.7.0 * and 1.9.3: Indeed, an exception was thrown in "ReadBoolean()" * if "KEEP_SOP_INSTANCE_UID" was absent, because of changeset: - * https://hg.orthanc-server.com/orthanc/rev/3860 + * https://orthanc.uclouvain.be/hg/orthanc/rev/3860 **/ keepSopInstanceUid_ = false; } @@ -1830,4 +1887,13 @@ (tag == DICOM_TAG_SOP_INSTANCE_UID && !keepSopInstanceUid_)); } + + void DicomModification::GetReplacedTags(std::set& target) const + { + target.clear(); + for (Replacements::const_iterator it = replacements_.begin(); it != replacements_.end(); ++it) + { + target.insert(it->first); + } + } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/DicomModification.h --- a/OrthancFramework/Sources/DicomParsing/DicomModification.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -128,8 +129,10 @@ SetOfTags removals_; SetOfTags clearings_; + SetOfTags keep_; Replacements replacements_; bool removePrivateTags_; + bool keepLabels_; ResourceType level_; UidMap uidMap_; SetOfTags privateTagsToKeep_; @@ -178,6 +181,8 @@ void SetupAnonymization2021b(); + void SetupAnonymization2023b(); + void UnserializeUidMap(ResourceType level, const Json::Value& serialized, const char* field); @@ -208,14 +213,22 @@ bool IsReplaced(const DicomTag& tag) const; + void GetReplacedTags(std::set& target) const; + const Json::Value& GetReplacement(const DicomTag& tag) const; std::string GetReplacementAsString(const DicomTag& tag) const; + bool IsKept(const DicomTag& tag) const; + void SetRemovePrivateTags(bool removed); bool ArePrivateTagsRemoved() const; + void SetKeepLabels(bool keep); + + bool AreLabelsKept() const; + void SetLevel(ResourceType level); ResourceType GetLevel() const; diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/DicomModification_Anonymization2023b.impl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification_Anonymization2023b.impl.h Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,610 @@ +// RelationshipsVisitor handles (0x0008, 0x1140) /* X/Z/U* */ // Referenced Image Sequence +// RelationshipsVisitor handles (0x0008, 0x2112) /* X/Z/U* */ // Source Image Sequence +// Tag (0x0008, 0x0018) is set in Apply() /* U */ // SOP Instance UID +// Tag (0x0010, 0x0010) is set below (*) /* Z */ // Patient's Name +// Tag (0x0010, 0x0020) is set below (*) /* Z */ // Patient ID +// Tag (0x0020, 0x000d) is set in Apply() /* U */ // Study Instance UID +// Tag (0x0020, 0x000e) is set in Apply() /* U */ // Series Instance UID +clearings_.insert(DicomTag(0x0008, 0x0020)); // Study Date +clearings_.insert(DicomTag(0x0008, 0x0023)); /* Z/D */ // Content Date +clearings_.insert(DicomTag(0x0008, 0x0030)); // Study Time +clearings_.insert(DicomTag(0x0008, 0x0033)); /* Z/D */ // Content Time +clearings_.insert(DicomTag(0x0008, 0x0050)); // Accession Number +clearings_.insert(DicomTag(0x0008, 0x0090)); // Referring Physician's Name +clearings_.insert(DicomTag(0x0008, 0x009c)); // Consulting Physician's Name +clearings_.insert(DicomTag(0x0008, 0x0106)); /* D */ // Context Group Version +clearings_.insert(DicomTag(0x0008, 0x0107)); /* D */ // Context Group Local Version +clearings_.insert(DicomTag(0x0010, 0x0030)); // Patient's Birth Date +clearings_.insert(DicomTag(0x0010, 0x0040)); // Patient's Sex +clearings_.insert(DicomTag(0x0012, 0x0010)); /* D */ // Clinical Trial Sponsor Name +clearings_.insert(DicomTag(0x0012, 0x0020)); /* D */ // Clinical Trial Protocol ID +clearings_.insert(DicomTag(0x0012, 0x0021)); // Clinical Trial Protocol Name +clearings_.insert(DicomTag(0x0012, 0x0030)); // Clinical Trial Site ID +clearings_.insert(DicomTag(0x0012, 0x0031)); // Clinical Trial Site Name +clearings_.insert(DicomTag(0x0012, 0x0040)); /* D */ // Clinical Trial Subject ID +clearings_.insert(DicomTag(0x0012, 0x0042)); /* D */ // Clinical Trial Subject Reading ID +clearings_.insert(DicomTag(0x0012, 0x0050)); // Clinical Trial Time Point ID +clearings_.insert(DicomTag(0x0012, 0x0060)); // Clinical Trial Coordinating Center Name +clearings_.insert(DicomTag(0x0012, 0x0081)); /* D */ // Clinical Trial Protocol Ethics Committee Name +clearings_.insert(DicomTag(0x0018, 0x0010)); /* Z/D */ // Contrast/Bolus Agent +clearings_.insert(DicomTag(0x0018, 0x11bb)); /* D */ // Acquisition Field Of View Label +clearings_.insert(DicomTag(0x0018, 0x1203)); // Calibration DateTime +clearings_.insert(DicomTag(0x0018, 0x9074)); /* D */ // Frame Acquisition DateTime +clearings_.insert(DicomTag(0x0018, 0x9151)); /* D */ // Frame Reference DateTime +clearings_.insert(DicomTag(0x0018, 0x9367)); /* D */ // X-Ray Source ID +clearings_.insert(DicomTag(0x0018, 0x9369)); /* D */ // Source Start DateTime +clearings_.insert(DicomTag(0x0018, 0x936a)); /* D */ // Source End DateTime +clearings_.insert(DicomTag(0x0018, 0x9371)); /* D */ // X-Ray Detector ID +clearings_.insert(DicomTag(0x0018, 0x9623)); /* D */ // Functional Sync Pulse +clearings_.insert(DicomTag(0x0018, 0x9701)); /* D */ // Decay Correction DateTime +clearings_.insert(DicomTag(0x0018, 0x9804)); /* D */ // Exclusion Start DateTime +clearings_.insert(DicomTag(0x0018, 0x9919)); /* Z/D */ // Instruction Performed DateTime +clearings_.insert(DicomTag(0x0020, 0x0010)); // Study ID +clearings_.insert(DicomTag(0x0034, 0x0001)); /* D */ // Flow Identifier Sequence +clearings_.insert(DicomTag(0x0034, 0x0002)); /* D */ // Flow Identifier +clearings_.insert(DicomTag(0x0034, 0x0005)); /* D */ // Source Identifier +clearings_.insert(DicomTag(0x0034, 0x0007)); /* D */ // Frame Origin Timestamp +clearings_.insert(DicomTag(0x003a, 0x0314)); /* D */ // Impedance Measurement DateTime +clearings_.insert(DicomTag(0x0040, 0x0512)); /* D */ // Container Identifier +clearings_.insert(DicomTag(0x0040, 0x0513)); // Issuer of the Container Identifier Sequence +clearings_.insert(DicomTag(0x0040, 0x0551)); /* D */ // Specimen Identifier +clearings_.insert(DicomTag(0x0040, 0x0562)); // Issuer of the Specimen Identifier Sequence +clearings_.insert(DicomTag(0x0040, 0x0610)); // Specimen Preparation Sequence +clearings_.insert(DicomTag(0x0040, 0x1101)); /* D */ // Person Identification Code Sequence +clearings_.insert(DicomTag(0x0040, 0x2016)); // Placer Order Number / Imaging Service Request +clearings_.insert(DicomTag(0x0040, 0x2017)); // Filler Order Number / Imaging Service Request +clearings_.insert(DicomTag(0x0040, 0xa027)); /* D */ // Verifying Organization +clearings_.insert(DicomTag(0x0040, 0xa030)); /* D */ // Verification DateTime +clearings_.insert(DicomTag(0x0040, 0xa073)); /* D */ // Verifying Observer Sequence +clearings_.insert(DicomTag(0x0040, 0xa075)); /* D */ // Verifying Observer Name +clearings_.insert(DicomTag(0x0040, 0xa082)); // Participation DateTime +clearings_.insert(DicomTag(0x0040, 0xa088)); // Verifying Observer Identification Code Sequence +clearings_.insert(DicomTag(0x0040, 0xa120)); /* D */ // DateTime +clearings_.insert(DicomTag(0x0040, 0xa121)); /* D */ // Date +clearings_.insert(DicomTag(0x0040, 0xa122)); /* D */ // Time +clearings_.insert(DicomTag(0x0040, 0xa123)); /* D */ // Person Name +clearings_.insert(DicomTag(0x0040, 0xa13a)); /* D */ // Referenced DateTime +clearings_.insert(DicomTag(0x0040, 0xa730)); /* D */ // Content Sequence +clearings_.insert(DicomTag(0x0042, 0x0011)); /* D */ // Encapsulated Document +clearings_.insert(DicomTag(0x0044, 0x0104)); /* D */ // Assertion DateTime +clearings_.insert(DicomTag(0x0068, 0x6226)); /* D */ // Effective DateTime +clearings_.insert(DicomTag(0x0068, 0x6270)); /* D */ // Information Issue DateTime +clearings_.insert(DicomTag(0x006a, 0x0003)); /* D */ // Annotation Group UID +clearings_.insert(DicomTag(0x006a, 0x0005)); /* D */ // Annotation Group Label +clearings_.insert(DicomTag(0x0070, 0x0001)); /* D */ // Graphic Annotation Sequence +clearings_.insert(DicomTag(0x0070, 0x0084)); /* Z/D */ // Content Creator's Name +clearings_.insert(DicomTag(0x0072, 0x000a)); /* D */ // Hanging Protocol Creation DateTime +clearings_.insert(DicomTag(0x0072, 0x005e)); /* D */ // Selector AE Value +clearings_.insert(DicomTag(0x0072, 0x005f)); /* D */ // Selector AS Value +clearings_.insert(DicomTag(0x0072, 0x0061)); /* D */ // Selector DA Value +clearings_.insert(DicomTag(0x0072, 0x0063)); /* D */ // Selector DT Value +clearings_.insert(DicomTag(0x0072, 0x0065)); /* D */ // Selector OB Value +clearings_.insert(DicomTag(0x0072, 0x0066)); /* D */ // Selector LO Value +clearings_.insert(DicomTag(0x0072, 0x0068)); /* D */ // Selector LT Value +clearings_.insert(DicomTag(0x0072, 0x006a)); /* D */ // Selector PN Value +clearings_.insert(DicomTag(0x0072, 0x006b)); /* D */ // Selector TM Value +clearings_.insert(DicomTag(0x0072, 0x006c)); /* D */ // Selector SH Value +clearings_.insert(DicomTag(0x0072, 0x006d)); /* D */ // Selector UN Value +clearings_.insert(DicomTag(0x0072, 0x006e)); /* D */ // Selector ST Value +clearings_.insert(DicomTag(0x0072, 0x0070)); /* D */ // Selector UT Value +clearings_.insert(DicomTag(0x0072, 0x0071)); /* D */ // Selector UR Value +clearings_.insert(DicomTag(0x0400, 0x0105)); /* D */ // Digital Signature DateTime +clearings_.insert(DicomTag(0x0400, 0x0115)); /* D */ // Certificate of Signer +clearings_.insert(DicomTag(0x0400, 0x0562)); /* D */ // Attribute Modification DateTime +clearings_.insert(DicomTag(0x0400, 0x0563)); /* D */ // Modifying System +clearings_.insert(DicomTag(0x0400, 0x0564)); // Source of Previous Values +clearings_.insert(DicomTag(0x0400, 0x0565)); /* D */ // Reason for the Attribute Modification +clearings_.insert(DicomTag(0x2100, 0x0140)); /* D */ // Destination AE +clearings_.insert(DicomTag(0x3006, 0x0002)); /* D */ // Structure Set Label +clearings_.insert(DicomTag(0x3006, 0x0008)); // Structure Set Date +clearings_.insert(DicomTag(0x3006, 0x0009)); // Structure Set Time +clearings_.insert(DicomTag(0x3006, 0x0026)); // ROI Name +clearings_.insert(DicomTag(0x3006, 0x00a6)); // ROI Interpreter +clearings_.insert(DicomTag(0x3008, 0x0024)); /* D */ // Treatment Control Point Date +clearings_.insert(DicomTag(0x3008, 0x0025)); /* D */ // Treatment Control Point Time +clearings_.insert(DicomTag(0x3008, 0x0162)); /* D */ // Safe Position Exit Date +clearings_.insert(DicomTag(0x3008, 0x0164)); /* D */ // Safe Position Exit Time +clearings_.insert(DicomTag(0x3008, 0x0166)); /* D */ // Safe Position Return Date +clearings_.insert(DicomTag(0x3008, 0x0168)); /* D */ // Safe Position Return Time +clearings_.insert(DicomTag(0x300a, 0x0002)); /* D */ // RT Plan Label +clearings_.insert(DicomTag(0x300a, 0x022c)); /* D */ // Source Strength Reference Date +clearings_.insert(DicomTag(0x300a, 0x022e)); /* D */ // Source Strength Reference Time +clearings_.insert(DicomTag(0x300a, 0x0608)); /* D */ // Treatment Position Group Label +clearings_.insert(DicomTag(0x300a, 0x0611)); // RT Accessory Holder Slot ID +clearings_.insert(DicomTag(0x300a, 0x0615)); // RT Accessory Device Slot ID +clearings_.insert(DicomTag(0x300a, 0x0619)); /* D */ // Radiation Dose Identification Label +clearings_.insert(DicomTag(0x300a, 0x0623)); /* D */ // Radiation Dose In-Vivo Measurement Label +clearings_.insert(DicomTag(0x300a, 0x062a)); /* D */ // RT Tolerance Set Label +clearings_.insert(DicomTag(0x300a, 0x067c)); /* D */ // Radiation Generation Mode Label +clearings_.insert(DicomTag(0x300a, 0x067d)); // Radiation Generation Mode Description +clearings_.insert(DicomTag(0x300a, 0x0734)); /* D */ // Treatment Tolerance Violation Description +clearings_.insert(DicomTag(0x300a, 0x0736)); /* D */ // Treatment Tolerance Violation DateTime +clearings_.insert(DicomTag(0x300a, 0x073a)); /* D */ // Recorded RT Control Point DateTime +clearings_.insert(DicomTag(0x300a, 0x0741)); /* D */ // Interlock DateTime +clearings_.insert(DicomTag(0x300a, 0x0742)); /* D */ // Interlock Description +clearings_.insert(DicomTag(0x300a, 0x0760)); /* D */ // Override DateTime +clearings_.insert(DicomTag(0x300a, 0x0783)); /* D */ // Interlock Origin Description +clearings_.insert(DicomTag(0x300c, 0x0127)); /* D */ // Beam Hold Transition DateTime +clearings_.insert(DicomTag(0x300e, 0x0004)); // Review Date +clearings_.insert(DicomTag(0x300e, 0x0005)); // Review Time +clearings_.insert(DicomTag(0x3010, 0x000f)); // Conceptual Volume Combination Description +clearings_.insert(DicomTag(0x3010, 0x0017)); // Conceptual Volume Description +clearings_.insert(DicomTag(0x3010, 0x001b)); // Device Alternate Identifier +clearings_.insert(DicomTag(0x3010, 0x002d)); /* D */ // Device Label +clearings_.insert(DicomTag(0x3010, 0x0033)); /* D */ // User Content Label +clearings_.insert(DicomTag(0x3010, 0x0034)); /* D */ // User Content Long Label +clearings_.insert(DicomTag(0x3010, 0x0035)); /* D */ // Entity Label +clearings_.insert(DicomTag(0x3010, 0x0038)); /* D */ // Entity Long Label +clearings_.insert(DicomTag(0x3010, 0x0043)); // Manufacturer's Device Identifier +clearings_.insert(DicomTag(0x3010, 0x0054)); /* D */ // RT Prescription Label +clearings_.insert(DicomTag(0x3010, 0x005a)); // RT Physician Intent Narrative +clearings_.insert(DicomTag(0x3010, 0x005c)); // Reason for Superseding +clearings_.insert(DicomTag(0x3010, 0x007a)); // Treatment Technique Notes +clearings_.insert(DicomTag(0x3010, 0x007b)); // Prescription Notes +clearings_.insert(DicomTag(0x3010, 0x007f)); // Fractionation Notes +clearings_.insert(DicomTag(0x3010, 0x0081)); // Prescription Notes Sequence +removals_.insert(DicomTag(0x0000, 0x1000)); // Affected SOP Instance UID +removals_.insert(DicomTag(0x0008, 0x0012)); /* X/D */ // Instance Creation Date +removals_.insert(DicomTag(0x0008, 0x0013)); /* X/Z/D */ // Instance Creation Time +removals_.insert(DicomTag(0x0008, 0x0015)); // Instance Coercion DateTime +removals_.insert(DicomTag(0x0008, 0x0021)); /* X/D */ // Series Date +removals_.insert(DicomTag(0x0008, 0x0022)); /* X/Z */ // Acquisition Date +removals_.insert(DicomTag(0x0008, 0x0024)); // Overlay Date +removals_.insert(DicomTag(0x0008, 0x0025)); // Curve Date +removals_.insert(DicomTag(0x0008, 0x002a)); /* X/Z/D */ // Acquisition DateTime +removals_.insert(DicomTag(0x0008, 0x0031)); /* X/D */ // Series Time +removals_.insert(DicomTag(0x0008, 0x0032)); /* X/Z */ // Acquisition Time +removals_.insert(DicomTag(0x0008, 0x0034)); // Overlay Time +removals_.insert(DicomTag(0x0008, 0x0035)); // Curve Time +removals_.insert(DicomTag(0x0008, 0x0054)); // Retrieve AE Title +removals_.insert(DicomTag(0x0008, 0x0055)); // Station AE Title +removals_.insert(DicomTag(0x0008, 0x0080)); /* X/Z/D */ // Institution Name +removals_.insert(DicomTag(0x0008, 0x0081)); // Institution Address +removals_.insert(DicomTag(0x0008, 0x0082)); /* X/Z/D */ // Institution Code Sequence +removals_.insert(DicomTag(0x0008, 0x0092)); // Referring Physician's Address +removals_.insert(DicomTag(0x0008, 0x0094)); // Referring Physician's Telephone Numbers +removals_.insert(DicomTag(0x0008, 0x0096)); // Referring Physician Identification Sequence +removals_.insert(DicomTag(0x0008, 0x009d)); // Consulting Physician Identification Sequence +removals_.insert(DicomTag(0x0008, 0x0201)); // Timezone Offset From UTC +removals_.insert(DicomTag(0x0008, 0x1000)); // Network ID +removals_.insert(DicomTag(0x0008, 0x1010)); /* X/Z/D */ // Station Name +removals_.insert(DicomTag(0x0008, 0x1030)); // Study Description +removals_.insert(DicomTag(0x0008, 0x103e)); // Series Description +removals_.insert(DicomTag(0x0008, 0x1040)); // Institutional Department Name +removals_.insert(DicomTag(0x0008, 0x1041)); // Institutional Department Type Code Sequence +removals_.insert(DicomTag(0x0008, 0x1048)); // Physician(s) of Record +removals_.insert(DicomTag(0x0008, 0x1049)); // Physician(s) of Record Identification Sequence +removals_.insert(DicomTag(0x0008, 0x1050)); // Performing Physician's Name +removals_.insert(DicomTag(0x0008, 0x1052)); // Performing Physician Identification Sequence +removals_.insert(DicomTag(0x0008, 0x1060)); // Name of Physician(s) Reading Study +removals_.insert(DicomTag(0x0008, 0x1062)); // Physician(s) Reading Study Identification Sequence +removals_.insert(DicomTag(0x0008, 0x1070)); /* X/Z/D */ // Operators' Name +removals_.insert(DicomTag(0x0008, 0x1072)); /* X/D */ // Operator Identification Sequence +removals_.insert(DicomTag(0x0008, 0x1080)); // Admitting Diagnoses Description +removals_.insert(DicomTag(0x0008, 0x1084)); // Admitting Diagnoses Code Sequence +removals_.insert(DicomTag(0x0008, 0x1088)); // Pyramid Description +removals_.insert(DicomTag(0x0008, 0x1110)); /* X/Z */ // Referenced Study Sequence +removals_.insert(DicomTag(0x0008, 0x1111)); /* X/Z/D */ // Referenced Performed Procedure Step Sequence +removals_.insert(DicomTag(0x0008, 0x1120)); // Referenced Patient Sequence +removals_.insert(DicomTag(0x0008, 0x2111)); // Derivation Description +removals_.insert(DicomTag(0x0008, 0x4000)); // Identifying Comments +removals_.insert(DicomTag(0x0010, 0x0021)); // Issuer of Patient ID +removals_.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time +removals_.insert(DicomTag(0x0010, 0x0050)); // Patient's Insurance Plan Code Sequence +removals_.insert(DicomTag(0x0010, 0x0101)); // Patient's Primary Language Code Sequence +removals_.insert(DicomTag(0x0010, 0x0102)); // Patient's Primary Language Modifier Code Sequence +removals_.insert(DicomTag(0x0010, 0x1000)); // Other Patient IDs +removals_.insert(DicomTag(0x0010, 0x1001)); // Other Patient Names +removals_.insert(DicomTag(0x0010, 0x1002)); // Other Patient IDs Sequence +removals_.insert(DicomTag(0x0010, 0x1005)); // Patient's Birth Name +removals_.insert(DicomTag(0x0010, 0x1010)); // Patient's Age +removals_.insert(DicomTag(0x0010, 0x1020)); // Patient's Size +removals_.insert(DicomTag(0x0010, 0x1030)); // Patient's Weight +removals_.insert(DicomTag(0x0010, 0x1040)); // Patient's Address +removals_.insert(DicomTag(0x0010, 0x1050)); // Insurance Plan Identification +removals_.insert(DicomTag(0x0010, 0x1060)); // Patient's Mother's Birth Name +removals_.insert(DicomTag(0x0010, 0x1080)); // Military Rank +removals_.insert(DicomTag(0x0010, 0x1081)); // Branch of Service +removals_.insert(DicomTag(0x0010, 0x1090)); // Medical Record Locator +removals_.insert(DicomTag(0x0010, 0x1100)); // Referenced Patient Photo Sequence +removals_.insert(DicomTag(0x0010, 0x2000)); // Medical Alerts +removals_.insert(DicomTag(0x0010, 0x2110)); // Allergies +removals_.insert(DicomTag(0x0010, 0x2150)); // Country of Residence +removals_.insert(DicomTag(0x0010, 0x2152)); // Region of Residence +removals_.insert(DicomTag(0x0010, 0x2154)); // Patient's Telephone Numbers +removals_.insert(DicomTag(0x0010, 0x2155)); // Patient's Telecom Information +removals_.insert(DicomTag(0x0010, 0x2160)); // Ethnic Group +removals_.insert(DicomTag(0x0010, 0x2180)); // Occupation +removals_.insert(DicomTag(0x0010, 0x21a0)); // Smoking Status +removals_.insert(DicomTag(0x0010, 0x21b0)); // Additional Patient History +removals_.insert(DicomTag(0x0010, 0x21c0)); // Pregnancy Status +removals_.insert(DicomTag(0x0010, 0x21d0)); // Last Menstrual Date +removals_.insert(DicomTag(0x0010, 0x21f0)); // Patient's Religious Preference +removals_.insert(DicomTag(0x0010, 0x2203)); /* X/Z */ // Patient's Sex Neutered +removals_.insert(DicomTag(0x0010, 0x2297)); // Responsible Person +removals_.insert(DicomTag(0x0010, 0x2299)); // Responsible Organization +removals_.insert(DicomTag(0x0010, 0x4000)); // Patient Comments +removals_.insert(DicomTag(0x0012, 0x0051)); // Clinical Trial Time Point Description +removals_.insert(DicomTag(0x0012, 0x0071)); // Clinical Trial Series ID +removals_.insert(DicomTag(0x0012, 0x0072)); // Clinical Trial Series Description +removals_.insert(DicomTag(0x0012, 0x0082)); // Clinical Trial Protocol Ethics Committee Approval Number +removals_.insert(DicomTag(0x0012, 0x0086)); // Ethics Committee Approval Effectiveness Start Date +removals_.insert(DicomTag(0x0012, 0x0087)); // Ethics Committee Approval Effectiveness End Date +removals_.insert(DicomTag(0x0014, 0x407c)); // Calibration Time +removals_.insert(DicomTag(0x0014, 0x407e)); // Calibration Date +removals_.insert(DicomTag(0x0016, 0x002b)); // Maker Note +removals_.insert(DicomTag(0x0016, 0x004b)); // Device Setting Description +removals_.insert(DicomTag(0x0016, 0x004d)); // Camera Owner Name +removals_.insert(DicomTag(0x0016, 0x004e)); // Lens Specification +removals_.insert(DicomTag(0x0016, 0x004f)); // Lens Make +removals_.insert(DicomTag(0x0016, 0x0050)); // Lens Model +removals_.insert(DicomTag(0x0016, 0x0051)); // Lens Serial Number +removals_.insert(DicomTag(0x0016, 0x0070)); // GPS Version ID +removals_.insert(DicomTag(0x0016, 0x0071)); // GPS Latitude Ref +removals_.insert(DicomTag(0x0016, 0x0072)); // GPS Latitude +removals_.insert(DicomTag(0x0016, 0x0073)); // GPS Longitude Ref +removals_.insert(DicomTag(0x0016, 0x0074)); // GPS Longitude +removals_.insert(DicomTag(0x0016, 0x0075)); // GPS Altitude Ref +removals_.insert(DicomTag(0x0016, 0x0076)); // GPS Altitude +removals_.insert(DicomTag(0x0016, 0x0077)); // GPS Time Stamp +removals_.insert(DicomTag(0x0016, 0x0078)); // GPS Satellites +removals_.insert(DicomTag(0x0016, 0x0079)); // GPS Status +removals_.insert(DicomTag(0x0016, 0x007a)); // GPS Measure Mode +removals_.insert(DicomTag(0x0016, 0x007b)); // GPS DOP +removals_.insert(DicomTag(0x0016, 0x007c)); // GPS Speed Ref +removals_.insert(DicomTag(0x0016, 0x007d)); // GPS Speed +removals_.insert(DicomTag(0x0016, 0x007e)); // GPS Track Ref +removals_.insert(DicomTag(0x0016, 0x007f)); // GPS Track +removals_.insert(DicomTag(0x0016, 0x0080)); // GPS Img Direction Ref +removals_.insert(DicomTag(0x0016, 0x0081)); // GPS Img Direction +removals_.insert(DicomTag(0x0016, 0x0082)); // GPS Map Datum +removals_.insert(DicomTag(0x0016, 0x0083)); // GPS Dest Latitude Ref +removals_.insert(DicomTag(0x0016, 0x0084)); // GPS Dest Latitude +removals_.insert(DicomTag(0x0016, 0x0085)); // GPS Dest Longitude Ref +removals_.insert(DicomTag(0x0016, 0x0086)); // GPS Dest Longitude +removals_.insert(DicomTag(0x0016, 0x0087)); // GPS Dest Bearing Ref +removals_.insert(DicomTag(0x0016, 0x0088)); // GPS Dest Bearing +removals_.insert(DicomTag(0x0016, 0x0089)); // GPS Dest Distance Ref +removals_.insert(DicomTag(0x0016, 0x008a)); // GPS Dest Distance +removals_.insert(DicomTag(0x0016, 0x008b)); // GPS Processing Method +removals_.insert(DicomTag(0x0016, 0x008c)); // GPS Area Information +removals_.insert(DicomTag(0x0016, 0x008d)); // GPS Date Stamp +removals_.insert(DicomTag(0x0016, 0x008e)); // GPS Differential +removals_.insert(DicomTag(0x0018, 0x0027)); // Intervention Drug Stop Time +removals_.insert(DicomTag(0x0018, 0x0035)); // Intervention Drug Start Time +removals_.insert(DicomTag(0x0018, 0x1000)); /* X/Z/D */ // Device Serial Number +removals_.insert(DicomTag(0x0018, 0x1004)); // Plate ID +removals_.insert(DicomTag(0x0018, 0x1005)); // Generator ID +removals_.insert(DicomTag(0x0018, 0x1007)); // Cassette ID +removals_.insert(DicomTag(0x0018, 0x1008)); // Gantry ID +removals_.insert(DicomTag(0x0018, 0x1009)); // Unique Device Identifier +removals_.insert(DicomTag(0x0018, 0x100a)); // UDI Sequence +removals_.insert(DicomTag(0x0018, 0x1012)); // Date of Secondary Capture +removals_.insert(DicomTag(0x0018, 0x1014)); // Time of Secondary Capture +removals_.insert(DicomTag(0x0018, 0x1030)); /* X/D */ // Protocol Name +removals_.insert(DicomTag(0x0018, 0x1042)); // Contrast/Bolus Start Time +removals_.insert(DicomTag(0x0018, 0x1043)); // Contrast/Bolus Stop Time +removals_.insert(DicomTag(0x0018, 0x1072)); // Radiopharmaceutical Start Time +removals_.insert(DicomTag(0x0018, 0x1073)); // Radiopharmaceutical Stop Time +removals_.insert(DicomTag(0x0018, 0x1078)); // Radiopharmaceutical Start DateTime +removals_.insert(DicomTag(0x0018, 0x1079)); // Radiopharmaceutical Stop DateTime +removals_.insert(DicomTag(0x0018, 0x1200)); // Date of Last Calibration +removals_.insert(DicomTag(0x0018, 0x1201)); // Time of Last Calibration +removals_.insert(DicomTag(0x0018, 0x1202)); // DateTime of Last Calibration +removals_.insert(DicomTag(0x0018, 0x1400)); /* X/D */ // Acquisition Device Processing Description +removals_.insert(DicomTag(0x0018, 0x4000)); // Acquisition Comments +removals_.insert(DicomTag(0x0018, 0x5011)); // Transducer Identification Sequence +removals_.insert(DicomTag(0x0018, 0x700a)); /* X/D */ // Detector ID +removals_.insert(DicomTag(0x0018, 0x700c)); /* X/D */ // Date of Last Detector Calibration +removals_.insert(DicomTag(0x0018, 0x700e)); /* X/D */ // Time of Last Detector Calibration +removals_.insert(DicomTag(0x0018, 0x9185)); // Respiratory Motion Compensation Technique Description +removals_.insert(DicomTag(0x0018, 0x9373)); // X-Ray Detector Label +removals_.insert(DicomTag(0x0018, 0x937b)); // Multi-energy Acquisition Description +removals_.insert(DicomTag(0x0018, 0x937f)); // Decomposition Description +removals_.insert(DicomTag(0x0018, 0x9424)); // Acquisition Protocol Description +removals_.insert(DicomTag(0x0018, 0x9516)); /* X/D */ // Start Acquisition DateTime +removals_.insert(DicomTag(0x0018, 0x9517)); /* X/D */ // End Acquisition DateTime +removals_.insert(DicomTag(0x0018, 0x9937)); // Requested Series Description +removals_.insert(DicomTag(0x0018, 0xa002)); // Contribution DateTime +removals_.insert(DicomTag(0x0018, 0xa003)); // Contribution Description +removals_.insert(DicomTag(0x0020, 0x0027)); // Pyramid Label +removals_.insert(DicomTag(0x0020, 0x3401)); // Modifying Device ID +removals_.insert(DicomTag(0x0020, 0x3403)); // Modified Image Date +removals_.insert(DicomTag(0x0020, 0x3405)); // Modified Image Time +removals_.insert(DicomTag(0x0020, 0x3406)); // Modified Image Description +removals_.insert(DicomTag(0x0020, 0x4000)); // Image Comments +removals_.insert(DicomTag(0x0020, 0x9158)); // Frame Comments +removals_.insert(DicomTag(0x0028, 0x4000)); // Image Presentation Comments +removals_.insert(DicomTag(0x0032, 0x0012)); // Study ID Issuer +removals_.insert(DicomTag(0x0032, 0x0032)); // Study Verified Date +removals_.insert(DicomTag(0x0032, 0x0033)); // Study Verified Time +removals_.insert(DicomTag(0x0032, 0x0034)); // Study Read Date +removals_.insert(DicomTag(0x0032, 0x0035)); // Study Read Time +removals_.insert(DicomTag(0x0032, 0x1000)); // Scheduled Study Start Date +removals_.insert(DicomTag(0x0032, 0x1001)); // Scheduled Study Start Time +removals_.insert(DicomTag(0x0032, 0x1010)); // Scheduled Study Stop Date +removals_.insert(DicomTag(0x0032, 0x1011)); // Scheduled Study Stop Time +removals_.insert(DicomTag(0x0032, 0x1020)); // Scheduled Study Location +removals_.insert(DicomTag(0x0032, 0x1021)); // Scheduled Study Location AE Title +removals_.insert(DicomTag(0x0032, 0x1021)); // Scheduled Study Location AE Title +removals_.insert(DicomTag(0x0032, 0x1030)); // Reason for Study +removals_.insert(DicomTag(0x0032, 0x1032)); // Requesting Physician +removals_.insert(DicomTag(0x0032, 0x1033)); // Requesting Service +removals_.insert(DicomTag(0x0032, 0x1040)); // Study Arrival Date +removals_.insert(DicomTag(0x0032, 0x1041)); // Study Arrival Time +removals_.insert(DicomTag(0x0032, 0x1050)); // Study Completion Date +removals_.insert(DicomTag(0x0032, 0x1051)); // Study Completion Time +removals_.insert(DicomTag(0x0032, 0x1060)); /* X/Z */ // Requested Procedure Description +removals_.insert(DicomTag(0x0032, 0x1066)); // Reason for Visit +removals_.insert(DicomTag(0x0032, 0x1067)); // Reason for Visit Code Sequence +removals_.insert(DicomTag(0x0032, 0x1070)); // Requested Contrast Agent +removals_.insert(DicomTag(0x0032, 0x4000)); // Study Comments +removals_.insert(DicomTag(0x0038, 0x0004)); // Referenced Patient Alias Sequence +removals_.insert(DicomTag(0x0038, 0x0010)); // Admission ID +removals_.insert(DicomTag(0x0038, 0x0011)); // Issuer of Admission ID +removals_.insert(DicomTag(0x0038, 0x0014)); // Issuer of Admission ID Sequence +removals_.insert(DicomTag(0x0038, 0x001a)); // Scheduled Admission Date +removals_.insert(DicomTag(0x0038, 0x001b)); // Scheduled Admission Time +removals_.insert(DicomTag(0x0038, 0x001c)); // Scheduled Discharge Date +removals_.insert(DicomTag(0x0038, 0x001d)); // Scheduled Discharge Time +removals_.insert(DicomTag(0x0038, 0x001e)); // Scheduled Patient Institution Residence +removals_.insert(DicomTag(0x0038, 0x0020)); // Admitting Date +removals_.insert(DicomTag(0x0038, 0x0021)); // Admitting Time +removals_.insert(DicomTag(0x0038, 0x0030)); // Discharge Date +removals_.insert(DicomTag(0x0038, 0x0032)); // Discharge Time +removals_.insert(DicomTag(0x0038, 0x0040)); // Discharge Diagnosis Description +removals_.insert(DicomTag(0x0038, 0x0050)); // Special Needs +removals_.insert(DicomTag(0x0038, 0x0060)); // Service Episode ID +removals_.insert(DicomTag(0x0038, 0x0061)); // Issuer of Service Episode ID +removals_.insert(DicomTag(0x0038, 0x0062)); // Service Episode Description +removals_.insert(DicomTag(0x0038, 0x0064)); // Issuer of Service Episode ID Sequence +removals_.insert(DicomTag(0x0038, 0x0300)); // Current Patient Location +removals_.insert(DicomTag(0x0038, 0x0400)); // Patient's Institution Residence +removals_.insert(DicomTag(0x0038, 0x0500)); // Patient State +removals_.insert(DicomTag(0x0038, 0x4000)); // Visit Comments +removals_.insert(DicomTag(0x003a, 0x0329)); // Waveform Filter Description +removals_.insert(DicomTag(0x003a, 0x032b)); // Filter Lookup Table Description +removals_.insert(DicomTag(0x0040, 0x0001)); // Scheduled Station AE Title +removals_.insert(DicomTag(0x0040, 0x0001)); // Scheduled Station AE Title +removals_.insert(DicomTag(0x0040, 0x0002)); // Scheduled Procedure Step Start Date +removals_.insert(DicomTag(0x0040, 0x0003)); // Scheduled Procedure Step Start Time +removals_.insert(DicomTag(0x0040, 0x0004)); // Scheduled Procedure Step End Date +removals_.insert(DicomTag(0x0040, 0x0005)); // Scheduled Procedure Step End Time +removals_.insert(DicomTag(0x0040, 0x0006)); // Scheduled Performing Physician's Name +removals_.insert(DicomTag(0x0040, 0x0007)); // Scheduled Procedure Step Description +removals_.insert(DicomTag(0x0040, 0x0009)); // Scheduled Procedure Step ID +removals_.insert(DicomTag(0x0040, 0x000b)); // Scheduled Performing Physician Identification Sequence +removals_.insert(DicomTag(0x0040, 0x0010)); // Scheduled Station Name +removals_.insert(DicomTag(0x0040, 0x0011)); // Scheduled Procedure Step Location +removals_.insert(DicomTag(0x0040, 0x0012)); // Pre-Medication +removals_.insert(DicomTag(0x0040, 0x0241)); // Performed Station AE Title +removals_.insert(DicomTag(0x0040, 0x0241)); // Performed Station AE Title +removals_.insert(DicomTag(0x0040, 0x0242)); // Performed Station Name +removals_.insert(DicomTag(0x0040, 0x0243)); // Performed Location +removals_.insert(DicomTag(0x0040, 0x0244)); // Performed Procedure Step Start Date +removals_.insert(DicomTag(0x0040, 0x0245)); // Performed Procedure Step Start Time +removals_.insert(DicomTag(0x0040, 0x0250)); // Performed Procedure Step End Date +removals_.insert(DicomTag(0x0040, 0x0251)); // Performed Procedure Step End Time +removals_.insert(DicomTag(0x0040, 0x0253)); // Performed Procedure Step ID +removals_.insert(DicomTag(0x0040, 0x0254)); // Performed Procedure Step Description +removals_.insert(DicomTag(0x0040, 0x0275)); // Request Attributes Sequence +removals_.insert(DicomTag(0x0040, 0x0280)); // Comments on the Performed Procedure Step +removals_.insert(DicomTag(0x0040, 0x0310)); // Comments on Radiation Dose +removals_.insert(DicomTag(0x0040, 0x050a)); // Specimen Accession Number +removals_.insert(DicomTag(0x0040, 0x051a)); // Container Description +removals_.insert(DicomTag(0x0040, 0x0555)); /* X/Z */ // Acquisition Context Sequence +removals_.insert(DicomTag(0x0040, 0x0600)); // Specimen Short Description +removals_.insert(DicomTag(0x0040, 0x0602)); // Specimen Detailed Description +removals_.insert(DicomTag(0x0040, 0x06fa)); // Slide Identifier +removals_.insert(DicomTag(0x0040, 0x1001)); // Requested Procedure ID +removals_.insert(DicomTag(0x0040, 0x1002)); // Reason for the Requested Procedure +removals_.insert(DicomTag(0x0040, 0x1004)); // Patient Transport Arrangements +removals_.insert(DicomTag(0x0040, 0x1005)); // Requested Procedure Location +removals_.insert(DicomTag(0x0040, 0x100a)); // Reason for Requested Procedure Code Sequence +removals_.insert(DicomTag(0x0040, 0x1010)); // Names of Intended Recipients of Results +removals_.insert(DicomTag(0x0040, 0x1011)); // Intended Recipients of Results Identification Sequence +removals_.insert(DicomTag(0x0040, 0x1102)); // Person's Address +removals_.insert(DicomTag(0x0040, 0x1103)); // Person's Telephone Numbers +removals_.insert(DicomTag(0x0040, 0x1104)); // Person's Telecom Information +removals_.insert(DicomTag(0x0040, 0x1400)); // Requested Procedure Comments +removals_.insert(DicomTag(0x0040, 0x2001)); // Reason for the Imaging Service Request +removals_.insert(DicomTag(0x0040, 0x2004)); // Issue Date of Imaging Service Request +removals_.insert(DicomTag(0x0040, 0x2005)); // Issue Time of Imaging Service Request +removals_.insert(DicomTag(0x0040, 0x2008)); // Order Entered By +removals_.insert(DicomTag(0x0040, 0x2009)); // Order Enterer's Location +removals_.insert(DicomTag(0x0040, 0x2010)); // Order Callback Phone Number +removals_.insert(DicomTag(0x0040, 0x2011)); // Order Callback Telecom Information +removals_.insert(DicomTag(0x0040, 0x2400)); // Imaging Service Request Comments +removals_.insert(DicomTag(0x0040, 0x3001)); // Confidentiality Constraint on Patient Data Description +removals_.insert(DicomTag(0x0040, 0x4005)); // Scheduled Procedure Step Start DateTime +removals_.insert(DicomTag(0x0040, 0x4008)); // Scheduled Procedure Step Expiration DateTime +removals_.insert(DicomTag(0x0040, 0x4010)); // Scheduled Procedure Step Modification DateTime +removals_.insert(DicomTag(0x0040, 0x4011)); // Expected Completion DateTime +removals_.insert(DicomTag(0x0040, 0x4025)); // Scheduled Station Name Code Sequence +removals_.insert(DicomTag(0x0040, 0x4027)); // Scheduled Station Geographic Location Code Sequence +removals_.insert(DicomTag(0x0040, 0x4028)); // Performed Station Name Code Sequence +removals_.insert(DicomTag(0x0040, 0x4030)); // Performed Station Geographic Location Code Sequence +removals_.insert(DicomTag(0x0040, 0x4034)); // Scheduled Human Performers Sequence +removals_.insert(DicomTag(0x0040, 0x4035)); // Actual Human Performers Sequence +removals_.insert(DicomTag(0x0040, 0x4036)); // Human Performer's Organization +removals_.insert(DicomTag(0x0040, 0x4037)); // Human Performer's Name +removals_.insert(DicomTag(0x0040, 0x4050)); // Performed Procedure Step Start DateTime +removals_.insert(DicomTag(0x0040, 0x4051)); // Performed Procedure Step End DateTime +removals_.insert(DicomTag(0x0040, 0x4052)); // Procedure Step Cancellation DateTime +removals_.insert(DicomTag(0x0040, 0xa023)); // Findings Group Recording Date (Trial) +removals_.insert(DicomTag(0x0040, 0xa024)); // Findings Group Recording Time (Trial) +removals_.insert(DicomTag(0x0040, 0xa032)); /* X/D */ // Observation DateTime +removals_.insert(DicomTag(0x0040, 0xa033)); // Observation Start DateTime +removals_.insert(DicomTag(0x0040, 0xa078)); // Author Observer Sequence +removals_.insert(DicomTag(0x0040, 0xa07a)); // Participant Sequence +removals_.insert(DicomTag(0x0040, 0xa07c)); // Custodial Organization Sequence +removals_.insert(DicomTag(0x0040, 0xa110)); // Date of Document or Verbal Transaction (Trial) +removals_.insert(DicomTag(0x0040, 0xa112)); // Time of Document or Verbal Transaction (Trial) +removals_.insert(DicomTag(0x0040, 0xa192)); // Observation Date (Trial) +removals_.insert(DicomTag(0x0040, 0xa193)); // Observation Time (Trial) +removals_.insert(DicomTag(0x0040, 0xa307)); // Current Observer (Trial) +removals_.insert(DicomTag(0x0040, 0xa352)); // Verbal Source (Trial) +removals_.insert(DicomTag(0x0040, 0xa353)); // Address (Trial) +removals_.insert(DicomTag(0x0040, 0xa354)); // Telephone Number (Trial) +removals_.insert(DicomTag(0x0040, 0xa358)); // Verbal Source Identifier Code Sequence (Trial) +removals_.insert(DicomTag(0x0040, 0xdb06)); // Template Version +removals_.insert(DicomTag(0x0040, 0xdb07)); // Template Local Version +removals_.insert(DicomTag(0x0040, 0xe004)); // HL7 Document Effective Time +removals_.insert(DicomTag(0x0044, 0x0004)); // Approval Status DateTime +removals_.insert(DicomTag(0x0044, 0x000b)); // Product Expiration DateTime +removals_.insert(DicomTag(0x0044, 0x0010)); // Substance Administration DateTime +removals_.insert(DicomTag(0x0044, 0x0105)); // Assertion Expiration DateTime +removals_.insert(DicomTag(0x0050, 0x001b)); // Container Component ID +removals_.insert(DicomTag(0x0050, 0x0020)); // Device Description +removals_.insert(DicomTag(0x0050, 0x0021)); // Long Device Description +removals_.insert(DicomTag(0x006a, 0x0006)); // Annotation Group Description +removals_.insert(DicomTag(0x0070, 0x0082)); // Presentation Creation Date +removals_.insert(DicomTag(0x0070, 0x0083)); // Presentation Creation Time +removals_.insert(DicomTag(0x0070, 0x0086)); // Content Creator's Identification Code Sequence +removals_.insert(DicomTag(0x0074, 0x1234)); // Receiving AE +removals_.insert(DicomTag(0x0074, 0x1236)); // Requesting AE +removals_.insert(DicomTag(0x0088, 0x0200)); // Icon Image Sequence +removals_.insert(DicomTag(0x0088, 0x0904)); // Topic Title +removals_.insert(DicomTag(0x0088, 0x0906)); // Topic Subject +removals_.insert(DicomTag(0x0088, 0x0910)); // Topic Author +removals_.insert(DicomTag(0x0088, 0x0912)); // Topic Keywords +removals_.insert(DicomTag(0x0100, 0x0420)); // SOP Authorization DateTime +removals_.insert(DicomTag(0x0400, 0x0310)); // Certified Timestamp +removals_.insert(DicomTag(0x0400, 0x0402)); // Referenced Digital Signature Sequence +removals_.insert(DicomTag(0x0400, 0x0403)); // Referenced SOP Instance MAC Sequence +removals_.insert(DicomTag(0x0400, 0x0404)); // MAC +removals_.insert(DicomTag(0x0400, 0x0550)); // Modified Attributes Sequence +removals_.insert(DicomTag(0x0400, 0x0551)); // Nonconforming Modified Attributes Sequence +removals_.insert(DicomTag(0x0400, 0x0552)); // Nonconforming Data Element Value +removals_.insert(DicomTag(0x0400, 0x0561)); // Original Attributes Sequence +removals_.insert(DicomTag(0x0400, 0x0600)); // Instance Origin Status +removals_.insert(DicomTag(0x2030, 0x0020)); // Text String +removals_.insert(DicomTag(0x2100, 0x0040)); // Creation Date +removals_.insert(DicomTag(0x2100, 0x0050)); // Creation Time +removals_.insert(DicomTag(0x2100, 0x0070)); // Originator +removals_.insert(DicomTag(0x2200, 0x0002)); /* X/Z */ // Label Text +removals_.insert(DicomTag(0x2200, 0x0005)); /* X/Z */ // Barcode Value +removals_.insert(DicomTag(0x3002, 0x0121)); // Position Acquisition Template Name +removals_.insert(DicomTag(0x3002, 0x0123)); // Position Acquisition Template Description +removals_.insert(DicomTag(0x3006, 0x0004)); // Structure Set Name +removals_.insert(DicomTag(0x3006, 0x0006)); // Structure Set Description +removals_.insert(DicomTag(0x3006, 0x0028)); // ROI Description +removals_.insert(DicomTag(0x3006, 0x0038)); // ROI Generation Description +removals_.insert(DicomTag(0x3006, 0x0085)); // ROI Observation Label +removals_.insert(DicomTag(0x3006, 0x0088)); // ROI Observation Description +removals_.insert(DicomTag(0x3008, 0x0054)); /* X/D */ // First Treatment Date +removals_.insert(DicomTag(0x3008, 0x0056)); /* X/D */ // Most Recent Treatment Date +removals_.insert(DicomTag(0x3008, 0x0105)); /* X/Z */ // Source Serial Number +removals_.insert(DicomTag(0x3008, 0x0250)); /* X/D */ // Treatment Date +removals_.insert(DicomTag(0x3008, 0x0251)); /* X/D */ // Treatment Time +removals_.insert(DicomTag(0x300a, 0x0003)); // RT Plan Name +removals_.insert(DicomTag(0x300a, 0x0004)); // RT Plan Description +removals_.insert(DicomTag(0x300a, 0x0006)); /* X/D */ // RT Plan Date +removals_.insert(DicomTag(0x300a, 0x0007)); /* X/D */ // RT Plan Time +removals_.insert(DicomTag(0x300a, 0x000b)); // Treatment Sites +removals_.insert(DicomTag(0x300a, 0x000e)); // Prescription Description +removals_.insert(DicomTag(0x300a, 0x0016)); // Dose Reference Description +removals_.insert(DicomTag(0x300a, 0x0072)); // Fraction Group Description +removals_.insert(DicomTag(0x300a, 0x00b2)); /* X/Z */ // Treatment Machine Name +removals_.insert(DicomTag(0x300a, 0x00c3)); // Beam Description +removals_.insert(DicomTag(0x300a, 0x00dd)); // Bolus Description +removals_.insert(DicomTag(0x300a, 0x0196)); // Fixation Device Description +removals_.insert(DicomTag(0x300a, 0x01a6)); // Shielding Device Description +removals_.insert(DicomTag(0x300a, 0x01b2)); // Setup Technique Description +removals_.insert(DicomTag(0x300a, 0x0216)); // Source Manufacturer +removals_.insert(DicomTag(0x300a, 0x02eb)); // Compensator Description +removals_.insert(DicomTag(0x300a, 0x0676)); // Equipment Frame of Reference Description +removals_.insert(DicomTag(0x300a, 0x078e)); // Patient Treatment Preparation Procedure Parameter Description +removals_.insert(DicomTag(0x300a, 0x0792)); // Patient Treatment Preparation Method Description +removals_.insert(DicomTag(0x300a, 0x0794)); // Patient Setup Photo Description +removals_.insert(DicomTag(0x300a, 0x079a)); // Displacement Reference Label +removals_.insert(DicomTag(0x300c, 0x0113)); // Reason for Omission Description +removals_.insert(DicomTag(0x300e, 0x0008)); /* X/Z */ // Reviewer Name +removals_.insert(DicomTag(0x3010, 0x0036)); // Entity Name +removals_.insert(DicomTag(0x3010, 0x0037)); // Entity Description +removals_.insert(DicomTag(0x3010, 0x004c)); /* X/D */ // Intended Phase Start Date +removals_.insert(DicomTag(0x3010, 0x004d)); /* X/D */ // Intended Phase End Date +removals_.insert(DicomTag(0x3010, 0x0056)); /* X/D */ // RT Treatment Approach Label +removals_.insert(DicomTag(0x3010, 0x0061)); // Prior Treatment Dose Description +removals_.insert(DicomTag(0x3010, 0x0077)); /* X/D */ // Treatment Site +removals_.insert(DicomTag(0x3010, 0x0085)); // Intended Fraction Start Time +removals_.insert(DicomTag(0x4000, 0x0010)); // Arbitrary +removals_.insert(DicomTag(0x4000, 0x4000)); // Text Comments +removals_.insert(DicomTag(0x4008, 0x0040)); // Results ID +removals_.insert(DicomTag(0x4008, 0x0042)); // Results ID Issuer +removals_.insert(DicomTag(0x4008, 0x0100)); // Interpretation Recorded Date +removals_.insert(DicomTag(0x4008, 0x0101)); // Interpretation Recorded Time +removals_.insert(DicomTag(0x4008, 0x0102)); // Interpretation Recorder +removals_.insert(DicomTag(0x4008, 0x0108)); // Interpretation Transcription Date +removals_.insert(DicomTag(0x4008, 0x0109)); // Interpretation Transcription Time +removals_.insert(DicomTag(0x4008, 0x010a)); // Interpretation Transcriber +removals_.insert(DicomTag(0x4008, 0x010b)); // Interpretation Text +removals_.insert(DicomTag(0x4008, 0x010c)); // Interpretation Author +removals_.insert(DicomTag(0x4008, 0x0111)); // Interpretation Approver Sequence +removals_.insert(DicomTag(0x4008, 0x0112)); // Interpretation Approval Date +removals_.insert(DicomTag(0x4008, 0x0113)); // Interpretation Approval Time +removals_.insert(DicomTag(0x4008, 0x0114)); // Physician Approving Interpretation +removals_.insert(DicomTag(0x4008, 0x0115)); // Interpretation Diagnosis Description +removals_.insert(DicomTag(0x4008, 0x0118)); // Results Distribution List Sequence +removals_.insert(DicomTag(0x4008, 0x0119)); // Distribution Name +removals_.insert(DicomTag(0x4008, 0x011a)); // Distribution Address +removals_.insert(DicomTag(0x4008, 0x0200)); // Interpretation ID +removals_.insert(DicomTag(0x4008, 0x0202)); // Interpretation ID Issuer +removals_.insert(DicomTag(0x4008, 0x0300)); // Impressions +removals_.insert(DicomTag(0x4008, 0x4000)); // Results Comments +removals_.insert(DicomTag(0xfffa, 0xfffa)); // Digital Signatures Sequence +removals_.insert(DicomTag(0xfffc, 0xfffc)); // Data Set Trailing Padding +removedRanges_.push_back(DicomTagRange(0x5000, 0x50ff, 0x0000, 0xffff)); // Curve Data +removedRanges_.push_back(DicomTagRange(0x6000, 0x60ff, 0x3000, 0x3000)); // Overlay Data +removedRanges_.push_back(DicomTagRange(0x6000, 0x60ff, 0x4000, 0x4000)); // Overlay Comments +uids_.insert(DicomTag(0x0000, 0x1001)); // Requested SOP Instance UID +uids_.insert(DicomTag(0x0002, 0x0003)); // Media Storage SOP Instance UID +uids_.insert(DicomTag(0x0004, 0x1511)); // Referenced SOP Instance UID in File +uids_.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID +uids_.insert(DicomTag(0x0008, 0x0017)); // Acquisition UID +uids_.insert(DicomTag(0x0008, 0x0019)); // Pyramid UID +uids_.insert(DicomTag(0x0008, 0x0058)); // Failed SOP Instance UID List +uids_.insert(DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID +uids_.insert(DicomTag(0x0008, 0x1195)); // Transaction UID +uids_.insert(DicomTag(0x0008, 0x3010)); // Irradiation Event UID +uids_.insert(DicomTag(0x0018, 0x1002)); // Device UID +uids_.insert(DicomTag(0x0018, 0x100b)); // Manufacturer's Device Class UID +uids_.insert(DicomTag(0x0018, 0x2042)); // Target UID +uids_.insert(DicomTag(0x0020, 0x0052)); // Frame of Reference UID +uids_.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID +uids_.insert(DicomTag(0x0020, 0x9161)); // Concatenation UID +uids_.insert(DicomTag(0x0020, 0x9164)); // Dimension Organization UID +uids_.insert(DicomTag(0x0028, 0x1199)); // Palette Color Lookup Table UID +uids_.insert(DicomTag(0x0028, 0x1214)); // Large Palette Color Lookup Table UID +uids_.insert(DicomTag(0x003a, 0x0310)); // Multiplex Group UID +uids_.insert(DicomTag(0x0040, 0x0554)); // Specimen UID +uids_.insert(DicomTag(0x0040, 0x4023)); // Referenced General Purpose Scheduled Procedure Step Transaction UID +uids_.insert(DicomTag(0x0040, 0xa124)); // UID +uids_.insert(DicomTag(0x0040, 0xa171)); // Observation UID +uids_.insert(DicomTag(0x0040, 0xa172)); // Referenced Observation UID (Trial) +uids_.insert(DicomTag(0x0040, 0xa402)); // Observation Subject UID (Trial) +uids_.insert(DicomTag(0x0040, 0xdb0c)); // Template Extension Organization UID +uids_.insert(DicomTag(0x0040, 0xdb0d)); // Template Extension Creator UID +uids_.insert(DicomTag(0x0062, 0x0021)); // Tracking UID +uids_.insert(DicomTag(0x0064, 0x0003)); // Source Frame of Reference UID +uids_.insert(DicomTag(0x0070, 0x031a)); // Fiducial UID +uids_.insert(DicomTag(0x0070, 0x1101)); // Presentation Display Collection UID +uids_.insert(DicomTag(0x0070, 0x1102)); // Presentation Sequence Collection UID +uids_.insert(DicomTag(0x0088, 0x0140)); // Storage Media File-set UID +uids_.insert(DicomTag(0x0400, 0x0100)); // Digital Signature UID +uids_.insert(DicomTag(0x3006, 0x0024)); // Referenced Frame of Reference UID +uids_.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID +uids_.insert(DicomTag(0x300a, 0x0013)); // Dose Reference UID +uids_.insert(DicomTag(0x300a, 0x0083)); // Referenced Dose Reference UID +uids_.insert(DicomTag(0x300a, 0x0609)); // Treatment Position Group UID +uids_.insert(DicomTag(0x300a, 0x0650)); // Patient Setup UID +uids_.insert(DicomTag(0x300a, 0x0700)); // Treatment Session UID +uids_.insert(DicomTag(0x300a, 0x0785)); // Referenced Treatment Position Group UID +uids_.insert(DicomTag(0x3010, 0x0006)); // Conceptual Volume UID +uids_.insert(DicomTag(0x3010, 0x000b)); // Referenced Conceptual Volume UID +uids_.insert(DicomTag(0x3010, 0x0013)); // Constituent Conceptual Volume UID +uids_.insert(DicomTag(0x3010, 0x0015)); // Source Conceptual Volume UID +uids_.insert(DicomTag(0x3010, 0x0031)); // Referenced Fiducials UID +uids_.insert(DicomTag(0x3010, 0x003b)); // RT Treatment Phase UID +uids_.insert(DicomTag(0x3010, 0x006e)); // Dosimetric Objective UID +uids_.insert(DicomTag(0x3010, 0x006f)); // Referenced Dosimetric Objective UID diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.cpp --- a/OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -436,7 +437,7 @@ /** * The test on "size > 0" is new in Orthanc 1.9.3, and fixes * issue #195 (No need for BulkDataURI when Data Element is - * empty): https://bugs.orthanc-server.com/show_bug.cgi?id=195 + * empty): https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=195 **/ if (size > 0 || tag == DICOM_TAG_PIXEL_DATA || diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.h --- a/OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp --- a/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -93,7 +94,9 @@ #endif #if DCMTK_USE_EMBEDDED_DICTIONARIES == 1 -# include +# if !defined(ORTHANC_FRAMEWORK_INCLUDE_RESOURCES) || (ORTHANC_FRAMEWORK_INCLUDE_RESOURCES == 1) +# include +# endif #endif #if ORTHANC_ENABLE_DCMTK_JPEG == 1 @@ -289,7 +292,7 @@ void FromDcmtkBridge::InitializeDictionary(bool loadPrivateDictionary) { - CLOG(INFO, DICOM) << "Using DCTMK version: " << DCMTK_VERSION_NUMBER; + CLOG(INFO, DICOM) << "Using DCMTK version: " << DCMTK_VERSION_NUMBER; #if DCMTK_USE_EMBEDDED_DICTIONARIES == 1 { @@ -580,8 +583,8 @@ ignoreTagLength, 1); } - target.SetValue(DicomTag(element->getTag().getGTag(), element->getTag().getETag()), - jsonSequence); + target.SetSequenceValue(DicomTag(element->getTag().getGTag(), element->getTag().getETag()), + jsonSequence); } } } @@ -1253,9 +1256,22 @@ } + static bool GetTagFromNameInternal(DicomTag& tag, const std::string& tagName) + { + // conversion from old tag names (ex: RETIRED_OtherPatientIDs is the new name for OtherPatientIDs that is still a valid name for DICOM_TAG_OTHER_PATIENT_IDS) + if (tagName == "OtherPatientIDs") + { + tag = DICOM_TAG_OTHER_PATIENT_IDS; + return true; + } + + return false; + } + std::string FromDcmtkBridge::GetTagName(const DicomTag& t, const std::string& privateCreator) { + DcmTag tag(t.GetGroup(), t.GetElement()); if (!privateCreator.empty()) @@ -1315,6 +1331,12 @@ } else { + DicomTag dcmTag(0, 0); + if (GetTagFromNameInternal(dcmTag, name)) + { + return dcmTag; + } + CLOG(INFO, DICOM) << "Unknown DICOM tag: \"" << name << "\""; throw OrthancException(ErrorCode_UnknownDicomTag, name, false); } @@ -1553,7 +1575,8 @@ static bool SaveToMemoryBufferInternal(std::string& buffer, DcmFileFormat& dicom, - E_TransferSyntax xfer) + E_TransferSyntax xfer, + std::string& errorMessage) { E_EncodingType encodingType = /*opt_sequenceType*/ EET_ExplicitLength; @@ -1592,14 +1615,24 @@ { // Error buffer.clear(); + errorMessage = std::string(c.text()); return false; } } - bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, DcmDataset& dataSet) { + std::string errorMessageNotUsed; + return SaveToMemoryBuffer(buffer, dataSet, errorMessageNotUsed); + } + + + + bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, + DcmDataset& dataSet, + std::string& errorMessage) + { // Determine the transfer syntax which shall be used to write the // information to the file. If not possible, switch to the Little // Endian syntax, with explicit length. @@ -1626,7 +1659,7 @@ ff.validateMetaInfo(xfer); ff.removeInvalidGroups(); - return SaveToMemoryBufferInternal(buffer, ff, xfer); + return SaveToMemoryBufferInternal(buffer, ff, xfer, errorMessage); } @@ -1797,7 +1830,7 @@ { // This solves issue 140 (Modifying private tags with REST API // changes VR from LO to UN) - // https://bugs.orthanc-server.com/show_bug.cgi?id=140 + // https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=140 LOG(WARNING) << "Private creator should not be empty while creating a private tag: " << tag.Format(); } @@ -1945,13 +1978,27 @@ case EVR_SL: // signed long { - ok = element.putSint32(boost::lexical_cast(*decoded)).good(); + if (decoded->find('\\') != std::string::npos) + { + ok = element.putString(decoded->c_str()).good(); + } + else + { + ok = element.putSint32(boost::lexical_cast(*decoded)).good(); + } break; } case EVR_SS: // signed short { - ok = element.putSint16(boost::lexical_cast(*decoded)).good(); + if (decoded->find('\\') != std::string::npos) + { + ok = element.putString(decoded->c_str()).good(); + } + else + { + ok = element.putSint16(boost::lexical_cast(*decoded)).good(); + } break; } @@ -1960,7 +2007,14 @@ case EVR_OL: // other long (requires byte-swapping) #endif { - ok = element.putUint32(boost::lexical_cast(*decoded)).good(); + if (decoded->find('\\') != std::string::npos) + { + ok = element.putString(decoded->c_str()).good(); + } + else + { + ok = element.putUint32(boost::lexical_cast(*decoded)).good(); + } break; } @@ -1983,14 +2037,28 @@ case EVR_US: // unsigned short { - ok = element.putUint16(boost::lexical_cast(*decoded)).good(); + if (decoded->find('\\') != std::string::npos) + { + ok = element.putString(decoded->c_str()).good(); + } + else + { + ok = element.putUint16(boost::lexical_cast(*decoded)).good(); + } break; } case EVR_FL: // float single-precision case EVR_OF: // other float (requires byte swapping) { - ok = element.putFloat32(boost::lexical_cast(*decoded)).good(); + if (decoded->find('\\') != std::string::npos) + { + ok = element.putString(decoded->c_str()).good(); + } + else + { + ok = element.putFloat32(boost::lexical_cast(*decoded)).good(); + } break; } @@ -1999,7 +2067,14 @@ case EVR_OD: // other double (requires byte-swapping) #endif { - ok = element.putFloat64(boost::lexical_cast(*decoded)).good(); + if (decoded->find('\\') != std::string::npos) + { + ok = element.putString(decoded->c_str()).good(); + } + else + { + ok = element.putFloat64(boost::lexical_cast(*decoded)).good(); + } break; } @@ -2439,7 +2514,7 @@ #if ORTHANC_ENABLE_DCMTK_JPEG == 1 CLOG(INFO, DICOM) << "Registering JPEG codecs in DCMTK"; - DJDecoderRegistration::registerCodecs(); + DJDecoderRegistration::registerCodecs(); # if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 DJEncoderRegistration::registerCodecs(); # endif @@ -2548,6 +2623,19 @@ { evr = EVR_OB; } + else if (evr == EVR_xs) // SS or US depending on context + { + // So far we assume that it's alway US (as a best guess: https://forum.dcmtk.org/viewtopic.php?t=932) + // However, e.g. in a LUTDescriptor (3 values), the middle value can be a SS depending on other tag values while first and third value are always US. + // This patch, although not perfect fixes https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=214. + // It might need some rework once we encounter a LUTDescriptor with a SS value. ref: https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.11.2.html#sect_C.11.2.1.1 + evr = EVR_US; + } + else if (evr == EVR_lt) // US, SS or OW depending on context, used for LUT Data (thus the name) + { + // best guess is OW: final user should be able to interpret it correctly depending on the context + evr = EVR_OW; + } if (evr == EVR_UNKNOWN || // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) evr == EVR_UNKNOWN2B) // used internally for elements with unknown VR with 2-byte length field in explicit VR diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h --- a/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -203,6 +204,10 @@ static bool SaveToMemoryBuffer(std::string& buffer, DcmDataset& dataSet); + static bool SaveToMemoryBuffer(std::string& buffer, + DcmDataset& dataSet, + std::string& errorMessage); + static bool Transcode(DcmFileFormat& dicom, DicomTransferSyntax syntax, const DcmRepresentationParameter* representation); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/FromDcmtkBridge_TransferSyntaxes.impl.h --- a/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge_TransferSyntaxes.impl.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge_TransferSyntaxes.impl.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/IDicomTranscoder.cpp --- a/OrthancFramework/Sources/DicomParsing/IDicomTranscoder.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/IDicomTranscoder.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/IDicomTranscoder.h --- a/OrthancFramework/Sources/DicomParsing/IDicomTranscoder.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/IDicomTranscoder.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/ITagVisitor.h --- a/OrthancFramework/Sources/DicomParsing/ITagVisitor.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ITagVisitor.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/Internals/DicomFrameIndex.cpp --- a/OrthancFramework/Sources/DicomParsing/Internals/DicomFrameIndex.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/Internals/DicomFrameIndex.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/Internals/DicomFrameIndex.h --- a/OrthancFramework/Sources/DicomParsing/Internals/DicomFrameIndex.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/Internals/DicomFrameIndex.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp --- a/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -644,6 +645,51 @@ } + static ImageAccessor* DecodePlanarConfiguration(const ImageAccessor& source) + { + /** + * This function will interleave the RGB channels, if the source + * DICOM image has the "Planar Configuration" (0028,0006) tag that + * equals 1. This process was not applied to images using the RLE + * codec, which led to the following issue: + * https://groups.google.com/g/orthanc-users/c/CSVWfRasSR0/m/y1XDRXVnAgAJ + **/ + + const unsigned int height = source.GetHeight(); + const unsigned int width = source.GetWidth(); + const size_t size = static_cast(height) * static_cast(width); + + if (source.GetFormat() != PixelFormat_RGB24 || + 3 * width != source.GetPitch()) + { + throw OrthancException(ErrorCode_NotImplemented); + } + + std::unique_ptr target(new Image(PixelFormat_RGB24, width, height, false)); + + const uint8_t* red = reinterpret_cast(source.GetConstBuffer()); + const uint8_t* green = red + size; + const uint8_t* blue = red + 2 * size; + + for (unsigned int y = 0; y < height; y++) + { + uint8_t* interleaved = reinterpret_cast(target->GetRow(y)); + for (unsigned int x = 0; x < width; x++) + { + interleaved[0] = *red; + interleaved[1] = *green; + interleaved[2] = *blue; + interleaved += 3; + red++; + green++; + blue++; + } + } + + return target.release(); + } + + ImageAccessor* DicomImageDecoder::ApplyCodec (const DcmCodec& codec, const DcmCodecParameter& parameters, @@ -700,7 +746,25 @@ "Cannot decode a non-palette image"); } - return target.release(); + std::string colorModel = Orthanc::Toolbox::StripSpaces(decompressedColorModel.c_str()); + + if (target->GetFormat() == PixelFormat_RGB24 && + (colorModel == "RGB" || colorModel == "YBR_FULL") && + info.IsPlanar()) + { + std::unique_ptr output(DecodePlanarConfiguration(*target)); + + if (colorModel == "YBR_FULL") + { + ImageProcessing::ConvertJpegYCbCrToRgb(*output); + } + + return output.release(); + } + else + { + return target.release(); + } } } @@ -885,12 +949,12 @@ { throw OrthancException(ErrorCode_NotImplemented, "The built-in DCMTK decoder cannot decode some DICOM instance " - "whose transfer syntax is: " + std::string(GetTransferSyntaxUid(s))); + "whose transfer syntax is: " + std::string(GetTransferSyntaxUid(s)), false /* don't log here*/); } else { throw OrthancException(ErrorCode_NotImplemented, - "The built-in DCMTK decoder cannot decode some DICOM instance"); + "The built-in DCMTK decoder cannot decode some DICOM instance", false /* don't log here*/); } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.h --- a/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/Internals/DicomImageDecoder.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.cpp --- a/OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.h --- a/OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/MemoryBufferTranscoder.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/ParsedDicomCache.cpp --- a/OrthancFramework/Sources/DicomParsing/ParsedDicomCache.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomCache.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/ParsedDicomCache.h --- a/OrthancFramework/Sources/DicomParsing/ParsedDicomCache.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomCache.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/ParsedDicomDir.cpp --- a/OrthancFramework/Sources/DicomParsing/ParsedDicomDir.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomDir.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/ParsedDicomDir.h --- a/OrthancFramework/Sources/DicomParsing/ParsedDicomDir.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomDir.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp --- a/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -76,6 +77,7 @@ #include "Internals/DicomImageDecoder.h" #include "ToDcmtkBridge.h" +#include "../DicomFormat/DicomImageInformation.h" #include "../Images/Image.h" #include "../Images/ImageProcessing.h" #include "../Images/PamReader.h" @@ -920,7 +922,7 @@ * equals the empty string, then proceed. In Orthanc <= 1.5.6, * an exception "Bad file format" was generated. * https://groups.google.com/d/msg/orthanc-users/aphG_h1AHVg/rfOTtTPTAgAJ - * https://hg.orthanc-server.com/orthanc/rev/4c45e018bd3de3cfa21d6efc6734673aaaee4435 + * https://orthanc.uclouvain.be/hg/orthanc/rev/4c45e018bd3de3cfa21d6efc6734673aaaee4435 **/ patientId.clear(); } @@ -938,9 +940,10 @@ void ParsedDicomFile::SaveToMemoryBuffer(std::string& buffer) { - if (!FromDcmtkBridge::SaveToMemoryBuffer(buffer, *GetDcmtkObject().getDataset())) + std::string errorMessage; + if (!FromDcmtkBridge::SaveToMemoryBuffer(buffer, *GetDcmtkObject().getDataset(), errorMessage)) { - throw OrthancException(ErrorCode_InternalError, "Cannot write DICOM file to memory"); + throw OrthancException(ErrorCode_InternalError, "Cannot write DICOM file to memory, DCMTK error: " + errorMessage); } } @@ -1003,6 +1006,10 @@ { SetEncoding(encoding); } + else if (permissive) + { + SetEncoding(defaultEncoding); + } else { throw OrthancException(ErrorCode_ParameterOutOfRange, @@ -1202,7 +1209,42 @@ break; case MimeType_Pdf: - EmbedPdf(content); + { + if (content.size() < 5 || // (*) + strncmp("%PDF-", content.c_str(), 5) != 0) + { + throw OrthancException(ErrorCode_BadFileFormat, "Not a PDF file"); + } + + EncapsulateDocument(MimeType_Pdf, content); + + // In Orthanc <= 1.9.7, the "Modality" would have always be overwritten as "OT" + // https://groups.google.com/g/orthanc-users/c/eNSddNrQDtM/m/wc1HahimAAAJ + + SetIfAbsent(DICOM_TAG_SOP_CLASS_UID, UID_EncapsulatedPDFStorage); + SetIfAbsent(DICOM_TAG_MODALITY, "OT"); + SetIfAbsent(FromDcmtkBridge::Convert(DCM_ConversionType), "WSD"); + //SetIfAbsent(FromDcmtkBridge::Convert(DCM_SeriesNumber), "1"); + + break; + } + + case MimeType_Mtl: + EncapsulateDocument(mime, content); + SetIfAbsent(DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.104.5"); + SetIfAbsent(DICOM_TAG_MODALITY, "M3D"); + break; + + case MimeType_Obj: + EncapsulateDocument(mime, content); + SetIfAbsent(DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.104.4"); + SetIfAbsent(DICOM_TAG_MODALITY, "M3D"); + break; + + case MimeType_Stl: + EncapsulateDocument(mime, content); + SetIfAbsent(DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.104.3"); + SetIfAbsent(DICOM_TAG_MODALITY, "M3D"); break; default: @@ -1525,28 +1567,16 @@ } - void ParsedDicomFile::EmbedPdf(const std::string& pdf) + void ParsedDicomFile::EncapsulateDocument(MimeType mime, + const std::string& document) { - if (pdf.size() < 5 || // (*) - strncmp("%PDF-", pdf.c_str(), 5) != 0) - { - throw OrthancException(ErrorCode_BadFileFormat, "Not a PDF file"); - } - InvalidateCache(); - // In Orthanc <= 1.9.7, the "Modality" would have always be overwritten as "OT" - // https://groups.google.com/g/orthanc-users/c/eNSddNrQDtM/m/wc1HahimAAAJ - - ReplacePlainString(DICOM_TAG_SOP_CLASS_UID, UID_EncapsulatedPDFStorage); - SetIfAbsent(FromDcmtkBridge::Convert(DCM_Modality), "OT"); - SetIfAbsent(FromDcmtkBridge::Convert(DCM_ConversionType), "WSD"); - SetIfAbsent(FromDcmtkBridge::Convert(DCM_MIMETypeOfEncapsulatedDocument), MIME_PDF); - //SetIfAbsent(FromDcmtkBridge::Convert(DCM_SeriesNumber), "1"); + ReplacePlainString(FromDcmtkBridge::Convert(DCM_MIMETypeOfEncapsulatedDocument), EnumerationToString(mime)); std::unique_ptr element(new DcmPolymorphOBOW(DCM_EncapsulatedDocument)); - size_t s = pdf.size(); + size_t s = document.size(); if (s & 1) { // The size of the buffer must be even @@ -1560,10 +1590,12 @@ throw OrthancException(ErrorCode_NotEnoughMemory); } - // Blank pad byte (no access violation, as "pdf.size() >= 5" because of (*) ) - bytes[s - 1] = 0; + if (s > 0) + { + bytes[s - 1] = 0; + } - memcpy(bytes, pdf.c_str(), pdf.size()); + memcpy(bytes, document.c_str(), document.size()); DcmPolymorphOBOW* obj = element.release(); result = GetDcmtkObject().getDataset()->insert(obj); @@ -2121,6 +2153,84 @@ } } + + void ParsedDicomFile::InjectEmptyPixelData(ValueRepresentation vr) + { + DcmItem& dataset = *GetDcmtkObject().getDataset(); + + DcmElement *element = NULL; + if (!dataset.findAndGetElement(DCM_PixelData, element).good() || + element == NULL) + { + // The pixel data is indeed nonexistent, insert it now + switch (vr) + { + case ValueRepresentation_OtherByte: + if (!dataset.putAndInsertUint8Array(DCM_PixelData, NULL, 0).good()) + { + throw OrthancException(ErrorCode_InternalError); + } + break; + + case ValueRepresentation_OtherWord: + if (!dataset.putAndInsertUint16Array(DCM_PixelData, NULL, 0).good()) + { + throw OrthancException(ErrorCode_InternalError); + } + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + } + + + void ParsedDicomFile::RemoveFromPixelData() + { + DcmItem& dataset = *GetDcmtkObject().getDataset(); + + // We need to go backward, otherwise "dataset.card()" is invalidated + for (unsigned long i = dataset.card(); i > 0; i--) + { + DcmElement* element = dataset.getElement(i - 1); + if (element == NULL) + { + throw OrthancException(ErrorCode_InternalError); + } + + if (element->getTag().getGroup() > DCM_PixelData.getGroup() || + (element->getTag().getGroup() == DCM_PixelData.getGroup() && + element->getTag().getElement() >= DCM_PixelData.getElement())) + { + std::unique_ptr removal(dataset.remove(i - 1)); + } + } + } + + + ValueRepresentation ParsedDicomFile::GuessPixelDataValueRepresentation() const + { + DicomTransferSyntax ts; + if (LookupTransferSyntax(ts)) + { + DcmItem& dataset = *GetDcmtkObjectConst().getDataset(); + + uint16_t bitsAllocated; + if (!dataset.findAndGetUint16(DCM_BitsAllocated, bitsAllocated).good()) + { + bitsAllocated = 8; + } + + return DicomImageInformation::GuessPixelDataValueRepresentation(ts, bitsAllocated); + } + else + { + // Assume "OB" if the transfer syntax is unknown + return ValueRepresentation_OtherByte; + } + } + #if ORTHANC_BUILDING_FRAMEWORK_LIBRARY == 1 // Alias for binary compatibility with Orthanc Framework 1.7.2 => don't use it anymore diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h --- a/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -97,6 +98,9 @@ bool EmbedContentInternal(const std::string& dataUriScheme); + void EncapsulateDocument(MimeType mime, + const std::string& document); + // For internal use only, in order to provide const-correctness on // the top of DCMTK API DcmFileFormat& GetDcmtkObjectConst() const; @@ -205,6 +209,7 @@ void SaveToFile(const std::string& path); #endif + // This method must only be used on the PixelData and EncapsulatedDocument tags void EmbedContent(const std::string& dataUriScheme); void EmbedImage(const ImageAccessor& accessor); @@ -236,8 +241,6 @@ bool HasTag(const DicomTag& tag) const; - void EmbedPdf(const std::string& pdf); - bool ExtractPdf(std::string& pdf) const; void GetRawFrame(std::string& target, // OUT @@ -309,5 +312,12 @@ ImageAccessor* DecodeAllOverlays(int& originX, int& originY) const; + + void InjectEmptyPixelData(ValueRepresentation vr); + + // Remove all the tags after pixel data + void RemoveFromPixelData(); + + ValueRepresentation GuessPixelDataValueRepresentation() const; }; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.cpp --- a/OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.h --- a/OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/ToDcmtkBridge.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Endianness.h --- a/OrthancFramework/Sources/Endianness.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Endianness.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -144,7 +145,7 @@ * This alternative implementation only hid an underlying problem * with pointer alignment on some architectures, and was thus * reverted. Check out issue #99: - * https://bugs.orthanc-server.com/show_bug.cgi?id=99 + * https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=99 **/ return (a << 8) | (a >> 8); } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/EnumerationDictionary.h --- a/OrthancFramework/Sources/EnumerationDictionary.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/EnumerationDictionary.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -105,5 +106,10 @@ return found->second; } } + + const std::map& GetAllEntries() const + { + return stringToEnumeration_; + } }; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Enumerations.cpp --- a/OrthancFramework/Sources/Enumerations.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Enumerations.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -24,36 +25,17 @@ #include "PrecompiledHeaders.h" #include "Enumerations.h" +#include "Logging.h" +#include "MultiThreading/Mutex.h" #include "OrthancException.h" #include "Toolbox.h" -#include "Logging.h" - -#include + #include #include +#include namespace Orthanc { - static const char* const MIME_CSS = "text/css"; - static const char* const MIME_DICOM = "application/dicom"; - static const char* const MIME_GIF = "image/gif"; - static const char* const MIME_GZIP = "application/gzip"; - static const char* const MIME_HTML = "text/html"; - static const char* const MIME_JAVASCRIPT = "application/javascript"; - static const char* const MIME_JPEG2000 = "image/jp2"; - static const char* const MIME_NACL = "application/x-nacl"; - static const char* const MIME_PLAIN_TEXT = "text/plain"; - static const char* const MIME_PNACL = "application/x-pnacl"; - static const char* const MIME_SVG = "image/svg+xml"; - static const char* const MIME_WEB_ASSEMBLY = "application/wasm"; - static const char* const MIME_WOFF = "application/x-font-woff"; - static const char* const MIME_WOFF2 = "font/woff2"; - static const char* const MIME_XML_2 = "text/xml"; - static const char* const MIME_ZIP = "application/zip"; - static const char* const MIME_DICOM_WEB_JSON = "application/dicom+json"; - static const char* const MIME_DICOM_WEB_XML = "application/dicom+xml"; - static const char* const MIME_ICO = "image/x-icon"; - // This function is autogenerated by the script // "Resources/CodeGeneration/GenerateErrorCodes.py" const char* EnumerationToString(ErrorCode error) @@ -198,6 +180,12 @@ case ErrorCode_MainDicomTagsMultiplyDefined: return "A main DICOM Tag has been defined multiple times for the same resource level"; + case ErrorCode_ForbiddenAccess: + return "Access to a resource is forbidden"; + + case ErrorCode_DuplicateResource: + return "Duplicate resource"; + case ErrorCode_SQLiteNotOpened: return "SQLite: The database is not opened"; @@ -877,15 +865,15 @@ { case DicomVersion_2008: return "2008"; - break; case DicomVersion_2017c: return "2017c"; - break; case DicomVersion_2021b: return "2021b"; - break; + + case DicomVersion_2023b: + return "2023b"; default: throw OrthancException(ErrorCode_ParameterOutOfRange); @@ -1110,6 +1098,15 @@ case MimeType_Ico: return MIME_ICO; + case MimeType_Obj: + return MIME_OBJ; + + case MimeType_Mtl: + return MIME_MTL; + + case MimeType_Stl: + return MIME_STL; + default: throw OrthancException(ErrorCode_ParameterOutOfRange); } @@ -1641,6 +1638,10 @@ { return DicomVersion_2021b; } + else if (version == "2023b") + { + return DicomVersion_2023b; + } else { throw OrthancException(ErrorCode_ParameterOutOfRange, @@ -1728,8 +1729,12 @@ target = MimeType_Dicom; return true; } - else if (source == MIME_JPEG) + else if (source == MIME_JPEG || + source == "image/jpg") { + // Note the tolerance for "image/jpg", which is *not* a standard MIME type + // https://groups.google.com/g/orthanc-users/c/Y5x37UFKiDg/m/1zI260KTAwAJ + // https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types target = MimeType_Jpeg; return true; } @@ -1844,6 +1849,21 @@ target = MimeType_Ico; return true; } + else if (source == MIME_OBJ) + { + target = MimeType_Obj; + return true; + } + else if (source == MIME_MTL) + { + target = MimeType_Mtl; + return true; + } + else if (source == MIME_STL) + { + target = MimeType_Stl; + return true; + } else { return false; @@ -1929,6 +1949,11 @@ std::string s = Toolbox::StripSpaces(specificCharacterSet); Toolbox::ToUpperCase(s); + // handle common spelling mistakes + boost::replace_all(s, "ISO_IR_", "ISO_IR "); + boost::replace_all(s, "ISO_2022_IR_", "ISO 2022 IR "); + + // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.12.1.1.2 // https://github.com/dcm4che/dcm4che/blob/master/dcm4che-core/src/main/java/org/dcm4che3/data/SpecificCharacterSet.java if (s == "ISO_IR 6" || @@ -2240,6 +2265,12 @@ case ErrorCode_Revision: return HttpStatus_409_Conflict; + case ErrorCode_ForbiddenAccess: + return HttpStatus_403_Forbidden; + + case ErrorCode_DuplicateResource: + return HttpStatus_409_Conflict; + case ErrorCode_CreateDicomNotString: return HttpStatus_400_BadRequest; @@ -2333,12 +2364,12 @@ } - static boost::mutex defaultEncodingMutex_; // Should not be necessary - static Encoding defaultEncoding_ = ORTHANC_DEFAULT_DICOM_ENCODING; + static Mutex defaultEncodingMutex_; // Should not be necessary + static Encoding defaultEncoding_ = ORTHANC_DEFAULT_DICOM_ENCODING; Encoding GetDefaultDicomEncoding() { - boost::mutex::scoped_lock lock(defaultEncodingMutex_); + Mutex::ScopedLock lock(defaultEncodingMutex_); return defaultEncoding_; } @@ -2347,7 +2378,7 @@ std::string name = EnumerationToString(encoding); { - boost::mutex::scoped_lock lock(defaultEncodingMutex_); + Mutex::ScopedLock lock(defaultEncodingMutex_); defaultEncoding_ = encoding; } @@ -2444,6 +2475,21 @@ throw OrthancException(ErrorCode_InternalError); } } + + DicomTransferSyntax GetTransferSyntax(const std::string& value) + { + DicomTransferSyntax syntax; + if (LookupTransferSyntax(syntax, value)) + { + return syntax; + } + else + { + throw OrthancException(ErrorCode_ParameterOutOfRange, + "Unknown transfer syntax: " + value); + } + } + } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Enumerations.h --- a/OrthancFramework/Sources/Enumerations.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Enumerations.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -42,6 +43,32 @@ static const char* const MIME_XML = "application/xml"; static const char* const MIME_XML_UTF8 = "application/xml; charset=utf-8"; + // Added in Orthanc 1.12.1 + static const char* const MIME_OBJ = "model/obj"; + static const char* const MIME_MTL = "model/mtl"; + static const char* const MIME_STL = "model/stl"; + + static const char* const MIME_CSS = "text/css"; + static const char* const MIME_DICOM = "application/dicom"; + static const char* const MIME_GIF = "image/gif"; + static const char* const MIME_GZIP = "application/gzip"; + static const char* const MIME_HTML = "text/html"; + static const char* const MIME_JAVASCRIPT = "application/javascript"; + static const char* const MIME_JPEG2000 = "image/jp2"; + static const char* const MIME_NACL = "application/x-nacl"; + static const char* const MIME_PLAIN_TEXT = "text/plain"; + static const char* const MIME_PNACL = "application/x-pnacl"; + static const char* const MIME_SVG = "image/svg+xml"; + static const char* const MIME_WEB_ASSEMBLY = "application/wasm"; + static const char* const MIME_WOFF = "application/x-font-woff"; + static const char* const MIME_WOFF2 = "font/woff2"; + static const char* const MIME_XML_2 = "text/xml"; + static const char* const MIME_ZIP = "application/zip"; + static const char* const MIME_DICOM_WEB_JSON = "application/dicom+json"; + static const char* const MIME_DICOM_WEB_XML = "application/dicom+xml"; + static const char* const MIME_ICO = "image/x-icon"; + + /** * "No Internet Media Type (aka MIME type, content type) for PBM has * been registered with IANA, but the unofficial value @@ -79,7 +106,10 @@ MimeType_PrometheusText, // Prometheus text-based exposition format (for metrics) MimeType_DicomWebJson, MimeType_DicomWebXml, - MimeType_Ico + MimeType_Ico, + MimeType_Mtl, // MTL - New in Orthanc 1.12.1 + MimeType_Obj, // OBJ - New in Orthanc 1.12.1 + MimeType_Stl // STL - New in Orthanc 1.12.1 }; @@ -140,6 +170,8 @@ ErrorCode_DatabaseCannotSerialize = 42 /*!< Database could not serialize access due to concurrent update, the transaction should be retried */, ErrorCode_Revision = 43 /*!< A bad revision number was provided, which might indicate conflict between multiple writers */, ErrorCode_MainDicomTagsMultiplyDefined = 44 /*!< A main DICOM Tag has been defined multiple times for the same resource level */, + ErrorCode_ForbiddenAccess = 45 /*!< Access to a resource is forbidden */, + ErrorCode_DuplicateResource = 46 /*!< Duplicate resource */, ErrorCode_SQLiteNotOpened = 1000 /*!< SQLite: The database is not opened */, ErrorCode_SQLiteAlreadyOpened = 1001 /*!< SQLite: Connection is already open */, ErrorCode_SQLiteCannotOpen = 1002 /*!< SQLite: Unable to open the database */, @@ -620,7 +652,8 @@ { DicomVersion_2008, DicomVersion_2017c, - DicomVersion_2021b + DicomVersion_2021b, + DicomVersion_2023b }; enum ModalityManufacturer @@ -904,9 +937,12 @@ const std::string& uid); ORTHANC_PUBLIC + DicomTransferSyntax GetTransferSyntax(const std::string& uid); + + ORTHANC_PUBLIC const char* GetResourceTypeText(ResourceType type, bool isPlural, - bool isLowerCase); + bool isUpperCase); ORTHANC_PUBLIC void GetAllDicomTransferSyntaxes(std::set& target); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Enumerations_TransferSyntaxes.impl.h --- a/OrthancFramework/Sources/Enumerations_TransferSyntaxes.impl.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Enumerations_TransferSyntaxes.impl.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileBuffer.cpp --- a/OrthancFramework/Sources/FileBuffer.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileBuffer.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileBuffer.h --- a/OrthancFramework/Sources/FileBuffer.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileBuffer.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileStorage/FileInfo.cpp --- a/OrthancFramework/Sources/FileStorage/FileInfo.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileStorage/FileInfo.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileStorage/FileInfo.h --- a/OrthancFramework/Sources/FileStorage/FileInfo.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileStorage/FileInfo.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp --- a/OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileStorage/FilesystemStorage.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -23,6 +24,7 @@ #include "../PrecompiledHeaders.h" #include "FilesystemStorage.h" +#include // http://stackoverflow.com/questions/1576272/storing-large-number-of-files-in-file-system // http://stackoverflow.com/questions/446358/storing-a-large-number-of-images @@ -122,8 +124,9 @@ size_t size, FileContentType type) { + Toolbox::ElapsedTimer timer; LOG(INFO) << "Creating attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) - << "\" type (size: " << (size / (1024 * 1024) + 1) << "MB)"; + << "\" type"; boost::filesystem::path path; @@ -133,37 +136,69 @@ { // Extremely unlikely case: This Uuid has already been created // in the past. - throw OrthancException(ErrorCode_InternalError); + throw OrthancException(ErrorCode_InternalError, "This file UUID already exists"); } - if (boost::filesystem::exists(path.parent_path())) + // In very unlikely cases, a thread could be deleting a + // directory while another thread needs it -> introduce 3 retries at 1 ms interval + int retryCount = 0; + const int maxRetryCount = 3; + + while (retryCount < maxRetryCount) { - if (!boost::filesystem::is_directory(path.parent_path())) + retryCount++; + if (retryCount > 1) + { + boost::this_thread::sleep(boost::posix_time::milliseconds(2 * retryCount + (rand() % 10))); + LOG(INFO) << "Retrying to create attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) + << "\" type"; + } + + try + { + boost::filesystem::create_directories(path.parent_path()); // the function ensures that the directory exists or throws + } + catch (boost::filesystem::filesystem_error& er) { - throw OrthancException(ErrorCode_DirectoryOverFile); + if (er.code() == boost::system::errc::file_exists // the last element of the parent_path is a file + || er.code() == boost::system::errc::not_a_directory) // one of the element of the parent_path is not a directory + { + throw OrthancException(ErrorCode_DirectoryOverFile, "One of the element of the path is a file"); // no need to retry this error + } + + // ignore other errors and retry + } + + try + { + SystemToolbox::WriteFile(content, size, path.string(), fsyncOnWrite_); + + LOG(INFO) << "Created attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, size) << ")"; + return; + } + catch (OrthancException& ex) + { + if (retryCount >= maxRetryCount) + { + throw ex; + } } } - else - { - if (!boost::filesystem::create_directories(path.parent_path())) - { - throw OrthancException(ErrorCode_FileStorageCannotWrite); - } - } - - SystemToolbox::WriteFile(content, size, path.string(), fsyncOnWrite_); } IMemoryBuffer* FilesystemStorage::Read(const std::string& uuid, FileContentType type) { + Toolbox::ElapsedTimer timer; LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) << "\" content type"; std::string content; SystemToolbox::ReadFile(content, GetPath(uuid).string()); + LOG(INFO) << "Read attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, content.size()) << ")"; + return StringMemoryBuffer::CreateFromSwap(content); } @@ -173,6 +208,7 @@ uint64_t start /* inclusive */, uint64_t end /* exclusive */) { + Toolbox::ElapsedTimer timer; LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) << "\" content type (range from " << start << " to " << end << ")"; @@ -180,6 +216,7 @@ SystemToolbox::ReadFileRange( content, GetPath(uuid).string(), start, end, true /* throw if overflow */); + LOG(INFO) << "Read range of attachment \"" << uuid << "\" (" << timer.GetHumanTransferSpeed(true, content.size()) << ")"; return StringMemoryBuffer::CreateFromSwap(content); } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileStorage/FilesystemStorage.h --- a/OrthancFramework/Sources/FileStorage/FilesystemStorage.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileStorage/FilesystemStorage.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileStorage/IStorageArea.h --- a/OrthancFramework/Sources/FileStorage/IStorageArea.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileStorage/IStorageArea.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileStorage/MemoryStorageArea.cpp --- a/OrthancFramework/Sources/FileStorage/MemoryStorageArea.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileStorage/MemoryStorageArea.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -27,6 +28,7 @@ #include "../Logging.h" #include "../OrthancException.h" #include "../StringMemoryBuffer.h" +#include "../Toolbox.h" namespace Orthanc { @@ -47,9 +49,9 @@ FileContentType type) { LOG(INFO) << "Creating attachment \"" << uuid << "\" of \"" << static_cast(type) - << "\" type (size: " << (size / (1024 * 1024) + 1) << "MB)"; + << "\" type (size: " << Toolbox::GetHumanFileSize(size) << ")"; - boost::mutex::scoped_lock lock(mutex_); + Mutex::ScopedLock lock(mutex_); if (size != 0 && content == NULL) @@ -73,7 +75,7 @@ LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << static_cast(type) << "\" content type"; - boost::mutex::scoped_lock lock(mutex_); + Mutex::ScopedLock lock(mutex_); Content::const_iterator found = content_.find(uuid); @@ -111,7 +113,7 @@ } else { - boost::mutex::scoped_lock lock(mutex_); + Mutex::ScopedLock lock(mutex_); Content::const_iterator found = content_.find(uuid); @@ -152,7 +154,7 @@ { LOG(INFO) << "Deleting attachment \"" << uuid << "\" of type " << static_cast(type); - boost::mutex::scoped_lock lock(mutex_); + Mutex::ScopedLock lock(mutex_); Content::iterator found = content_.find(uuid); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileStorage/MemoryStorageArea.h --- a/OrthancFramework/Sources/FileStorage/MemoryStorageArea.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileStorage/MemoryStorageArea.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -26,8 +27,8 @@ #include "IStorageArea.h" #include "../Compatibility.h" // For ORTHANC_OVERRIDE +#include "../MultiThreading/Mutex.h" -#include #include namespace Orthanc @@ -37,8 +38,8 @@ private: typedef std::map Content; - boost::mutex mutex_; - Content content_; + Mutex mutex_; + Content content_; public: virtual ~MemoryStorageArea(); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileStorage/StorageAccessor.cpp --- a/OrthancFramework/Sources/FileStorage/StorageAccessor.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileStorage/StorageAccessor.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -38,9 +39,13 @@ #endif -static const std::string METRICS_CREATE = "orthanc_storage_create_duration_ms"; -static const std::string METRICS_READ = "orthanc_storage_read_duration_ms"; -static const std::string METRICS_REMOVE = "orthanc_storage_remove_duration_ms"; +static const std::string METRICS_CREATE_DURATION = "orthanc_storage_create_duration_ms"; +static const std::string METRICS_READ_DURATION = "orthanc_storage_read_duration_ms"; +static const std::string METRICS_REMOVE_DURATION = "orthanc_storage_remove_duration_ms"; +static const std::string METRICS_READ_BYTES = "orthanc_storage_read_bytes"; +static const std::string METRICS_WRITTEN_BYTES = "orthanc_storage_written_bytes"; +static const std::string METRICS_CACHE_HIT_COUNT = "orthanc_storage_cache_hit_count"; +static const std::string METRICS_CACHE_MISS_COUNT = "orthanc_storage_cache_miss_count"; namespace Orthanc @@ -62,18 +67,36 @@ }; - StorageAccessor::StorageAccessor(IStorageArea &area, StorageCache* cache) : + StorageAccessor::StorageAccessor(IStorageArea& area) : area_(area), - cache_(cache), + cache_(NULL), + metrics_(NULL) + { + } + + + StorageAccessor::StorageAccessor(IStorageArea& area, + StorageCache& cache) : + area_(area), + cache_(&cache), metrics_(NULL) { } - StorageAccessor::StorageAccessor(IStorageArea &area, - StorageCache* cache, - MetricsRegistry &metrics) : + + StorageAccessor::StorageAccessor(IStorageArea& area, + MetricsRegistry& metrics) : area_(area), - cache_(cache), + cache_(NULL), + metrics_(&metrics) + { + } + + StorageAccessor::StorageAccessor(IStorageArea& area, + StorageCache& cache, + MetricsRegistry& metrics) : + area_(area), + cache_(&cache), metrics_(&metrics) { } @@ -99,13 +122,20 @@ { case CompressionType_None: { - MetricsTimer timer(*this, METRICS_CREATE); + { + MetricsTimer timer(*this, METRICS_CREATE_DURATION); + area_.CreateInstance(customData, instance, uuid, data, size, type, false); + } - area_.CreateInstance(customData, instance, uuid, data, size, type, false); + if (metrics_ != NULL) + { + metrics_->IncrementIntegerValue(METRICS_WRITTEN_BYTES, size); + } if (cache_ != NULL) { - cache_->Add(uuid, type, data, size); + StorageCache::Accessor cacheAccessor(*cache_); + cacheAccessor.Add(uuid, type, data, size); } return FileInfo(uuid, type, size, md5, customData); @@ -126,7 +156,7 @@ } { - MetricsTimer timer(*this, METRICS_CREATE); + MetricsTimer timer(*this, METRICS_CREATE_DURATION); if (compressed.size() > 0) { @@ -138,9 +168,15 @@ } } + if (metrics_ != NULL) + { + metrics_->IncrementIntegerValue(METRICS_WRITTEN_BYTES, compressed.size()); + } + if (cache_ != NULL) { - cache_->Add(uuid, type, data, size); // always add uncompressed data to cache + StorageCache::Accessor cacheAccessor(*cache_); + cacheAccessor.Add(uuid, type, data, size); // always add uncompressed data to cache } return FileInfo(uuid, type, size, md5, @@ -173,15 +209,23 @@ { case CompressionType_None: { - MetricsTimer timer(*this, METRICS_CREATE); - - area_.CreateAttachment(customData, resourceId, resourceType, uuid, data, size, type, false); + { + MetricsTimer timer(*this, METRICS_CREATE_DURATION); + area_.CreateAttachment(customData, resourceId, resourceType, uuid, data, size, type, false); + } + + if (metrics_ != NULL) + { + metrics_->IncrementIntegerValue(METRICS_WRITTEN_BYTES, size); + } if (cache_ != NULL) { - cache_->Add(uuid, type, data, size); + StorageCache::Accessor cacheAccessor(*cache_); + cacheAccessor.Add(uuid, type, data, size); } + return FileInfo(uuid, type, size, md5, customData); } @@ -200,7 +244,7 @@ } { - MetricsTimer timer(*this, METRICS_CREATE); + MetricsTimer timer(*this, METRICS_CREATE_DURATION); if (compressed.size() > 0) { @@ -212,9 +256,15 @@ } } + if (metrics_ != NULL) + { + metrics_->IncrementIntegerValue(METRICS_WRITTEN_BYTES, compressed.size()); + } + if (cache_ != NULL) { - cache_->Add(uuid, type, data, size); // always add uncompressed data to cache + StorageCache::Accessor cacheAccessor(*cache_); + cacheAccessor.Add(uuid, type, data, size); // always add uncompressed data to cache } return FileInfo(uuid, type, size, md5, @@ -230,46 +280,81 @@ void StorageAccessor::Read(std::string& content, const FileInfo& info) { - if (cache_ == NULL || - !cache_->Fetch(content, info.GetUuid(), info.GetContentType())) + if (cache_ == NULL) { - switch (info.GetCompressionType()) + ReadWholeInternal(content, info); + } + else + { + StorageCache::Accessor cacheAccessor(*cache_); + + if (!cacheAccessor.Fetch(content, info.GetUuid(), info.GetContentType())) { - case CompressionType_None: + if (metrics_ != NULL) { - MetricsTimer timer(*this, METRICS_READ); - std::unique_ptr buffer(area_.Read(info.GetUuid(), info.GetContentType(), info.GetCustomData())); - buffer->MoveToString(content); - - break; + metrics_->IncrementIntegerValue(METRICS_CACHE_MISS_COUNT, 1); } - case CompressionType_ZlibWithSize: - { - ZlibCompressor zlib; + ReadWholeInternal(content, info); + + // always store the uncompressed data in cache + cacheAccessor.Add(info.GetUuid(), info.GetContentType(), content); + } + else if (metrics_ != NULL) + { + metrics_->IncrementIntegerValue(METRICS_CACHE_HIT_COUNT, 1); + } + } + } - std::unique_ptr compressed; - - { - MetricsTimer timer(*this, METRICS_READ); - compressed.reset(area_.Read(info.GetUuid(), info.GetContentType(), info.GetCustomData())); - } - - zlib.Uncompress(content, compressed->GetData(), compressed->GetSize()); + void StorageAccessor::ReadWholeInternal(std::string& content, + const FileInfo& info) + { + switch (info.GetCompressionType()) + { + case CompressionType_None: + { + std::unique_ptr buffer; - break; + { + MetricsTimer timer(*this, METRICS_READ_DURATION); + buffer.reset(area_.Read(info.GetUuid(), info.GetContentType(), info.GetCustomData())); } - default: + if (metrics_ != NULL) { - throw OrthancException(ErrorCode_NotImplemented); + metrics_->IncrementIntegerValue(METRICS_READ_BYTES, buffer->GetSize()); } + + buffer->MoveToString(content); + + break; } - // always store the uncompressed data in cache - if (cache_ != NULL) + case CompressionType_ZlibWithSize: { - cache_->Add(info.GetUuid(), info.GetContentType(), content); + ZlibCompressor zlib; + + std::unique_ptr compressed; + + { + MetricsTimer timer(*this, METRICS_READ_DURATION); + compressed.reset(area_.Read(info.GetUuid(), info.GetContentType(), info.GetCustomData())); + } + + if (metrics_ != NULL) + { + metrics_->IncrementIntegerValue(METRICS_READ_BYTES, compressed->GetSize()); + } + + zlib.Uncompress(content, compressed->GetData(), compressed->GetSize()); + + break; + } + + default: + { + throw OrthancException(ErrorCode_NotImplemented); } } @@ -280,12 +365,48 @@ void StorageAccessor::ReadRaw(std::string& content, const FileInfo& info) { - if (cache_ == NULL || !cache_->Fetch(content, info.GetUuid(), info.GetContentType())) + if (cache_ == NULL || info.GetCompressionType() != CompressionType_None) { - MetricsTimer timer(*this, METRICS_READ); - std::unique_ptr buffer(area_.Read(info.GetUuid(), info.GetContentType(), info.GetCustomData())); - buffer->MoveToString(content); + ReadRawInternal(content, info); } + else + {// use the cache only if the data is uncompressed. + StorageCache::Accessor cacheAccessor(*cache_); + + if (!cacheAccessor.Fetch(content, info.GetUuid(), info.GetContentType())) + { + if (metrics_ != NULL) + { + metrics_->IncrementIntegerValue(METRICS_CACHE_MISS_COUNT, 1); + } + + ReadRawInternal(content, info); + + cacheAccessor.Add(info.GetUuid(), info.GetContentType(), content); + } + else if (metrics_ != NULL) + { + metrics_->IncrementIntegerValue(METRICS_CACHE_HIT_COUNT, 1); + } + } + } + + void StorageAccessor::ReadRawInternal(std::string& content, + const FileInfo& info) + { + std::unique_ptr buffer; + + { + MetricsTimer timer(*this, METRICS_READ_DURATION); + buffer.reset(area_.Read(info.GetUuid(), info.GetContentType(), info.GetCustomData())); + } + + if (metrics_ != NULL) + { + metrics_->IncrementIntegerValue(METRICS_READ_BYTES, buffer->GetSize()); + } + + buffer->MoveToString(content); } @@ -299,7 +420,7 @@ } { - MetricsTimer timer(*this, METRICS_REMOVE); + MetricsTimer timer(*this, METRICS_REMOVE_DURATION); area_.Remove(fileUuid, type, customData); } } @@ -311,26 +432,84 @@ } + void ReadStartRangeFromAreaInternal(std::string& target, + IStorageArea& area, + const std::string& fileUuid, + FileContentType contentType, + uint64_t end /* exclusive */) + { + + } + void StorageAccessor::ReadStartRange(std::string& target, - const std::string& fileUuid, - FileContentType contentType, - uint64_t end /* exclusive */, - const std::string& customData) + const FileInfo& info, + uint64_t end /* exclusive */) { - if (cache_ == NULL || !cache_->FetchStartRange(target, fileUuid, contentType, end)) + if (cache_ == NULL) + { + ReadStartRangeInternal(target, info, end); + } + else { - MetricsTimer timer(*this, METRICS_READ); - std::unique_ptr buffer(area_.ReadRange(fileUuid, contentType, 0, end, customData)); - assert(buffer->GetSize() == end); - buffer->MoveToString(target); + StorageCache::Accessor accessorStartRange(*cache_); + if (!accessorStartRange.FetchStartRange(target, info.GetUuid(), info.GetContentType(), end)) + { + // the start range is not in cache, let's check if the whole file is + StorageCache::Accessor accessorWhole(*cache_); + if (!accessorWhole.Fetch(target, info.GetUuid(), info.GetContentType())) + { + if (metrics_ != NULL) + { + metrics_->IncrementIntegerValue(METRICS_CACHE_MISS_COUNT, 1); + } - if (cache_ != NULL) + // if nothing is in the cache, let's read and cache only the start + ReadStartRangeInternal(target, info, end); + accessorStartRange.AddStartRange(info.GetUuid(), info.GetContentType(), target); + } + else + { + if (metrics_ != NULL) + { + metrics_->IncrementIntegerValue(METRICS_CACHE_HIT_COUNT, 1); + } + + // we have read the whole file, check size and resize if needed + if (target.size() < end) + { + throw OrthancException(ErrorCode_CorruptedFile); + } + + target.resize(end); + } + } + else if (metrics_ != NULL) { - cache_->AddStartRange(fileUuid, contentType, target); + metrics_->IncrementIntegerValue(METRICS_CACHE_HIT_COUNT, 1); } } } + void StorageAccessor::ReadStartRangeInternal(std::string& target, + const FileInfo& info, + uint64_t end /* exclusive */) + { + std::unique_ptr buffer; + + { + MetricsTimer timer(*this, METRICS_READ_DURATION); + buffer.reset(area_.ReadRange(info.GetUuid(), info.GetContentType(), 0, end, info.GetCustomData())); + assert(buffer->GetSize() == end); + } + + if (metrics_ != NULL) + { + metrics_->IncrementIntegerValue(METRICS_READ_BYTES, buffer->GetSize()); + } + + buffer->MoveToString(target); + } + #if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 void StorageAccessor::SetupSender(BufferHttpSender& sender, diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileStorage/StorageAccessor.h --- a/OrthancFramework/Sources/FileStorage/StorageAccessor.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileStorage/StorageAccessor.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -78,11 +79,16 @@ #endif public: - explicit StorageAccessor(IStorageArea& area, - StorageCache* cache); + explicit StorageAccessor(IStorageArea& area); StorageAccessor(IStorageArea& area, - StorageCache* cache, + StorageCache& cache); + + StorageAccessor(IStorageArea& area, + MetricsRegistry& metrics); + + StorageAccessor(IStorageArea& area, + StorageCache& cache, MetricsRegistry& metrics); // FileInfo Write(const void* data, @@ -134,10 +140,8 @@ const FileInfo& info); void ReadStartRange(std::string& target, - const std::string& fileUuid, - FileContentType fullFileContentType, - uint64_t end /* exclusive */, - const std::string& customData); + const FileInfo& info, + uint64_t end /* exclusive */); void Remove(const std::string& fileUuid, FileContentType type, @@ -172,5 +176,17 @@ // size_t size, // FileContentType type, // bool compression); + + private: + void ReadStartRangeInternal(std::string& target, + const FileInfo& info, + uint64_t end /* exclusive */); + + void ReadWholeInternal(std::string& content, + const FileInfo& info); + + void ReadRawInternal(std::string& content, + const FileInfo& info); + }; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileStorage/StorageCache.cpp --- a/OrthancFramework/Sources/FileStorage/StorageCache.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileStorage/StorageCache.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -38,65 +39,91 @@ { return uuid + ":" + boost::lexical_cast(contentType) + ":1"; } - + + static std::string GetCacheKeyStartRange(const std::string& uuid, FileContentType contentType) { return uuid + ":" + boost::lexical_cast(contentType) + ":0"; } - + + + static std::string GetCacheKeyTranscodedInstance(const std::string& uuid, + DicomTransferSyntax transferSyntax) + { + return uuid + ":ts:" + GetTransferSyntaxUid(transferSyntax); + } + + void StorageCache::SetMaximumSize(size_t size) { cache_.SetMaximumSize(size); } - void StorageCache::Add(const std::string& uuid, - FileContentType contentType, - const std::string& value) - { - const std::string key = GetCacheKeyFullFile(uuid, contentType); - cache_.Add(key, value); - } - - - void StorageCache::Add(const std::string& uuid, - FileContentType contentType, - const void* buffer, - size_t size) - { - const std::string key = GetCacheKeyFullFile(uuid, contentType); - cache_.Add(key, buffer, size); - } - - - void StorageCache::AddStartRange(const std::string& uuid, - FileContentType contentType, - const std::string& value) - { - const std::string key = GetCacheKeyStartRange(uuid, contentType); - cache_.Add(key, value); - } - - void StorageCache::Invalidate(const std::string& uuid, FileContentType contentType) { - // invalidate both full file + start range file + std::set transferSyntaxes; + + { + boost::mutex::scoped_lock lock(subKeysMutex_); + transferSyntaxes = subKeysTransferSyntax_; + } + + // invalidate full file, start range file and possible transcoded instances const std::string keyFullFile = GetCacheKeyFullFile(uuid, contentType); cache_.Invalidate(keyFullFile); const std::string keyPartialFile = GetCacheKeyStartRange(uuid, contentType); cache_.Invalidate(keyPartialFile); + + for (std::set::const_iterator it = transferSyntaxes.begin(); it != transferSyntaxes.end(); ++it) + { + const std::string keyTransferSyntax = GetCacheKeyTranscodedInstance(uuid, *it); + cache_.Invalidate(keyTransferSyntax); + } } - + + + StorageCache::Accessor::Accessor(StorageCache& cache) + : MemoryStringCache::Accessor(cache.cache_), + storageCache_(cache) + { + } - bool StorageCache::Fetch(std::string& value, - const std::string& uuid, - FileContentType contentType) + void StorageCache::Accessor::Add(const std::string& uuid, + FileContentType contentType, + const std::string& value) + { + + std::string key = GetCacheKeyFullFile(uuid, contentType); + MemoryStringCache::Accessor::Add(key, value); + } + + void StorageCache::Accessor::AddStartRange(const std::string& uuid, + FileContentType contentType, + const std::string& value) + { + const std::string key = GetCacheKeyStartRange(uuid, contentType); + MemoryStringCache::Accessor::Add(key, value); + } + + void StorageCache::Accessor::Add(const std::string& uuid, + FileContentType contentType, + const void* buffer, + size_t size) { const std::string key = GetCacheKeyFullFile(uuid, contentType); - if (cache_.Fetch(value, key)) + MemoryStringCache::Accessor::Add(key, reinterpret_cast(buffer), size); + } + + bool StorageCache::Accessor::Fetch(std::string& value, + const std::string& uuid, + FileContentType contentType) + { + const std::string key = GetCacheKeyFullFile(uuid, contentType); + if (MemoryStringCache::Accessor::Fetch(value, key)) { LOG(INFO) << "Read attachment \"" << uuid << "\" with content type " << boost::lexical_cast(contentType) << " from cache"; @@ -108,14 +135,44 @@ } } - bool StorageCache::FetchStartRange(std::string& value, - const std::string& uuid, - FileContentType contentType, - uint64_t end) + bool StorageCache::Accessor::FetchTranscodedInstance(std::string& value, + const std::string& uuid, + DicomTransferSyntax targetSyntax) { - // first try to get the start of file only from cache + const std::string key = GetCacheKeyTranscodedInstance(uuid, targetSyntax); + if (MemoryStringCache::Accessor::Fetch(value, key)) + { + LOG(INFO) << "Read instance \"" << uuid << "\" transcoded to " + << GetTransferSyntaxUid(targetSyntax) << " from cache"; + return true; + } + else + { + return false; + } + } + + void StorageCache::Accessor::AddTranscodedInstance(const std::string& uuid, + DicomTransferSyntax targetSyntax, + const void* buffer, + size_t size) + { + { + boost::mutex::scoped_lock lock(storageCache_.subKeysMutex_); + storageCache_.subKeysTransferSyntax_.insert(targetSyntax); + } + + const std::string key = GetCacheKeyTranscodedInstance(uuid, targetSyntax); + MemoryStringCache::Accessor::Add(key, reinterpret_cast(buffer), size); + } + + bool StorageCache::Accessor::FetchStartRange(std::string& value, + const std::string& uuid, + FileContentType contentType, + uint64_t end /* exclusive */) + { const std::string keyPartialFile = GetCacheKeyStartRange(uuid, contentType); - if (cache_.Fetch(value, keyPartialFile) && value.size() >= end) + if (MemoryStringCache::Accessor::Fetch(value, keyPartialFile) && value.size() >= end) { if (value.size() > end) // the start range that has been cached is larger than the requested value { @@ -126,23 +183,19 @@ << boost::lexical_cast(contentType) << " from cache"; return true; } - else - { - // try to get the full file from cache - if (Fetch(value, uuid, contentType)) - { - if (value.size() < end) - { - throw OrthancException(ErrorCode_CorruptedFile); - } + + return false; + } + - value.resize(end); - return true; - } - else - { - return false; - } - } + size_t StorageCache::GetCurrentSize() const + { + return cache_.GetCurrentSize(); } + + size_t StorageCache::GetNumberOfItems() const + { + return cache_.GetNumberOfItems(); + } + } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/FileStorage/StorageCache.h --- a/OrthancFramework/Sources/FileStorage/StorageCache.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/FileStorage/StorageCache.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -37,12 +38,67 @@ **/ class ORTHANC_PUBLIC StorageCache : public boost::noncopyable { + public: + + // The StorageCache is only accessible through this accessor. + // It will make sure that only one user will fill load data and fill + // the cache if multiple users try to access the same item at the same time. + // This scenario happens a lot when multiple workers from a viewer access + // the same file. + class Accessor : public MemoryStringCache::Accessor + { + StorageCache& storageCache_; + public: + explicit Accessor(StorageCache& cache); + + void Add(const std::string& uuid, + FileContentType contentType, + const std::string& value); + + void AddStartRange(const std::string& uuid, + FileContentType contentType, + const std::string& value); + + void Add(const std::string& uuid, + FileContentType contentType, + const void* buffer, + size_t size); + + bool Fetch(std::string& value, + const std::string& uuid, + FileContentType contentType); + + bool FetchStartRange(std::string& value, + const std::string& uuid, + FileContentType contentType, + uint64_t end /* exclusive */); + + bool FetchTranscodedInstance(std::string& value, + const std::string& uuid, + DicomTransferSyntax targetSyntax); + + void AddTranscodedInstance(const std::string& uuid, + DicomTransferSyntax targetSyntax, + const void* buffer, + size_t size); + }; + private: - MemoryStringCache cache_; - + MemoryStringCache cache_; + std::set subKeysTransferSyntax_; + boost::mutex subKeysMutex_; + public: void SetMaximumSize(size_t size); + void Invalidate(const std::string& uuid, + FileContentType contentType); + + size_t GetCurrentSize() const; + + size_t GetNumberOfItems() const; + + private: void Add(const std::string& uuid, FileContentType contentType, const std::string& value); @@ -56,9 +112,6 @@ const void* buffer, size_t size); - void Invalidate(const std::string& uuid, - FileContentType contentType); - bool Fetch(std::string& value, const std::string& uuid, FileContentType contentType); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpClient.cpp --- a/OrthancFramework/Sources/HttpClient.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpClient.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -46,7 +47,7 @@ extern "C" { - static CURLcode GetHttpStatus(CURLcode code, CURL* curl, long* status) + static CURLcode GetHttpStatus(CURLcode code, CURL* curl, long* status, const std::string& url) { if (code == CURLE_OK) { @@ -55,8 +56,6 @@ } else { - LOG(ERROR) << "Error code " << static_cast(code) - << " in libcurl: " << curl_easy_strerror(code); *status = 0; return code; } @@ -68,10 +67,10 @@ #if defined(__GNUC__) || defined(__clang__) __attribute__((noinline)) #endif -static CURLcode OrthancHttpClientPerformSSL(CURL* curl, long* status) +static CURLcode OrthancHttpClientPerformSSL(CURL* curl, long* status, const std::string& url) { #if ORTHANC_ENABLE_SSL == 1 - return GetHttpStatus(curl_easy_perform(curl), curl, status); + return GetHttpStatus(curl_easy_perform(curl), curl, status, url); #else throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Orthanc was compiled without SSL support, " @@ -101,6 +100,24 @@ return code; } + static CURLcode CheckCode(CURLcode code, const std::string& url) + { + if (code == CURLE_NOT_BUILT_IN) + { + throw OrthancException(ErrorCode_InternalError, + "Your libcurl does not contain a required feature, " + "please recompile Orthanc with -DUSE_SYSTEM_CURL=OFF"); + } + + if (code != CURLE_OK) + { + throw OrthancException(ErrorCode_NetworkProtocol, + "libCURL error: " + std::string(curl_easy_strerror(code)) + " while accessing " + url); + } + + return code; + } + // RAII pattern around a "curl_slist" class HttpClient::CurlHeaders : public boost::noncopyable @@ -666,7 +683,7 @@ SetPkcs11Enabled(service.IsPkcs11Enabled()); - SetUrl(service.GetUrl() + uri); + SetUrl(Toolbox::JoinUri(service.GetUrl(), uri)); for (WebServiceParameters::Dictionary::const_iterator it = service.GetHttpHeaders().begin(); @@ -1045,11 +1062,11 @@ if (boost::starts_with(url_, "https://")) { - code = OrthancHttpClientPerformSSL(pimpl_->curl_, &status); + code = OrthancHttpClientPerformSSL(pimpl_->curl_, &status, url_); } else { - code = GetHttpStatus(curl_easy_perform(pimpl_->curl_), pimpl_->curl_, &status); + code = GetHttpStatus(curl_easy_perform(pimpl_->curl_), pimpl_->curl_, &status, url_); } const boost::posix_time::ptime end = boost::posix_time::microsec_clock::universal_time(); @@ -1063,7 +1080,7 @@ CLOG(INFO, HTTP) << "cURL status code: " << code; } - CheckCode(code); + CheckCode(code, url_); // throws on HTTP error if (status == 0) { diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpClient.h --- a/OrthancFramework/Sources/HttpClient.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpClient.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/BufferHttpSender.cpp --- a/OrthancFramework/Sources/HttpServer/BufferHttpSender.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/BufferHttpSender.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/BufferHttpSender.h --- a/OrthancFramework/Sources/HttpServer/BufferHttpSender.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/BufferHttpSender.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/CStringMatcher.cpp --- a/OrthancFramework/Sources/HttpServer/CStringMatcher.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/CStringMatcher.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/CStringMatcher.h --- a/OrthancFramework/Sources/HttpServer/CStringMatcher.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/CStringMatcher.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.cpp --- a/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -153,7 +154,7 @@ { FilesystemHttpSender sender(p); sender.SetContentType(SystemToolbox::AutodetectMimeType(p.string())); - output.Answer(sender); // TODO COMPRESSION + output.Answer(sender); } else if (listDirectoryContent_ && fs::exists(p) && diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.h --- a/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/FilesystemHttpSender.cpp --- a/OrthancFramework/Sources/HttpServer/FilesystemHttpSender.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpSender.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/FilesystemHttpSender.h --- a/OrthancFramework/Sources/HttpServer/FilesystemHttpSender.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpSender.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/HttpContentNegociation.cpp --- a/OrthancFramework/Sources/HttpServer/HttpContentNegociation.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpContentNegociation.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -49,28 +50,68 @@ { return true; } - - if (subtype == "*" && type == type_) + else if (subtype == "*" && type == type_) { return true; } - - return type == type_ && subtype == subtype_; + else + { + return type == type_ && subtype == subtype_; + } } - struct HttpContentNegociation::Reference : public boost::noncopyable + class HttpContentNegociation::Reference : public boost::noncopyable { + private: const Handler& handler_; uint8_t level_; float quality_; + Dictionary parameters_; + static float GetQuality(const Dictionary& parameters) + { + Dictionary::const_iterator found = parameters.find("q"); + + if (found != parameters.end()) + { + float quality; + bool ok = false; + + try + { + quality = boost::lexical_cast(found->second); + ok = (quality >= 0.0f && quality <= 1.0f); + } + catch (boost::bad_lexical_cast&) + { + } + + if (ok) + { + return quality; + } + else + { + throw OrthancException( + ErrorCode_BadRequest, + "Quality parameter out of range in a HTTP request (must be between 0 and 1): " + found->second); + } + } + else + { + return 1.0f; // Default quality + } + } + + public: Reference(const Handler& handler, const std::string& type, const std::string& subtype, - float quality) : + const Dictionary& parameters) : handler_(handler), - quality_(quality) + quality_(GetQuality(parameters)), + parameters_(parameters) { if (type == "*" && subtype == "*") { @@ -85,6 +126,11 @@ level_ = 2; } } + + void Call() const + { + handler_.Call(parameters_); + } bool operator< (const Reference& other) const { @@ -92,13 +138,14 @@ { return true; } - - if (level_ > other.level_) + else if (level_ > other.level_) { return false; } - - return quality_ < other.quality_; + else + { + return quality_ < other.quality_; + } } }; @@ -123,58 +170,21 @@ } - float HttpContentNegociation::GetQuality(const Tokens& parameters) - { - for (size_t i = 1; i < parameters.size(); i++) - { - std::string key, value; - if (SplitPair(key, value, parameters[i], '=') && - key == "q") - { - float quality; - bool ok = false; - - try - { - quality = boost::lexical_cast(value); - ok = (quality >= 0.0f && quality <= 1.0f); - } - catch (boost::bad_lexical_cast&) - { - } - - if (ok) - { - return quality; - } - else - { - throw OrthancException( - ErrorCode_BadRequest, - "Quality parameter out of range in a HTTP request (must be between 0 and 1): " + value); - } - } - } - - return 1.0f; // Default quality - } - - - void HttpContentNegociation::SelectBestMatch(std::unique_ptr& best, + void HttpContentNegociation::SelectBestMatch(std::unique_ptr& target, const Handler& handler, const std::string& type, const std::string& subtype, - float quality) + const Dictionary& parameters) { - std::unique_ptr match(new Reference(handler, type, subtype, quality)); + std::unique_ptr match(new Reference(handler, type, subtype, parameters)); - if (best.get() == NULL || - *best < *match) + if (target.get() == NULL || + *target < *match) { #if __cplusplus < 201103L - best.reset(match.release()); + target.reset(match.release()); #else - best = std::move(match); + target = std::move(match); #endif } } @@ -198,9 +208,9 @@ } - bool HttpContentNegociation::Apply(const HttpHeaders& headers) + bool HttpContentNegociation::Apply(const Dictionary& headers) { - HttpHeaders::const_iterator accept = headers.find("accept"); + Dictionary::const_iterator accept = headers.find("accept"); if (accept != headers.end()) { return Apply(accept->second); @@ -226,22 +236,44 @@ for (Tokens::const_iterator it = mediaRanges.begin(); it != mediaRanges.end(); ++it) { - Tokens parameters; - Toolbox::TokenizeString(parameters, *it, ';'); + Tokens tokens; + Toolbox::TokenizeString(tokens, *it, ';'); - if (parameters.size() > 0) + if (tokens.size() > 0) { - float quality = GetQuality(parameters); + Dictionary parameters; + for (size_t i = 1; i < tokens.size(); i++) + { + std::string key, value; + + if (SplitPair(key, value, tokens[i], '=')) + { + // Remove the enclosing quotes, if present + if (!value.empty() && + value[0] == '"' && + value[value.size() - 1] == '"') + { + value = value.substr(1, value.size() - 2); + } + } + else + { + key = Toolbox::StripSpaces(tokens[i]); + value = ""; + } + parameters[key] = value; + } + std::string type, subtype; - if (SplitPair(type, subtype, parameters[0], '/')) + if (SplitPair(type, subtype, tokens[0], '/')) { for (Handlers::const_iterator it2 = handlers_.begin(); it2 != handlers_.end(); ++it2) { if (it2->IsMatch(type, subtype)) { - SelectBestMatch(bestMatch, *it2, type, subtype, quality); + SelectBestMatch(bestMatch, *it2, type, subtype, parameters); } } } @@ -254,7 +286,7 @@ } else { - bestMatch->handler_.Call(); + bestMatch->Call(); return true; } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/HttpContentNegociation.h --- a/OrthancFramework/Sources/HttpServer/HttpContentNegociation.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpContentNegociation.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -39,7 +40,7 @@ class ORTHANC_PUBLIC HttpContentNegociation : public boost::noncopyable { public: - typedef std::map HttpHeaders; + typedef std::map Dictionary; class IHandler : public boost::noncopyable { @@ -49,7 +50,8 @@ } virtual void Handle(const std::string& type, - const std::string& subtype) = 0; + const std::string& subtype, + const Dictionary& parameters) = 0; }; private: @@ -66,9 +68,9 @@ bool IsMatch(const std::string& type, const std::string& subtype) const; - void Call() const + void Call(const Dictionary& parameters) const { - handler_.Handle(type_, subtype_); + handler_.Handle(type_, subtype_, parameters); } }; @@ -86,19 +88,17 @@ const std::string& source, char separator); - static float GetQuality(const Tokens& parameters); - - static void SelectBestMatch(std::unique_ptr& best, + static void SelectBestMatch(std::unique_ptr& target, const Handler& handler, const std::string& type, const std::string& subtype, - float quality); + const Dictionary& parameters); public: void Register(const std::string& mime, IHandler& handler); - bool Apply(const HttpHeaders& headers); + bool Apply(const Dictionary& headers); bool Apply(const std::string& accept); }; diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/HttpFileSender.cpp --- a/OrthancFramework/Sources/HttpServer/HttpFileSender.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpFileSender.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -53,7 +54,8 @@ if (contentType_.empty()) { - contentType_ = SystemToolbox::AutodetectMimeType(filename); + MimeType mimeType = SystemToolbox::AutodetectMimeType(filename); + contentType_ = EnumerationToString(mimeType); } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/HttpFileSender.h --- a/OrthancFramework/Sources/HttpServer/HttpFileSender.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpFileSender.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/HttpOutput.cpp --- a/OrthancFramework/Sources/HttpServer/HttpOutput.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpOutput.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -30,6 +31,7 @@ #include "../Logging.h" #include "../OrthancException.h" #include "../Toolbox.h" +#include "../SystemToolbox.h" #include #include @@ -43,18 +45,24 @@ # endif #endif +static const std::string X_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options"; + namespace Orthanc { HttpOutput::StateMachine::StateMachine(IHttpOutputStream& stream, - bool isKeepAlive) : + bool isKeepAlive, + unsigned int keepAliveTimeout) : stream_(stream), state_(State_WritingHeader), + isContentCompressible_(false), status_(HttpStatus_200_Ok), hasContentLength_(false), contentLength_(0), contentPosition_(0), - keepAlive_(isKeepAlive) + keepAlive_(isKeepAlive), + keepAliveTimeout_(keepAliveTimeout), + hasXContentTypeOptions_(false) { } @@ -68,7 +76,7 @@ if (hasContentLength_ && contentPosition_ != contentLength_) { - LOG(ERROR) << "This HTTP answer has not sent the proper number of bytes in its body"; + LOG(ERROR) << "This HTTP answer has not sent the proper number of bytes in its body. The remote client has likely closed the connection."; } } @@ -100,6 +108,17 @@ AddHeader("Content-Type", contentType); } + void HttpOutput::StateMachine::SetContentCompressible(bool isContentCompressible) + { + isContentCompressible_ = isContentCompressible; + } + + bool HttpOutput::StateMachine::IsContentCompressible() const + { + // We assume that all files that compress correctly (mainly JSON, XML) are clearly identified. + return isContentCompressible_; + } + void HttpOutput::StateMachine::SetContentFilename(const char* filename) { // TODO Escape double quotes @@ -127,6 +146,11 @@ throw OrthancException(ErrorCode_BadSequenceOfCalls); } + if (header == X_CONTENT_TYPE_OPTIONS) + { + hasXContentTypeOptions_ = true; + } + headers_.push_back(header + ": " + value + "\r\n"); } @@ -189,7 +213,7 @@ * HTTP header, so we can't use the milliseconds granularity. **/ s += ("Keep-Alive: timeout=" + - boost::lexical_cast(CIVETWEB_KEEP_ALIVE_TIMEOUT_SECONDS) + "\r\n"); + boost::lexical_cast(keepAliveTimeout_) + "\r\n"); } else { @@ -202,6 +226,13 @@ s += *it; } + if (!hasXContentTypeOptions_) + { + // Always include this header to prevent MIME Confusion attacks: + // https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-content-type-options + s += X_CONTENT_TYPE_OPTIONS + ": nosniff\r\n"; + } + if (status_ != HttpStatus_200_Ok) { hasContentLength_ = false; @@ -273,13 +304,11 @@ HttpCompression HttpOutput::GetPreferredCompression(size_t bodySize) const { -#if 0 - // TODO Do not compress small files? - if (bodySize < 512) + // Do not compress small files since there is no real size benefit. + if (bodySize < 2048) { return HttpCompression_None; } -#endif // Prefer "gzip" over "deflate" if the choice is offered @@ -299,8 +328,9 @@ HttpOutput::HttpOutput(IHttpOutputStream &stream, - bool isKeepAlive) : - stateMachine_(stream, isKeepAlive), + bool isKeepAlive, + unsigned int keepAliveTimeout) : + stateMachine_(stream, isKeepAlive, keepAliveTimeout), isDeflateAllowed_(false), isGzipAllowed_(false) { @@ -337,8 +367,8 @@ void HttpOutput::SendStatus(HttpStatus status, - const char* message, - size_t messageSize) + const char* message, + size_t messageSize) { if (status == HttpStatus_301_MovedPermanently || //status == HttpStatus_401_Unauthorized || @@ -349,6 +379,13 @@ } stateMachine_.SetHttpStatus(status); + + if (messageSize > 0) + { + // Assume that the body always contains a textual description of the error + stateMachine_.SetContentType("text/plain"); + } + stateMachine_.SendBody(message, messageSize); } @@ -365,11 +402,13 @@ void HttpOutput::SetContentType(MimeType contentType) { stateMachine_.SetContentType(EnumerationToString(contentType)); + stateMachine_.SetContentCompressible(SystemToolbox::IsContentCompressible(contentType)); } void HttpOutput::SetContentType(const std::string &contentType) { stateMachine_.SetContentType(contentType.c_str()); + stateMachine_.SetContentCompressible(SystemToolbox::IsContentCompressible(contentType)); } void HttpOutput::SetContentFilename(const char *filename) @@ -390,8 +429,13 @@ void HttpOutput::Redirect(const std::string& path) { + /** + * "HttpStatus_301_MovedPermanently" was used in Orthanc <= + * 1.12.3. This caused issues on changes in the configuration of + * Orthanc. + **/ stateMachine_.ClearHeaders(); - stateMachine_.SetHttpStatus(HttpStatus_301_MovedPermanently); + stateMachine_.SetHttpStatus(HttpStatus_307_TemporaryRedirect); stateMachine_.AddHeader("Location", path); stateMachine_.SendBody(NULL, 0); } @@ -439,7 +483,7 @@ HttpCompression compression = GetPreferredCompression(length); - if (compression == HttpCompression_None) + if (compression == HttpCompression_None || !IsContentCompressible()) { stateMachine_.SetContentLength(length); stateMachine_.SendBody(buffer, length); @@ -539,7 +583,7 @@ * Full history is available at the following locations: * - In changeset 2248:69b0f4e8a49b: * # hg history -v -r 2248 - * - https://bugs.orthanc-server.com/show_bug.cgi?id=54 + * - https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=54 * - https://groups.google.com/d/msg/orthanc-users/65zhIM5xbKI/TU5Q1_LhAwAJ **/ std::string tmp; @@ -561,7 +605,7 @@ * within the encapsulations, and must be no longer than 70 * characters, not counting the two leading hyphens." * https://tools.ietf.org/html/rfc1521 - * https://bugs.orthanc-server.com/show_bug.cgi?id=165 + * https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=165 **/ if (boundary.size() != 36 + 1 + 36) // one UUID contains 36 characters { diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/HttpOutput.h --- a/OrthancFramework/Sources/HttpServer/HttpOutput.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpOutput.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -56,12 +57,15 @@ IHttpOutputStream& stream_; State state_; + bool isContentCompressible_; HttpStatus status_; bool hasContentLength_; uint64_t contentLength_; uint64_t contentPosition_; bool keepAlive_; + unsigned int keepAliveTimeout_; std::list headers_; + bool hasXContentTypeOptions_; std::string multipartBoundary_; std::string multipartContentType_; @@ -70,7 +74,8 @@ public: StateMachine(IHttpOutputStream& stream, - bool isKeepAlive); + bool isKeepAlive, + unsigned int keepAliveTimeout); ~StateMachine(); @@ -80,6 +85,8 @@ void SetContentType(const char* contentType); + void SetContentCompressible(bool isCompressible); + void SetContentFilename(const char* filename); void SetCookie(const std::string& cookie, @@ -108,6 +115,8 @@ return state_; } + bool IsContentCompressible() const; + void CheckHeadersCompatibilityWithMultipart() const; void StartStream(const std::string& contentType); @@ -126,7 +135,8 @@ public: HttpOutput(IHttpOutputStream& stream, - bool isKeepAlive); + bool isKeepAlive, + unsigned int keepAliveTimeout); void SetDeflateAllowed(bool allowed); @@ -136,6 +146,11 @@ bool IsGzipAllowed() const; + bool IsContentCompressible() const + { + return stateMachine_.IsContentCompressible(); + } + void SendStatus(HttpStatus status, const char* message, size_t messageSize); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/HttpServer.cpp --- a/OrthancFramework/Sources/HttpServer/HttpServer.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpServer.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -35,6 +36,7 @@ #include "IHttpHandler.h" #include "MultipartStreamReader.h" #include "StringHttpOutput.h" +#include #if ORTHANC_ENABLE_PUGIXML == 1 # include "IWebDavBucket.h" @@ -109,12 +111,25 @@ { if (length > 0) { - int status = mg_write(connection_, buffer, length); - if (status != static_cast(length)) + // mg_write does not support buffers > 2GB (INT_MAX) -> need to split it + size_t offset = 0; + size_t remainingSize = length; + + while (remainingSize > 0) { - // status == 0 when the connection has been closed, -1 on error - throw OrthancException(ErrorCode_NetworkProtocol); - } + size_t packetSize = std::min(remainingSize, static_cast(INT_MAX)); + + int status = mg_write(connection_, &(reinterpret_cast(buffer)[offset]), packetSize); + + if (status != static_cast(packetSize)) + { + // status == 0 when the connection has been closed, -1 on error + throw OrthancException(ErrorCode_NetworkProtocol); + } + + offset += packetSize; + remainingSize -= packetSize; + } } } @@ -339,7 +354,7 @@ size_t size) { StringHttpOutput stringOutput; - HttpOutput fakeOutput(stringOutput, false); + HttpOutput fakeOutput(stringOutput, false /* assume no keep-alive */, 0); HttpToolbox::GetArguments getArguments; if (!handler_.Handle(fakeOutput, RequestOrigin_RestApi, remoteIp_.c_str(), username_.c_str(), @@ -1442,13 +1457,13 @@ if (server == NULL) { MongooseOutputStream stream(connection); - HttpOutput output(stream, false /* assume no keep-alive */); + HttpOutput output(stream, false /* assume no keep-alive */, 0); output.SendStatus(HttpStatus_500_InternalServerError); return; } MongooseOutputStream stream(connection); - HttpOutput output(stream, server->IsKeepAliveEnabled()); + HttpOutput output(stream, server->IsKeepAliveEnabled(), server->GetKeepAliveTimeout()); HttpMethod method = HttpMethod_Get; try @@ -1519,6 +1534,7 @@ } } + static uint16_t threadCounter = 0; #if MONGOOSE_USE_CALLBACKS == 0 static void* Callback(enum mg_event event, @@ -1543,6 +1559,11 @@ { const struct mg_request_info *request = mg_get_request_info(connection); + if (!Logging::HasCurrentThreadName()) + { + Logging::SetCurrentThreadName(std::string("HTTP-") + boost::lexical_cast(threadCounter++)); + } + ProtectedCallback(connection, request); return 1; // Do not let Mongoose handle the request by itself @@ -1574,6 +1595,7 @@ port_(8000), filter_(NULL), keepAlive_(false), + keepAliveTimeout_(1), httpCompression_(true), exceptionFormatter_(NULL), realm_(ORTHANC_REALM), @@ -1628,6 +1650,9 @@ void HttpServer::Start() { + // reset thread counter used to generate HTTP thread names. + threadCounter = 0; + #if ORTHANC_ENABLE_MONGOOSE == 1 CLOG(INFO, HTTP) << "Starting embedded Web server using Mongoose"; #elif ORTHANC_ENABLE_CIVETWEB == 1 @@ -1641,7 +1666,7 @@ std::string port = boost::lexical_cast(port_); std::string numThreads = boost::lexical_cast(threadsCount_); std::string requestTimeoutMilliseconds = boost::lexical_cast(requestTimeout_ * 1000); - std::string keepAliveTimeoutMilliseconds = boost::lexical_cast(CIVETWEB_KEEP_ALIVE_TIMEOUT_SECONDS * 1000); + std::string keepAliveTimeoutMilliseconds = boost::lexical_cast(keepAliveTimeout_ * 1000); std::string sslMinimumVersion = boost::lexical_cast(sslMinimumVersion_); if (ssl_) @@ -1945,6 +1970,20 @@ #endif } + void HttpServer::SetKeepAliveTimeout(unsigned int timeout) + { + Stop(); + keepAliveTimeout_ = timeout; + CLOG(INFO, HTTP) << "HTTP keep alive Timeout is now " << keepAliveTimeout_ << " seconds"; + +#if ORTHANC_ENABLE_MONGOOSE == 1 + if (enabled) + { + CLOG(WARNING, HTTP) << "You should disable HTTP keep alive, as you are using Mongoose"; + } +#endif + } + const std::string &HttpServer::GetSslCertificate() const { return certificate_; @@ -1984,6 +2023,11 @@ return keepAlive_; } + unsigned int HttpServer::GetKeepAliveTimeout() const + { + return keepAliveTimeout_; + } + void HttpServer::SetRemoteAccessAllowed(bool allowed) { Stop(); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/HttpServer.h --- a/OrthancFramework/Sources/HttpServer/HttpServer.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpServer.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -106,6 +107,7 @@ uint16_t port_; IIncomingHttpRequestFilter* filter_; bool keepAlive_; + unsigned int keepAliveTimeout_; bool httpCompression_; IHttpExceptionFormatter* exceptionFormatter_; std::string realm_; @@ -157,8 +159,12 @@ bool IsKeepAliveEnabled() const; + unsigned int GetKeepAliveTimeout() const; + void SetKeepAliveEnabled(bool enabled); + void SetKeepAliveTimeout(unsigned int timeout); + const std::string& GetSslCertificate() const; void SetSslCertificate(const char* path); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.cpp --- a/OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.h --- a/OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/HttpToolbox.cpp --- a/OrthancFramework/Sources/HttpServer/HttpToolbox.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpToolbox.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/HttpToolbox.h --- a/OrthancFramework/Sources/HttpServer/HttpToolbox.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpToolbox.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/IHttpHandler.cpp --- a/OrthancFramework/Sources/HttpServer/IHttpHandler.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/IHttpHandler.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -45,7 +46,7 @@ HttpToolbox::ParseGetQuery(curi, getArguments, uri.c_str()); StringHttpOutput stream; - HttpOutput http(stream, false /* no keep alive */); + HttpOutput http(stream, false /* assume no keep-alive */, 0); if (handler.Handle(http, origin, LOCALHOST, "", HttpMethod_Get, curi, httpHeaders, getArguments, NULL /* no body for GET */, 0)) @@ -82,7 +83,7 @@ Toolbox::SplitUriComponents(curi, uri); StringHttpOutput stream; - HttpOutput http(stream, false /* no keep alive */); + HttpOutput http(stream, false /* assume no keep-alive */, 0); if (handler.Handle(http, origin, LOCALHOST, "", method, curi, httpHeaders, getArguments, bodyData, bodySize)) @@ -141,7 +142,7 @@ HttpToolbox::GetArguments getArguments; // No GET argument for DELETE StringHttpOutput stream; - HttpOutput http(stream, false /* no keep alive */); + HttpOutput http(stream, false /* assume no keep-alive */, 0); if (handler.Handle(http, origin, LOCALHOST, "", HttpMethod_Delete, curi, httpHeaders, getArguments, NULL /* no body for DELETE */, 0)) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/IHttpHandler.h --- a/OrthancFramework/Sources/HttpServer/IHttpHandler.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/IHttpHandler.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/IHttpOutputStream.h --- a/OrthancFramework/Sources/HttpServer/IHttpOutputStream.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/IHttpOutputStream.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/IHttpStreamAnswer.h --- a/OrthancFramework/Sources/HttpServer/IHttpStreamAnswer.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/IHttpStreamAnswer.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/IIncomingHttpRequestFilter.h --- a/OrthancFramework/Sources/HttpServer/IIncomingHttpRequestFilter.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/IIncomingHttpRequestFilter.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/IWebDavBucket.cpp --- a/OrthancFramework/Sources/HttpServer/IWebDavBucket.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/IWebDavBucket.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/IWebDavBucket.h --- a/OrthancFramework/Sources/HttpServer/IWebDavBucket.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/IWebDavBucket.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/MultipartStreamReader.cpp --- a/OrthancFramework/Sources/HttpServer/MultipartStreamReader.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/MultipartStreamReader.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -384,7 +385,7 @@ { boundary = Toolbox::StripSpaces(items[1]); - // https://bugs.orthanc-server.com/show_bug.cgi?id=190 + // https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=190 RemoveSurroundingQuotes(boundary); valid = !boundary.empty(); @@ -394,7 +395,7 @@ subType = Toolbox::StripSpaces(items[1]); Toolbox::ToLowerCase(subType); - // https://bugs.orthanc-server.com/show_bug.cgi?id=54 + // https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=54 // https://tools.ietf.org/html/rfc7231#section-3.1.1.1 RemoveSurroundingQuotes(subType); } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/MultipartStreamReader.h --- a/OrthancFramework/Sources/HttpServer/MultipartStreamReader.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/MultipartStreamReader.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/StringHttpOutput.cpp --- a/OrthancFramework/Sources/HttpServer/StringHttpOutput.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/StringHttpOutput.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/StringHttpOutput.h --- a/OrthancFramework/Sources/HttpServer/StringHttpOutput.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/StringHttpOutput.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/StringMatcher.cpp --- a/OrthancFramework/Sources/HttpServer/StringMatcher.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/StringMatcher.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/StringMatcher.h --- a/OrthancFramework/Sources/HttpServer/StringMatcher.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/StringMatcher.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/WebDavStorage.cpp --- a/OrthancFramework/Sources/HttpServer/WebDavStorage.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/WebDavStorage.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/HttpServer/WebDavStorage.h --- a/OrthancFramework/Sources/HttpServer/WebDavStorage.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/HttpServer/WebDavStorage.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/IDynamicObject.h --- a/OrthancFramework/Sources/IDynamicObject.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/IDynamicObject.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/IMemoryBuffer.h --- a/OrthancFramework/Sources/IMemoryBuffer.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/IMemoryBuffer.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/Font.cpp --- a/OrthancFramework/Sources/Images/Font.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/Font.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -37,6 +38,7 @@ #include "Image.h" #include "ImageProcessing.h" +#include #include #include #include diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/Font.h --- a/OrthancFramework/Sources/Images/Font.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/Font.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/FontRegistry.cpp --- a/OrthancFramework/Sources/Images/FontRegistry.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/FontRegistry.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/FontRegistry.h --- a/OrthancFramework/Sources/Images/FontRegistry.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/FontRegistry.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/IImageWriter.cpp --- a/OrthancFramework/Sources/Images/IImageWriter.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/IImageWriter.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/IImageWriter.h --- a/OrthancFramework/Sources/Images/IImageWriter.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/IImageWriter.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/Image.cpp --- a/OrthancFramework/Sources/Images/Image.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/Image.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/Image.h --- a/OrthancFramework/Sources/Images/Image.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/Image.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/ImageAccessor.cpp --- a/OrthancFramework/Sources/Images/ImageAccessor.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/ImageAccessor.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/ImageAccessor.h --- a/OrthancFramework/Sources/Images/ImageAccessor.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/ImageAccessor.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/ImageBuffer.cpp --- a/OrthancFramework/Sources/Images/ImageBuffer.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/ImageBuffer.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/ImageBuffer.h --- a/OrthancFramework/Sources/Images/ImageBuffer.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/ImageBuffer.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/ImageProcessing.cpp --- a/OrthancFramework/Sources/Images/ImageProcessing.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/ImageProcessing.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/ImageProcessing.h --- a/OrthancFramework/Sources/Images/ImageProcessing.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/ImageProcessing.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/ImageTraits.h --- a/OrthancFramework/Sources/Images/ImageTraits.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/ImageTraits.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/JpegErrorManager.cpp --- a/OrthancFramework/Sources/Images/JpegErrorManager.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/JpegErrorManager.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/JpegErrorManager.h --- a/OrthancFramework/Sources/Images/JpegErrorManager.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/JpegErrorManager.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/JpegReader.cpp --- a/OrthancFramework/Sources/Images/JpegReader.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/JpegReader.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -158,8 +159,7 @@ jpeg_create_decompress(&cinfo); jpeg_mem_src(&cinfo, const_cast( - reinterpret_cast(buffer)), - static_cast(size)); + reinterpret_cast(buffer)), size); try { diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/JpegReader.h --- a/OrthancFramework/Sources/Images/JpegReader.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/JpegReader.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/JpegWriter.cpp --- a/OrthancFramework/Sources/Images/JpegWriter.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/JpegWriter.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -177,7 +178,17 @@ Internals::JpegErrorManager jerr; unsigned char* data = NULL; + +#if ((JPEG_LIB_VERSION_MAJOR < 9) || \ + (JPEG_LIB_VERSION_MAJOR == 9 && JPEG_LIB_VERSION_MINOR <= 3)) + /** + * jpeg_mem_dest() has "unsigned long*" as its 3rd parameter until + * jpeg-9c. Since jpeg-9d, this is a "size_t*". + **/ unsigned long size; +#else + size_t size; +#endif if (setjmp(jerr.GetJumpBuffer())) { @@ -202,7 +213,7 @@ // Everything went fine, "setjmp()" didn't get called - jpeg.assign(reinterpret_cast(data), size); + jpeg.assign(reinterpret_cast(data), static_cast(size)); free(data); } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/JpegWriter.h --- a/OrthancFramework/Sources/Images/JpegWriter.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/JpegWriter.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/NumpyWriter.cpp --- a/OrthancFramework/Sources/Images/NumpyWriter.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/NumpyWriter.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -154,7 +155,7 @@ { if (compress) { -#if ORTHANC_ENABLE_ZLIB == 1 +#if (ORTHANC_ENABLE_ZLIB == 1) && (ORTHANC_SANDBOXED == 0) // This is the default name of the first array if arrays are // specified as positional arguments in "numpy.savez()" // https://numpy.org/doc/stable/reference/generated/numpy.savez.html @@ -172,7 +173,7 @@ writer.Write(uncompressed); writer.Close(); #else - throw OrthancException(ErrorCode_InternalError, "Orthanc was compiled without support for zlib"); + throw OrthancException(ErrorCode_InternalError, "Orthanc was compiled without support for ZIP"); #endif } else diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/NumpyWriter.h --- a/OrthancFramework/Sources/Images/NumpyWriter.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/NumpyWriter.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/PamReader.cpp --- a/OrthancFramework/Sources/Images/PamReader.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/PamReader.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -242,7 +243,7 @@ * in Orthanc <= 1.8.0 (i.e. make a "memcpy()" to a local * uint16_t variable) doesn't seem work for WebAssembly. We * thus use a plain old C implementation. Check out issue - * #99: https://bugs.orthanc-server.com/show_bug.cgi?id=99 + * #99: https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=99 * * Here is the crash log on WebAssembly (2019-08-05): * diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/PamReader.h --- a/OrthancFramework/Sources/Images/PamReader.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/PamReader.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/PamWriter.cpp --- a/OrthancFramework/Sources/Images/PamWriter.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/PamWriter.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -28,6 +29,7 @@ #include "../OrthancException.h" #include "../Toolbox.h" +#include #include @@ -130,7 +132,7 @@ * in Orthanc <= 1.8.0 (i.e. make a "memcpy()" to a local * uint16_t variable) doesn't seem work for WebAssembly. We * thus use a plain old C implementation. Check out issue - * #99: https://bugs.orthanc-server.com/show_bug.cgi?id=99 + * #99: https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=99 **/ const uint8_t* a = reinterpret_cast(p); uint8_t* b = reinterpret_cast(q); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/PamWriter.h --- a/OrthancFramework/Sources/Images/PamWriter.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/PamWriter.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/PixelTraits.h --- a/OrthancFramework/Sources/Images/PixelTraits.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/PixelTraits.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/PngReader.cpp --- a/OrthancFramework/Sources/Images/PngReader.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/PngReader.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/PngReader.h --- a/OrthancFramework/Sources/Images/PngReader.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/PngReader.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/PngWriter.cpp --- a/OrthancFramework/Sources/Images/PngWriter.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/PngWriter.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Images/PngWriter.h --- a/OrthancFramework/Sources/Images/PngWriter.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Images/PngWriter.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.cpp --- a/OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.h --- a/OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/IJob.h --- a/OrthancFramework/Sources/JobsEngine/IJob.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/IJob.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -62,5 +63,13 @@ MimeType& mime, std::string& filename, const std::string& key) = 0; + + // This function can only be called if the job has reached its + // "success" state + virtual bool DeleteOutput(const std::string& key) = 0; + + // This function can only be called if the job has reached its + // "success" state + virtual void DeleteAllOutputs() {} }; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/IJobUnserializer.h --- a/OrthancFramework/Sources/JobsEngine/IJobUnserializer.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/IJobUnserializer.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/JobInfo.cpp --- a/OrthancFramework/Sources/JobsEngine/JobInfo.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobInfo.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/JobInfo.h --- a/OrthancFramework/Sources/JobsEngine/JobInfo.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobInfo.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/JobStatus.cpp --- a/OrthancFramework/Sources/JobsEngine/JobStatus.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobStatus.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/JobStatus.h --- a/OrthancFramework/Sources/JobsEngine/JobStatus.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobStatus.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/JobStepResult.cpp --- a/OrthancFramework/Sources/JobsEngine/JobStepResult.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobStepResult.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/JobStepResult.h --- a/OrthancFramework/Sources/JobsEngine/JobStepResult.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobStepResult.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/JobsEngine.cpp --- a/OrthancFramework/Sources/JobsEngine/JobsEngine.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobsEngine.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -122,7 +123,7 @@ size_t workerIndex) { assert(engine != NULL); - + Logging::SetCurrentThreadName(std::string("JOBS-WORKER-") + boost::lexical_cast(workerIndex)); CLOG(INFO, JOBS) << "Worker thread " << workerIndex << " has started"; while (engine->IsRunning()) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/JobsEngine.h --- a/OrthancFramework/Sources/JobsEngine/JobsEngine.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobsEngine.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/JobsRegistry.cpp --- a/OrthancFramework/Sources/JobsEngine/JobsRegistry.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobsRegistry.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -649,6 +650,42 @@ } + bool JobsRegistry::DeleteJobInfo(const std::string& id) + { + LOG(INFO) << "Deleting job: " << id; + + boost::mutex::scoped_lock lock(mutex_); + CheckInvariants(); + + JobsIndex::iterator found = jobsIndex_.find(id); + + if (found == jobsIndex_.end()) + { + LOG(WARNING) << "Unknown job to delete: " << id; + return false; + } + else + { + for (CompletedJobs::iterator it = completedJobs_.begin(); + it != completedJobs_.end(); ++it) + { + if (*it == found->second) + { + found->second->GetJob().DeleteAllOutputs(); + delete found->second; + + completedJobs_.erase(it); + jobsIndex_.erase(id); + return true; + } + } + + LOG(WARNING) << "Can not delete a job that is not complete: " << id; + return false; + } + } + + bool JobsRegistry::GetJobOutput(std::string& output, MimeType& mime, std::string& filename, @@ -679,6 +716,33 @@ } } + bool JobsRegistry::DeleteJobOutput(const std::string& job, + const std::string& key) + { + boost::mutex::scoped_lock lock(mutex_); + CheckInvariants(); + + JobsIndex::const_iterator found = jobsIndex_.find(job); + + if (found == jobsIndex_.end()) + { + return false; + } + else + { + const JobHandler& handler = *found->second; + + if (handler.GetState() == JobState_Success) + { + return handler.GetJob().DeleteOutput(key); + } + else + { + return false; + } + } + } + void JobsRegistry::SubmitInternal(std::string& id, JobHandler* handler) diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/JobsRegistry.h --- a/OrthancFramework/Sources/JobsEngine/JobsRegistry.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/JobsRegistry.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -147,12 +148,17 @@ bool GetJobInfo(JobInfo& target, const std::string& id); + bool DeleteJobInfo(const std::string& id); + bool GetJobOutput(std::string& output, MimeType& mime, std::string& filename, const std::string& job, const std::string& key); + bool DeleteJobOutput(const std::string& job, + const std::string& key); + void Serialize(Json::Value& target); void Submit(std::string& id, diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/Operations/IJobOperation.h --- a/OrthancFramework/Sources/JobsEngine/Operations/IJobOperation.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/IJobOperation.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/Operations/IJobOperationValue.h --- a/OrthancFramework/Sources/JobsEngine/Operations/IJobOperationValue.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/IJobOperationValue.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.cpp --- a/OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.h --- a/OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.cpp --- a/OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.h --- a/OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.cpp --- a/OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.h --- a/OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.cpp --- a/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -447,13 +448,6 @@ return true; } - bool SequenceOfOperationsJob::GetOutput(std::string& output, - MimeType& mime, - std::string& filename, - const std::string& key) - { - return false; - } void SequenceOfOperationsJob::AwakeTrailingSleep() { diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h --- a/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -127,7 +128,15 @@ virtual bool GetOutput(std::string& output, MimeType& mime, std::string& filename, - const std::string& key) ORTHANC_OVERRIDE; + const std::string& key) ORTHANC_OVERRIDE + { + return false; + } + + virtual bool DeleteOutput(const std::string& key) ORTHANC_OVERRIDE + { + return false; + } void AwakeTrailingSleep(); }; diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.cpp --- a/OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.h --- a/OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.cpp --- a/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -269,14 +270,6 @@ return true; } - bool SetOfCommandsJob::GetOutput(std::string &output, - MimeType &mime, - std::string& filename, - const std::string &key) - { - return false; - } - SetOfCommandsJob::SetOfCommandsJob(ICommandUnserializer* unserializer, const Json::Value& source) : diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h --- a/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/SetOfCommandsJob.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -106,6 +107,14 @@ virtual bool GetOutput(std::string& output, MimeType& mime, std::string& filename, - const std::string& key) ORTHANC_OVERRIDE; + const std::string& key) ORTHANC_OVERRIDE + { + return false; + } + + virtual bool DeleteOutput(const std::string& key) ORTHANC_OVERRIDE + { + return false; + } }; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.cpp --- a/OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.h --- a/OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Logging.cpp --- a/OrthancFramework/Sources/Logging.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Logging.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -26,6 +27,7 @@ #include "OrthancException.h" +#include #include @@ -310,6 +312,10 @@ { } + void InitializePluginContext(void* pluginContext, const char* pluginName) + { + } + void Initialize() { } @@ -438,6 +444,10 @@ { } + void InitializePluginContext(void* pluginContext, const char* pluginName) + { + } + void Initialize() { } @@ -472,6 +482,7 @@ * mimics behavior from Google Log. *********************************************************/ +#include #include namespace @@ -486,6 +497,7 @@ _OrthancPluginService_LogInfo = 1, _OrthancPluginService_LogWarning = 2, _OrthancPluginService_LogError = 3, + _OrthancPluginService_LogMessage = 45, _OrthancPluginService_INTERNAL = 0x7fffffff } _OrthancPluginService; @@ -498,11 +510,23 @@ _OrthancPluginService service, const void* params); } OrthancPluginContext; + + typedef struct + { + const char* message; + const char* plugin; + const char* file; + uint32_t line; + uint32_t category; // can be a LogCategory or a OrthancPluginLogCategory + uint32_t level; // can be a LogLevel or a OrthancPluginLogLevel + } _OrthancPluginLogMessage; + } #include "Enumerations.h" #include "SystemToolbox.h" +#include "Toolbox.h" #include #include @@ -534,16 +558,27 @@ -static std::unique_ptr loggingStreamsContext_; -static boost::mutex loggingStreamsMutex_; -static Orthanc::Logging::NullStream nullStream_; -static OrthancPluginContext* pluginContext_ = NULL; +static std::unique_ptr loggingStreamsContext_; +static boost::mutex loggingStreamsMutex_; +static Orthanc::Logging::NullStream nullStream_; +static OrthancPluginContext* pluginContext_ = NULL; // this is != NULL only when running from a plugin +static std::string pluginName_; // this string can only be non-empty if running from a plugin +static bool hasOrthancAdvancedLogging_ = false; // Whether the Orthanc runtime is >= 1.12.4 +static boost::recursive_mutex threadNamesMutex_; +static std::map threadNames_; +static bool enableThreadNames_ = true; + namespace Orthanc { namespace Logging { + void EnableThreadNames(bool enabled) + { + enableThreadNames_ = enabled; + } + static void GetLogPath(boost::filesystem::path& log, boost::filesystem::path& link, const std::string& suffix, @@ -612,10 +647,51 @@ throw OrthancException(ErrorCode_CannotWriteFile); } } - + + void SetCurrentThreadNameInternal(const boost::thread::id& id, const std::string& name) + { + boost::recursive_mutex::scoped_lock lock(threadNamesMutex_); + + if (name.size() > 16) + { + throw OrthancException(ErrorCode_InternalError, std::string("Thread name can not exceed 16 characters: ") + name); + } + + threadNames_[id] = name; + } + + void SetCurrentThreadName(const std::string& name) + { + boost::recursive_mutex::scoped_lock lock(threadNamesMutex_); + SetCurrentThreadNameInternal(boost::this_thread::get_id(), name); + } + + bool HasCurrentThreadName() + { + boost::thread::id threadId = boost::this_thread::get_id(); + + boost::mutex::scoped_lock lock(loggingStreamsMutex_); + return threadNames_.find(threadId) != threadNames_.end(); + } + + static std::string GetCurrentThreadName() + { + boost::thread::id threadId = boost::this_thread::get_id(); + + boost::recursive_mutex::scoped_lock lock(threadNamesMutex_); + + if (threadNames_.find(threadId) == threadNames_.end()) + { + // set the threadId as the thread name + SetCurrentThreadNameInternal(threadId, boost::lexical_cast(threadId)); + } + + return threadNames_[threadId]; + } static void GetLinePrefix(std::string& prefix, LogLevel level, + const char* pluginName, // when logging in the core but coming from a plugin, pluginName_ is NULL but this argument is != NULL const char* file, int line, LogCategory category) @@ -679,7 +755,23 @@ static_cast(duration.seconds()), static_cast(duration.fractional_seconds())); - prefix = (std::string(date) + path.filename().string() + ":" + + char threadName[20]; // thread names are limited to 16 char + a space + if (enableThreadNames_) + { + sprintf(threadName, "%16s ", GetCurrentThreadName().c_str()); + } + else + { + threadName[0] = '\0'; + } + + std::string internalPluginName = ""; + if (pluginName != NULL) + { + internalPluginName = std::string(pluginName) + ":/"; + } + + prefix = (std::string(date) + threadName + internalPluginName + path.filename().string() + ":" + boost::lexical_cast(line) + "] "); if (level != LogLevel_ERROR && @@ -695,14 +787,29 @@ { assert(sizeof(_OrthancPluginService) == sizeof(int32_t)); + if (pluginContext == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + boost::mutex::scoped_lock lock(loggingStreamsMutex_); loggingStreamsContext_.reset(NULL); pluginContext_ = reinterpret_cast(pluginContext); + // The value "hasOrthancAdvancedLogging_" is cached to avoid computing it on every logged message + hasOrthancAdvancedLogging_ = Toolbox::IsVersionAbove(pluginContext_->orthancVersion, 1, 12, 4); + EnableInfoLevel(true); // allow the plugin to log at info level (but the Orthanc Core still decides of the level) } + void InitializePluginContext(void* pluginContext, const std::string& pluginName) + { + InitializePluginContext(pluginContext); + pluginName_ = pluginName; + } + + void Initialize() { boost::mutex::scoped_lock lock(loggingStreamsMutex_); @@ -775,9 +882,17 @@ } - void InternalLogger::Setup(LogCategory category, - const char* file, - int line) + InternalLogger::InternalLogger(LogLevel level, + LogCategory category, + const char* pluginName, + const char* file, + int line) : + lock_(loggingStreamsMutex_, boost::defer_lock_t()), + level_(level), + stream_(&nullStream_), // By default, logging to "/dev/null" is simulated + category_(category), + file_(file), + line_(line) { if (pluginContext_ != NULL) { @@ -808,7 +923,7 @@ } std::string prefix; - GetLinePrefix(prefix, level_, file, line, category); + GetLinePrefix(prefix, level_, pluginName, file, line, category); { // We lock the global mutex. The mutex is locked until the @@ -817,7 +932,9 @@ if (loggingStreamsContext_.get() == NULL) { - fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n"); + // Have you called Orthanc::Logging::InitializePluginContext()? + fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine " + "(or did you forgot to initialize it?)\n"); lock_.unlock(); return; } @@ -867,28 +984,6 @@ } - InternalLogger::InternalLogger(LogLevel level, - LogCategory category, - const char* file, - int line) : - lock_(loggingStreamsMutex_, boost::defer_lock_t()), - level_(level), - stream_(&nullStream_) // By default, logging to "/dev/null" is simulated - { - Setup(category, file, line); - } - - - InternalLogger::InternalLogger(LogLevel level, - const char* file, - int line) : - lock_(loggingStreamsMutex_, boost::defer_lock_t()), - level_(level), - stream_(&nullStream_) // By default, logging to "/dev/null" is simulated - { - Setup(LogCategory_GENERIC, file, line); - } - InternalLogger::~InternalLogger() { @@ -900,22 +995,37 @@ if (pluginContext_ != NULL) { - switch (level_) + if (!pluginName_.empty() && + hasOrthancAdvancedLogging_) { - case LogLevel_ERROR: - pluginContext_->InvokeService(pluginContext_, _OrthancPluginService_LogError, message.c_str()); - break; + _OrthancPluginLogMessage m; + m.category = category_; + m.level = level_; + m.file = file_; + m.line = line_; + m.plugin = pluginName_.c_str(); + m.message = message.c_str(); + pluginContext_->InvokeService(pluginContext_, _OrthancPluginService_LogMessage, &m); + } + else + { + switch (level_) + { + case LogLevel_ERROR: + pluginContext_->InvokeService(pluginContext_, _OrthancPluginService_LogError, message.c_str()); + break; - case LogLevel_WARNING: - pluginContext_->InvokeService(pluginContext_, _OrthancPluginService_LogWarning, message.c_str()); - break; + case LogLevel_WARNING: + pluginContext_->InvokeService(pluginContext_, _OrthancPluginService_LogWarning, message.c_str()); + break; - case LogLevel_INFO: - pluginContext_->InvokeService(pluginContext_, _OrthancPluginService_LogInfo, message.c_str()); - break; + case LogLevel_INFO: + pluginContext_->InvokeService(pluginContext_, _OrthancPluginService_LogInfo, message.c_str()); + break; - default: - break; + default: + break; + } } } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Logging.h --- a/OrthancFramework/Sources/Logging.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Logging.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -28,6 +29,7 @@ #include "Compatibility.h" #include +#include #if !defined(ORTHANC_ENABLE_LOGGING) # error The macro ORTHANC_ENABLE_LOGGING must be defined @@ -46,12 +48,13 @@ { namespace Logging { + // Note: these values must match the ones in OrthancCPlugin.h enum LogLevel { - LogLevel_ERROR, - LogLevel_WARNING, - LogLevel_INFO, - LogLevel_TRACE + LogLevel_ERROR = 0, + LogLevel_WARNING = 1, + LogLevel_INFO = 2, + LogLevel_TRACE = 3 }; /** @@ -59,6 +62,7 @@ * mask. As a consequence, there can be up to 31 log categories * (not 32, as the value GENERIC is reserved for the log commands * that don't fall in a specific category). + * Note: these values must match the ones in OrthancCPlugin.h **/ enum LogCategory { @@ -78,6 +82,9 @@ // "pluginContext" must be of type "OrthancPluginContext" ORTHANC_PUBLIC void InitializePluginContext(void* pluginContext); + ORTHANC_PUBLIC void InitializePluginContext(void* pluginContext, + const std::string& pluginName); + ORTHANC_PUBLIC void Initialize(); ORTHANC_PUBLIC void Finalize(); @@ -86,6 +93,12 @@ ORTHANC_PUBLIC void Flush(); + ORTHANC_PUBLIC void SetCurrentThreadName(const std::string& name); + + ORTHANC_PUBLIC bool HasCurrentThreadName(); + + ORTHANC_PUBLIC void EnableThreadNames(bool enabled); + ORTHANC_PUBLIC void EnableInfoLevel(bool enabled); ORTHANC_PUBLIC void EnableTraceLevel(bool enabled); @@ -156,16 +169,36 @@ # define LOG(level) ::Orthanc::Logging::NullStream() # define VLOG(unused) ::Orthanc::Logging::NullStream() # define CLOG(level, category) ::Orthanc::Logging::NullStream() +# define LOG_FROM_PLUGIN(level, category, pluginName, file, line) ::Orthanc::Logging::NullStream() #else /* ORTHANC_ENABLE_LOGGING == 1 */ -# define LOG(level) ::Orthanc::Logging::InternalLogger \ - (::Orthanc::Logging::LogLevel_ ## level, \ - ::Orthanc::Logging::LogCategory_GENERIC, __FILE__, __LINE__) -# define VLOG(unused) ::Orthanc::Logging::InternalLogger \ - (::Orthanc::Logging::LogLevel_TRACE, \ - ::Orthanc::Logging::LogCategory_GENERIC, __FILE__, __LINE__) + +#if !defined(__ORTHANC_FILE__) +# if defined(_MSC_VER) +# pragma message("Warning: Macro __ORTHANC_FILE__ is not defined, this will leak the full path of the source files in the binaries") +# else +# warning Warning: Macro __ORTHANC_FILE__ is not defined, this will leak the full path of the source files in the binaries +# endif +# define __ORTHANC_FILE__ __FILE__ +#endif + +# define LOG(level) ::Orthanc::Logging::InternalLogger \ + (::Orthanc::Logging::LogLevel_ ## level, \ + ::Orthanc::Logging::LogCategory_GENERIC, NULL /* no plugin */, \ + __ORTHANC_FILE__, __LINE__) + +# define VLOG(unused) ::Orthanc::Logging::InternalLogger \ + (::Orthanc::Logging::LogLevel_TRACE, \ + ::Orthanc::Logging::LogCategory_GENERIC, NULL /* no plugin */, \ + __ORTHANC_FILE__, __LINE__) + # define CLOG(level, category) ::Orthanc::Logging::InternalLogger \ (::Orthanc::Logging::LogLevel_ ## level, \ - ::Orthanc::Logging::LogCategory_ ## category, __FILE__, __LINE__) + ::Orthanc::Logging::LogCategory_ ## category, NULL /* no plugin */, \ + __ORTHANC_FILE__, __LINE__) + +# define LOG_FROM_PLUGIN(level, category, pluginName, file, line) \ + ::Orthanc::Logging::InternalLogger(level, category, pluginName, file, line) + #endif @@ -192,6 +225,7 @@ public: InternalLogger(LogLevel level, LogCategory category, + const char* pluginName /* ignored */, const char* file /* ignored */, int line /* ignored */) : level_(level), @@ -199,15 +233,6 @@ { } - // For backward binary compatibility with Orthanc Framework <= 1.8.0 - InternalLogger(LogLevel level, - const char* file /* ignored */, - int line /* ignored */) : - level_(level), - category_(LogCategory_GENERIC) - { - } - ~InternalLogger(); template @@ -242,19 +267,14 @@ LogLevel level_; std::unique_ptr pluginStream_; std::ostream* stream_; - - void Setup(LogCategory category, - const char* file, - int line); + LogCategory category_; + const char* file_; + uint32_t line_; public: InternalLogger(LogLevel level, LogCategory category, - const char* file, - int line); - - // For backward binary compatibility with Orthanc Framework <= 1.8.0 - InternalLogger(LogLevel level, + const char* pluginName, const char* file, int line); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Lua/LuaContext.cpp --- a/OrthancFramework/Sources/Lua/LuaContext.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Lua/LuaContext.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -396,10 +397,6 @@ const std::string s = value.asString(); lua_pushlstring(lua_, s.c_str(), s.size()); } - else if (value.isDouble()) - { - lua_pushnumber(lua_, value.asDouble()); - } else if (value.isInt()) { lua_pushinteger(lua_, value.asInt()); @@ -408,6 +405,10 @@ { lua_pushinteger(lua_, value.asUInt()); } + else if (value.isDouble()) + { + lua_pushnumber(lua_, value.asDouble()); + } else if (value.isBool()) { lua_pushboolean(lua_, value.asBool()); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Lua/LuaContext.h --- a/OrthancFramework/Sources/Lua/LuaContext.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Lua/LuaContext.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Lua/LuaFunctionCall.cpp --- a/OrthancFramework/Sources/Lua/LuaFunctionCall.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Lua/LuaFunctionCall.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Lua/LuaFunctionCall.h --- a/OrthancFramework/Sources/Lua/LuaFunctionCall.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Lua/LuaFunctionCall.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/MallocMemoryBuffer.cpp --- a/OrthancFramework/Sources/MallocMemoryBuffer.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/MallocMemoryBuffer.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/MallocMemoryBuffer.h --- a/OrthancFramework/Sources/MallocMemoryBuffer.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/MallocMemoryBuffer.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/MetricsRegistry.cpp --- a/OrthancFramework/Sources/MetricsRegistry.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/MetricsRegistry.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -28,6 +29,8 @@ #include "Compatibility.h" #include "OrthancException.h" +#include + namespace Orthanc { static const boost::posix_time::ptime GetNow() @@ -35,134 +38,280 @@ return boost::posix_time::microsec_clock::universal_time(); } - class MetricsRegistry::Item + namespace { - private: - MetricsType type_; - boost::posix_time::ptime time_; - bool hasValue_; - float value_; - - void Touch(float value, - const boost::posix_time::ptime& now) + template + class TimestampedValue : public boost::noncopyable { - hasValue_ = true; - value_ = value; - time_ = now; - } + private: + boost::posix_time::ptime time_; + bool hasValue_; + T value_; + + void SetValue(const T& value, + const boost::posix_time::ptime& now) + { + hasValue_ = true; + value_ = value; + time_ = now; + } - void Touch(float value) - { - Touch(value, GetNow()); - } + bool IsLargerOverPeriod(const T& value, + int duration, + const boost::posix_time::ptime& now) const + { + if (hasValue_) + { + return (value > value_ || + (now - time_).total_seconds() > duration /* old value has expired */); + } + else + { + return true; // No value yet + } + } - void UpdateMax(float value, - int duration) - { - if (hasValue_) + bool IsSmallerOverPeriod(const T& value, + int duration, + const boost::posix_time::ptime& now) const + { + if (hasValue_) + { + return (value < value_ || + (now - time_).total_seconds() > duration /* old value has expired */); + } + else + { + return true; // No value yet + } + } + + public: + explicit TimestampedValue() : + hasValue_(false), + value_(0) + { + } + + void Update(const T& value, + const MetricsUpdatePolicy& policy) { const boost::posix_time::ptime now = GetNow(); - if (value > value_ || - (now - time_).total_seconds() > duration) + switch (policy) { - Touch(value, now); + case MetricsUpdatePolicy_Directly: + SetValue(value, now); + break; + + case MetricsUpdatePolicy_MaxOver10Seconds: + if (IsLargerOverPeriod(value, 10, now)) + { + SetValue(value, now); + } + break; + + case MetricsUpdatePolicy_MaxOver1Minute: + if (IsLargerOverPeriod(value, 60, now)) + { + SetValue(value, now); + } + break; + + case MetricsUpdatePolicy_MinOver10Seconds: + if (IsSmallerOverPeriod(value, 10, now)) + { + SetValue(value, now); + } + break; + + case MetricsUpdatePolicy_MinOver1Minute: + if (IsSmallerOverPeriod(value, 60, now)) + { + SetValue(value, now); + } + break; + + default: + throw OrthancException(ErrorCode_NotImplemented); } } - else + + void Increment(const T& delta) + { + time_ = GetNow(); + + if (hasValue_) + { + value_ += delta; + } + else + { + value_ = delta; + hasValue_ = true; + } + } + + bool HasValue() const + { + return hasValue_; + } + + const boost::posix_time::ptime& GetTime() const { - Touch(value); + if (hasValue_) + { + return time_; + } + else + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } } + + const T& GetValue() const + { + if (hasValue_) + { + return value_; + } + else + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + } + }; + } + + + class MetricsRegistry::Item : public boost::noncopyable + { + private: + MetricsUpdatePolicy policy_; + + public: + explicit Item(MetricsUpdatePolicy policy) : + policy_(policy) + { } - void UpdateMin(float value, - int duration) - { - if (hasValue_) - { - const boost::posix_time::ptime now = GetNow(); - - if (value < value_ || - (now - time_).total_seconds() > duration) - { - Touch(value, now); - } - } - else - { - Touch(value); - } - } - - public: - explicit Item(MetricsType type) : - type_(type), - hasValue_(false), - value_(0) + virtual ~Item() { } - MetricsType GetType() const + MetricsUpdatePolicy GetPolicy() const { - return type_; + return policy_; + } + + virtual void UpdateFloat(float value) = 0; + + virtual void UpdateInteger(int64_t value) = 0; + + virtual void IncrementInteger(int64_t delta) = 0; + + virtual MetricsDataType GetDataType() const = 0; + + virtual bool HasValue() const = 0; + + virtual const boost::posix_time::ptime& GetTime() const = 0; + + virtual std::string FormatValue() const = 0; + }; + + + class MetricsRegistry::FloatItem : public Item + { + private: + TimestampedValue value_; + + public: + explicit FloatItem(MetricsUpdatePolicy policy) : + Item(policy) + { + } + + virtual void UpdateFloat(float value) ORTHANC_OVERRIDE + { + value_.Update(value, GetPolicy()); + } + + virtual void UpdateInteger(int64_t value) ORTHANC_OVERRIDE + { + value_.Update(static_cast(value), GetPolicy()); + } + + virtual void IncrementInteger(int64_t delta) ORTHANC_OVERRIDE + { + value_.Increment(static_cast(delta)); + } + + virtual MetricsDataType GetDataType() const ORTHANC_OVERRIDE + { + return MetricsDataType_Float; + } + + virtual bool HasValue() const ORTHANC_OVERRIDE + { + return value_.HasValue(); } - void Update(float value) + virtual const boost::posix_time::ptime& GetTime() const ORTHANC_OVERRIDE { - switch (type_) - { - case MetricsType_Default: - Touch(value); - break; - - case MetricsType_MaxOver10Seconds: - UpdateMax(value, 10); - break; + return value_.GetTime(); + } + + virtual std::string FormatValue() const ORTHANC_OVERRIDE + { + return boost::lexical_cast(value_.GetValue()); + } + }; - case MetricsType_MaxOver1Minute: - UpdateMax(value, 60); - break; - - case MetricsType_MinOver10Seconds: - UpdateMin(value, 10); - break; + + class MetricsRegistry::IntegerItem : public Item + { + private: + TimestampedValue value_; - case MetricsType_MinOver1Minute: - UpdateMin(value, 60); - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } + public: + explicit IntegerItem(MetricsUpdatePolicy policy) : + Item(policy) + { + } + + virtual void UpdateFloat(float value) ORTHANC_OVERRIDE + { + value_.Update(boost::math::llround(value), GetPolicy()); } - bool HasValue() const + virtual void UpdateInteger(int64_t value) ORTHANC_OVERRIDE { - return hasValue_; + value_.Update(value, GetPolicy()); + } + + virtual void IncrementInteger(int64_t delta) ORTHANC_OVERRIDE + { + value_.Increment(delta); } - const boost::posix_time::ptime& GetTime() const + virtual MetricsDataType GetDataType() const ORTHANC_OVERRIDE { - if (hasValue_) - { - return time_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } + return MetricsDataType_Integer; } - float GetValue() const + virtual bool HasValue() const ORTHANC_OVERRIDE + { + return value_.HasValue(); + } + + virtual const boost::posix_time::ptime& GetTime() const ORTHANC_OVERRIDE { - if (hasValue_) - { - return value_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } + return value_.GetTime(); + } + + virtual std::string FormatValue() const ORTHANC_OVERRIDE + { + return boost::lexical_cast(value_.GetValue()); } }; @@ -190,48 +339,53 @@ void MetricsRegistry::Register(const std::string& name, - MetricsType type) + MetricsUpdatePolicy policy, + MetricsDataType type) { boost::mutex::scoped_lock lock(mutex_); + if (content_.find(name) != content_.end()) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls, "Cannot register twice the same metrics: " + name); + } + else + { + GetItemInternal(name, policy, type); + } + } + + + MetricsRegistry::Item& MetricsRegistry::GetItemInternal(const std::string& name, + MetricsUpdatePolicy policy, + MetricsDataType type) + { Content::iterator found = content_.find(name); if (found == content_.end()) { - content_[name] = new Item(type); + Item* item = NULL; + + switch (type) + { + case MetricsDataType_Float: + item = new FloatItem(policy); + break; + + case MetricsDataType_Integer: + item = new IntegerItem(policy); + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + content_[name] = item; + return *item; } else { assert(found->second != NULL); - - // This metrics already exists: Only recreate it if there is a - // mismatch in the type of metrics - if (found->second->GetType() != type) - { - delete found->second; - found->second = new Item(type); - } - } - } - - void MetricsRegistry::SetValueInternal(const std::string& name, - float value, - MetricsType type) - { - boost::mutex::scoped_lock lock(mutex_); - - Content::iterator found = content_.find(name); - - if (found == content_.end()) - { - std::unique_ptr item(new Item(type)); - item->Update(value); - content_[name] = item.release(); - } - else - { - assert(found->second != NULL); - found->second->Update(value); + return *found->second; } } @@ -241,29 +395,49 @@ } - void MetricsRegistry::SetValue(const std::string &name, - float value, - MetricsType type) + void MetricsRegistry::SetFloatValue(const std::string& name, + float value, + MetricsUpdatePolicy policy) { // Inlining to avoid loosing time if metrics are disabled if (enabled_) { - SetValueInternal(name, value, type); + boost::mutex::scoped_lock lock(mutex_); + GetItemInternal(name, policy, MetricsDataType_Float).UpdateFloat(value); + } + } + + + void MetricsRegistry::SetIntegerValue(const std::string &name, + int64_t value, + MetricsUpdatePolicy policy) + { + // Inlining to avoid loosing time if metrics are disabled + if (enabled_) + { + boost::mutex::scoped_lock lock(mutex_); + GetItemInternal(name, policy, MetricsDataType_Integer).UpdateInteger(value); } } - void MetricsRegistry::SetValue(const std::string &name, float value) + void MetricsRegistry::IncrementIntegerValue(const std::string &name, + int64_t delta) { - SetValue(name, value, MetricsType_Default); + // Inlining to avoid loosing time if metrics are disabled + if (enabled_) + { + boost::mutex::scoped_lock lock(mutex_); + GetItemInternal(name, MetricsUpdatePolicy_Directly, MetricsDataType_Integer).IncrementInteger(delta); + } } - MetricsType MetricsRegistry::GetMetricsType(const std::string& name) + MetricsUpdatePolicy MetricsRegistry::GetUpdatePolicy(const std::string& metrics) { boost::mutex::scoped_lock lock(mutex_); - Content::const_iterator found = content_.find(name); + Content::const_iterator found = content_.find(metrics); if (found == content_.end()) { @@ -272,7 +446,25 @@ else { assert(found->second != NULL); - return found->second->GetType(); + return found->second->GetPolicy(); + } + } + + + MetricsDataType MetricsRegistry::GetDataType(const std::string& metrics) + { + boost::mutex::scoped_lock lock(mutex_); + + Content::const_iterator found = content_.find(metrics); + + if (found == content_.end()) + { + throw OrthancException(ErrorCode_InexistentItem); + } + else + { + assert(found->second != NULL); + return found->second->GetDataType(); } } @@ -303,7 +495,7 @@ boost::posix_time::time_duration diff = it->second->GetTime() - EPOCH; std::string line = (it->first + " " + - boost::lexical_cast(it->second->GetValue()) + " " + + it->second->FormatValue() + " " + boost::lexical_cast(diff.total_milliseconds()) + "\n"); buffer.AddChunk(line); @@ -316,18 +508,18 @@ MetricsRegistry::SharedMetrics::SharedMetrics(MetricsRegistry ®istry, const std::string &name, - MetricsType type) : + MetricsUpdatePolicy policy) : registry_(registry), name_(name), value_(0) { } - void MetricsRegistry::SharedMetrics::Add(float delta) + void MetricsRegistry::SharedMetrics::Add(int64_t delta) { boost::mutex::scoped_lock lock(mutex_); value_ += delta; - registry_.SetValue(name_, value_); + registry_.SetIntegerValue(name_, value_); } @@ -361,7 +553,7 @@ const std::string &name) : registry_(registry), name_(name), - type_(MetricsType_MaxOver10Seconds) + policy_(MetricsUpdatePolicy_MaxOver10Seconds) { Start(); } @@ -369,10 +561,10 @@ MetricsRegistry::Timer::Timer(MetricsRegistry ®istry, const std::string &name, - MetricsType type) : + MetricsUpdatePolicy policy) : registry_(registry), name_(name), - type_(type) + policy_(policy) { Start(); } @@ -383,8 +575,7 @@ if (active_) { boost::posix_time::time_duration diff = GetNow() - start_; - registry_.SetValue( - name_, static_cast(diff.total_milliseconds()), type_); + registry_.SetIntegerValue(name_, static_cast(diff.total_milliseconds()), policy_); } } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/MetricsRegistry.h --- a/OrthancFramework/Sources/MetricsRegistry.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/MetricsRegistry.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -35,22 +36,31 @@ #include #include +#include namespace Orthanc { - enum MetricsType + enum MetricsUpdatePolicy { - MetricsType_Default, - MetricsType_MaxOver10Seconds, - MetricsType_MaxOver1Minute, - MetricsType_MinOver10Seconds, - MetricsType_MinOver1Minute + MetricsUpdatePolicy_Directly, + MetricsUpdatePolicy_MaxOver10Seconds, + MetricsUpdatePolicy_MaxOver1Minute, + MetricsUpdatePolicy_MinOver10Seconds, + MetricsUpdatePolicy_MinOver1Minute + }; + + enum MetricsDataType + { + MetricsDataType_Float, + MetricsDataType_Integer }; class ORTHANC_PUBLIC MetricsRegistry : public boost::noncopyable { private: class Item; + class FloatItem; + class IntegerItem; typedef std::map Content; @@ -58,9 +68,10 @@ boost::mutex mutex_; Content content_; - void SetValueInternal(const std::string& name, - float value, - MetricsType type); + // The mutex must be locked + Item& GetItemInternal(const std::string& name, + MetricsUpdatePolicy policy, + MetricsDataType type); public: MetricsRegistry(); @@ -72,16 +83,35 @@ void SetEnabled(bool enabled); void Register(const std::string& name, - MetricsType type); + MetricsUpdatePolicy policy, + MetricsDataType type); - void SetValue(const std::string& name, - float value, - MetricsType type); + void SetFloatValue(const std::string& name, + float value, + MetricsUpdatePolicy policy /* only used if this is a new metrics */); + + void SetFloatValue(const std::string& name, + float value) + { + SetFloatValue(name, value, MetricsUpdatePolicy_Directly); + } - void SetValue(const std::string& name, - float value); + void SetIntegerValue(const std::string& name, + int64_t value, + MetricsUpdatePolicy policy /* only used if this is a new metrics */); + + void SetIntegerValue(const std::string& name, + int64_t value) + { + SetIntegerValue(name, value, MetricsUpdatePolicy_Directly); + } + + void IncrementIntegerValue(const std::string& name, + int64_t delta); - MetricsType GetMetricsType(const std::string& name); + MetricsUpdatePolicy GetUpdatePolicy(const std::string& metrics); + + MetricsDataType GetDataType(const std::string& metrics); // https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format void ExportPrometheusText(std::string& s); @@ -93,14 +123,14 @@ boost::mutex mutex_; MetricsRegistry& registry_; std::string name_; - float value_; + int64_t value_; public: SharedMetrics(MetricsRegistry& registry, const std::string& name, - MetricsType type); + MetricsUpdatePolicy policy); - void Add(float delta); + void Add(int64_t delta); }; @@ -121,7 +151,7 @@ private: MetricsRegistry& registry_; std::string name_; - MetricsType type_; + MetricsUpdatePolicy policy_; bool active_; boost::posix_time::ptime start_; @@ -133,7 +163,7 @@ Timer(MetricsRegistry& registry, const std::string& name, - MetricsType type); + MetricsUpdatePolicy policy); ~Timer(); }; diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/MultiThreading/IRunnableBySteps.h --- a/OrthancFramework/Sources/MultiThreading/IRunnableBySteps.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/MultiThreading/IRunnableBySteps.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/MultiThreading/Mutex.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Sources/MultiThreading/Mutex.h Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,70 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * . + **/ + + +#pragma once + +#if !defined(__EMSCRIPTEN__) +# include +#endif + +namespace Orthanc +{ + // Wrapper class for compatibility with Emscripten + +#if defined(__EMSCRIPTEN__) + + class ORTHANC_PUBLIC Mutex : public boost::noncopyable + { + public: + class ORTHANC_PUBLIC ScopedLock : public boost::noncopyable + { + public: + explicit ScopedLock(Mutex& mutex) + { + } + }; + }; + +#else + + class ORTHANC_PUBLIC Mutex : public boost::noncopyable + { + private: + boost::mutex mutex_; + + public: + class ORTHANC_PUBLIC ScopedLock : public boost::noncopyable + { + private: + boost::mutex::scoped_lock lock_; + + public: + explicit ScopedLock(Mutex& mutex) : + lock_(mutex.mutex_) + { + } + }; + }; +#endif +} diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/MultiThreading/RunnableWorkersPool.cpp --- a/OrthancFramework/Sources/MultiThreading/RunnableWorkersPool.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/MultiThreading/RunnableWorkersPool.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -39,9 +40,12 @@ const bool& continue_; SharedMessageQueue& queue_; boost::thread thread_; + std::string name_; static void WorkerThread(Worker* that) { + Logging::SetCurrentThreadName(that->name_); + while (that->continue_) { try @@ -81,9 +85,11 @@ public: Worker(const bool& globalContinue, - SharedMessageQueue& queue) : + SharedMessageQueue& queue, + const std::string& name) : continue_(globalContinue), - queue_(queue) + queue_(queue), + name_(name) { thread_ = boost::thread(WorkerThread, this); } @@ -105,7 +111,7 @@ - RunnableWorkersPool::RunnableWorkersPool(size_t countWorkers) : pimpl_(new PImpl) + RunnableWorkersPool::RunnableWorkersPool(size_t countWorkers, const std::string& name) : pimpl_(new PImpl) { pimpl_->continue_ = true; @@ -118,7 +124,8 @@ for (size_t i = 0; i < countWorkers; i++) { - pimpl_->workers_[i] = new PImpl::Worker(pimpl_->continue_, pimpl_->queue_); + std::string workerName = name + boost::lexical_cast(i); + pimpl_->workers_[i] = new PImpl::Worker(pimpl_->continue_, pimpl_->queue_, workerName); } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/MultiThreading/RunnableWorkersPool.h --- a/OrthancFramework/Sources/MultiThreading/RunnableWorkersPool.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/MultiThreading/RunnableWorkersPool.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -38,7 +39,7 @@ void Stop(); public: - explicit RunnableWorkersPool(size_t countWorkers); + explicit RunnableWorkersPool(size_t countWorkers, const std::string& name); ~RunnableWorkersPool(); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/MultiThreading/Semaphore.cpp --- a/OrthancFramework/Sources/MultiThreading/Semaphore.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/MultiThreading/Semaphore.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/MultiThreading/Semaphore.h --- a/OrthancFramework/Sources/MultiThreading/Semaphore.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/MultiThreading/Semaphore.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/MultiThreading/SharedMessageQueue.cpp --- a/OrthancFramework/Sources/MultiThreading/SharedMessageQueue.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/MultiThreading/SharedMessageQueue.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/MultiThreading/SharedMessageQueue.h --- a/OrthancFramework/Sources/MultiThreading/SharedMessageQueue.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/MultiThreading/SharedMessageQueue.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/OrthancException.cpp --- a/OrthancFramework/Sources/OrthancException.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/OrthancException.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -31,7 +32,8 @@ { OrthancException::OrthancException(const OrthancException& other) : errorCode_(other.errorCode_), - httpStatus_(other.httpStatus_) + httpStatus_(other.httpStatus_), + logged_(false) { if (other.details_.get() != NULL) { @@ -41,7 +43,8 @@ OrthancException::OrthancException(ErrorCode errorCode) : errorCode_(errorCode), - httpStatus_(ConvertErrorCodeToHttpStatus(errorCode)) + httpStatus_(ConvertErrorCodeToHttpStatus(errorCode)), + logged_(false) { } @@ -50,6 +53,7 @@ bool log) : errorCode_(errorCode), httpStatus_(ConvertErrorCodeToHttpStatus(errorCode)), + logged_(log), details_(new std::string(details)) { #if ORTHANC_ENABLE_LOGGING == 1 @@ -63,7 +67,8 @@ OrthancException::OrthancException(ErrorCode errorCode, HttpStatus httpStatus) : errorCode_(errorCode), - httpStatus_(httpStatus) + httpStatus_(httpStatus), + logged_(false) { } @@ -73,6 +78,7 @@ bool log) : errorCode_(errorCode), httpStatus_(httpStatus), + logged_(log), details_(new std::string(details)) { #if ORTHANC_ENABLE_LOGGING == 1 @@ -114,4 +120,10 @@ return details_->c_str(); } } + + bool OrthancException::HasBeenLogged() const + { + return logged_; + } + } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/OrthancException.h --- a/OrthancFramework/Sources/OrthancException.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/OrthancException.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -38,6 +39,7 @@ ErrorCode errorCode_; HttpStatus httpStatus_; + bool logged_; // has the exception already been logged ? (to avoid double logs) // New in Orthanc 1.5.0 std::unique_ptr details_; @@ -68,5 +70,7 @@ bool HasDetails() const; const char* GetDetails() const; + + bool HasBeenLogged() const; }; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/OrthancFramework.cpp --- a/OrthancFramework/Sources/OrthancFramework.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/OrthancFramework.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/OrthancFramework.h --- a/OrthancFramework/Sources/OrthancFramework.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/OrthancFramework.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Pkcs11.cpp --- a/OrthancFramework/Sources/Pkcs11.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Pkcs11.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Pkcs11.h --- a/OrthancFramework/Sources/Pkcs11.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Pkcs11.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/PrecompiledHeaders.cpp --- a/OrthancFramework/Sources/PrecompiledHeaders.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/PrecompiledHeaders.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/PrecompiledHeaders.h --- a/OrthancFramework/Sources/PrecompiledHeaders.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/PrecompiledHeaders.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApi.cpp --- a/OrthancFramework/Sources/RestApi/RestApi.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApi.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -138,6 +139,7 @@ protected: virtual bool HandleCall(RestApiCall& call, + const std::string& path, const std::set& uriArgumentsNames) = 0; public: @@ -157,7 +159,7 @@ std::string path = Toolbox::FlattenUri(uri); if (hasTrailing) { - path += "/{...}"; + path += "/{path}"; } std::set uriArgumentsNames; @@ -173,8 +175,8 @@ if (hasTrailing) { - uriArgumentsNames.insert("..."); - uriArguments["..."] = ""; + uriArgumentsNames.insert("path"); + uriArguments["path"] = ""; } if (resource.HasHandler(HttpMethod_Get)) @@ -182,7 +184,7 @@ totalPathsCount_ ++; StringHttpOutput o1; - HttpOutput o2(o1, false); + HttpOutput o2(o1, false /* assume no keep-alive */, 0); RestApiOutput o3(o2, HttpMethod_Get); RestApiGetCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */, "" /* username */, HttpToolbox::Arguments() /* HTTP headers */, @@ -194,7 +196,7 @@ try { ok = (resource.Handle(call) && - HandleCall(call, uriArgumentsNames)); + HandleCall(call, path, uriArgumentsNames)); } catch (OrthancException& e) { @@ -220,7 +222,7 @@ totalPathsCount_ ++; StringHttpOutput o1; - HttpOutput o2(o1, false); + HttpOutput o2(o1, false /* assume no keep-alive */, 0); RestApiOutput o3(o2, HttpMethod_Post); RestApiPostCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */, "" /* username */, HttpToolbox::Arguments() /* HTTP headers */, @@ -232,7 +234,7 @@ try { ok = (resource.Handle(call) && - HandleCall(call, uriArgumentsNames)); + HandleCall(call, path, uriArgumentsNames)); } catch (OrthancException& e) { @@ -258,7 +260,7 @@ totalPathsCount_ ++; StringHttpOutput o1; - HttpOutput o2(o1, false); + HttpOutput o2(o1, false /* assume no keep-alive */, 0); RestApiOutput o3(o2, HttpMethod_Delete); RestApiDeleteCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */, "" /* username */, HttpToolbox::Arguments() /* HTTP headers */, @@ -269,7 +271,7 @@ try { ok = (resource.Handle(call) && - HandleCall(call, uriArgumentsNames)); + HandleCall(call, path, uriArgumentsNames)); } catch (OrthancException& e) { @@ -295,7 +297,7 @@ totalPathsCount_ ++; StringHttpOutput o1; - HttpOutput o2(o1, false); + HttpOutput o2(o1, false /* assume no keep-alive */, 0); RestApiOutput o3(o2, HttpMethod_Put); RestApiPutCall call(o3, restApi_, RequestOrigin_Documentation, "" /* remote IP */, "" /* username */, HttpToolbox::Arguments() /* HTTP headers */, @@ -307,7 +309,7 @@ try { ok = (resource.Handle(call) && - HandleCall(call, uriArgumentsNames)); + HandleCall(call, path, uriArgumentsNames)); } catch (OrthancException& e) { @@ -366,10 +368,9 @@ protected: virtual bool HandleCall(RestApiCall& call, + const std::string& path, const std::set& uriArgumentsNames) ORTHANC_OVERRIDE { - const std::string path = Toolbox::FlattenUri(call.GetFullUri()); - Json::Value v; if (call.GetDocumentation().FormatOpenApi(v, uriArgumentsNames, path)) { @@ -684,9 +685,10 @@ protected: virtual bool HandleCall(RestApiCall& call, + const std::string& _path, const std::set& uriArgumentsNames) ORTHANC_OVERRIDE { - Path& path = paths_[ Toolbox::FlattenUri(call.GetFullUri()) ]; + Path& path = paths_[ _path ]; path.AddMethod(call.GetMethod(), call.GetDocumentation().GetTag(), call.GetDocumentation().IsDeprecated()); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApi.h --- a/OrthancFramework/Sources/RestApi/RestApi.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApi.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiCall.cpp --- a/OrthancFramework/Sources/RestApi/RestApiCall.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiCall.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiCall.h --- a/OrthancFramework/Sources/RestApi/RestApiCall.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiCall.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiCallDocumentation.cpp --- a/OrthancFramework/Sources/RestApi/RestApiCallDocumentation.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiCallDocumentation.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiCallDocumentation.h --- a/OrthancFramework/Sources/RestApi/RestApiCallDocumentation.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiCallDocumentation.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiDeleteCall.h --- a/OrthancFramework/Sources/RestApi/RestApiDeleteCall.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiDeleteCall.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiGetCall.cpp --- a/OrthancFramework/Sources/RestApi/RestApiGetCall.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiGetCall.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiGetCall.h --- a/OrthancFramework/Sources/RestApi/RestApiGetCall.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiGetCall.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiHierarchy.cpp --- a/OrthancFramework/Sources/RestApi/RestApiHierarchy.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiHierarchy.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiHierarchy.h --- a/OrthancFramework/Sources/RestApi/RestApiHierarchy.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiHierarchy.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiOutput.cpp --- a/OrthancFramework/Sources/RestApi/RestApiOutput.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiOutput.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiOutput.h --- a/OrthancFramework/Sources/RestApi/RestApiOutput.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiOutput.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiPath.cpp --- a/OrthancFramework/Sources/RestApi/RestApiPath.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiPath.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiPath.h --- a/OrthancFramework/Sources/RestApi/RestApiPath.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiPath.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiPostCall.h --- a/OrthancFramework/Sources/RestApi/RestApiPostCall.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiPostCall.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/RestApi/RestApiPutCall.h --- a/OrthancFramework/Sources/RestApi/RestApiPutCall.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/RestApi/RestApiPutCall.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/Connection.cpp --- a/OrthancFramework/Sources/SQLite/Connection.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/Connection.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/Connection.h --- a/OrthancFramework/Sources/SQLite/Connection.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/Connection.h Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * @@ -46,7 +47,16 @@ #include #include -#define SQLITE_FROM_HERE ::Orthanc::SQLite::StatementId(__FILE__, __LINE__) +#if !defined(__ORTHANC_FILE__) +# if defined(_MSC_VER) +# pragma message("Warning: Macro __ORTHANC_FILE__ is not defined, this will leak the full path of the source files in the binaries") +# else +# warning Warning: Macro __ORTHANC_FILE__ is not defined, this will leak the full path of the source files in the binaries +# endif +# define __ORTHANC_FILE__ __FILE__ +#endif + +#define SQLITE_FROM_HERE ::Orthanc::SQLite::StatementId(__ORTHANC_FILE__, __LINE__) namespace Orthanc { diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/FunctionContext.cpp --- a/OrthancFramework/Sources/SQLite/FunctionContext.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/FunctionContext.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/FunctionContext.h --- a/OrthancFramework/Sources/SQLite/FunctionContext.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/FunctionContext.h Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/IScalarFunction.h --- a/OrthancFramework/Sources/SQLite/IScalarFunction.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/IScalarFunction.h Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/ITransaction.h --- a/OrthancFramework/Sources/SQLite/ITransaction.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/ITransaction.h Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/NonCopyable.h --- a/OrthancFramework/Sources/SQLite/NonCopyable.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/NonCopyable.h Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/OrthancSQLiteException.h --- a/OrthancFramework/Sources/SQLite/OrthancSQLiteException.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/OrthancSQLiteException.h Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/SQLiteTypes.h --- a/OrthancFramework/Sources/SQLite/SQLiteTypes.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/SQLiteTypes.h Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/Statement.cpp --- a/OrthancFramework/Sources/SQLite/Statement.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/Statement.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/Statement.h --- a/OrthancFramework/Sources/SQLite/Statement.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/Statement.h Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/StatementId.cpp --- a/OrthancFramework/Sources/SQLite/StatementId.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/StatementId.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/StatementId.h --- a/OrthancFramework/Sources/SQLite/StatementId.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/StatementId.h Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/StatementReference.cpp --- a/OrthancFramework/Sources/SQLite/StatementReference.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/StatementReference.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/StatementReference.h --- a/OrthancFramework/Sources/SQLite/StatementReference.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/StatementReference.h Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/Transaction.cpp --- a/OrthancFramework/Sources/SQLite/Transaction.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/Transaction.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SQLite/Transaction.h --- a/OrthancFramework/Sources/SQLite/Transaction.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SQLite/Transaction.h Tue Sep 24 11:39:52 2024 +0200 @@ -3,8 +3,9 @@ * * Copyright (C) 2012-2016 Sebastien Jodogne , * Medical Physics Department, CHU of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * Copyright (c) 2012 The Chromium Authors. All rights reserved. * diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SerializationToolbox.cpp --- a/OrthancFramework/Sources/SerializationToolbox.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SerializationToolbox.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -72,6 +73,21 @@ } + std::string SerializationToolbox::ReadString(const Json::Value& value, + const std::string& field, + const std::string& defaultValue) + { + if (value.isMember(field.c_str())) + { + return ReadString(value, field); + } + else + { + return defaultValue; + } + } + + int SerializationToolbox::ReadInteger(const Json::Value& value, const std::string& field) { @@ -155,31 +171,52 @@ void SerializationToolbox::ReadArrayOfStrings(std::vector& target, - const Json::Value& value, + const Json::Value& valueObject, const std::string& field) { - if (value.type() != Json::objectValue || - !value.isMember(field.c_str()) || - value[field.c_str()].type() != Json::arrayValue) + if (valueObject.type() != Json::objectValue || + !valueObject.isMember(field.c_str()) || + valueObject[field.c_str()].type() != Json::arrayValue) { throw OrthancException(ErrorCode_BadFileFormat, - "List of strings expected in field: " + field); + "List of strings expected in field: " + field); } - const Json::Value& arr = value[field.c_str()]; + const Json::Value& arr = valueObject[field.c_str()]; - target.resize(arr.size()); + try + { + ReadArrayOfStrings(target, arr); + } + catch (OrthancException& ex) + { // more detailed error + throw OrthancException(ErrorCode_BadFileFormat, + "List of strings expected in field: " + field); + } + } + - for (Json::Value::ArrayIndex i = 0; i < arr.size(); i++) + void SerializationToolbox::ReadArrayOfStrings(std::vector& target, + const Json::Value& valueArray) + { + if (valueArray.type() != Json::arrayValue) { - if (arr[i].type() != Json::stringValue) + throw OrthancException(ErrorCode_BadFileFormat, + "List of strings expected"); + } + + target.resize(valueArray.size()); + + for (Json::Value::ArrayIndex i = 0; i < valueArray.size(); i++) + { + if (valueArray[i].type() != Json::stringValue) { throw OrthancException(ErrorCode_BadFileFormat, - "List of strings expected in field: " + field); + "List of strings expected"); } else { - target[i] = arr[i].asString(); + target[i] = valueArray[i].asString(); } } } @@ -201,11 +238,25 @@ void SerializationToolbox::ReadSetOfStrings(std::set& target, - const Json::Value& value, + const Json::Value& valueObject, const std::string& field) { std::vector tmp; - ReadArrayOfStrings(tmp, value, field); + ReadArrayOfStrings(tmp, valueObject, field); + + target.clear(); + for (size_t i = 0; i < tmp.size(); i++) + { + target.insert(tmp[i]); + } + } + + + void SerializationToolbox::ReadSetOfStrings(std::set& target, + const Json::Value& valueArray) + { + std::vector tmp; + ReadArrayOfStrings(tmp, valueArray); target.clear(); for (size_t i = 0; i < tmp.size(); i++) @@ -364,24 +415,38 @@ } - void SerializationToolbox::WriteSetOfStrings(Json::Value& target, + void SerializationToolbox::WriteSetOfStrings(Json::Value& targetObject, const std::set& values, const std::string& field) { - if (target.type() != Json::objectValue || - target.isMember(field.c_str())) + if (targetObject.type() != Json::objectValue || + targetObject.isMember(field.c_str())) { throw OrthancException(ErrorCode_BadFileFormat); } - Json::Value& value = target[field]; + Json::Value& targetArray = targetObject[field]; + + targetArray = Json::arrayValue; + + WriteSetOfStrings(targetArray, values); + } + - value = Json::arrayValue; + void SerializationToolbox::WriteSetOfStrings(Json::Value& targetArray, + const std::set& values) + { + if (targetArray.type() != Json::arrayValue) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + targetArray.clear(); for (std::set::const_iterator it = values.begin(); it != values.end(); ++it) { - value.append(*it); + targetArray.append(*it); } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SerializationToolbox.h --- a/OrthancFramework/Sources/SerializationToolbox.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SerializationToolbox.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -38,6 +39,10 @@ static std::string ReadString(const Json::Value& value, const std::string& field); + static std::string ReadString(const Json::Value& value, + const std::string& field, + const std::string& defaultValue); + static int ReadInteger(const Json::Value& value, const std::string& field); @@ -56,17 +61,23 @@ const std::string& field); static void ReadArrayOfStrings(std::vector& target, - const Json::Value& value, + const Json::Value& valueObject, const std::string& field); + static void ReadArrayOfStrings(std::vector& target, + const Json::Value& valueArray); + static void ReadListOfStrings(std::list& target, const Json::Value& value, const std::string& field); static void ReadSetOfStrings(std::set& target, - const Json::Value& value, + const Json::Value& valueObject, const std::string& field); + static void ReadSetOfStrings(std::set& target, + const Json::Value& valueArray); + static void ReadSetOfTags(std::set& target, const Json::Value& value, const std::string& field); @@ -87,10 +98,13 @@ const std::list& values, const std::string& field); - static void WriteSetOfStrings(Json::Value& target, + static void WriteSetOfStrings(Json::Value& targetObject, const std::set& values, const std::string& field); + static void WriteSetOfStrings(Json::Value& targetArray, + const std::set& values); + static void WriteSetOfTags(Json::Value& target, const std::set& tags, const std::string& field); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SharedLibrary.cpp --- a/OrthancFramework/Sources/SharedLibrary.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SharedLibrary.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SharedLibrary.h --- a/OrthancFramework/Sources/SharedLibrary.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SharedLibrary.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/StringMemoryBuffer.cpp --- a/OrthancFramework/Sources/StringMemoryBuffer.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/StringMemoryBuffer.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/StringMemoryBuffer.h --- a/OrthancFramework/Sources/StringMemoryBuffer.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/StringMemoryBuffer.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SystemToolbox.cpp --- a/OrthancFramework/Sources/SystemToolbox.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SystemToolbox.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -520,7 +521,7 @@ { // This is an adapted version of the patch proposed in issue #64 // without an explicit call to "malloc()" to prevent memory leak - // https://bugs.orthanc-server.com/show_bug.cgi?id=64 + // https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=64 // https://stackoverflow.com/q/31494901/881731 const int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV }; @@ -725,10 +726,56 @@ } } + bool SystemToolbox::IsContentCompressible(MimeType mime) + { + switch (mime) + { + case MimeType_Css: + case MimeType_Html: + case MimeType_JavaScript: + case MimeType_Json: + case MimeType_Pam: + case MimeType_Pdf: + case MimeType_PlainText: + case MimeType_WebAssembly: + case MimeType_Xml: + case MimeType_PrometheusText: + case MimeType_DicomWebJson: + case MimeType_DicomWebXml: + return true; + default: // for all other (JPEG, DICOM, binary, ...) + return false; + } + } + + bool SystemToolbox::IsContentCompressible(const std::string& contentType) + { + if (contentType.empty()) + { + return false; + } + + if (contentType.find(MIME_JSON) != std::string::npos || + contentType.find(MIME_XML) != std::string::npos || + contentType.find(MIME_DICOM_WEB_JSON) != std::string::npos || + contentType.find(MIME_DICOM_WEB_XML) != std::string::npos || + contentType.find(MIME_PDF) != std::string::npos || + contentType.find(MIME_CSS) != std::string::npos || + contentType.find(MIME_HTML) != std::string::npos || + contentType.find(MIME_JAVASCRIPT) != std::string::npos || + contentType.find(MIME_PLAIN_TEXT) != std::string::npos || + contentType.find(MIME_WEB_ASSEMBLY) != std::string::npos || + contentType.find(MIME_XML_2) != std::string::npos) + { + return true; + } + + return false; + } MimeType SystemToolbox::AutodetectMimeType(const std::string& path) { - std::string extension = boost::filesystem::extension(path); + std::string extension = boost::filesystem::path(path).extension().string(); Toolbox::ToLowerCase(extension); // http://en.wikipedia.org/wiki/Mime_types @@ -825,6 +872,18 @@ { return MimeType_Zip; } + else if (extension == ".mtl") + { + return MimeType_Mtl; + } + else if (extension == ".obj") + { + return MimeType_Obj; + } + else if (extension == ".stl") + { + return MimeType_Stl; + } // Default type else diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/SystemToolbox.h --- a/OrthancFramework/Sources/SystemToolbox.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/SystemToolbox.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -108,6 +109,10 @@ static unsigned int GetHardwareConcurrency(); + static bool IsContentCompressible(MimeType mime); + + static bool IsContentCompressible(const std::string& contentType); + static MimeType AutodetectMimeType(const std::string& path); static void GetEnvironmentVariables(std::map& env); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/TemporaryFile.cpp --- a/OrthancFramework/Sources/TemporaryFile.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/TemporaryFile.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/TemporaryFile.h --- a/OrthancFramework/Sources/TemporaryFile.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/TemporaryFile.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Toolbox.cpp --- a/OrthancFramework/Sources/Toolbox.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Toolbox.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -36,6 +37,10 @@ # error Cannot access the version of JsonCpp #endif +#if !defined(ORTHANC_ENABLE_ICU) +# define ORTHANC_ENABLE_ICU 1 +#endif + /** * We use deprecated "Json::Reader", "Json::StyledWriter" and @@ -143,8 +148,14 @@ #if defined(ORTHANC_STATIC_ICU) + +# if (ORTHANC_STATIC_ICU == 1) && (ORTHANC_ENABLE_ICU == 1) +# if !defined(ORTHANC_FRAMEWORK_INCLUDE_RESOURCES) || (ORTHANC_FRAMEWORK_INCLUDE_RESOURCES == 1) +# include +# endif +# endif + # if (ORTHANC_STATIC_ICU == 1 && ORTHANC_ENABLE_LOCALE == 1) -# include # include # include # include "Compression/GzipCompressor.h" @@ -414,6 +425,23 @@ } } + std::string Toolbox::JoinUri(const std::string& base, const std::string& uri) + { + if (uri.size() > 0 && base.size() > 0) + { + if (base[base.size() - 1] == '/' && uri[0] == '/') + { + return base + uri.substr(1, uri.size() - 1); + } + else if (base[base.size() - 1] != '/' && uri[0] != '/') + { + return base + "/" + uri; + } + } + + return base + uri; + } + #if ORTHANC_ENABLE_MD5 == 1 static char GetHexadecimalCharacter(uint8_t value) @@ -469,6 +497,20 @@ result[2 * i + 1] = GetHexadecimalCharacter(static_cast(actualHash[i] % 16)); } } + + void Toolbox::ComputeMD5(std::string& result, + const std::set& data) + { + std::string s; + + for (std::set::const_iterator it = data.begin(); it != data.end(); ++it) + { + s += *it; + } + + ComputeMD5(result, s); + } + #endif @@ -609,11 +651,15 @@ bool hasCodeExtensions) { #if ORTHANC_STATIC_ICU == 1 +# if ORTHANC_ENABLE_ICU == 0 + throw OrthancException(ErrorCode_NotImplemented, "ICU is disabled for this target"); +# else if (globalIcuData_.empty()) { throw OrthancException(ErrorCode_BadSequenceOfCalls, "Call Toolbox::InitializeGlobalLocale()"); } +# endif #endif // The "::skip" flag makes boost skip invalid UTF-8 @@ -668,11 +714,15 @@ Encoding targetEncoding) { #if ORTHANC_STATIC_ICU == 1 +# if ORTHANC_ENABLE_ICU == 0 + throw OrthancException(ErrorCode_NotImplemented, "ICU is disabled for this target"); +# else if (globalIcuData_.empty()) { throw OrthancException(ErrorCode_BadSequenceOfCalls, "Call Toolbox::InitializeGlobalLocale()"); } +# endif #endif // The "::skip" flag makes boost skip invalid UTF-8 @@ -751,7 +801,6 @@ return result; } - void Toolbox::ComputeSHA1(std::string& result, const void* data, size_t size) @@ -764,11 +813,13 @@ } unsigned int digest[5]; - // Sanity check for the memory layout: A SHA-1 digest is 160 bits wide - assert(sizeof(unsigned int) == 4 && sizeof(digest) == (160 / 8)); + assert(sizeof(unsigned int) == 4 && sizeof(digest) == (160 / 8)); + assert(sizeof(boost::uuids::detail::sha1::digest_type) == 20); - sha1.get_digest(digest); + // From Boost 1.86, digest_type is "unsigned char[20]" while it was "unsigned int[5]"" in previous versions. + // Always perform the cast even if it is useless for Boost < 1.86 + sha1.get_digest(*(reinterpret_cast(digest))); result.resize(8 * 5 + 4); sprintf(&result[0], "%08x-%08x-%08x-%08x-%08x", @@ -1000,10 +1051,10 @@ return result; } - - void Toolbox::TokenizeString(std::vector& result, + static void TokenizeStringInternal(std::vector& result, const std::string& value, - char separator) + char separator, + bool includeEmptyStrings) { size_t countSeparators = 0; @@ -1033,20 +1084,54 @@ } } - result.push_back(currentItem); + if (includeEmptyStrings || !currentItem.empty()) + { + result.push_back(currentItem); + } + } + + + void Toolbox::TokenizeString(std::vector& result, + const std::string& value, + char separator) + { + TokenizeStringInternal(result, value, separator, true); + } + + + void Toolbox::SplitString(std::set& result, + const std::string& value, + char separator) + { + result.clear(); + + std::vector temp; + TokenizeStringInternal(temp, value, separator, false); + for (size_t i = 0; i < temp.size(); ++i) + { + result.insert(temp[i]); + } + } + + + void Toolbox::SplitString(std::vector& result, + const std::string& value, + char separator) + { + TokenizeStringInternal(result, value, separator, false); } void Toolbox::JoinStrings(std::string& result, - std::set& source, + const std::set& source, const char* separator) { result = boost::algorithm::join(source, separator); } - void JoinStrings(std::string& result, - std::vector& source, - const char* separator) + void Toolbox::JoinStrings(std::string& result, + const std::vector& source, + const char* separator) { result = boost::algorithm::join(source, separator); } @@ -1508,7 +1593,7 @@ static void InitializeIcu() { -#if ORTHANC_STATIC_ICU == 1 +#if (ORTHANC_STATIC_ICU == 1) && (ORTHANC_ENABLE_ICU == 1) if (globalIcuData_.empty()) { LOG(INFO) << "Setting up the ICU common data"; @@ -1676,10 +1761,14 @@ bool error = (globalLocale_.get() == NULL); #if ORTHANC_STATIC_ICU == 1 +# if ORTHANC_ENABLE_ICU == 0 + throw OrthancException(ErrorCode_NotImplemented, "ICU is disabled for this target"); +# else if (globalIcuData_.empty()) { error = true; } +# endif #endif if (error) @@ -1797,7 +1886,7 @@ std::string Toolbox::GenerateUuid() { -#ifdef WIN32 +#ifdef _WIN32 UUID uuid; UuidCreate ( &uuid ); @@ -2426,6 +2515,302 @@ value = value.substr(1, value.size() - 2); } } + + Toolbox::ElapsedTimer::ElapsedTimer() + { + Restart(); + } + + void Toolbox::ElapsedTimer::Restart() + { + start_ = boost::posix_time::microsec_clock::universal_time(); + } + + uint64_t Toolbox::ElapsedTimer::GetElapsedMilliseconds() + { + return GetElapsedNanoseconds() / 1000000; + } + + uint64_t Toolbox::ElapsedTimer::GetElapsedMicroseconds() + { + return GetElapsedNanoseconds() / 1000; + } + + uint64_t Toolbox::ElapsedTimer::GetElapsedNanoseconds() + { + boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); + boost::posix_time::time_duration diff = now - start_; + return static_cast(diff.total_nanoseconds()); + } + + std::string Toolbox::ElapsedTimer::GetHumanElapsedDuration() + { + return Toolbox::GetHumanDuration(GetElapsedNanoseconds()); + } + + // in "full" mode, returns " 26.45MB in 2.25s = 94.04Mbps" + // else, returns "94.04Mbps" + std::string Toolbox::ElapsedTimer::GetHumanTransferSpeed(bool full, uint64_t sizeInBytes) + { + return Toolbox::GetHumanTransferSpeed(full, sizeInBytes, GetElapsedNanoseconds()); + } + + Toolbox::ElapsedTimeLogger::ElapsedTimeLogger(const std::string& message) + : message_(message), + logged_(false) + { + Restart(); + } + + Toolbox::ElapsedTimeLogger::~ElapsedTimeLogger() + { + if (!logged_) + { + StopAndLog(); + } + } + + void Toolbox::ElapsedTimeLogger::Restart() + { + timer_.Restart(); + } + + void Toolbox::ElapsedTimeLogger::StopAndLog() + { + LOG(WARNING) << "ELAPSED TIMER: " << message_ << " (" << timer_.GetElapsedMicroseconds() << " us)"; + logged_ = true; + } + + std::string Toolbox::GetHumanFileSize(uint64_t sizeInBytes) + { + if (sizeInBytes < 1024) + { + std::ostringstream oss; + oss << sizeInBytes << "bytes"; + return oss.str(); + } + else + { + static const char* suffixes[] = {"KB", "MB", "GB", "TB"}; + static const int suffixesCount = sizeof(suffixes) / sizeof(suffixes[0]); + + int i = 0; + double size = static_cast(sizeInBytes)/1024.0; + + while (size >= 1024.0 && i < suffixesCount - 1) + { + size /= 1024.0; + i++; + } + + std::ostringstream oss; + oss << std::fixed << std::setprecision(2) << size << suffixes[i]; + return oss.str(); + } + } + + std::string Toolbox::GetHumanDuration(uint64_t durationInNanoseconds) + { + if (durationInNanoseconds < 1024) + { + std::ostringstream oss; + oss << durationInNanoseconds << "ns"; + return oss.str(); + } + else + { + static const char* suffixes[] = {"ns", "us", "ms", "s"}; + static const int suffixesCount = sizeof(suffixes) / sizeof(suffixes[0]); + + int i = 0; + double duration = static_cast(durationInNanoseconds); + + while (duration >= 1000.0 && i < suffixesCount - 1) + { + duration /= 1000.0; + i++; + } + + std::ostringstream oss; + oss << std::fixed << std::setprecision(2) << duration << suffixes[i]; + return oss.str(); + } + } + + std::string Toolbox::GetHumanTransferSpeed(bool full, uint64_t sizeInBytes, uint64_t durationInNanoseconds) + { + // in "full" mode, returns " 26.45MB in 2.25s = 94.04Mbps" + // else, return "94.04Mbps" + + if (full) + { + std::ostringstream oss; + oss << Toolbox::GetHumanFileSize(sizeInBytes) << " in " << Toolbox::GetHumanDuration(durationInNanoseconds) << " = " << GetHumanTransferSpeed(false, sizeInBytes, durationInNanoseconds); + return oss.str(); + } + + double throughputInBps = 8.0 * 1000000000.0 * static_cast(sizeInBytes) / static_cast(durationInNanoseconds); + + if (throughputInBps < 1000.0) + { + std::ostringstream oss; + oss << throughputInBps << "bps"; + return oss.str(); + } + else + { + throughputInBps /= 1000.0; + static const char* suffixes[] = {"kbps", "Mbps", "Gbps"}; + static const int suffixesCount = sizeof(suffixes) / sizeof(suffixes[0]); + + int i = 0; + + while (throughputInBps >= 1000.0 && i < suffixesCount - 1) + { + throughputInBps /= 1000.0; + i++; + } + + std::ostringstream oss; + oss << std::fixed << std::setprecision(2) << throughputInBps << suffixes[i]; + return oss.str(); + } + } + + + bool Toolbox::ParseVersion(unsigned int& major, + unsigned int& minor, + unsigned int& revision, + const char* version) + { + if (version == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + +#ifdef _MSC_VER +#define ORTHANC_SCANF sscanf_s +#else +#define ORTHANC_SCANF sscanf +#endif + + int a, b, c; + if (ORTHANC_SCANF(version, "%4d.%4d.%4d", &a, &b, &c) == 3) + { + if (a >= 0 && + b >= 0 && + c >= 0) + { + major = static_cast(a); + minor = static_cast(b); + revision = static_cast(c); + return true; + } + else + { + return false; + } + } + else if (ORTHANC_SCANF(version, "%4d.%4d", &a, &b) == 2) + { + if (a >= 0 && + b >= 0) + { + major = static_cast(a); + minor = static_cast(b); + revision = 0; + return true; + } + else + { + return false; + } + } + else if (ORTHANC_SCANF(version, "%4d", &a) == 1 && + a >= 0) + { + if (a >= 0) + { + major = static_cast(a); + minor = 0; + revision = 0; + return true; + } + else + { + return false; + } + } + else + { + return false; + } + } + + + bool Toolbox::IsVersionAbove(const char* version, + unsigned int major, + unsigned int minor, + unsigned int revision) + { + /** + * Note: Similar standalone functions are implemented in + * "OrthancCPlugin.h" and "OrthancPluginCppWrapper.cpp". + **/ + + unsigned int actualMajor, actualMinor, actualRevision; + + if (version == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + else if (!strcmp(version, "mainline")) + { + // Assume compatibility with the mainline + return true; + } + else if (ParseVersion(actualMajor, actualMinor, actualRevision, version)) + { + if (actualMajor > major) + { + return true; + } + + if (actualMajor < major) + { + return false; + } + + // Check the minor version number + assert(actualMajor == major); + + if (actualMinor > minor) + { + return true; + } + + if (actualMinor < minor) + { + return false; + } + + // Check the patch level version number + assert(actualMajor == major); + + if (actualRevision >= revision) + { + return true; + } + else + { + return false; + } + } + else + { + throw OrthancException(ErrorCode_ParameterOutOfRange, "Not a valid version: " + std::string(version)); + } + } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/Toolbox.h --- a/OrthancFramework/Sources/Toolbox.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/Toolbox.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -67,6 +68,8 @@ # include #endif +#include + namespace Orthanc { @@ -119,6 +122,8 @@ static std::string FlattenUri(const UriComponents& components, size_t fromLevel = 0); + static std::string JoinUri(const std::string& base, const std::string& uri); + #if ORTHANC_ENABLE_MD5 == 1 static void ComputeMD5(std::string& result, const std::string& data); @@ -126,6 +131,9 @@ static void ComputeMD5(std::string& result, const void* data, size_t size); + + static void ComputeMD5(std::string& result, + const std::set& data); #endif static void ComputeSHA1(std::string& result, @@ -181,16 +189,27 @@ static std::string WildcardToRegularExpression(const std::string& s); + // TokenizeString result might contain empty strings (not SplitString) static void TokenizeString(std::vector& result, const std::string& source, char separator); + // SplitString result won't contain empty strings (compared to TokenizeString) + static void SplitString(std::vector& result, + const std::string& source, + char separator); + + // SplitString result won't contain empty strings (compared to TokenizeString) + static void SplitString(std::set& result, + const std::string& source, + char separator); + static void JoinStrings(std::string& result, - std::set& source, + const std::set& source, const char* separator); static void JoinStrings(std::string& result, - std::vector& source, + const std::vector& source, const char* separator); // returns true if all element of 'needles' are found in 'haystack' @@ -243,6 +262,22 @@ } } + // returns true if all element of 'needles' are found in 'haystack' + template static void GetIntersection(std::set& target, const std::set& a, const std::set& b) + { + target.clear(); + + for (typename std::set::const_iterator it = a.begin(); + it != a.end(); ++it) + { + if (b.count(*it) > 0) + { + target.insert(*it); + } + } + } + + #if ORTHANC_ENABLE_PUGIXML == 1 static void JsonToXml(std::string& target, const Json::Value& source, @@ -341,6 +376,56 @@ const Json::Value& source); static void RemoveSurroundingQuotes(std::string& value); + + class ORTHANC_PUBLIC ElapsedTimer + { + boost::posix_time::ptime start_; + public: + explicit ElapsedTimer(); + + uint64_t GetElapsedMilliseconds(); + uint64_t GetElapsedMicroseconds(); + uint64_t GetElapsedNanoseconds(); + + std::string GetHumanElapsedDuration(); + std::string GetHumanTransferSpeed(bool full, uint64_t sizeInBytes); + + void Restart(); + }; + + // This is a helper class to measure and log time spend e.g in a method. + // This should be used only during debugging and should likely not ever used in a release. + // By default, you should use it as a RAII but you may force Restart/StopAndLog manually if needed. + class ORTHANC_PUBLIC ElapsedTimeLogger + { + private: + ElapsedTimer timer_; + const std::string message_; + bool logged_; + + public: + explicit ElapsedTimeLogger(const std::string& message); + ~ElapsedTimeLogger(); + + void Restart(); + void StopAndLog(); + }; + + static std::string GetHumanFileSize(uint64_t sizeInBytes); + + static std::string GetHumanDuration(uint64_t durationInNanoseconds); + + static std::string GetHumanTransferSpeed(bool full, uint64_t sizeInBytes, uint64_t durationInNanoseconds); + + static bool ParseVersion(unsigned int& major, + unsigned int& minor, + unsigned int& revision, + const char* version); + + static bool IsVersionAbove(const char* version, + unsigned int major, + unsigned int minor, + unsigned int revision); }; } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/WebServiceParameters.cpp --- a/OrthancFramework/Sources/WebServiceParameters.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/WebServiceParameters.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/Sources/WebServiceParameters.h --- a/OrthancFramework/Sources/WebServiceParameters.h Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/WebServiceParameters.h Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/BitbucketCACertificates.h --- a/OrthancFramework/UnitTestsSources/BitbucketCACertificates.h Thu Sep 15 18:13:17 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -#define BITBUCKET_CERTIFICATES \ -"-----BEGIN CERTIFICATE-----\n" \ -"MIIEFzCCAv+gAwIBAgIQB/LzXIeod6967+lHmTUlvTANBgkqhkiG9w0BAQwFADBh\n" \ -"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \ -"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" \ -"QTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaMFYxCzAJBgNVBAYTAlVT\n" \ -"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMDAuBgNVBAMTJ0RpZ2lDZXJ0IFRMUyBI\n" \ -"eWJyaWQgRUNDIFNIQTM4NCAyMDIwIENBMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA\n" \ -"BMEbxppbmNmkKaDp1AS12+umsmxVwP/tmMZJLwYnUcu/cMEFesOxnYeJuq20ExfJ\n" \ -"qLSDyLiQ0cx0NTY8g3KwtdD3ImnI8YDEe0CPz2iHJlw5ifFNkU3aiYvkA8ND5b8v\n" \ -"c6OCAYIwggF+MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFAq8CCkXjKU5\n" \ -"bXoOzjPHLrPt+8N6MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4G\n" \ -"A1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYI\n" \ -"KwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j\n" \ -"b20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp\n" \ -"Q2VydEdsb2JhbFJvb3RDQS5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny\n" \ -"bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDA9BgNVHSAE\n" \ -"NjA0MAsGCWCGSAGG/WwCATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgG\n" \ -"BmeBDAECAzANBgkqhkiG9w0BAQwFAAOCAQEAR1mBf9QbH7Bx9phdGLqYR5iwfnYr\n" \ -"6v8ai6wms0KNMeZK6BnQ79oU59cUkqGS8qcuLa/7Hfb7U7CKP/zYFgrpsC62pQsY\n" \ -"kDUmotr2qLcy/JUjS8ZFucTP5Hzu5sn4kL1y45nDHQsFfGqXbbKrAjbYwrwsAZI/\n" \ -"BKOLdRHHuSm8EdCGupK8JvllyDfNJvaGEwwEqonleLHBTnm8dqMLUeTF0J5q/hos\n" \ -"Vq4GNiejcxwIfZMy0MJEGdqN9A57HSgDKwmKdsp33Id6rHtSJlWncg+d0ohP/rEh\n" \ -"xRqhqjn1VtvChMQ1H3Dau0bwhr9kAMQ+959GG50jBbl9s08PqUU643QwmA==\n" \ -"-----END CERTIFICATE-----\n" \ -"\n" diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/CMakeLists.txt --- a/OrthancFramework/UnitTestsSources/CMakeLists.txt Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/CMakeLists.txt Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public License @@ -109,6 +110,8 @@ ${GOOGLE_TEST_SOURCES} ) +DefineSourceBasenameForTarget(UnitTests) + target_link_libraries(UnitTests ${ORTHANC_FRAMEWORK_LIBRARIES}) install(TARGETS UnitTests diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/DicomMapTests.cpp --- a/OrthancFramework/UnitTestsSources/DicomMapTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/DicomMapTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -42,6 +43,7 @@ #include "../Sources/DicomParsing/DicomWebJsonVisitor.h" #include +#include using namespace Orthanc; @@ -81,7 +83,8 @@ ASSERT_TRUE(DicomMap::IsMainDicomTag(DICOM_TAG_SOP_INSTANCE_UID)); { - const std::set& s = DicomMap::GetAllMainDicomTags(); + std::set s; + DicomMap::GetAllMainDicomTags(s); ASSERT_TRUE(s.end() != s.find(DICOM_TAG_PATIENT_ID)); ASSERT_TRUE(s.end() != s.find(DICOM_TAG_STUDY_INSTANCE_UID)); ASSERT_TRUE(s.end() != s.find(DICOM_TAG_ACCESSION_NUMBER)); @@ -90,26 +93,30 @@ } { - const std::set& s = DicomMap::GetMainDicomTags(ResourceType_Patient); + std::set s; + DicomMap::GetMainDicomTags(s, ResourceType_Patient); ASSERT_TRUE(s.end() != s.find(DICOM_TAG_PATIENT_ID)); ASSERT_TRUE(s.end() == s.find(DICOM_TAG_STUDY_INSTANCE_UID)); } { - const std::set& s = DicomMap::GetMainDicomTags(ResourceType_Study); + std::set s; + DicomMap::GetMainDicomTags(s, ResourceType_Study); ASSERT_TRUE(s.end() != s.find(DICOM_TAG_STUDY_INSTANCE_UID)); ASSERT_TRUE(s.end() != s.find(DICOM_TAG_ACCESSION_NUMBER)); ASSERT_TRUE(s.end() == s.find(DICOM_TAG_PATIENT_ID)); } { - const std::set& s = DicomMap::GetMainDicomTags(ResourceType_Series); + std::set s; + DicomMap::GetMainDicomTags(s, ResourceType_Series); ASSERT_TRUE(s.end() != s.find(DICOM_TAG_SERIES_INSTANCE_UID)); ASSERT_TRUE(s.end() == s.find(DICOM_TAG_PATIENT_ID)); } { - const std::set& s = DicomMap::GetMainDicomTags(ResourceType_Instance); + std::set s; + DicomMap::GetMainDicomTags(s, ResourceType_Instance); ASSERT_TRUE(s.end() != s.find(DICOM_TAG_SOP_INSTANCE_UID)); ASSERT_TRUE(s.end() == s.find(DICOM_TAG_PATIENT_ID)); } @@ -120,12 +127,14 @@ DicomMap::AddMainDicomTag(DICOM_TAG_BITS_ALLOCATED, ResourceType_Instance); { - const std::set& s = DicomMap::GetMainDicomTags(ResourceType_Instance); + std::set s; + DicomMap::GetMainDicomTags(s, ResourceType_Instance); ASSERT_TRUE(s.end() != s.find(DICOM_TAG_BITS_ALLOCATED)); ASSERT_TRUE(s.end() != s.find(DICOM_TAG_SOP_INSTANCE_UID)); } { - const std::set& s = DicomMap::GetMainDicomTags(ResourceType_Series); + std::set s; + DicomMap::GetMainDicomTags(s, ResourceType_Series); ASSERT_TRUE(s.end() == s.find(DICOM_TAG_BITS_ALLOCATED)); } @@ -242,8 +251,10 @@ // REFERENCE: DICOM PS3.3 2015c - Information Object Definitions // http://dicom.nema.org/medical/dicom/current/output/html/part03.html + std::set main; + DicomMap::GetMainDicomTags(main, level); + std::set moduleTags; - const std::set& main = DicomMap::GetMainDicomTags(level); DicomTag::AddTagsForModule(moduleTags, module); // The main dicom tags are a subset of the module @@ -707,7 +718,7 @@ DicomMap sequencesOnly; m.ExtractSequences(sequencesOnly); - ASSERT_EQ(1, sequencesOnly.GetSize()); + ASSERT_EQ(1u, sequencesOnly.GetSize()); ASSERT_TRUE(sequencesOnly.HasTag(0x0008, 0x1111)); ASSERT_TRUE(sequencesOnly.GetValue(0x0008, 0x1111).GetSequenceContent()[0].isMember("0008,1150")); @@ -715,7 +726,7 @@ DicomMap sequencesCopy; sequencesCopy.SetValue(0x0008, 0x1111, sequencesOnly.GetValue(0x0008, 0x1111)); - ASSERT_EQ(1, sequencesCopy.GetSize()); + ASSERT_EQ(1u, sequencesCopy.GetSize()); ASSERT_TRUE(sequencesCopy.HasTag(0x0008, 0x1111)); ASSERT_TRUE(sequencesCopy.GetValue(0x0008, 0x1111).GetSequenceContent()[0].isMember("0008,1150")); } @@ -918,7 +929,8 @@ { ResourceType level = static_cast(i); - const std::set& tags = DicomMap::GetMainDicomTags(level); + std::set tags; + DicomMap::GetMainDicomTags(tags, level); for (std::set::const_iterator it = tags.begin(); it != tags.end(); ++it) { @@ -1056,6 +1068,113 @@ } +TEST(DicomMap, SetupFindTemplates) +{ + /** + * The templates for C-FIND must be common to all the Orthanc + * servers, and must not be altered by the "ExtraMainDicomTags" + * configuration option that was introduced in Orthanc 1.11.0. + **/ + + { + DicomMap m; + m.SetValue(DICOM_TAG_ENCAPSULATED_DOCUMENT, "nope", false); + m.SetValue(DICOM_TAG_PATIENT_ID, "patient_id", false); + + DicomMap::SetupFindPatientTemplate(m); + std::set tags; + m.GetTags(tags); + + // This corresponds to the values of DEFAULT_PATIENT_MAIN_DICOM_TAGS + ASSERT_EQ(5u, tags.size()); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_PATIENT_ID, "nope", false)); + + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_OTHER_PATIENT_IDS, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_PATIENT_BIRTH_DATE, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_PATIENT_NAME, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_PATIENT_SEX, "nope", false)); + } + + { + DicomMap m; + m.SetValue(DICOM_TAG_ENCAPSULATED_DOCUMENT, "nope", false); + m.SetValue(DICOM_TAG_PATIENT_ID, "patient_id", false); + + DicomMap::SetupFindStudyTemplate(m); + std::set tags; + m.GetTags(tags); + + // This corresponds to the values of DEFAULT_STUDY_MAIN_DICOM_TAGS + ASSERT_EQ(8u, tags.size()); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_PATIENT_ID, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_ACCESSION_NUMBER, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_STUDY_INSTANCE_UID, "nope", false)); + + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_REFERRING_PHYSICIAN_NAME, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_STUDY_DATE, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_STUDY_DESCRIPTION, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_STUDY_ID, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_STUDY_TIME, "nope", false)); + } + + { + DicomMap m; + m.SetValue(DICOM_TAG_ENCAPSULATED_DOCUMENT, "nope", false); + m.SetValue(DICOM_TAG_PATIENT_ID, "patient_id", false); + + DicomMap::SetupFindSeriesTemplate(m); + std::set tags; + m.GetTags(tags); + + // This corresponds to the values of DEFAULT_SERIES_MAIN_DICOM_TAGS + ASSERT_EQ(13u, tags.size()); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_PATIENT_ID, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_ACCESSION_NUMBER, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_STUDY_INSTANCE_UID, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_SERIES_INSTANCE_UID, "nope", false)); + + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_BODY_PART_EXAMINED, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_MODALITY, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_OPERATOR_NAME, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_PERFORMED_PROCEDURE_STEP_DESCRIPTION, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_PROTOCOL_NAME, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_SERIES_DATE, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_SERIES_DESCRIPTION, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_SERIES_NUMBER, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_SERIES_TIME, "nope", false)); + } + + { + DicomMap m; + m.SetValue(DICOM_TAG_ENCAPSULATED_DOCUMENT, "nope", false); + m.SetValue(DICOM_TAG_PATIENT_ID, "patient_id", false); + + DicomMap::SetupFindInstanceTemplate(m); + std::set tags; + m.GetTags(tags); + + // This corresponds to the values of DEFAULT_INSTANCE_MAIN_DICOM_TAGS + ASSERT_EQ(15u, tags.size()); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_PATIENT_ID, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_ACCESSION_NUMBER, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_STUDY_INSTANCE_UID, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_SERIES_INSTANCE_UID, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_SOP_INSTANCE_UID, "nope", false)); + + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_ACQUISITION_NUMBER, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_IMAGE_COMMENTS, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_IMAGE_INDEX, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_IMAGE_POSITION_PATIENT, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_INSTANCE_CREATION_DATE, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_INSTANCE_CREATION_TIME, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_INSTANCE_NUMBER, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_NUMBER_OF_FRAMES, "nope", false)); + ASSERT_EQ("", m.GetStringValue(DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER, "nope", false)); + } +} + + #if ORTHANC_SANDBOXED != 1 #include "../Sources/SystemToolbox.h" @@ -1171,50 +1290,61 @@ { static const std::string PATH = "/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/"; - typedef std::list< std::pair > Sources; + typedef boost::tuple Source; + typedef std::list Sources; + + // $ ~/Subversion/orthanc-tests/Tests/GetPixelDataVR.py ~/Subversion/orthanc-tests/Database/ColorTestMalaterre.dcm ~/Subversion/orthanc-tests/Database/ColorTestImageJ.dcm ~/Subversion/orthanc-tests/Database/Knee/T1/IM-0001-0001.dcm ~/Subversion/orthanc-tests/Database/TransferSyntaxes/*.dcm Sources sources; - sources.push_back(std::make_pair(PATH + "../ColorTestMalaterre.dcm", 0x03a0u)); - sources.push_back(std::make_pair(PATH + "1.2.840.10008.1.2.1.dcm", 0x037cu)); - sources.push_back(std::make_pair(PATH + "1.2.840.10008.1.2.2.dcm", 0x03e8u)); // Big Endian - sources.push_back(std::make_pair(PATH + "1.2.840.10008.1.2.4.50.dcm", 0x04acu)); - sources.push_back(std::make_pair(PATH + "1.2.840.10008.1.2.4.51.dcm", 0x072cu)); - sources.push_back(std::make_pair(PATH + "1.2.840.10008.1.2.4.57.dcm", 0x0620u)); - sources.push_back(std::make_pair(PATH + "1.2.840.10008.1.2.4.70.dcm", 0x065au)); - sources.push_back(std::make_pair(PATH + "1.2.840.10008.1.2.4.80.dcm", 0x0b46u)); - sources.push_back(std::make_pair(PATH + "1.2.840.10008.1.2.4.81.dcm", 0x073eu)); - sources.push_back(std::make_pair(PATH + "1.2.840.10008.1.2.4.90.dcm", 0x0b66u)); - sources.push_back(std::make_pair(PATH + "1.2.840.10008.1.2.4.91.dcm", 0x19b8u)); - sources.push_back(std::make_pair(PATH + "1.2.840.10008.1.2.5.dcm", 0x0b0au)); + sources.push_back(Source(PATH + "../ColorTestMalaterre.dcm", 0x03a0u, ValueRepresentation_Unknown)); // This file has strange VR + sources.push_back(Source(PATH + "../ColorTestImageJ.dcm", 0x00924, ValueRepresentation_OtherByte)); + sources.push_back(Source(PATH + "../Knee/T1/IM-0001-0001.dcm", 0x00c78, ValueRepresentation_OtherWord)); + sources.push_back(Source(PATH + "1.2.840.10008.1.2.1.dcm", 0x037cu, ValueRepresentation_OtherByte)); + sources.push_back(Source(PATH + "1.2.840.10008.1.2.2.dcm", 0x03e8u, ValueRepresentation_OtherByte)); // Big Endian + sources.push_back(Source(PATH + "1.2.840.10008.1.2.4.50.dcm", 0x04acu, ValueRepresentation_OtherByte)); + sources.push_back(Source(PATH + "1.2.840.10008.1.2.4.51.dcm", 0x072cu, ValueRepresentation_OtherByte)); + sources.push_back(Source(PATH + "1.2.840.10008.1.2.4.57.dcm", 0x0620u, ValueRepresentation_OtherByte)); + sources.push_back(Source(PATH + "1.2.840.10008.1.2.4.70.dcm", 0x065au, ValueRepresentation_OtherByte)); + sources.push_back(Source(PATH + "1.2.840.10008.1.2.4.80.dcm", 0x0b46u, ValueRepresentation_OtherByte)); + sources.push_back(Source(PATH + "1.2.840.10008.1.2.4.81.dcm", 0x073eu, ValueRepresentation_OtherByte)); + sources.push_back(Source(PATH + "1.2.840.10008.1.2.4.90.dcm", 0x0b66u, ValueRepresentation_OtherByte)); + sources.push_back(Source(PATH + "1.2.840.10008.1.2.4.91.dcm", 0x19b8u, ValueRepresentation_OtherByte)); + sources.push_back(Source(PATH + "1.2.840.10008.1.2.5.dcm", 0x0b0au, ValueRepresentation_OtherByte)); { std::string dicom; uint64_t offset; + ValueRepresentation vr; + // Not a DICOM image SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.50.png", false); - ASSERT_FALSE(DicomStreamReader::LookupPixelDataOffset(offset, dicom)); + ASSERT_FALSE(DicomStreamReader::LookupPixelDataOffset(offset, vr, dicom)); // Image without valid DICOM preamble SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.dcm", false); - ASSERT_FALSE(DicomStreamReader::LookupPixelDataOffset(offset, dicom)); + ASSERT_FALSE(DicomStreamReader::LookupPixelDataOffset(offset, vr, dicom)); } for (Sources::const_iterator it = sources.begin(); it != sources.end(); ++it) { std::string dicom; - SystemToolbox::ReadFile(dicom, it->first, false); + SystemToolbox::ReadFile(dicom, it->get<0>(), false); { uint64_t offset; - ASSERT_TRUE(DicomStreamReader::LookupPixelDataOffset(offset, dicom)); - ASSERT_EQ(it->second, offset); + ValueRepresentation vr; + ASSERT_TRUE(DicomStreamReader::LookupPixelDataOffset(offset, vr, dicom)); + ASSERT_EQ(it->get<1>(), offset); + ASSERT_EQ(it->get<2>(), vr); } { uint64_t offset; - ASSERT_TRUE(DicomStreamReader::LookupPixelDataOffset(offset, dicom.c_str(), dicom.size())); - ASSERT_EQ(it->second, offset); + ValueRepresentation vr; + ASSERT_TRUE(DicomStreamReader::LookupPixelDataOffset(offset, vr, dicom.c_str(), dicom.size())); + ASSERT_EQ(it->get<1>(), offset); + ASSERT_EQ(it->get<2>(), vr); } ParsedDicomFile a(dicom); @@ -1238,7 +1368,7 @@ r.Consume(visitor); - ASSERT_EQ(it->second, visitor.GetPixelDataOffset()); + ASSERT_EQ(it->get<1>(), visitor.GetPixelDataOffset()); // Truncate the original DICOM up to pixel data dicom.resize(visitor.GetPixelDataOffset()); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/FileStorageTests.cpp --- a/OrthancFramework/UnitTestsSources/FileStorageTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/FileStorageTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -36,6 +37,7 @@ #include "../Sources/Logging.h" #include "../Sources/OrthancException.h" #include "../Sources/Toolbox.h" +#include "../Sources/SystemToolbox.h" #include @@ -87,6 +89,48 @@ ASSERT_EQ(s.GetSize(uid), data.size()); } +TEST(FilesystemStorage, FileWithSameNameAsTopDirectory) +{ + FilesystemStorage s("UnitTestsStorageTop"); + s.Clear(); + + std::vector data; + StringToVector(data, Toolbox::GenerateUuid()); + + SystemToolbox::WriteFile("toto", "UnitTestsStorageTop/12"); + ASSERT_THROW(s.Create("12345678-1234-1234-1234-1234567890ab", &data[0], data.size(), FileContentType_Unknown), OrthancException); + s.Clear(); +} + +TEST(FilesystemStorage, FileWithSameNameAsChildDirectory) +{ + FilesystemStorage s("UnitTestsStorageChild"); + s.Clear(); + + std::vector data; + StringToVector(data, Toolbox::GenerateUuid()); + + SystemToolbox::MakeDirectory("UnitTestsStorageChild/12"); + SystemToolbox::WriteFile("toto", "UnitTestsStorageChild/12/34"); + ASSERT_THROW(s.Create("12345678-1234-1234-1234-1234567890ab", &data[0], data.size(), FileContentType_Unknown), OrthancException); + s.Clear(); +} + +TEST(FilesystemStorage, FileAlreadyExists) +{ + FilesystemStorage s("UnitTestsStorageFileAlreadyExists"); + s.Clear(); + + std::vector data; + StringToVector(data, Toolbox::GenerateUuid()); + + SystemToolbox::MakeDirectory("UnitTestsStorageFileAlreadyExists/12/34"); + SystemToolbox::WriteFile("toto", "UnitTestsStorageFileAlreadyExists/12/34/12345678-1234-1234-1234-1234567890ab"); + ASSERT_THROW(s.Create("12345678-1234-1234-1234-1234567890ab", &data[0], data.size(), FileContentType_Unknown), OrthancException); + s.Clear(); +} + + TEST(FilesystemStorage, EndToEnd) { FilesystemStorage s("UnitTestsStorage"); @@ -127,7 +171,7 @@ { FilesystemStorage s("UnitTestsStorage"); StorageCache cache; - StorageAccessor accessor(s, &cache); + StorageAccessor accessor(s, cache); std::string data = "Hello world"; std::string uuid = Toolbox::GenerateUuid(); @@ -150,7 +194,7 @@ { FilesystemStorage s("UnitTestsStorage"); StorageCache cache; - StorageAccessor accessor(s, &cache); + StorageAccessor accessor(s, cache); std::string data = "Hello world"; std::string uuid = Toolbox::GenerateUuid(); @@ -173,7 +217,7 @@ { FilesystemStorage s("UnitTestsStorage"); StorageCache cache; - StorageAccessor accessor(s, &cache); + StorageAccessor accessor(s, cache); std::string r; std::string compressedData = "Hello"; diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/FrameworkTests.cpp --- a/OrthancFramework/UnitTestsSources/FrameworkTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/FrameworkTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -363,6 +364,10 @@ ASSERT_STREQ("image/svg+xml", EnumerationToString(SystemToolbox::AutodetectMimeType(".svg"))); ASSERT_STREQ("text/css", EnumerationToString(SystemToolbox::AutodetectMimeType(".css"))); ASSERT_STREQ("text/html", EnumerationToString(SystemToolbox::AutodetectMimeType(".html"))); + + ASSERT_STREQ("model/obj", EnumerationToString(SystemToolbox::AutodetectMimeType(".obj"))); + ASSERT_STREQ("model/mtl", EnumerationToString(SystemToolbox::AutodetectMimeType(".mtl"))); + ASSERT_STREQ("model/stl", EnumerationToString(SystemToolbox::AutodetectMimeType(".stl"))); } #endif @@ -377,6 +382,21 @@ ASSERT_EQ("8b1a9953c4611296a827abf8c47804d7", s); Toolbox::ComputeMD5(s, ""); ASSERT_EQ("d41d8cd98f00b204e9800998ecf8427e", s); + + Toolbox::ComputeMD5(s, "aaabbbccc"); + ASSERT_EQ("d1aaf4767a3c10a473407a4e47b02da6", s); + + std::set set; + + Toolbox::ComputeMD5(s, set); + ASSERT_EQ("d41d8cd98f00b204e9800998ecf8427e", s); // empty set same as empty string + + set.insert("bbb"); + set.insert("ccc"); + set.insert("aaa"); + + Toolbox::ComputeMD5(s, set); + ASSERT_EQ("d1aaf4767a3c10a473407a4e47b02da6", s); // set md5 same as string with the values sorted } TEST(Toolbox, ComputeSHA1) @@ -702,6 +722,82 @@ ASSERT_EQ("", t[3]); } +TEST(Toolbox, SplitString) +{ + { + std::set result; + Toolbox::SplitString(result, "", ';'); + ASSERT_EQ(0u, result.size()); + } + + { + std::set result; + Toolbox::SplitString(result, "a", ';'); + ASSERT_EQ(1u, result.size()); + ASSERT_TRUE(result.end() != result.find("a")); + } + + { + std::set result; + Toolbox::SplitString(result, "a;b", ';'); + ASSERT_EQ(2u, result.size()); + ASSERT_TRUE(result.end() != result.find("a")); + ASSERT_TRUE(result.end() != result.find("b")); + } + + { + std::set result; + Toolbox::SplitString(result, "a;b;", ';'); + ASSERT_EQ(2u, result.size()); + ASSERT_TRUE(result.end() != result.find("a")); + ASSERT_TRUE(result.end() != result.find("b")); + } + + { + std::set result; + Toolbox::SplitString(result, "a;a", ';'); + ASSERT_EQ(1u, result.size()); + ASSERT_TRUE(result.end() != result.find("a")); + } + + { + std::vector result; + Toolbox::SplitString(result, "", ';'); + ASSERT_EQ(0u, result.size()); + } + + { + std::vector result; + Toolbox::SplitString(result, "a", ';'); + ASSERT_EQ(1u, result.size()); + ASSERT_EQ("a", result[0]); + } + + { + std::vector result; + Toolbox::SplitString(result, "a;b", ';'); + ASSERT_EQ(2u, result.size()); + ASSERT_EQ("a", result[0]); + ASSERT_EQ("b", result[1]); + } + + { + std::vector result; + Toolbox::SplitString(result, "a;b;", ';'); + ASSERT_EQ(2u, result.size()); + ASSERT_EQ("a", result[0]); + ASSERT_EQ("b", result[1]); + } + + { + std::vector result; + Toolbox::TokenizeString(result, "a;a", ';'); + ASSERT_EQ(2u, result.size()); + ASSERT_EQ("a", result[0]); + ASSERT_EQ("a", result[1]); + } +} + TEST(Toolbox, Enumerations) { ASSERT_EQ(Encoding_Utf8, StringToEncoding(EnumerationToString(Encoding_Utf8))); @@ -749,6 +845,7 @@ ASSERT_EQ(DicomVersion_2008, StringToDicomVersion(EnumerationToString(DicomVersion_2008))); ASSERT_EQ(DicomVersion_2017c, StringToDicomVersion(EnumerationToString(DicomVersion_2017c))); ASSERT_EQ(DicomVersion_2021b, StringToDicomVersion(EnumerationToString(DicomVersion_2021b))); + ASSERT_EQ(DicomVersion_2023b, StringToDicomVersion(EnumerationToString(DicomVersion_2023b))); for (int i = static_cast(ValueRepresentation_ApplicationEntity); i < static_cast(ValueRepresentation_NotSupported); i += 1) @@ -790,6 +887,9 @@ ASSERT_EQ(MimeType_Xml, StringToMimeType(EnumerationToString(MimeType_Xml))); ASSERT_EQ(MimeType_DicomWebJson, StringToMimeType(EnumerationToString(MimeType_DicomWebJson))); ASSERT_EQ(MimeType_DicomWebXml, StringToMimeType(EnumerationToString(MimeType_DicomWebXml))); + ASSERT_EQ(MimeType_Mtl, StringToMimeType(EnumerationToString(MimeType_Mtl))); + ASSERT_EQ(MimeType_Obj, StringToMimeType(EnumerationToString(MimeType_Obj))); + ASSERT_EQ(MimeType_Stl, StringToMimeType(EnumerationToString(MimeType_Stl))); ASSERT_THROW(StringToMimeType("nope"), OrthancException); ASSERT_TRUE(IsResourceLevelAboveOrEqual(ResourceType_Patient, ResourceType_Patient)); @@ -1311,7 +1411,7 @@ { MetricsRegistry m; m.SetEnabled(false); - m.SetValue("hello.world", 42.5f); + m.SetIntegerValue("hello.world", 42); std::string s; m.ExportPrometheusText(s); @@ -1320,7 +1420,7 @@ { MetricsRegistry m; - m.Register("hello.world", MetricsType_Default); + m.Register("hello.world", MetricsUpdatePolicy_Directly, MetricsDataType_Integer); std::string s; m.ExportPrometheusText(s); @@ -1329,9 +1429,9 @@ { MetricsRegistry m; - m.SetValue("hello.world", 42.5f); - ASSERT_EQ(MetricsType_Default, m.GetMetricsType("hello.world")); - ASSERT_THROW(m.GetMetricsType("nope"), OrthancException); + m.SetIntegerValue("hello.world", -42); + ASSERT_EQ(MetricsUpdatePolicy_Directly, m.GetUpdatePolicy("hello.world")); + ASSERT_THROW(m.GetUpdatePolicy("nope"), OrthancException); std::string s; m.ExportPrometheusText(s); @@ -1339,33 +1439,33 @@ std::vector t; Toolbox::TokenizeString(t, s, '\n'); ASSERT_EQ(2u, t.size()); - ASSERT_EQ("hello.world 42.5 ", t[0].substr(0, 17)); + ASSERT_EQ("hello.world -42 ", t[0].substr(0, 16)); ASSERT_TRUE(t[1].empty()); } { MetricsRegistry m; - m.Register("hello.max", MetricsType_MaxOver10Seconds); - m.SetValue("hello.max", 10); - m.SetValue("hello.max", 20); - m.SetValue("hello.max", -10); - m.SetValue("hello.max", 5); + m.Register("hello.max", MetricsUpdatePolicy_MaxOver10Seconds, MetricsDataType_Integer); + m.SetIntegerValue("hello.max", 10); + m.SetIntegerValue("hello.max", 20); + m.SetIntegerValue("hello.max", -10); + m.SetIntegerValue("hello.max", 5); - m.Register("hello.min", MetricsType_MinOver10Seconds); - m.SetValue("hello.min", 10); - m.SetValue("hello.min", 20); - m.SetValue("hello.min", -10); - m.SetValue("hello.min", 5); + m.Register("hello.min", MetricsUpdatePolicy_MinOver10Seconds, MetricsDataType_Integer); + m.SetIntegerValue("hello.min", 10); + m.SetIntegerValue("hello.min", 20); + m.SetIntegerValue("hello.min", -10); + m.SetIntegerValue("hello.min", 5); - m.Register("hello.default", MetricsType_Default); - m.SetValue("hello.default", 10); - m.SetValue("hello.default", 20); - m.SetValue("hello.default", -10); - m.SetValue("hello.default", 5); + m.Register("hello.directly", MetricsUpdatePolicy_Directly, MetricsDataType_Integer); + m.SetIntegerValue("hello.directly", 10); + m.SetIntegerValue("hello.directly", 20); + m.SetIntegerValue("hello.directly", -10); + m.SetIntegerValue("hello.directly", 5); - ASSERT_EQ(MetricsType_MaxOver10Seconds, m.GetMetricsType("hello.max")); - ASSERT_EQ(MetricsType_MinOver10Seconds, m.GetMetricsType("hello.min")); - ASSERT_EQ(MetricsType_Default, m.GetMetricsType("hello.default")); + ASSERT_EQ(MetricsUpdatePolicy_MaxOver10Seconds, m.GetUpdatePolicy("hello.max")); + ASSERT_EQ(MetricsUpdatePolicy_MinOver10Seconds, m.GetUpdatePolicy("hello.min")); + ASSERT_EQ(MetricsUpdatePolicy_Directly, m.GetUpdatePolicy("hello.directly")); std::string s; m.ExportPrometheusText(s); @@ -1385,25 +1485,25 @@ ASSERT_EQ("20", u["hello.max"]); ASSERT_EQ("-10", u["hello.min"]); - ASSERT_EQ("5", u["hello.default"]); + ASSERT_EQ("5", u["hello.directly"]); } { MetricsRegistry m; - m.SetValue("a", 10); - m.SetValue("b", 10, MetricsType_MinOver10Seconds); + m.SetIntegerValue("a", 10); + m.SetIntegerValue("b", 10, MetricsUpdatePolicy_MinOver10Seconds); - m.Register("c", MetricsType_MaxOver10Seconds); - m.SetValue("c", 10, MetricsType_MinOver10Seconds); + m.Register("c", MetricsUpdatePolicy_MaxOver10Seconds, MetricsDataType_Integer); + m.SetIntegerValue("c", 10, MetricsUpdatePolicy_MinOver10Seconds); - m.Register("d", MetricsType_MaxOver10Seconds); - m.Register("d", MetricsType_Default); + m.Register("d", MetricsUpdatePolicy_MaxOver10Seconds, MetricsDataType_Integer); + ASSERT_THROW(m.Register("d", MetricsUpdatePolicy_Directly, MetricsDataType_Integer), OrthancException); - ASSERT_EQ(MetricsType_Default, m.GetMetricsType("a")); - ASSERT_EQ(MetricsType_MinOver10Seconds, m.GetMetricsType("b")); - ASSERT_EQ(MetricsType_MaxOver10Seconds, m.GetMetricsType("c")); - ASSERT_EQ(MetricsType_Default, m.GetMetricsType("d")); + ASSERT_EQ(MetricsUpdatePolicy_Directly, m.GetUpdatePolicy("a")); + ASSERT_EQ(MetricsUpdatePolicy_MinOver10Seconds, m.GetUpdatePolicy("b")); + ASSERT_EQ(MetricsUpdatePolicy_MaxOver10Seconds, m.GetUpdatePolicy("c")); + ASSERT_EQ(MetricsUpdatePolicy_MaxOver10Seconds, m.GetUpdatePolicy("d")); } { @@ -1411,11 +1511,47 @@ { MetricsRegistry::Timer t1(m, "a"); - MetricsRegistry::Timer t2(m, "b", MetricsType_MinOver10Seconds); + MetricsRegistry::Timer t2(m, "b", MetricsUpdatePolicy_MinOver10Seconds); } - ASSERT_EQ(MetricsType_MaxOver10Seconds, m.GetMetricsType("a")); - ASSERT_EQ(MetricsType_MinOver10Seconds, m.GetMetricsType("b")); + ASSERT_EQ(MetricsUpdatePolicy_MaxOver10Seconds, m.GetUpdatePolicy("a")); + ASSERT_EQ(MetricsUpdatePolicy_MinOver10Seconds, m.GetUpdatePolicy("b")); + } + + { + MetricsRegistry m; + m.Register("c", MetricsUpdatePolicy_MaxOver10Seconds, MetricsDataType_Integer); + m.SetFloatValue("c", 100, MetricsUpdatePolicy_MinOver10Seconds); + + ASSERT_EQ(MetricsUpdatePolicy_MaxOver10Seconds, m.GetUpdatePolicy("c")); + ASSERT_EQ(MetricsDataType_Integer, m.GetDataType("c")); + } + + { + MetricsRegistry m; + m.Register("c", MetricsUpdatePolicy_MaxOver10Seconds, MetricsDataType_Float); + m.SetIntegerValue("c", 100, MetricsUpdatePolicy_MinOver10Seconds); + + ASSERT_EQ(MetricsUpdatePolicy_MaxOver10Seconds, m.GetUpdatePolicy("c")); + ASSERT_EQ(MetricsDataType_Float, m.GetDataType("c")); + } + + { + MetricsRegistry m; + m.SetIntegerValue("c", 100, MetricsUpdatePolicy_MinOver10Seconds); + m.SetFloatValue("c", 101, MetricsUpdatePolicy_MaxOver10Seconds); + + ASSERT_EQ(MetricsUpdatePolicy_MinOver10Seconds, m.GetUpdatePolicy("c")); + ASSERT_EQ(MetricsDataType_Integer, m.GetDataType("c")); + } + + { + MetricsRegistry m; + m.SetIntegerValue("c", 100); + m.SetFloatValue("c", 101, MetricsUpdatePolicy_MaxOver10Seconds); + + ASSERT_EQ(MetricsUpdatePolicy_Directly, m.GetUpdatePolicy("c")); + ASSERT_EQ(MetricsDataType_Integer, m.GetDataType("c")); } } #endif @@ -1467,3 +1603,53 @@ } } #endif + + +TEST(Toolbox, IsVersionAbove) +{ + unsigned int a, b, c; + ASSERT_FALSE(Toolbox::ParseVersion(a, b, c, "nope")); + ASSERT_FALSE(Toolbox::ParseVersion(a, b, c, "mainline")); + ASSERT_FALSE(Toolbox::ParseVersion(a, b, c, "")); + ASSERT_FALSE(Toolbox::ParseVersion(a, b, c, "-1")); + ASSERT_FALSE(Toolbox::ParseVersion(a, b, c, "1.-1")); + ASSERT_FALSE(Toolbox::ParseVersion(a, b, c, "1.1.-1")); + + ASSERT_TRUE(Toolbox::ParseVersion(a, b, c, "14.17.20")); + ASSERT_EQ(14u, a); + ASSERT_EQ(17u, b); + ASSERT_EQ(20u, c); + + ASSERT_TRUE(Toolbox::ParseVersion(a, b, c, "18.19")); + ASSERT_EQ(18u, a); + ASSERT_EQ(19u, b); + ASSERT_EQ(0u, c); + + ASSERT_TRUE(Toolbox::ParseVersion(a, b, c, "78")); + ASSERT_EQ(78u, a); + ASSERT_EQ(0u, b); + ASSERT_EQ(0u, c); + + ASSERT_TRUE(Toolbox::IsVersionAbove("mainline", 99, 99, 99)); + + ASSERT_TRUE(Toolbox::IsVersionAbove("18", 17, 99, 99)); + ASSERT_TRUE(Toolbox::IsVersionAbove("18", 18, 0, 0)); + ASSERT_FALSE(Toolbox::IsVersionAbove("18", 18, 0, 1)); + ASSERT_FALSE(Toolbox::IsVersionAbove("18", 18, 1, 0)); + ASSERT_FALSE(Toolbox::IsVersionAbove("18", 19, 0, 0)); + + ASSERT_TRUE(Toolbox::IsVersionAbove("18.19", 17, 99, 99)); + ASSERT_TRUE(Toolbox::IsVersionAbove("18.19", 18, 18, 99)); + ASSERT_TRUE(Toolbox::IsVersionAbove("18.19", 18, 19, 0)); + ASSERT_FALSE(Toolbox::IsVersionAbove("18.19", 18, 19, 1)); + ASSERT_FALSE(Toolbox::IsVersionAbove("18.19", 18, 20, 0)); + ASSERT_FALSE(Toolbox::IsVersionAbove("18.19", 19, 0, 0)); + + ASSERT_TRUE(Toolbox::IsVersionAbove("18.19.20", 17, 99, 99)); + ASSERT_TRUE(Toolbox::IsVersionAbove("18.19.20", 18, 18, 99)); + ASSERT_TRUE(Toolbox::IsVersionAbove("18.19.20", 18, 19, 19)); + ASSERT_TRUE(Toolbox::IsVersionAbove("18.19.20", 18, 19, 20)); + ASSERT_FALSE(Toolbox::IsVersionAbove("18.19.20", 18, 19, 21)); + ASSERT_FALSE(Toolbox::IsVersionAbove("18.19.20", 18, 20, 0)); + ASSERT_FALSE(Toolbox::IsVersionAbove("18.19.20", 19, 0, 0)); +} diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp --- a/OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/FromDcmtkTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -37,6 +38,7 @@ #include #include "../Sources/Compatibility.h" +#include "../Sources/DicomFormat/DicomImageInformation.h" #include "../Sources/DicomFormat/DicomPath.h" #include "../Sources/DicomNetworking/DicomFindAnswers.h" #include "../Sources/DicomParsing/DicomModification.h" @@ -314,6 +316,10 @@ ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 192")); ASSERT_EQ(Encoding_Utf8, e); ASSERT_TRUE(GetDicomEncoding(e, "GB18030")); ASSERT_EQ(Encoding_Chinese, e); ASSERT_TRUE(GetDicomEncoding(e, "GBK")); ASSERT_EQ(Encoding_Chinese, e); + + // common spelling mistakes + ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR_100")); ASSERT_EQ(Encoding_Latin1, e); + ASSERT_TRUE(GetDicomEncoding(e, "ISO_2022_IR_6")); ASSERT_EQ(Encoding_Ascii, e); } @@ -2767,7 +2773,7 @@ { DicomModification modif; - modif.SetupAnonymization(DicomVersion_2021b); + modif.SetupAnonymization(DicomVersion_2023b); modif.Apply(*dicom1); modif.Apply(*dicom2); } @@ -2794,7 +2800,7 @@ { DicomModification modif; - modif.SetupAnonymization(DicomVersion_2021b); + modif.SetupAnonymization(DicomVersion_2023b); modif.Keep(DicomPath::Parse("ReferencedImageSequence[1].ReferencedSOPInstanceUID")); modif.Keep(DicomPath::Parse("RelatedSeriesSequence")); modif.Apply(*dicom); @@ -3086,6 +3092,21 @@ } +TEST(ParsedDicomFile, MultipleFloatValue) +{ + // from https://discourse.orthanc-server.org/t/qido-includefield-with-sequences/4746/6 + Json::Value v = Json::objectValue; + v["4010,1001"][0]["4010,1004"] = "30\\20\\10"; + std::unique_ptr dicom(ParsedDicomFile::CreateFromJson(v, DicomFromJsonFlags_None, "")); + ASSERT_TRUE(dicom->HasTag(Orthanc::DicomTag(0x4010, 0x1001))); + + DicomMap m; + ASSERT_TRUE(dicom->LookupSequenceItem(m, DicomPath(DicomTag(0x4010, 0x1001)), 0)); + ASSERT_EQ(1u, m.GetSize()); + std::string value = m.GetStringValue(DicomTag(0x4010, 0x1004), "", false); + ASSERT_EQ("30\\20\\10", value); +} + TEST(ParsedDicomFile, ImageInformation) { @@ -3217,6 +3238,313 @@ } +TEST(ParsedDicomFile, InjectEmptyPixelData) +{ + static const char* PIXEL_DATA = "7FE00010"; + + { + ParsedDicomFile dicom(true); + + DicomWebJsonVisitor visitor; + dicom.Apply(visitor); + + ASSERT_FALSE(visitor.GetResult().isMember(PIXEL_DATA)); + } + + { + ParsedDicomFile dicom(true); + dicom.InjectEmptyPixelData(ValueRepresentation_OtherByte); + dicom.InjectEmptyPixelData(ValueRepresentation_OtherWord); // Must be ignored + + DicomWebJsonVisitor visitor; + dicom.Apply(visitor); + + ASSERT_TRUE(visitor.GetResult().isMember(PIXEL_DATA)); + ASSERT_EQ(2u, visitor.GetResult() [PIXEL_DATA].size()); + ASSERT_EQ("", visitor.GetResult() [PIXEL_DATA]["InlineBinary"].asString()); + ASSERT_EQ("OB", visitor.GetResult() [PIXEL_DATA]["vr"].asString()); + } + + { + ParsedDicomFile dicom(true); + dicom.InjectEmptyPixelData(ValueRepresentation_OtherWord); + dicom.InjectEmptyPixelData(ValueRepresentation_OtherByte); // Must be ignored + + DicomWebJsonVisitor visitor; + dicom.Apply(visitor); + + ASSERT_TRUE(visitor.GetResult().isMember(PIXEL_DATA)); + ASSERT_EQ(2u, visitor.GetResult() [PIXEL_DATA].size()); + ASSERT_EQ("", visitor.GetResult() [PIXEL_DATA]["InlineBinary"].asString()); + ASSERT_EQ("OW", visitor.GetResult() [PIXEL_DATA]["vr"].asString()); + } +} + + +TEST(ParsedDicomFile, RemoveFromPixelData) +{ + ParsedDicomFile dicom(true); + ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->putAndInsertString(DcmTag(0x7fe0, 0x0000), "").good()); + ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->putAndInsertString(DcmTag(0x7fe0, 0x0009), "").good()); + ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->putAndInsertUint8Array(DcmTag(0x7fe0, 0x0010), NULL, 0).good()); + ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->putAndInsertString(DcmTag(0x7fe0, 0x0011), "").good()); + ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->putAndInsertString(DcmTag(0x7fe1, 0x0000), "").good()); + + { + DicomMap m; + dicom.ExtractDicomSummary(m, 0); + + ASSERT_EQ(10u, m.GetSize()); + ASSERT_TRUE(m.HasTag(DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID)); + ASSERT_TRUE(m.HasTag(DICOM_TAG_SOP_INSTANCE_UID)); + ASSERT_TRUE(m.HasTag(DICOM_TAG_PATIENT_ID)); + ASSERT_TRUE(m.HasTag(DICOM_TAG_SERIES_INSTANCE_UID)); + ASSERT_TRUE(m.HasTag(DICOM_TAG_STUDY_INSTANCE_UID)); + ASSERT_TRUE(m.HasTag(0x7fe0, 0x0000)); + ASSERT_TRUE(m.HasTag(0x7fe0, 0x0009)); + ASSERT_TRUE(m.HasTag(DICOM_TAG_PIXEL_DATA)); + ASSERT_TRUE(m.HasTag(0x7fe0, 0x0011)); + ASSERT_TRUE(m.HasTag(0x7fe1, 0x0000)); + } + + dicom.RemoveFromPixelData(); + + { + DicomMap m; + dicom.ExtractDicomSummary(m, 0); + + ASSERT_EQ(7u, m.GetSize()); + ASSERT_TRUE(m.HasTag(DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID)); + ASSERT_TRUE(m.HasTag(DICOM_TAG_SOP_INSTANCE_UID)); + ASSERT_TRUE(m.HasTag(DICOM_TAG_PATIENT_ID)); + ASSERT_TRUE(m.HasTag(DICOM_TAG_SERIES_INSTANCE_UID)); + ASSERT_TRUE(m.HasTag(DICOM_TAG_STUDY_INSTANCE_UID)); + ASSERT_TRUE(m.HasTag(0x7fe0, 0x0000)); + ASSERT_TRUE(m.HasTag(0x7fe0, 0x0009)); + ASSERT_FALSE(m.HasTag(DICOM_TAG_PIXEL_DATA)); + ASSERT_FALSE(m.HasTag(0x7fe0, 0x0011)); + ASSERT_FALSE(m.HasTag(0x7fe1, 0x0000)); + } +} + + +TEST(ParsedDicomFile, GuessPixelDataValueRepresentation) +{ + typedef std::list< std::pair > Syntaxes; + + // Create a list of the main non-retired transfer syntaxes, from: + // https://www.dicomlibrary.com/dicom/transfer-syntax/ + Syntaxes compressedSyntaxes; + compressedSyntaxes.push_back(std::make_pair(EXS_DeflatedLittleEndianExplicit, DicomTransferSyntax_DeflatedLittleEndianExplicit)); + compressedSyntaxes.push_back(std::make_pair(EXS_JPEGProcess1, DicomTransferSyntax_JPEGProcess1)); + compressedSyntaxes.push_back(std::make_pair(EXS_JPEGProcess2_4, DicomTransferSyntax_JPEGProcess2_4)); + compressedSyntaxes.push_back(std::make_pair(EXS_JPEGProcess14, DicomTransferSyntax_JPEGProcess14)); + compressedSyntaxes.push_back(std::make_pair(EXS_JPEGProcess14SV1, DicomTransferSyntax_JPEGProcess14SV1)); + compressedSyntaxes.push_back(std::make_pair(EXS_JPEGLSLossless, DicomTransferSyntax_JPEGLSLossless)); + compressedSyntaxes.push_back(std::make_pair(EXS_JPEGLSLossy, DicomTransferSyntax_JPEGLSLossy)); + compressedSyntaxes.push_back(std::make_pair(EXS_JPEG2000LosslessOnly, DicomTransferSyntax_JPEG2000LosslessOnly)); + compressedSyntaxes.push_back(std::make_pair(EXS_JPEG2000, DicomTransferSyntax_JPEG2000)); + compressedSyntaxes.push_back(std::make_pair(EXS_JPEG2000MulticomponentLosslessOnly, DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly)); + compressedSyntaxes.push_back(std::make_pair(EXS_JPEG2000Multicomponent, DicomTransferSyntax_JPEG2000Multicomponent)); + compressedSyntaxes.push_back(std::make_pair(EXS_JPIPReferenced, DicomTransferSyntax_JPIPReferenced)); + compressedSyntaxes.push_back(std::make_pair(EXS_JPIPReferencedDeflate, DicomTransferSyntax_JPIPReferencedDeflate)); + compressedSyntaxes.push_back(std::make_pair(EXS_RLELossless, DicomTransferSyntax_RLELossless)); + compressedSyntaxes.push_back(std::make_pair(EXS_MPEG2MainProfileAtMainLevel, DicomTransferSyntax_MPEG2MainProfileAtMainLevel)); + compressedSyntaxes.push_back(std::make_pair(EXS_MPEG4HighProfileLevel4_1, DicomTransferSyntax_MPEG4HighProfileLevel4_1)); + compressedSyntaxes.push_back(std::make_pair(EXS_MPEG4BDcompatibleHighProfileLevel4_1, DicomTransferSyntax_MPEG4BDcompatibleHighProfileLevel4_1)); + + for (unsigned int i = 0; i < 3; i++) + { + unsigned int bitsAllocated; + switch (i) + { + case 0: bitsAllocated = 1; break; + case 1: bitsAllocated = 8; break; + case 2: bitsAllocated = 16; break; + default: + throw OrthancException(ErrorCode_InternalError); + } + + for (Syntaxes::const_iterator it = compressedSyntaxes.begin(); it != compressedSyntaxes.end(); ++it) + { + // All the compressed transfer syntaxes must have "OB" pixel data + ASSERT_EQ(ValueRepresentation_OtherByte, DicomImageInformation::GuessPixelDataValueRepresentation(it->second, bitsAllocated)); + + { + DicomMap dicom; + dicom.SetValue(DICOM_TAG_BITS_ALLOCATED, boost::lexical_cast(bitsAllocated), false); + ASSERT_EQ(ValueRepresentation_OtherByte, dicom.GuessPixelDataValueRepresentation(it->second)); + } + + { + DicomMap dicom; + ASSERT_EQ(ValueRepresentation_OtherByte, dicom.GuessPixelDataValueRepresentation(it->second)); + } + + { + ParsedDicomFile dicom(true); + ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->putAndInsertUint16(DCM_BitsAllocated, bitsAllocated).good()); + ASSERT_TRUE(dicom.GetDcmtkObject().chooseRepresentation(it->first, NULL).good()); + dicom.GetDcmtkObject().removeAllButCurrentRepresentations(); + DicomTransferSyntax ts; + ASSERT_TRUE(dicom.LookupTransferSyntax(ts)); + ASSERT_EQ(ts, it->second); + ASSERT_EQ(ValueRepresentation_OtherByte, dicom.GuessPixelDataValueRepresentation()); + } + } + + { + // Little endian implicit is always OW + ASSERT_EQ(ValueRepresentation_OtherWord, DicomImageInformation::GuessPixelDataValueRepresentation(DicomTransferSyntax_LittleEndianImplicit, bitsAllocated)); + + { + DicomMap dicom; + dicom.SetValue(DICOM_TAG_BITS_ALLOCATED, boost::lexical_cast(bitsAllocated), false); + ASSERT_EQ(ValueRepresentation_OtherWord, dicom.GuessPixelDataValueRepresentation(DicomTransferSyntax_LittleEndianImplicit)); + } + + { + DicomMap dicom; + ASSERT_EQ(ValueRepresentation_OtherWord, dicom.GuessPixelDataValueRepresentation(DicomTransferSyntax_LittleEndianImplicit)); + } + + { + ParsedDicomFile dicom(true); + ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->putAndInsertUint16(DCM_BitsAllocated, bitsAllocated).good()); + ASSERT_TRUE(dicom.GetDcmtkObject().chooseRepresentation(EXS_LittleEndianImplicit, NULL).good()); + dicom.GetDcmtkObject().removeAllButCurrentRepresentations(); + ASSERT_EQ(ValueRepresentation_OtherWord, dicom.GuessPixelDataValueRepresentation()); + } + } + + } + + // Explicit little and big endian with <= 8 bpp is OB + + for (unsigned int i = 0; i < 2; i++) + { + unsigned int bitsAllocated; + switch (i) + { + case 0: bitsAllocated = 1; break; + case 1: bitsAllocated = 8; break; + default: + throw OrthancException(ErrorCode_InternalError); + } + + ASSERT_EQ(ValueRepresentation_OtherByte, DicomImageInformation::GuessPixelDataValueRepresentation(DicomTransferSyntax_LittleEndianExplicit, bitsAllocated)); + ASSERT_EQ(ValueRepresentation_OtherByte, DicomImageInformation::GuessPixelDataValueRepresentation(DicomTransferSyntax_BigEndianExplicit, bitsAllocated)); + + { + DicomMap dicom; + dicom.SetValue(DICOM_TAG_BITS_ALLOCATED, boost::lexical_cast(bitsAllocated), false); + ASSERT_EQ(ValueRepresentation_OtherByte, dicom.GuessPixelDataValueRepresentation(DicomTransferSyntax_LittleEndianExplicit)); + ASSERT_EQ(ValueRepresentation_OtherByte, dicom.GuessPixelDataValueRepresentation(DicomTransferSyntax_BigEndianExplicit)); + } + + { + DicomMap dicom; + ASSERT_EQ(ValueRepresentation_OtherByte, dicom.GuessPixelDataValueRepresentation(DicomTransferSyntax_LittleEndianExplicit)); + ASSERT_EQ(ValueRepresentation_OtherByte, dicom.GuessPixelDataValueRepresentation(DicomTransferSyntax_BigEndianExplicit)); + } + + { + ParsedDicomFile dicom(true); + ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->putAndInsertUint16(DCM_BitsAllocated, bitsAllocated).good()); + ASSERT_TRUE(dicom.GetDcmtkObject().chooseRepresentation(EXS_LittleEndianExplicit, NULL).good()); + dicom.GetDcmtkObject().removeAllButCurrentRepresentations(); + ASSERT_EQ(ValueRepresentation_OtherByte, dicom.GuessPixelDataValueRepresentation()); + } + + { + ParsedDicomFile dicom(true); + ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->putAndInsertUint16(DCM_BitsAllocated, bitsAllocated).good()); + ASSERT_TRUE(dicom.GetDcmtkObject().chooseRepresentation(EXS_BigEndianExplicit, NULL).good()); + dicom.GetDcmtkObject().removeAllButCurrentRepresentations(); + ASSERT_EQ(ValueRepresentation_OtherByte, dicom.GuessPixelDataValueRepresentation()); + } + } + + // Explicit little and big endian with > 8 bpp is OW + + ASSERT_EQ(ValueRepresentation_OtherWord, DicomImageInformation::GuessPixelDataValueRepresentation(DicomTransferSyntax_LittleEndianExplicit, 16)); + ASSERT_EQ(ValueRepresentation_OtherWord, DicomImageInformation::GuessPixelDataValueRepresentation(DicomTransferSyntax_BigEndianExplicit, 16)); + + { + DicomMap dicom; + dicom.SetValue(DICOM_TAG_BITS_ALLOCATED, "16", false); + ASSERT_EQ(ValueRepresentation_OtherWord, dicom.GuessPixelDataValueRepresentation(DicomTransferSyntax_LittleEndianExplicit)); + ASSERT_EQ(ValueRepresentation_OtherWord, dicom.GuessPixelDataValueRepresentation(DicomTransferSyntax_BigEndianExplicit)); + } + + { + ParsedDicomFile dicom(true); + ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->putAndInsertUint16(DCM_BitsAllocated, 16).good()); + ASSERT_TRUE(dicom.GetDcmtkObject().chooseRepresentation(EXS_LittleEndianExplicit, NULL).good()); + dicom.GetDcmtkObject().removeAllButCurrentRepresentations(); + ASSERT_EQ(ValueRepresentation_OtherWord, dicom.GuessPixelDataValueRepresentation()); + } + + { + ParsedDicomFile dicom(true); + ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->putAndInsertUint16(DCM_BitsAllocated, 16).good()); + ASSERT_TRUE(dicom.GetDcmtkObject().chooseRepresentation(EXS_BigEndianExplicit, NULL).good()); + dicom.GetDcmtkObject().removeAllButCurrentRepresentations(); + ASSERT_EQ(ValueRepresentation_OtherWord, dicom.GuessPixelDataValueRepresentation()); + } +} + + +#if ORTHANC_SANDBOXED != 1 +TEST(ParsedDicomFile, DISABLED_InjectEmptyPixelData2) +{ + static const char* PIXEL_DATA = "7FE00010"; + + for (int i = 0; i <= DicomTransferSyntax_XML; i++) + { + DicomTransferSyntax a = (DicomTransferSyntax) i; + + std::string path = (std::string(getenv("HOME")) + + "/Subversion/orthanc-tests/Database/TransferSyntaxes/" + + std::string(GetTransferSyntaxUid(a)) + ".dcm"); + if (Orthanc::SystemToolbox::IsRegularFile(path)) + { + printf("\n======= %s\n", GetTransferSyntaxUid(a)); + + std::string source; + Orthanc::SystemToolbox::ReadFile(source, path); + + ParsedDicomFile dicom(source); + std::unique_ptr removal(dicom.GetDcmtkObject().getDataset()->remove(DCM_PixelData)); + + { + DicomWebJsonVisitor visitor; + dicom.Apply(visitor); + ASSERT_FALSE(visitor.GetResult().isMember(PIXEL_DATA)); + } + + { + DicomWebJsonVisitor visitor; + dicom.InjectEmptyPixelData(ValueRepresentation_OtherByte); + dicom.Apply(visitor); + ASSERT_TRUE(visitor.GetResult().isMember(PIXEL_DATA)); + ASSERT_EQ("OB", visitor.GetResult() [PIXEL_DATA]["vr"].asString()); + } + + removal.reset(dicom.GetDcmtkObject().getDataset()->remove(DCM_PixelData)); + + { + DicomWebJsonVisitor visitor; + dicom.InjectEmptyPixelData(ValueRepresentation_OtherWord); + dicom.Apply(visitor); + ASSERT_TRUE(visitor.GetResult().isMember(PIXEL_DATA)); + ASSERT_EQ("OW", visitor.GetResult() [PIXEL_DATA]["vr"].asString()); + } + } + } +} +#endif + #if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 @@ -3236,11 +3564,13 @@ DcmtkTranscoder transcoder; for (int j = 0; j < 2; j++) + { for (int i = 0; i <= DicomTransferSyntax_XML; i++) { DicomTransferSyntax a = (DicomTransferSyntax) i; - std::string path = ("/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/" + + std::string path = (std::string(getenv("HOME")) + + "/Subversion/orthanc-tests/Database/TransferSyntaxes/" + std::string(GetTransferSyntaxUid(a)) + ".dcm"); if (Orthanc::SystemToolbox::IsRegularFile(path)) { @@ -3268,6 +3598,7 @@ } } } + } } @@ -3277,7 +3608,8 @@ { std::string source; - Orthanc::SystemToolbox::ReadFile(source, "/home/jodogne/Subversion/orthanc-tests/Database/KarstenHilbertRF.dcm"); + Orthanc::SystemToolbox::ReadFile(source, std::string(getenv("HOME")) + + "/Subversion/orthanc-tests/Database/KarstenHilbertRF.dcm"); toto.reset(FromDcmtkBridge::LoadFromMemoryBuffer(source.c_str(), source.size())); } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/GithubCACertificates.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/UnitTestsSources/GithubCACertificates.h Tue Sep 24 11:39:52 2024 +0200 @@ -0,0 +1,30 @@ +#define GITHUB_CERTIFICATES \ +"-----BEGIN CERTIFICATE-----\n" \ +"MIIEyDCCA7CgAwIBAgIQDPW9BitWAvR6uFAsI8zwZjANBgkqhkiG9w0BAQsFADBh\n" \ +"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \ +"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n" \ +"MjAeFw0yMTAzMzAwMDAwMDBaFw0zMTAzMjkyMzU5NTlaMFkxCzAJBgNVBAYTAlVT\n" \ +"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMzAxBgNVBAMTKkRpZ2lDZXJ0IEdsb2Jh\n" \ +"bCBHMiBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTCCASIwDQYJKoZIhvcNAQEBBQAD\n" \ +"ggEPADCCAQoCggEBAMz3EGJPprtjb+2QUlbFbSd7ehJWivH0+dbn4Y+9lavyYEEV\n" \ +"cNsSAPonCrVXOFt9slGTcZUOakGUWzUb+nv6u8W+JDD+Vu/E832X4xT1FE3LpxDy\n" \ +"FuqrIvAxIhFhaZAmunjZlx/jfWardUSVc8is/+9dCopZQ+GssjoP80j812s3wWPc\n" \ +"3kbW20X+fSP9kOhRBx5Ro1/tSUZUfyyIxfQTnJcVPAPooTncaQwywa8WV0yUR0J8\n" \ +"osicfebUTVSvQpmowQTCd5zWSOTOEeAqgJnwQ3DPP3Zr0UxJqyRewg2C/Uaoq2yT\n" \ +"zGJSQnWS+Jr6Xl6ysGHlHx+5fwmY6D36g39HaaECAwEAAaOCAYIwggF+MBIGA1Ud\n" \ +"EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHSFgMBmx9833s+9KTeqAx2+7c0XMB8G\n" \ +"A1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA4GA1UdDwEB/wQEAwIBhjAd\n" \ +"BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYIKwYBBQUHAQEEajBoMCQG\n" \ +"CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQAYIKwYBBQUHMAKG\n" \ +"NGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RH\n" \ +"Mi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29t\n" \ +"L0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDA9BgNVHSAENjA0MAsGCWCGSAGG/WwC\n" \ +"ATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgGBmeBDAECAzANBgkqhkiG\n" \ +"9w0BAQsFAAOCAQEAkPFwyyiXaZd8dP3A+iZ7U6utzWX9upwGnIrXWkOH7U1MVl+t\n" \ +"wcW1BSAuWdH/SvWgKtiwla3JLko716f2b4gp/DA/JIS7w7d7kwcsr4drdjPtAFVS\n" \ +"slme5LnQ89/nD/7d+MS5EHKBCQRfz5eeLjJ1js+aWNJXMX43AYGyZm0pGrFmCW3R\n" \ +"bpD0ufovARTFXFZkAdl9h6g4U5+LXUZtXMYnhIHUfoyMo5tS58aI7Dd8KvvwVVo4\n" \ +"chDYABPPTHPbqjc1qCmBaZx2vN4Ye5DUys/vZwP9BFohFrH/6j/f3IL16/RZkiMN\n" \ +"JCqVJUzKoZHm1Lesh3Sz8W2jmdv51b2EQJ8HmA==\n" \ +"-----END CERTIFICATE-----\n" \ +"\n" diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/ImageProcessingTests.cpp --- a/OrthancFramework/UnitTestsSources/ImageProcessingTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/ImageProcessingTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/ImageTests.cpp --- a/OrthancFramework/UnitTestsSources/ImageTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/ImageTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -33,10 +34,11 @@ #include "../Sources/Images/ImageProcessing.h" #include "../Sources/Images/JpegReader.h" #include "../Sources/Images/JpegWriter.h" +#include "../Sources/Images/PamReader.h" +#include "../Sources/Images/PamWriter.h" #include "../Sources/Images/PngReader.h" #include "../Sources/Images/PngWriter.h" -#include "../Sources/Images/PamReader.h" -#include "../Sources/Images/PamWriter.h" +#include "../Sources/OrthancException.h" #include "../Sources/Toolbox.h" #if ORTHANC_SANDBOXED != 1 @@ -96,14 +98,33 @@ uint8_t *p = &image[0] + y * pitch; for (unsigned int x = 0; x < width; x++, p += 8) { - p[0] = (y % 8 == 0) ? 255 : 0; - p[1] = (y % 8 == 1) ? 255 : 0; - p[2] = (y % 8 == 2) ? 255 : 0; - p[3] = (y % 8 == 3) ? 255 : 0; - p[4] = (y % 8 == 4) ? 255 : 0; - p[5] = (y % 8 == 5) ? 255 : 0; - p[6] = (y % 8 == 6) ? 255 : 0; - p[7] = (y % 8 == 7) ? 255 : 0; + switch (Orthanc::Toolbox::DetectEndianness()) + { + case Orthanc::Endianness_Little: + p[0] = (y % 8 == 0) ? 255 : 0; + p[1] = (y % 8 == 1) ? 255 : 0; + p[2] = (y % 8 == 2) ? 255 : 0; + p[3] = (y % 8 == 3) ? 255 : 0; + p[4] = (y % 8 == 4) ? 255 : 0; + p[5] = (y % 8 == 5) ? 255 : 0; + p[6] = (y % 8 == 6) ? 255 : 0; + p[7] = (y % 8 == 7) ? 255 : 0; + break; + + case Orthanc::Endianness_Big: + p[0] = (y % 8 == 1) ? 255 : 0; + p[1] = (y % 8 == 0) ? 255 : 0; + p[2] = (y % 8 == 3) ? 255 : 0; + p[3] = (y % 8 == 2) ? 255 : 0; + p[4] = (y % 8 == 5) ? 255 : 0; + p[5] = (y % 8 == 4) ? 255 : 0; + p[6] = (y % 8 == 7) ? 255 : 0; + p[7] = (y % 8 == 6) ? 255 : 0; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } } } diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/JobsTests.cpp --- a/OrthancFramework/UnitTestsSources/JobsTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/JobsTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -131,6 +132,11 @@ { return false; } + + virtual bool DeleteOutput(const std::string& key) ORTHANC_OVERRIDE + { + return false; + } }; diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/JpegLosslessTests.cpp --- a/OrthancFramework/UnitTestsSources/JpegLosslessTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/JpegLosslessTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/LoggingTests.cpp --- a/OrthancFramework/UnitTestsSources/LoggingTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/LoggingTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -69,7 +70,7 @@ const std::string& logLine) { const char* regexStr = "[A-Z][0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{6} " - "[a-zA-Z\\.\\-_]+:[0-9]+\\] (.*)" EOLSTRING "$"; + ".{16} [a-zA-Z\\.\\-_]+:[0-9]+\\] (.*)" EOLSTRING "$"; boost::regex regexObj(regexStr); diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/LuaTests.cpp --- a/OrthancFramework/UnitTestsSources/LuaTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/LuaTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/MemoryCacheTests.cpp --- a/OrthancFramework/UnitTestsSources/MemoryCacheTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/MemoryCacheTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -33,6 +34,7 @@ #include "../Sources/Cache/SharedArchive.h" #include "../Sources/IDynamicObject.h" #include "../Sources/Logging.h" +#include "../Sources/SystemToolbox.h" #include #include @@ -319,44 +321,260 @@ Orthanc::MemoryStringCache c; ASSERT_THROW(c.SetMaximumSize(0), Orthanc::OrthancException); - c.SetMaximumSize(2); + c.SetMaximumSize(3); std::string v; - ASSERT_FALSE(c.Fetch(v, "hello")); + { + Orthanc::MemoryStringCache::Accessor a(c); + ASSERT_FALSE(a.Fetch(v, "key1")); + } - c.Add("hello", "a"); - ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); - ASSERT_FALSE(c.Fetch(v, "hello2")); - ASSERT_FALSE(c.Fetch(v, "hello3")); + { + Orthanc::MemoryStringCache::Accessor a(c); + ASSERT_FALSE(a.Fetch(v, "key1")); + a.Add("key1", "a"); + ASSERT_TRUE(a.Fetch(v, "key1")); + ASSERT_EQ("a", v); - c.Add("hello2", "b"); - ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); - ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); - ASSERT_FALSE(c.Fetch(v, "hello3")); + ASSERT_FALSE(a.Fetch(v, "key2")); + ASSERT_FALSE(a.Fetch(v, "key3")); + + a.Add("key2", "b"); + ASSERT_TRUE(a.Fetch(v, "key1")); + ASSERT_EQ("a", v); + ASSERT_TRUE(a.Fetch(v, "key2")); + ASSERT_EQ("b", v); - c.Add("hello3", "too large value"); - ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); - ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); - ASSERT_FALSE(c.Fetch(v, "hello3")); - - c.Add("hello3", "c"); - ASSERT_FALSE(c.Fetch(v, "hello")); // Recycled - ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); - ASSERT_TRUE(c.Fetch(v, "hello3")); ASSERT_EQ("c", v); + a.Add("key3", "too-large-value"); + ASSERT_TRUE(a.Fetch(v, "key1")); + ASSERT_EQ("a", v); + ASSERT_TRUE(a.Fetch(v, "key2")); + ASSERT_EQ("b", v); + ASSERT_FALSE(a.Fetch(v, "key3")); + + a.Add("key3", "c"); + ASSERT_TRUE(a.Fetch(v, "key2")); + ASSERT_EQ("b", v); + ASSERT_TRUE(a.Fetch(v, "key1")); + ASSERT_EQ("a", v); + ASSERT_TRUE(a.Fetch(v, "key3")); + ASSERT_EQ("c", v); + + // adding a fourth value should remove the oldest accessed value (key2) + a.Add("key4", "d"); + ASSERT_FALSE(a.Fetch(v, "key2")); + ASSERT_TRUE(a.Fetch(v, "key1")); + ASSERT_EQ("a", v); + ASSERT_TRUE(a.Fetch(v, "key3")); + ASSERT_EQ("c", v); + ASSERT_TRUE(a.Fetch(v, "key4")); + ASSERT_EQ("d", v); + + } } - TEST(MemoryStringCache, Invalidate) { Orthanc::MemoryStringCache c; - c.Add("hello", "a"); - c.Add("hello2", "b"); + Orthanc::MemoryStringCache::Accessor a(c); + + a.Add("hello", "a"); + a.Add("hello2", "b"); std::string v; - ASSERT_TRUE(c.Fetch(v, "hello")); ASSERT_EQ("a", v); - ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); + ASSERT_TRUE(a.Fetch(v, "hello")); + ASSERT_EQ("a", v); + ASSERT_TRUE(a.Fetch(v, "hello2")); + ASSERT_EQ("b", v); c.Invalidate("hello"); - ASSERT_FALSE(c.Fetch(v, "hello")); - ASSERT_TRUE(c.Fetch(v, "hello2")); ASSERT_EQ("b", v); + ASSERT_FALSE(a.Fetch(v, "hello")); + ASSERT_TRUE(a.Fetch(v, "hello2")); + ASSERT_EQ("b", v); +} + + +static int ThreadingScenarioHappyStep = 0; +static Orthanc::MemoryStringCache ThreadingScenarioHappyCache; + +void ThreadingScenarioHappyThread1() +{ + // the first thread to call Fetch (will be in charge of adding) + Orthanc::MemoryStringCache::Accessor a(ThreadingScenarioHappyCache); + std::string v; + + LOG(INFO) << "Thread1 will fetch"; + if (!a.Fetch(v, "key1")) + { + LOG(INFO) << "Thread1 has fetch"; + ThreadingScenarioHappyStep = 1; + + // wait for the other thread to fetch too + while (ThreadingScenarioHappyStep < 2) + { + Orthanc::SystemToolbox::USleep(10000); + } + LOG(INFO) << "Thread1 will add after a short sleep"; + Orthanc::SystemToolbox::USleep(100000); + LOG(INFO) << "Thread1 will add"; + + a.Add("key1", "value1"); + + LOG(INFO) << "Thread1 has added"; + } +} + +void ThreadingScenarioHappyThread2() +{ + Orthanc::MemoryStringCache::Accessor a(ThreadingScenarioHappyCache); + std::string v; + + // nobody has added key2 -> go + if (!a.Fetch(v, "key2")) + { + a.Add("key2", "value2"); + } + + // wait until thread 1 has completed its "Fetch" but not added yet + while (ThreadingScenarioHappyStep < 1) + { + Orthanc::SystemToolbox::USleep(10000); + } + + ThreadingScenarioHappyStep = 2; + LOG(INFO) << "Thread2 will fetch"; + // this should wait until thread 1 has added + if (!a.Fetch(v, "key1")) + { + ASSERT_FALSE(true); // this thread should not add since thread1 should have done it + } + LOG(INFO) << "Thread2 has fetched the value"; + ASSERT_EQ("value1", v); +} + + +TEST(MemoryStringCache, ThreadingScenarioHappy) +{ + boost::thread thread1 = boost::thread(ThreadingScenarioHappyThread1); + boost::thread thread2 = boost::thread(ThreadingScenarioHappyThread2); + + thread1.join(); + thread2.join(); } + + +static int ThreadingScenarioFailureStep = 0; +static Orthanc::MemoryStringCache ThreadingScenarioFailureCache; + +void ThreadingScenarioFailureThread1() +{ + // the first thread to call Fetch (will be in charge of adding) + Orthanc::MemoryStringCache::Accessor a(ThreadingScenarioFailureCache); + std::string v; + + LOG(INFO) << "Thread1 will fetch"; + if (!a.Fetch(v, "key1")) + { + LOG(INFO) << "Thread1 has fetch"; + ThreadingScenarioFailureStep = 1; + + // wait for the other thread to fetch too + while (ThreadingScenarioFailureStep < 2) + { + Orthanc::SystemToolbox::USleep(10000); + } + LOG(INFO) << "Thread1 will add after a short sleep"; + Orthanc::SystemToolbox::USleep(100000); + LOG(INFO) << "Thread1 fails to add because of an error"; + } +} + +void ThreadingScenarioFailureThread2() +{ + Orthanc::MemoryStringCache::Accessor a(ThreadingScenarioFailureCache); + std::string v; + + // wait until thread 1 has completed its "Fetch" but not added yet + while (ThreadingScenarioFailureStep < 1) + { + Orthanc::SystemToolbox::USleep(10000); + } + + ThreadingScenarioFailureStep = 2; + LOG(INFO) << "Thread2 will fetch and wait for thread1 to add"; + // this should wait until thread 1 has added + if (!a.Fetch(v, "key1")) + { + LOG(INFO) << "Thread2 has been awaken and will add since Thread1 has failed to add"; + a.Add("key1", "value1"); + } + LOG(INFO) << "Thread2 has added the value"; +} + + +TEST(MemoryStringCache, ThreadingScenarioFailure) +{ + boost::thread thread1 = boost::thread(ThreadingScenarioFailureThread1); + boost::thread thread2 = boost::thread(ThreadingScenarioFailureThread2); + + thread1.join(); + thread2.join(); +} + + +static int ThreadingScenarioInvalidateStep = 0; +static Orthanc::MemoryStringCache ThreadingScenarioInvalidateCache; + +void ThreadingScenarioInvalidateThread1() +{ + // the first thread to call Fetch (will be in charge of adding) + Orthanc::MemoryStringCache::Accessor a(ThreadingScenarioInvalidateCache); + std::string v; + + LOG(INFO) << "Thread1 will fetch"; + if (!a.Fetch(v, "key1")) + { + LOG(INFO) << "Thread1 has fetch"; + ThreadingScenarioInvalidateStep = 1; + + // wait for the other thread to fetch too + while (ThreadingScenarioInvalidateStep < 2) + { + Orthanc::SystemToolbox::USleep(10000); + } + LOG(INFO) << "Thread1 will invalidate after a short sleep"; + Orthanc::SystemToolbox::USleep(100000); + LOG(INFO) << "Thread1 is invalidating"; + ThreadingScenarioInvalidateCache.Invalidate("key1"); + } +} + +void ThreadingScenarioInvalidateThread2() +{ + Orthanc::MemoryStringCache::Accessor a(ThreadingScenarioInvalidateCache); + std::string v; + + // wait until thread 1 has completed its "Fetch" but not added yet + while (ThreadingScenarioInvalidateStep < 1) + { + Orthanc::SystemToolbox::USleep(10000); + } + + ThreadingScenarioInvalidateStep = 2; + LOG(INFO) << "Thread2 will fetch and wait for thread1 to add"; + // this should wait until thread 1 has added + if (!a.Fetch(v, "key1")) + { + LOG(INFO) << "Thread2 has been awaken because thread1 has invalidated the key"; + } +} + + +TEST(MemoryStringCache, ThreadingScenarioInvalidate) +{ + boost::thread thread1 = boost::thread(ThreadingScenarioInvalidateThread1); + boost::thread thread2 = boost::thread(ThreadingScenarioInvalidateThread2); + + thread1.join(); + thread2.join(); +} diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/RestApiTests.cpp --- a/OrthancFramework/UnitTestsSources/RestApiTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/RestApiTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -95,29 +96,22 @@ /** The HTTPS CA certificates for BitBucket were extracted as follows: - (1) We retrieve the certification chain of BitBucket: - - # echo | openssl s_client -showcerts -connect www.bitbucket.org:443 + (1) We retrieve the URI of the root CA of BitBucket: - (2) We see that the certification authority (CA) is - "www.digicert.com", and the root certificate is "DigiCert High - Assurance EV Root CA". As a consequence, we navigate to DigiCert to - find the URL to this CA certificate: + # echo | openssl s_client -servername raw.githubusercontent.com -connect raw.githubusercontent.com:443 2>/dev/null | openssl x509 -text | grep "CA Issuers" - firefox https://www.digicert.com/digicert-root-certificates.htm - - (3) Once we get the URL to the CA certificate, we convert it to a C + (2) Once we get the URL to the CA certificate, we convert it to a C macro that can be used by libcurl: # cd UnitTestsSources - # ../Resources/RetrieveCACertificates.py BITBUCKET_CERTIFICATES https://cacerts.digicert.com/DigiCertTLSHybridECCSHA3842020CA1-1.crt > BitbucketCACertificates.h + # python2 ../Resources/RetrieveCACertificates.py GITHUB_CERTIFICATES http://cacerts.digicert.com/DigiCertGlobalG2TLSRSASHA2562020CA1-1.crt > GithubCACertificates.h **/ -#include "BitbucketCACertificates.h" +#include "GithubCACertificates.h" TEST(HttpClient, Ssl) { - SystemToolbox::WriteFile(BITBUCKET_CERTIFICATES, "UnitTestsResults/bitbucket.cert"); + SystemToolbox::WriteFile(GITHUB_CERTIFICATES, "UnitTestsResults/github.cert"); /*{ std::string s; @@ -128,12 +122,12 @@ HttpClient c; //c.SetVerbose(true); c.SetHttpsVerifyPeers(true); - c.SetHttpsCACertificates("UnitTestsResults/bitbucket.cert"); + c.SetHttpsCACertificates("UnitTestsResults/github.cert"); // Test file modified on 2020-04-20, in order to use a git // repository on BitBucket instead of a Mercurial repository // (because Mercurial support disappears on 2020-05-31) - c.SetUrl("https://bitbucket.org/osimis/orthanc-setup-samples/raw/master/docker/serve-folders/orthanc/serve-folders.json"); + c.SetUrl("https://raw.githubusercontent.com/orthanc-server/orthanc-setup-samples/refs/heads/master/docker/serve-folders/orthanc/serve-folders.json"); Json::Value v; c.Apply(v); @@ -144,7 +138,7 @@ { HttpClient c; c.SetHttpsVerifyPeers(false); - c.SetUrl("https://bitbucket.org/osimis/orthanc-setup-samples/raw/master/docker/serve-folders/orthanc/serve-folders.json"); + c.SetUrl("https://raw.githubusercontent.com/orthanc-server/orthanc-setup-samples/refs/heads/master/docker/serve-folders/orthanc/serve-folders.json"); Json::Value v; c.Apply(v); @@ -391,6 +385,7 @@ private: std::string type_; std::string subtype_; + HttpContentNegociation::Dictionary parameters_; public: AcceptHandler() @@ -400,7 +395,8 @@ void Reset() { - Handle("nope", "nope"); + HttpContentNegociation::Dictionary parameters; + Handle("nope", "nope", parameters); } const std::string& GetType() const @@ -413,11 +409,18 @@ return subtype_; } + HttpContentNegociation::Dictionary& GetParameters() + { + return parameters_; + } + virtual void Handle(const std::string& type, - const std::string& subtype) ORTHANC_OVERRIDE + const std::string& subtype, + const HttpContentNegociation::Dictionary& parameters) ORTHANC_OVERRIDE { type_ = type; subtype_ = subtype; + parameters_ = parameters; } }; } @@ -437,22 +440,29 @@ ASSERT_TRUE(d.Apply("audio/*; q=0.2, audio/basic")); ASSERT_EQ("audio", h.GetType()); ASSERT_EQ("basic", h.GetSubType()); + ASSERT_EQ(0u, h.GetParameters().size()); - ASSERT_TRUE(d.Apply("audio/*; q=0.2, audio/nope")); + ASSERT_TRUE(d.Apply("audio/*; q=0.2 ; type = test ; hello , audio/nope")); ASSERT_EQ("audio", h.GetType()); ASSERT_EQ("mp3", h.GetSubType()); + ASSERT_EQ(3u, h.GetParameters().size()); + ASSERT_EQ("0.2", h.GetParameters() ["q"]); + ASSERT_EQ("test", h.GetParameters() ["type"]); + ASSERT_EQ("", h.GetParameters() ["hello"]); ASSERT_FALSE(d.Apply("application/*; q=0.2, application/pdf")); - ASSERT_TRUE(d.Apply("*/*; application/*; q=0.2, application/pdf")); + ASSERT_TRUE(d.Apply("*/*; hello=world, application/*; q=0.2, application/pdf")); ASSERT_EQ("audio", h.GetType()); + ASSERT_EQ(1u, h.GetParameters().size()); + ASSERT_EQ("world", h.GetParameters() ["hello"]); } // "This would be interpreted as "text/html and text/x-c are the // preferred media types, but if they do not exist, then send the // text/x-dvi entity, and if that does not exist, send the // text/plain entity."" - const std::string T1 = "text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"; + const std::string T1 = "text/plain; q=0.5, text/html ; hello = \"world\" , text/x-dvi; q=0.8, text/x-c"; { HttpContentNegociation d; @@ -462,6 +472,8 @@ ASSERT_TRUE(d.Apply(T1)); ASSERT_EQ("text", h.GetType()); ASSERT_EQ("html", h.GetSubType()); + ASSERT_EQ(1u, h.GetParameters().size()); + ASSERT_EQ("world", h.GetParameters() ["hello"]); } { @@ -472,6 +484,7 @@ ASSERT_TRUE(d.Apply(T1)); ASSERT_EQ("text", h.GetType()); ASSERT_EQ("x-c", h.GetSubType()); + ASSERT_EQ(0u, h.GetParameters().size()); } { @@ -483,6 +496,15 @@ ASSERT_TRUE(d.Apply(T1)); ASSERT_EQ("text", h.GetType()); ASSERT_TRUE(h.GetSubType() == "x-c" || h.GetSubType() == "html"); + if (h.GetSubType() == "x-c") + { + ASSERT_EQ(0u, h.GetParameters().size()); + } + else + { + ASSERT_EQ(1u, h.GetParameters().size()); + ASSERT_EQ("world", h.GetParameters() ["hello"]); + } } { @@ -492,6 +514,8 @@ ASSERT_TRUE(d.Apply(T1)); ASSERT_EQ("text", h.GetType()); ASSERT_EQ("x-dvi", h.GetSubType()); + ASSERT_EQ(1u, h.GetParameters().size()); + ASSERT_EQ("0.8", h.GetParameters() ["q"]); } { @@ -500,6 +524,51 @@ ASSERT_TRUE(d.Apply(T1)); ASSERT_EQ("text", h.GetType()); ASSERT_EQ("plain", h.GetSubType()); + ASSERT_EQ(1u, h.GetParameters().size()); + ASSERT_EQ("0.5", h.GetParameters() ["q"]); + } + + // Below are the tests from issue 216: + // https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=216 + + { + HttpContentNegociation d; + d.Register("application/dicom+json", h); + ASSERT_TRUE(d.Apply("image/webp, */*;q=0.8, text/html, application/xhtml+xml, application/xml;q=0.9")); + ASSERT_EQ("application", h.GetType()); + ASSERT_EQ("dicom+json", h.GetSubType()); + ASSERT_EQ(1u, h.GetParameters().size()); + ASSERT_EQ("0.8", h.GetParameters() ["q"]); + } + + { + HttpContentNegociation d; + d.Register("application/dicom+json", h); + ASSERT_TRUE(d.Apply("image/webp, */*; q = \"0.8\" , text/html, application/xhtml+xml, application/xml;q=0.9")); + ASSERT_EQ("application", h.GetType()); + ASSERT_EQ("dicom+json", h.GetSubType()); + ASSERT_EQ(1u, h.GetParameters().size()); + ASSERT_EQ("0.8", h.GetParameters() ["q"]); + } + + { + HttpContentNegociation d; + d.Register("application/dicom+json", h); + ASSERT_TRUE(d.Apply("text/html, application/xhtml+xml, application/xml, image/webp, */*;q=0.8")); + ASSERT_EQ("application", h.GetType()); + ASSERT_EQ("dicom+json", h.GetSubType()); + ASSERT_EQ(1u, h.GetParameters().size()); + ASSERT_EQ("0.8", h.GetParameters() ["q"]); + } + + { + HttpContentNegociation d; + d.Register("application/dicom+json", h); + ASSERT_TRUE(d.Apply("text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2")); + ASSERT_EQ("application", h.GetType()); + ASSERT_EQ("dicom+json", h.GetSubType()); + ASSERT_EQ(1u, h.GetParameters().size()); + ASSERT_EQ(".2", h.GetParameters() ["q"]); } } @@ -1045,8 +1114,8 @@ TEST(MultipartStreamReader, Issue190) { - // https://bugs.orthanc-server.com/show_bug.cgi?id=190 - // https://hg.orthanc-server.com/orthanc-dicomweb/rev/6dc2f79b5579 + // https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=190 + // https://orthanc.uclouvain.be/hg/orthanc-dicomweb/rev/6dc2f79b5579 std::map headers; headers["content-type"] = "multipart/related; type=application/dicom; boundary=0f3cf5c0-70e0-41ef-baef-c6f9f65ec3e1"; @@ -1255,7 +1324,7 @@ TEST(HttpClient, DISABLED_Issue156_Slow) { - // https://bugs.orthanc-server.com/show_bug.cgi?id=156 + // https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=156 TotoServer handler; HttpServer server; diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/SQLiteChromiumTests.cpp --- a/OrthancFramework/UnitTestsSources/SQLiteChromiumTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/SQLiteChromiumTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/SQLiteTests.cpp --- a/OrthancFramework/UnitTestsSources/SQLiteTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/SQLiteTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/SharedLibraryUnitTests.cpp --- a/OrthancFramework/UnitTestsSources/SharedLibraryUnitTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/SharedLibraryUnitTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/StreamTests.cpp --- a/OrthancFramework/UnitTestsSources/StreamTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/StreamTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/ToolboxTests.cpp --- a/OrthancFramework/UnitTestsSources/ToolboxTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/ToolboxTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -280,6 +281,48 @@ } } +TEST(Toolbox, GetSetIntersection) +{ + { + std::set target; + std::set a; + std::set b; + + Toolbox::GetIntersection(target, a, b); + ASSERT_EQ(0u, target.size()); + } + + { + std::set target; + std::set a; + std::set b; + + a.insert(1); + b.insert(1); + + Toolbox::GetIntersection(target, a, b); + ASSERT_EQ(1u, target.size()); + ASSERT_EQ(1u, target.count(1)); + } + + { + std::set target; + std::set a; + std::set b; + + a.insert(1); + a.insert(2); + b.insert(2); + + Toolbox::GetIntersection(target, a, b); + ASSERT_EQ(1u, target.size()); + ASSERT_EQ(0u, target.count(1)); + ASSERT_EQ(1u, target.count(2)); + } + +} + + TEST(Toolbox, JoinStrings) { { @@ -322,3 +365,46 @@ ASSERT_EQ("1\\2", result); } } + +TEST(Toolbox, JoinUri) +{ + ASSERT_EQ("https://test.org/path", Toolbox::JoinUri("https://test.org", "path")); + ASSERT_EQ("https://test.org/path", Toolbox::JoinUri("https://test.org/", "path")); + ASSERT_EQ("https://test.org/path", Toolbox::JoinUri("https://test.org", "/path")); + ASSERT_EQ("https://test.org/path", Toolbox::JoinUri("https://test.org/", "/path")); + + ASSERT_EQ("http://test.org:8042", Toolbox::JoinUri("http://test.org:8042", "")); + ASSERT_EQ("http://test.org:8042/", Toolbox::JoinUri("http://test.org:8042/", "")); +} + +TEST(Toolbox, GetHumanFileSize) +{ + ASSERT_EQ("234bytes", Toolbox::GetHumanFileSize(234)); + ASSERT_EQ("2.29KB", Toolbox::GetHumanFileSize(2345)); + ASSERT_EQ("22.91KB", Toolbox::GetHumanFileSize(23456)); + ASSERT_EQ("229.07KB", Toolbox::GetHumanFileSize(234567)); + ASSERT_EQ("2.24MB", Toolbox::GetHumanFileSize(2345678)); + ASSERT_EQ("22.37MB", Toolbox::GetHumanFileSize(23456789)); + ASSERT_EQ("223.70MB", Toolbox::GetHumanFileSize(234567890)); + ASSERT_EQ("2.18GB", Toolbox::GetHumanFileSize(2345678901)); + ASSERT_EQ("21.33TB", Toolbox::GetHumanFileSize(23456789012345)); +} + +TEST(Toolbox, GetHumanDuration) +{ + ASSERT_EQ("234ns", Toolbox::GetHumanDuration(234)); + ASSERT_EQ("2.35us", Toolbox::GetHumanDuration(2345)); + ASSERT_EQ("23.46us", Toolbox::GetHumanDuration(23456)); + ASSERT_EQ("234.57us", Toolbox::GetHumanDuration(234567)); + ASSERT_EQ("2.35ms", Toolbox::GetHumanDuration(2345678)); + ASSERT_EQ("2.35s", Toolbox::GetHumanDuration(2345678901)); + ASSERT_EQ("23456.79s", Toolbox::GetHumanDuration(23456789012345)); +} + +TEST(Toolbox, GetHumanTransferSpeed) +{ + ASSERT_EQ("8.00Mbps", Toolbox::GetHumanTransferSpeed(false, 1000, 1000000)); + ASSERT_EQ("8.59Gbps", Toolbox::GetHumanTransferSpeed(false, 1024*1024*1024, 1000000000)); + ASSERT_EQ("1.00GB in 1.00s = 8.59Gbps", Toolbox::GetHumanTransferSpeed(true, 1024*1024*1024, 1000000000)); + ASSERT_EQ("976.56KB in 1.00s = 8.00Mbps", Toolbox::GetHumanTransferSpeed(true, 1000*1000, 1000000000)); +} \ No newline at end of file diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancFramework/UnitTestsSources/ZipTests.cpp --- a/OrthancFramework/UnitTestsSources/ZipTests.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/UnitTestsSources/ZipTests.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancServer/CMakeLists.txt --- a/OrthancServer/CMakeLists.txt Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancServer/CMakeLists.txt Tue Sep 24 11:39:52 2024 +0200 @@ -1,8 +1,9 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2022 Osimis S.A., Belgium -# Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# Copyright (C) 2017-2023 Osimis S.A., Belgium +# Copyright (C) 2024-2024 Orthanc Team SRL, Belgium +# Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU General Public License as @@ -62,6 +63,7 @@ SET(BUILD_HOUSEKEEPER ON CACHE BOOL "Whether to build the Housekeeper plugin") SET(BUILD_DELAYED_DELETION ON CACHE BOOL "Whether to build the DelayedDeletion plugin") SET(BUILD_ADVANCED_STORAGE ON CACHE BOOL "Whether to build the AdvancedStorage plugin") +SET(BUILD_MULTITENANT_DICOM ON CACHE BOOL "Whether to build the MultitenantDicom plugin") SET(ENABLE_PLUGINS ON CACHE BOOL "Enable plugins") SET(UNIT_TESTS_WITH_HTTP_CONNEXIONS ON CACHE BOOL "Allow unit tests to make HTTP requests") @@ -70,6 +72,11 @@ ## Configuration of the Orthanc framework ##################################################################### +if (ENABLE_PLUGINS) + set(ENABLE_PROTOBUF ON) + set(ENABLE_PROTOBUF_COMPILER ON) +endif() + include(${CMAKE_SOURCE_DIR}/../OrthancFramework/Resources/CMake/VisualStudioPrecompiledHeaders.cmake) include(${CMAKE_SOURCE_DIR}/../OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake) @@ -82,6 +89,7 @@ ##################################################################### set(ORTHANC_SERVER_SOURCES + ${CMAKE_SOURCE_DIR}/Sources/Database/BaseDatabaseWrapper.cpp ${CMAKE_SOURCE_DIR}/Sources/Database/Compatibility/DatabaseLookup.cpp ${CMAKE_SOURCE_DIR}/Sources/Database/Compatibility/ICreateInstance.cpp ${CMAKE_SOURCE_DIR}/Sources/Database/Compatibility/IGetChildrenMetadata.cpp @@ -137,6 +145,7 @@ ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/ResourceModificationJob.cpp ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/SplitStudyJob.cpp ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/StorageCommitmentScpJob.cpp + ${CMAKE_SOURCE_DIR}/Sources/ServerJobs/ThreadedSetOfInstancesJob.cpp ${CMAKE_SOURCE_DIR}/Sources/ServerToolbox.cpp ${CMAKE_SOURCE_DIR}/Sources/SliceOrdering.cpp ${CMAKE_SOURCE_DIR}/Sources/StorageCommitmentReports.cpp @@ -223,18 +232,16 @@ ##################################################################### set(ORTHANC_EMBEDDED_FILES - CONFIGURATION_SAMPLE ${CMAKE_SOURCE_DIR}/Resources/Configuration.json - DICOM_CONFORMANCE_STATEMENT ${CMAKE_SOURCE_DIR}/Resources/DicomConformanceStatement.txt - FONT_UBUNTU_MONO_BOLD_16 ${CMAKE_SOURCE_DIR}/Resources/Fonts/UbuntuMonoBold-16.json - LUA_TOOLBOX ${CMAKE_SOURCE_DIR}/Resources/Toolbox.lua - PREPARE_DATABASE ${CMAKE_SOURCE_DIR}/Sources/Database/PrepareDatabase.sql - UPGRADE_DATABASE_3_TO_4 ${CMAKE_SOURCE_DIR}/Sources/Database/Upgrade3To4.sql - UPGRADE_DATABASE_4_TO_5 ${CMAKE_SOURCE_DIR}/Sources/Database/Upgrade4To5.sql - INSTALL_REVISION_AND_CUSTOM_DATA - ${CMAKE_SOURCE_DIR}/Sources/Database/InstallRevisionAndCustomData.sql - - INSTALL_TRACK_ATTACHMENTS_SIZE - ${CMAKE_SOURCE_DIR}/Sources/Database/InstallTrackAttachmentsSize.sql + CONFIGURATION_SAMPLE ${CMAKE_SOURCE_DIR}/Resources/Configuration.json + DICOM_CONFORMANCE_STATEMENT ${CMAKE_SOURCE_DIR}/Resources/DicomConformanceStatement.txt + FONT_UBUNTU_MONO_BOLD_16 ${CMAKE_SOURCE_DIR}/Resources/Fonts/UbuntuMonoBold-16.json + LUA_TOOLBOX ${CMAKE_SOURCE_DIR}/Resources/Toolbox.lua + PREPARE_DATABASE ${CMAKE_SOURCE_DIR}/Sources/Database/PrepareDatabase.sql + UPGRADE_DATABASE_3_TO_4 ${CMAKE_SOURCE_DIR}/Sources/Database/Upgrade3To4.sql + UPGRADE_DATABASE_4_TO_5 ${CMAKE_SOURCE_DIR}/Sources/Database/Upgrade4To5.sql + INSTALL_TRACK_ATTACHMENTS_SIZE ${CMAKE_SOURCE_DIR}/Sources/Database/InstallTrackAttachmentsSize.sql + INSTALL_LABELS_TABLE ${CMAKE_SOURCE_DIR}/Sources/Database/InstallLabelsTable.sql + INSTALL_REVISION_AND_CUSTOM_DATA ${CMAKE_SOURCE_DIR}/Sources/Database/InstallRevisionAndCustomData.sql ) if (STANDALONE_BUILD) @@ -284,6 +291,7 @@ ##################################################################### check_symbol_exists(mallopt "malloc.h" HAVE_MALLOPT) +check_symbol_exists(malloc_trim "malloc.h" HAVE_MALLOC_TRIM) if (HAVE_MALLOPT) add_definitions(-DHAVE_MALLOPT=1) @@ -291,6 +299,11 @@ add_definitions(-DHAVE_MALLOPT=0) endif() +if (HAVE_MALLOC_TRIM) + add_definitions(-DHAVE_MALLOC_TRIM=1) +else() + add_definitions(-DHAVE_MALLOC_TRIM=0) +endif() if (STATIC_BUILD) add_definitions(-DORTHANC_STATIC=1) @@ -316,13 +329,9 @@ add_definitions( -DORTHANC_BUILD_UNIT_TESTS=1 -DORTHANC_BUILDING_SERVER_LIBRARY=1 - + # Macros for the plugins -DHAS_ORTHANC_EXCEPTION=0 - -DMODALITY_WORKLISTS_VERSION="${ORTHANC_VERSION}" - -DSERVE_FOLDERS_VERSION="${ORTHANC_VERSION}" - -DHOUSEKEEPER_VERSION="${ORTHANC_VERSION}" - -DADVANCED_STORAGE_VERSION="${ORTHANC_VERSION}" ) @@ -334,7 +343,7 @@ if (MSVC) add_definitions(-DORTHANC_USE_PRECOMPILED_HEADERS=1) - + set(TMP ${ORTHANC_CORE_SOURCES_INTERNAL} ${ORTHANC_DICOM_SOURCES_INTERNAL} @@ -359,8 +368,13 @@ ## Build the core of Orthanc ##################################################################### +add_custom_target(AutogeneratedTarget + DEPENDS + ${AUTOGENERATED_SOURCES} + ) + # "CoreLibrary" contains all the third-party dependencies and the -# content of the "Core" folder +# content of the "OrthancFramework" folder add_library(CoreLibrary STATIC ${ORTHANC_CORE_PCH} @@ -369,6 +383,10 @@ ${AUTOGENERATED_SOURCES} ) +DefineSourceBasenameForTarget(CoreLibrary) + +add_dependencies(CoreLibrary AutogeneratedTarget) + if (LIBICU_LIBRARIES) target_link_libraries(CoreLibrary ${LIBICU_LIBRARIES}) endif() @@ -378,20 +396,51 @@ ## Build the Orthanc server ##################################################################### +if (ENABLE_PLUGINS) + add_custom_command( + COMMAND + ${PROTOC_EXECUTABLE} ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancDatabasePlugin.proto --cpp_out=${AUTOGENERATED_DIR} -I${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc + COMMAND + ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/Resources/PreventProtobufDirectoryLeaks.py ${AUTOGENERATED_DIR}/OrthancDatabasePlugin.pb.cc + DEPENDS + ProtobufCompiler + ${CMAKE_SOURCE_DIR}/Resources/PreventProtobufDirectoryLeaks.py + ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancDatabasePlugin.proto + OUTPUT + ${AUTOGENERATED_DIR}/OrthancDatabasePlugin.pb.cc + ${AUTOGENERATED_DIR}/OrthancDatabasePlugin.pb.h + ) + + add_custom_target(OrthancDatabaseProtobuf + DEPENDS + ${AUTOGENERATED_DIR}/OrthancDatabasePlugin.pb.h + ) + + list(APPEND ORTHANC_SERVER_SOURCES + ${AUTOGENERATED_DIR}/OrthancDatabasePlugin.pb.cc + ) +else() + add_custom_target(OrthancDatabaseProtobuf) +endif() + add_library(ServerLibrary STATIC ${ORTHANC_SERVER_PCH} ${ORTHANC_SERVER_SOURCES} ) +DefineSourceBasenameForTarget(ServerLibrary) + # Ensure autogenerated code is built before building ServerLibrary -add_dependencies(ServerLibrary CoreLibrary) +add_dependencies(ServerLibrary CoreLibrary OrthancDatabaseProtobuf) add_executable(Orthanc ${CMAKE_SOURCE_DIR}/Sources/main.cpp ${ORTHANC_RESOURCES} ) +DefineSourceBasenameForTarget(Orthanc) + target_link_libraries(Orthanc ServerLibrary CoreLibrary ${DCMTK_LIBRARIES}) if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") @@ -422,6 +471,8 @@ ${BOOST_EXTENDED_SOURCES} ) +DefineSourceBasenameForTarget(UnitTests) + target_link_libraries(UnitTests ServerLibrary CoreLibrary @@ -431,28 +482,52 @@ ##################################################################### -## Build a static library to share code between the plugins +## Static library to share third-party libraries between the plugins ##################################################################### if (ENABLE_PLUGINS AND - (BUILD_SERVE_FOLDERS OR BUILD_MODALITY_WORKLISTS OR BUILD_HOUSEKEEPER OR BUILD_ADVANCED_STORAGE)) - add_library(ThirdPartyPlugins STATIC + (BUILD_SERVE_FOLDERS OR BUILD_MODALITY_WORKLISTS OR BUILD_HOUSEKEEPER OR + BUILD_DELAYED_DELETION OR BUILD_MULTITENANT_DICOM OR BUILD_ADVANCED_STORAGE)) + set(PLUGINS_DEPENDENCIES_SOURCES ${BOOST_SOURCES} ${JSONCPP_SOURCES} ${LIBICONV_SOURCES} ${LIBICU_SOURCES} + ${PUGIXML_SOURCES} + ${UUID_SOURCES} + ${ZLIB_SOURCES} + + ${CMAKE_SOURCE_DIR}/../OrthancFramework/Resources/ThirdParty/base64/base64.cpp + ${CMAKE_SOURCE_DIR}/../OrthancFramework/Resources/ThirdParty/md5/md5.c Plugins/Samples/Common/OrthancPluginCppWrapper.cpp ) - if (LIBICU_LIBRARIES) - target_link_libraries(ThirdPartyPlugins ${LIBICU_LIBRARIES}) + if (BUILD_DELAYED_DELETION) + list(APPEND PLUGINS_DEPENDENCIES_SOURCES + ${SQLITE_SOURCES} + ) endif() + + if (BUILD_MULTITENANT_DICOM) + list(APPEND PLUGINS_DEPENDENCIES_SOURCES + ${DCMTK_SOURCES} + ${OPENSSL_SOURCES} + ${LIBJPEG_SOURCES} + ${LIBPNG_SOURCES} + ) + endif() + + add_library(PluginsDependencies STATIC + ${PLUGINS_DEPENDENCIES_SOURCES} + ) + + DefineSourceBasenameForTarget(PluginsDependencies) # Add the "-fPIC" option as this static library must be embedded # inside shared libraries (important on UNIX) - set_property( - TARGET ThirdPartyPlugins - PROPERTY POSITION_INDEPENDENT_CODE ON + set_target_properties( + PluginsDependencies + PROPERTIES POSITION_INDEPENDENT_CODE ON ) endif() @@ -478,12 +553,19 @@ list(APPEND SERVE_FOLDERS_RESOURCES ${AUTOGENERATED_DIR}/ServeFolders.rc) endif() + set_source_files_properties( + ${CMAKE_SOURCE_DIR}/Plugins/Samples/ServeFolders/Plugin.cpp + PROPERTIES COMPILE_DEFINITIONS "SERVE_FOLDERS_VERSION=\"${ORTHANC_VERSION}\"" + ) + add_library(ServeFolders SHARED ${CMAKE_SOURCE_DIR}/Plugins/Samples/ServeFolders/Plugin.cpp ${SERVE_FOLDERS_RESOURCES} ) - target_link_libraries(ServeFolders ThirdPartyPlugins) + DefineSourceBasenameForTarget(ServeFolders) + + target_link_libraries(ServeFolders PluginsDependencies) set_target_properties( ServeFolders PROPERTIES @@ -521,12 +603,19 @@ list(APPEND MODALITY_WORKLISTS_RESOURCES ${AUTOGENERATED_DIR}/ModalityWorklists.rc) endif() + set_source_files_properties( + ${CMAKE_SOURCE_DIR}/Plugins/Samples/ModalityWorklists/Plugin.cpp + PROPERTIES COMPILE_DEFINITIONS "MODALITY_WORKLISTS_VERSION=\"${ORTHANC_VERSION}\"" + ) + add_library(ModalityWorklists SHARED ${CMAKE_SOURCE_DIR}/Plugins/Samples/ModalityWorklists/Plugin.cpp ${MODALITY_WORKLISTS_RESOURCES} ) - target_link_libraries(ModalityWorklists ThirdPartyPlugins) + DefineSourceBasenameForTarget(ModalityWorklists) + + target_link_libraries(ModalityWorklists PluginsDependencies) set_target_properties( ModalityWorklists PROPERTIES @@ -542,80 +631,67 @@ endif() -if (ENABLE_PLUGINS AND (BUILD_DELAYED_DELETION OR BUILD_CONNECTIVITY_CHECKS)) - include(ExternalProject) - -endif() - ##################################################################### ## Build the "ConnectivityChecks" plugin ##################################################################### if (ENABLE_PLUGINS AND BUILD_CONNECTIVITY_CHECKS) - - set(ConnectivityChecksFlags) - - if (CMAKE_TOOLCHAIN_FILE) - # Take absolute path to the toolchain - get_filename_component(TMP ${CMAKE_TOOLCHAIN_FILE} REALPATH BASE ${CMAKE_SOURCE_DIR}) - list(APPEND ConnectivityChecksFlags -DCMAKE_TOOLCHAIN_FILE=${TMP}) - endif() - - if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - list(APPEND ConnectivityChecksFlags - -DLSB_CC=${CMAKE_LSB_CC} - -DLSB_CXX=${CMAKE_LSB_CXX} + if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + execute_process( + COMMAND + ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/../OrthancFramework/Resources/WindowsResources.py + ${ORTHANC_VERSION} ConnectivityChecks ConnectivityChecks.dll "Orthanc plugin to show connectivity status" + ERROR_VARIABLE Failure + OUTPUT_FILE ${AUTOGENERATED_DIR}/ConnectivityChecks.rc ) + + if (Failure) + message(FATAL_ERROR "Error while computing the version information: ${Failure}") + endif() + + list(APPEND CONNECTIVITY_CHECKS_RESOURCES ${AUTOGENERATED_DIR}/ConnectivityChecks.rc) endif() - externalproject_add(ConnectivityChecks - SOURCE_DIR "${CMAKE_SOURCE_DIR}/Plugins/Samples/ConnectivityChecks" - - # We explicitly provide a build directory, in order to avoid paths - # that are too long on our Visual Studio 2008 CIS - BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/ConnectivityChecks-build" - - # this helps triggering build when changing the external project - BUILD_ALWAYS 1 - - CMAKE_ARGS - -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} - -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR} - -DPLUGIN_VERSION=${ORTHANC_VERSION} - -DSTATIC_BUILD=${STATIC_BUILD} - -DALLOW_DOWNLOADS=${ALLOW_DOWNLOADS} - -DUSE_SYSTEM_BOOST=${USE_SYSTEM_BOOST} - -DUSE_LEGACY_JSONCPP=${USE_LEGACY_JSONCPP} - -DUSE_LEGACY_BOOST=${USE_LEGACY_BOOST} - ${ConnectivityChecksFlags} - - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} - -DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} - -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} + include(${CMAKE_SOURCE_DIR}/Plugins/Samples/ConnectivityChecks/JavaScriptLibraries.cmake) + + EmbedResources( + --target=ConnectivityChecksResources + --framework-path=${CMAKE_SOURCE_DIR}/../OrthancFramework/Sources + WEB_RESOURCES ${CMAKE_SOURCE_DIR}/Plugins/Samples/ConnectivityChecks/WebResources + LIBRARIES ${CONNECTIVITY_CHECKS_JAVASCRIPT_DIR} ) - if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - if (MSVC) - set(Prefix "") - else() - set(Prefix "lib") # MinGW - endif() + set_source_files_properties( + ${CMAKE_SOURCE_DIR}/Plugins/Samples/ConnectivityChecks/Plugin.cpp + PROPERTIES COMPILE_DEFINITIONS "ORTHANC_PLUGIN_NAME=\"connectivity-checks\";ORTHANC_PLUGIN_VERSION=\"${ORTHANC_VERSION}\"" + ) + + # The "OrthancFrameworkDependencies.cpp" file is used to bypass the + # precompiled headers if compiling with Visual Studio + add_library(ConnectivityChecks SHARED + ${AUTOGENERATED_DIR}/ConnectivityChecksResources.cpp + ${CMAKE_SOURCE_DIR}/Plugins/Samples/ConnectivityChecks/Plugin.cpp + + ${CMAKE_SOURCE_DIR}/Plugins/Samples/ConnectivityChecks/OrthancFrameworkDependencies.cpp + ${CONNECTIVITY_CHECKS_RESOURCES} + ) - install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/${Prefix}ConnectivityChecks.dll - DESTINATION "lib") - else() - list(GET CMAKE_FIND_LIBRARY_PREFIXES 0 Prefix) - list(GET CMAKE_FIND_LIBRARY_SUFFIXES 0 Suffix) - install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/${Prefix}ConnectivityChecks${Suffix} - ${CMAKE_CURRENT_BINARY_DIR}/${Prefix}ConnectivityChecks${Suffix}.${ORTHANC_VERSION} - DESTINATION "share/orthanc/plugins") - endif() + DefineSourceBasenameForTarget(ConnectivityChecks) + + target_link_libraries(ConnectivityChecks PluginsDependencies) + + set_target_properties( + ConnectivityChecks PROPERTIES + VERSION ${ORTHANC_VERSION} + SOVERSION ${ORTHANC_VERSION} + ) + + install( + TARGETS ConnectivityChecks + RUNTIME DESTINATION lib # Destination for Windows + LIBRARY DESTINATION share/orthanc/plugins # Destination for Linux + ) endif() @@ -624,69 +700,52 @@ ##################################################################### if (ENABLE_PLUGINS AND BUILD_DELAYED_DELETION) - - set(DelayedDeletionFlags) - - if (CMAKE_TOOLCHAIN_FILE) - # Take absolute path to the toolchain - get_filename_component(TMP ${CMAKE_TOOLCHAIN_FILE} REALPATH BASE ${CMAKE_SOURCE_DIR}) - list(APPEND DelayedDeletionFlags -DCMAKE_TOOLCHAIN_FILE=${TMP}) - endif() - - if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - list(APPEND DelayedDeletionFlags - -DLSB_CC=${CMAKE_LSB_CC} - -DLSB_CXX=${CMAKE_LSB_CXX} + if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + execute_process( + COMMAND + ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/../OrthancFramework/Resources/WindowsResources.py + ${ORTHANC_VERSION} DelayedDeletion DelayedDeletion.dll "Orthanc plugin to delay deletion of files" + ERROR_VARIABLE Failure + OUTPUT_FILE ${AUTOGENERATED_DIR}/DelayedDeletion.rc ) + + if (Failure) + message(FATAL_ERROR "Error while computing the version information: ${Failure}") + endif() + + list(APPEND DELAYED_DELETION_RESOURCES ${AUTOGENERATED_DIR}/DelayedDeletion.rc) endif() - externalproject_add(DelayedDeletion - SOURCE_DIR "${CMAKE_SOURCE_DIR}/Plugins/Samples/DelayedDeletion" - - # We explicitly provide a build directory, in order to avoid paths - # that are too long on our Visual Studio 2008 CIS - BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/DelayedDeletion-build" - - # this helps triggering build when changing the external project - BUILD_ALWAYS 1 - - CMAKE_ARGS - -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} - -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR} - -DPLUGIN_VERSION=${ORTHANC_VERSION} - -DSTATIC_BUILD=${STATIC_BUILD} - -DALLOW_DOWNLOADS=${ALLOW_DOWNLOADS} - -DUSE_SYSTEM_BOOST=${USE_SYSTEM_BOOST} - -DUSE_LEGACY_JSONCPP=${USE_LEGACY_JSONCPP} - -DUSE_LEGACY_BOOST=${USE_LEGACY_BOOST} - ${DelayedDeletionFlags} - - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} - -DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} - -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} + set_source_files_properties( + ${CMAKE_SOURCE_DIR}/Plugins/Samples/DelayedDeletion/Plugin.cpp + PROPERTIES COMPILE_DEFINITIONS "ORTHANC_PLUGIN_NAME=\"delayed-deletion\";ORTHANC_PLUGIN_VERSION=\"${ORTHANC_VERSION}\"" ) - if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - if (MSVC) - set(Prefix "") - else() - set(Prefix "lib") # MinGW - endif() + # The "OrthancFrameworkDependencies.cpp" file is used to bypass the + # precompiled headers if compiling with Visual Studio + add_library(DelayedDeletion SHARED + ${CMAKE_SOURCE_DIR}/Plugins/Samples/DelayedDeletion/PendingDeletionsDatabase.cpp + ${CMAKE_SOURCE_DIR}/Plugins/Samples/DelayedDeletion/Plugin.cpp + + ${CMAKE_SOURCE_DIR}/Plugins/Samples/DelayedDeletion/OrthancFrameworkDependencies.cpp + ${DELAYED_DELETION_RESOURCES} + ) + + DefineSourceBasenameForTarget(DelayedDeletion) - install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/${Prefix}DelayedDeletion.dll - DESTINATION "lib") - else() - list(GET CMAKE_FIND_LIBRARY_PREFIXES 0 Prefix) - list(GET CMAKE_FIND_LIBRARY_SUFFIXES 0 Suffix) - install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/${Prefix}DelayedDeletion${Suffix} - ${CMAKE_CURRENT_BINARY_DIR}/${Prefix}DelayedDeletion${Suffix}.${ORTHANC_VERSION} - DESTINATION "share/orthanc/plugins") - endif() + target_link_libraries(DelayedDeletion PluginsDependencies) + + set_target_properties( + DelayedDeletion PROPERTIES + VERSION ${ORTHANC_VERSION} + SOVERSION ${ORTHANC_VERSION} + ) + + install( + TARGETS DelayedDeletion + RUNTIME DESTINATION lib # Destination for Windows + LIBRARY DESTINATION share/orthanc/plugins # Destination for Linux + ) endif() @@ -711,14 +770,19 @@ list(APPEND HOUSEKEEPER_RESOURCES ${AUTOGENERATED_DIR}/Housekeeper.rc) endif() + set_source_files_properties( + ${CMAKE_SOURCE_DIR}/Plugins/Samples/Housekeeper/Plugin.cpp + PROPERTIES COMPILE_DEFINITIONS "HOUSEKEEPER_VERSION=\"${ORTHANC_VERSION}\"" + ) + add_library(Housekeeper SHARED ${CMAKE_SOURCE_DIR}/Plugins/Samples/Housekeeper/Plugin.cpp ${HOUSEKEEPER_RESOURCES} ) - target_link_libraries(Housekeeper - ThirdPartyPlugins - ) + DefineSourceBasenameForTarget(Housekeeper) + + target_link_libraries(Housekeeper PluginsDependencies) set_target_properties( Housekeeper PROPERTIES @@ -739,69 +803,120 @@ ##################################################################### if (ENABLE_PLUGINS AND BUILD_ADVANCED_STORAGE) - - set(AdvancedStorageFlags) + if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + execute_process( + COMMAND + ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/../OrthancFramework/Resources/WindowsResources.py + ${ORTHANC_VERSION} AdvancedStorage AdvancedStorage.dll "Orthanc plugin to provide advanced file storage" + ERROR_VARIABLE Failure + OUTPUT_FILE ${AUTOGENERATED_DIR}/AdvancedStorage.rc + ) - if (CMAKE_TOOLCHAIN_FILE) - # Take absolute path to the toolchain - get_filename_component(TMP ${CMAKE_TOOLCHAIN_FILE} REALPATH BASE ${CMAKE_SOURCE_DIR}) - list(APPEND AdvancedStorageFlags -DCMAKE_TOOLCHAIN_FILE=${TMP}) - endif() + if (Failure) + message(FATAL_ERROR "Error while computing the version information: ${Failure}") + endif() - if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - list(APPEND AdvancedStorageFlags - -DLSB_CC=${CMAKE_LSB_CC} - -DLSB_CXX=${CMAKE_LSB_CXX} - ) + list(APPEND ADVANCED_STORAGE_RESOURCES ${AUTOGENERATED_DIR}/AdvancedStorage.rc) endif() - externalproject_add(AdvancedStorage - SOURCE_DIR "${CMAKE_SOURCE_DIR}/Plugins/Samples/AdvancedStorage" - - # We explicitly provide a build directory, in order to avoid paths - # that are too long on our Visual Studio 2008 CIS - BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/AdvancedStorage-build" - - # this helps triggering build when changing the external project - BUILD_ALWAYS 1 + set_source_files_properties( + ${CMAKE_SOURCE_DIR}/Plugins/Samples/AdvancedStorage/Plugin.cpp + PROPERTIES COMPILE_DEFINITIONS "ADVANCED_STORAGE_VERSION=\"${ORTHANC_VERSION}\"" + ) - CMAKE_ARGS - -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} - -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR} - -DPLUGIN_VERSION=${ORTHANC_VERSION} - -DSTATIC_BUILD=${STATIC_BUILD} - -DALLOW_DOWNLOADS=${ALLOW_DOWNLOADS} - -DUSE_SYSTEM_BOOST=${USE_SYSTEM_BOOST} - -DUSE_LEGACY_JSONCPP=${USE_LEGACY_JSONCPP} - -DUSE_LEGACY_BOOST=${USE_LEGACY_BOOST} - ${AdvancedStorageFlags} - - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} - -DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} - -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} + add_library(AdvancedStorage SHARED + ${CMAKE_SOURCE_DIR}/Plugins/Samples/AdvancedStorage/Plugin.cpp + ${ORTHANC} + ${CMAKE_SOURCE_DIR}/../OrthancFramework/Sources/OrthancException.cpp + ${CMAKE_SOURCE_DIR}/../OrthancFramework/Sources/SystemToolbox.cpp + ${CMAKE_SOURCE_DIR}/../OrthancFramework/Sources/Toolbox.cpp + ${CMAKE_SOURCE_DIR}/../OrthancFramework/Sources/Logging.cpp + ${CMAKE_SOURCE_DIR}/../OrthancFramework/Sources/ChunkedBuffer.cpp + ${CMAKE_SOURCE_DIR}/../OrthancFramework/Sources/Enumerations.cpp ) + DefineSourceBasenameForTarget(AdvancedStorage) + + target_link_libraries(AdvancedStorage PluginsDependencies) + + set_target_properties( + AdvancedStorage PROPERTIES + VERSION ${ORTHANC_VERSION} + SOVERSION ${ORTHANC_VERSION} + ) + + install( + TARGETS AdvancedStorage + RUNTIME DESTINATION lib # Destination for Windows + LIBRARY DESTINATION share/orthanc/plugins # Destination for Linux + ) +endif() + +##################################################################### +## Build the "MultitenantDicom" plugin +##################################################################### + +if (ENABLE_PLUGINS AND BUILD_MULTITENANT_DICOM) if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - if (MSVC) - set(Prefix "") - else() - set(Prefix "lib") # MinGW + execute_process( + COMMAND + ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/../OrthancFramework/Resources/WindowsResources.py + ${ORTHANC_VERSION} MultitenantDicom MultitenantDicom.dll "Orthanc plugin to provide a multitenant DICOM server" + ERROR_VARIABLE Failure + OUTPUT_FILE ${AUTOGENERATED_DIR}/MultitenantDicom.rc + ) + + if (Failure) + message(FATAL_ERROR "Error while computing the version information: ${Failure}") endif() + + list(APPEND MULTITENANT_DICOM_RESOURCES ${AUTOGENERATED_DIR}/MultitenantDicom.rc) + endif() - install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/${Prefix}AdvancedStorage.dll - DESTINATION "lib") - else() - list(GET CMAKE_FIND_LIBRARY_PREFIXES 0 Prefix) - list(GET CMAKE_FIND_LIBRARY_SUFFIXES 0 Suffix) - install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/${Prefix}AdvancedStorage${Suffix} - ${CMAKE_CURRENT_BINARY_DIR}/${Prefix}AdvancedStorage${Suffix}.${ORTHANC_VERSION} - DESTINATION "share/orthanc/plugins") - endif() + EmbedResources( + --target=MultitenantDicomResources + --namespace=Orthanc.FrameworkResources + --framework-path=${CMAKE_SOURCE_DIR}/../OrthancFramework/Sources + ${LIBICU_RESOURCES} + ${DCMTK_DICTIONARIES} + ) + + set_source_files_properties( + ${CMAKE_SOURCE_DIR}/Plugins/Samples/MultitenantDicom/Plugin.cpp + PROPERTIES COMPILE_DEFINITIONS "ORTHANC_PLUGIN_VERSION=\"${ORTHANC_VERSION}\"" + ) + + # The "OrthancFrameworkDependencies.cpp" file is used to bypass the + # precompiled headers if compiling with Visual Studio + add_library(MultitenantDicom SHARED + ${CMAKE_SOURCE_DIR}/Plugins/Samples/MultitenantDicom/DicomFilter.cpp + ${CMAKE_SOURCE_DIR}/Plugins/Samples/MultitenantDicom/FindRequestHandler.cpp + ${CMAKE_SOURCE_DIR}/Plugins/Samples/MultitenantDicom/MoveRequestHandler.cpp + ${CMAKE_SOURCE_DIR}/Plugins/Samples/MultitenantDicom/MultitenantDicomServer.cpp + ${CMAKE_SOURCE_DIR}/Plugins/Samples/MultitenantDicom/Plugin.cpp + ${CMAKE_SOURCE_DIR}/Plugins/Samples/MultitenantDicom/PluginToolbox.cpp + ${CMAKE_SOURCE_DIR}/Plugins/Samples/MultitenantDicom/StoreRequestHandler.cpp + + ${CMAKE_SOURCE_DIR}/Plugins/Samples/MultitenantDicom/OrthancFrameworkDependencies.cpp + ${AUTOGENERATED_DIR}/MultitenantDicomResources.cpp + ${MULTITENANT_DICOM_RESOURCES} + ) + + DefineSourceBasenameForTarget(MultitenantDicom) + + target_link_libraries(MultitenantDicom PluginsDependencies ${DCMTK_LIBRARIES}) + + set_target_properties( + MultitenantDicom PROPERTIES + VERSION ${ORTHANC_VERSION} + SOVERSION ${ORTHANC_VERSION} + ) + + install( + TARGETS MultitenantDicom + RUNTIME DESTINATION lib # Destination for Windows + LIBRARY DESTINATION share/orthanc/plugins # Destination for Linux + ) endif() @@ -834,6 +949,7 @@ endif() add_executable(OrthancRecoverCompressedFile ${RECOVER_COMPRESSED_SOURCES}) + DefineSourceBasenameForTarget(OrthancRecoverCompressedFile) target_link_libraries(OrthancRecoverCompressedFile CoreLibrary) @@ -890,8 +1006,9 @@ if (ENABLE_PLUGINS) install( FILES - ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancCPlugin.h - ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancCDatabasePlugin.h + ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancCPlugin.h + ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancCDatabasePlugin.h + ${CMAKE_SOURCE_DIR}/Plugins/Include/orthanc/OrthancDatabasePlugin.proto DESTINATION include/orthanc ) endif() diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancServer/OrthancExplorer/explorer.css --- a/OrthancServer/OrthancExplorer/explorer.css Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancServer/OrthancExplorer/explorer.css Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -63,3 +64,22 @@ .switch-container .ui-slider-switch { width: 100%; } + +.label { + display: inline-block; + background-color: gray; + margin: 5px; + padding: 5px; + border-radius: 10px; +} + +.label button { + background-color: transparent; + border: 0px; + cursor: pointer; + border-radius: 10px; +} + +.label button:hover { + background-color: lightgray; +} diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancServer/OrthancExplorer/explorer.html --- a/OrthancServer/OrthancExplorer/explorer.html Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancServer/OrthancExplorer/explorer.html Tue Sep 24 11:39:52 2024 +0200 @@ -81,6 +81,11 @@ +
+ + +
+
+
diff -r 79f98ee4f04b -r 8279eaab0d1d OrthancServer/OrthancExplorer/explorer.js --- a/OrthancServer/OrthancExplorer/explorer.js Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancServer/OrthancExplorer/explorer.js Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -65,6 +66,12 @@ var MODIFIED_FROM = 'ModifiedFrom'; +function IsAlphanumeric(s) +{ + return s.match(/^[0-9a-zA-Z]+$/); +} + + function DeepCopy(obj) { return jQuery.extend(true, {}, obj); @@ -479,6 +486,14 @@ } else { $('.warning-insecure').hide(); } + + // New in Orthanc 1.12.0 + if ('HasLabels' in s && + s.HasLabels) { + $('#lookup-study-labels-div').show(); + } else { + $('#lookup-study-labels-div').hide(); + } } }); }); @@ -550,6 +565,10 @@ else if (input.id == 'lookup-study-date-specific') { // Ignore } + else if (input.id == 'lookup-study-labels') { + // New in Orthanc 1.12.0 + lookup['Labels'] = input.value.split(' '); + } else { console.error('Unknown lookup field: ' + input.id); } @@ -696,14 +715,99 @@ $('.' + liClass).remove(); for (var key in attachments) { if (attachments[key] >= 1024) { - target.append('
  • Download ' + key + '
  • ') + target.append('
  • Download attachment "' + key + '"
  • ') } } target.listview('refresh'); }); +} + + +function RefreshLabels(nodeLabels, resourceLevel, resourceId) +{ + GetResource('/' + resourceLevel + '/' + resourceId + '/labels', function(labels) { + nodeLabels.empty(); + + if (labels.length > 0) { + nodeLabels.css('display', 'block'); + + for (var i = 0; i < labels.length; i++) { + var removeButton = $('